home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / other / talkspk / talk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-14  |  17.3 KB  |  849 lines

  1. /*
  2.  * NAME
  3.  *     talk - speak text from the command line or a file
  4.  * 
  5.  * SYNOPSIS
  6.  *     talk [-v] [-] [-f file] [string...]
  7.  * 
  8.  * DESCRIPTION
  9.  *     this program uses speak.tos to speak text from the command line,
  10.  *    one or more files, or stdin. it is a front end to the old speak.tos
  11.  *    program.
  12.  * 
  13.  * NOTES
  14.  *     talk uses two entry points into speak.tos. the process works
  15.  *     as follows: Load speak.tos into memory using the Mode 3 option
  16.  *     of the Pexec GEMDOS call (load/nogo). if successful, this call will
  17.  *     return the address of the base page of the loaded program.
  18.  *     Add 0x100 to this to get the first byte of the executable
  19.  *     code. then create "subroutines" by poking in rts instructions in
  20.  *    the right places. at this point, we can jump into speak.tos,
  21.  *    executing the 2 subroutines. you MUST save registers (not sure
  22.  *    which, i save 'em all) since speak clobbers them. the text to
  23.  *    speak is poked into a Cconrs-like buffer.
  24.  * 
  25.  *    here are the addresses (relative to start of program):
  26.  *
  27.  *        routine 1 start        0x32    (muck with phonemes)
  28.  *        routine 1 rts        0x0e
  29.  *        routine 2 start        0x88    (generate speach)
  30.  *        routine 2 rts        0x6c
  31.  *
  32.  *        input buffer        0x6eee
  33.  *
  34.  *     calling the subroutines for phoneme and speech generation is
  35.  *     currently done in c_speak.s which also saves all the registers prior
  36.  *     to making the actual calls. i tried this in C and it failed. you
  37.  *    really need to save registers and i don't know a way to do that
  38.  *    without using assembler somehow (inline __asm__ or routine). note
  39.  *    that the inline assembler code in speak_line() has not been tested
  40.  *    and is for GNU C anyway.
  41.  *
  42.  *    talk looks for speak.tos in the current directory, with environment
  43.  *    variable SPEAK or via the path.
  44.  *
  45.  *    it would be nice to beef up the clean_line() function to remove
  46.  *    non-letters and perhaps fix things like numbers, acronyms, etc.
  47.  *
  48.  * ABOUT SPEAK.TOS
  49.  *    i know little of its history. it has a limited user interface, so
  50.  *    i know it got hacked up (like this here) for other uses. i picked
  51.  *    this up on compuserve ages ago. if you think you may have it but
  52.  *    the name has changed, here are some facts:
  53.  *
  54.  *    sum speak.tos            56759 28
  55.  *    ls -l speak.tos            28416 bytes
  56.  *    strings -5 speak.tos turned up:
  57.  *
  58.  *        Atari 520ST speech synthesizer V2.0
  59.  *
  60.  *        MC68000/AY-3-8910 SPEECH SYNTHERSIZER V:2.0
  61.  *        Copyright 1986 A.D.BEVERIDGE & M.N.DAY
  62.  *        ALL RIGHTS RESERVED.
  63.  *
  64.  *    so i guess it can't be used commercially.
  65.  *
  66.  * RELEASE NOTES
  67.  *    hacked together, originally in alcyon and now GNU C by:
  68.  *    Bill Rosenkranz, 1989? through 14 sep 1991
  69.  *    rosenkra@convex.com
  70.  *
  71.  *    my last source mod dates from 18 sep 1990
  72.  */
  73.  
  74.  
  75. #ifndef lint
  76. static char *rcsid_talk_c = "$Id: talk.c,v 2.1 1991/09/14 21:13:34 rosenkra Exp $";
  77. #endif /*lint*/
  78.  
  79. /*
  80.  * $Log: talk.c,v $
  81.  * Revision 2.1  1991/09/14  21:13:34  rosenkra
  82.  * clean up for release to atari.archive.
  83.  *
  84.  * Revision 2.0  1991/09/14  15:52:28  rosenkra
  85.  * GNU C version. improved user interface (stdin, file(s), and cmdline;
  86.  * search cwd, env, and PATH for speak, etc). also has inline assembly
  87.  * for c_speak.s, but is still untested. includes which() function
  88.  * which functions like which(1) only it can use any env variable (not
  89.  * just PATH) and any of a pool of path name seperators.
  90.  *
  91.  * Revision 1.0  1991/09/14  01:51:22  rosenkra
  92.  * Initial revision
  93.  *
  94.  */
  95.  
  96.  
  97. #include <stdio.h>
  98. #include <stdlib.h>        /* for getenv() */
  99. #include <strings.h>        /* for str*() */
  100. #include <osbind.h>        /* for Pexec */
  101. #ifdef HAS_ACCESS
  102. #include <unistd.h>        /* for access() */
  103. #endif /*HAS_ACCESS*/
  104.  
  105. /*
  106.  *    name of the speak program
  107.  */
  108. #define SPEAK_PROG    "speak.tos"
  109.  
  110. #ifdef DBG
  111. # undef DBG
  112. #endif
  113. #ifdef DEBUG
  114. # define DBG(x)        printf x
  115. #else
  116. # define DBG(x)
  117. #endif
  118.  
  119. #ifdef MAXLINE
  120. # undef MAXLINE
  121. #endif
  122. #define MAXLINE        256    /* max length of input line (stream or cmd) */
  123.  
  124. #ifndef MAXPATH
  125. # define MAXPATH    256    /* max length of file path */
  126. #endif
  127.  
  128. #ifdef SEARCH_PATH
  129. # define MAXENV        1024    /* max size of env string */
  130. #endif
  131.  
  132. /*
  133.  *    globals:
  134.  */
  135. char    rts[2] = {0x4E, 0x75};        /* patch for subs (68000 rts inst) */
  136. long    program;            /* The base of SPEAK */
  137. char    speak_path[MAXPATH];        /* for path of speak.tos */
  138. char    line_buf[MAXLINE];        /* holds string to speak */
  139. int    verbose = 0;            /* tells what is going on */
  140.  
  141.  
  142. /*
  143.  *    local fcns:
  144.  */
  145. void    usage (void);
  146. void    load_speak_prog (void);
  147. void    speak_line (char *);
  148. void    speak_stream (FILE *);
  149. void    wait_ms (long);
  150. void    c_speak (void);
  151. char   *clean_line (char *);
  152. #ifdef SEARCH_PATH
  153. char   *which (char *, char *, char *);
  154. #endif /*SEARCH_PATH*/
  155.  
  156.  
  157.  
  158. /*------------------------------*/
  159. /*    main            */
  160. /*------------------------------*/
  161. int main (int argc, char *argv[])
  162. {
  163.     FILE   *in;        /* stream if file */
  164.  
  165.  
  166.  
  167.     /*
  168.      *   check first arg for "-v"
  169.      */
  170.     argc--, argv++;
  171.     if ((argv[0][0] == '-') && (argv[0][1] == 'v') && (argv[0][2] == 0))
  172.     {
  173.         verbose = 1;
  174.         argc--, argv++;
  175.     }
  176.  
  177.  
  178.  
  179.     /*
  180.      *   Load in SPEAK and fix it up...if successful, we'll be able
  181.      *   to TELL the user if he made any errors :-)
  182.      */
  183.     load_speak_prog();
  184.  
  185.  
  186.  
  187.     /*
  188.      *   parse command line
  189.      */
  190.     for ( ; argc && (**argv == '-'); argc--, argv++)
  191.     {
  192.         switch (*(*argv+1))
  193.         {
  194.         case 'v':
  195.             if (strncmp (*argv, "-vers", 5) == 0)
  196.             {
  197.                 printf ("%s\n", rcsid_talk_c);
  198.                 exit (0);
  199.             }
  200.             verbose = 1;
  201.             break;
  202.  
  203.         case 'h':
  204.             usage ();
  205.             exit (0);
  206.             break;    /*NOTREACHED*/
  207.  
  208.         case 0:
  209.             speak_stream (stdin);
  210.             break;
  211.  
  212.         case 'f':
  213.              /*
  214.               *   read file
  215.               *
  216.               *   first open it...
  217.               */
  218.             argv++, argc--;
  219.             if (!argc)
  220.             {
  221.                 usage ();
  222.                 exit (1);
  223.             }
  224.             if ((in = fopen (*argv, "r")) == (FILE *) 0L)
  225.             {
  226.                 printf ("talk: could not open data file\n");
  227.                 speak_line ("could not open data file");
  228.                 exit (1);
  229.             }
  230.  
  231.             speak_stream (in);
  232.  
  233.             fclose (in);
  234.             break;
  235.  
  236.         default:
  237.             usage ();
  238.             exit (1);
  239.             break;    /*NOTREACHED*/
  240.         }
  241.     }
  242.  
  243.  
  244.     for ( ; argc && *argv; argc--, argv++)
  245.      {
  246.         /*
  247.          *   copy all words on command line to a buffer. use spaces
  248.          *   between words
  249.          */
  250.         line_buf[0] = '\0';
  251.         while (argc--)
  252.         {
  253.             strcat (line_buf, *argv++);
  254.             strcat (line_buf, " ");
  255.         }
  256.  
  257.  
  258.         /*
  259.          *   do it!
  260.          */
  261.         if (verbose)
  262.             printf ("%s\n", line_buf);
  263.  
  264.         speak_line (line_buf);
  265.     }
  266.  
  267.     exit (0);
  268. }
  269.  
  270.  
  271.  
  272.  
  273. /*------------------------------*/
  274. /*    usage            */
  275. /*------------------------------*/
  276. void usage ()
  277. {
  278. printf ("Usage:   talk [-v] [-] [-f file] [words ...]\n");
  279. printf ("\n");
  280. printf ("-v means verbose and should be first argument (echo line).\n");
  281. printf ("- or -f file must appear before any words on command line.\n");
  282. printf ("can have more than one -f file option and optional words.\n");
  283. printf ("- means read from stdin.\n");
  284. printf ("\n");
  285. printf ("Example: talk -f f1 - -f f2 and now some words\n");
  286. printf ("\n");
  287. printf ("speaks file f1, then stdin, then file f2 then words on command.\n");
  288. }
  289.  
  290.  
  291.  
  292.  
  293. /*------------------------------*/
  294. /*    load_speak_prog        */
  295. /*------------------------------*/
  296. void load_speak_prog ()
  297. {
  298.     long    base;            /* basepage location of loaded speak */
  299.     char   *penv;            /* -> environment variable SPEAK */
  300.     char   *p;
  301. #ifndef HAS_ACCESS
  302.     FILE   *ftest;            /* stream for speak.tos */
  303. #endif /*HAS_ACCESS*/
  304.  
  305.  
  306.     speak_path[0] = 0;
  307.  
  308.  
  309.     /*
  310.      *   find speak.tos. search order:
  311.      *
  312.      *    1) cwd
  313.      *    2) env variable SPEAK contains full path (eg c:\bin\speak.tos)
  314.      *    3) search path
  315.      */
  316. #ifdef HAS_ACCESS
  317.     if (access (SPEAK_PROG, F_OK) >= 0)
  318.     {
  319.         strcpy (speak_path, SPEAK_PROG);
  320.  
  321.         if (verbose)
  322.             printf ("talk: found %s in current directory\n",
  323.                 speak_path);
  324.     }
  325. #else /*! HAS_ACCESS*/
  326.     if ((ftest = fopen (SPEAK_PROG, "r")) != (FILE *) 0L)
  327.     {
  328.         fclose (ftest);
  329.         strcpy (speak_path, SPEAK_PROG);
  330.  
  331.         if (verbose)
  332.             printf ("talk: found %s in current directory\n",
  333.                 speak_path);
  334.     }
  335. #endif /*HAS_ACCESS*/
  336.     else
  337.     {
  338.         if (verbose)
  339.             printf ("talk: %s not in current directory. check env.\n",
  340.                 SPEAK_PROG);
  341.  
  342.         if ((penv = getenv ("SPEAK")) != (char *) NULL)
  343.         {
  344.             strcpy (speak_path, penv);
  345.  
  346.             if (verbose)
  347.                 printf ("found %s from SPEAK env variable.\n",
  348.                     speak_path);
  349.         }
  350. #ifdef SEARCH_PATH
  351.         else
  352.         {
  353.             if (verbose)
  354.                 printf ("talk: cannot find SPEAK in env. Search path.\n");
  355.  
  356.             if ((p = which (SPEAK_PROG, "PATH", ",")) == (char *) NULL)
  357.             {
  358.                 printf ("talk: %s not found in PATH=%s\n",
  359.                     SPEAK_PROG,
  360.                     getenv ("PATH"));
  361. printf ("Either set environment variable SPEAK to the full path of %s\n", SPEAK_PROG);
  362. printf ("or make sure %s is in current directory or in your PATH.\n", SPEAK_PROG);
  363.                  exit(1);
  364.             }
  365.             else
  366.             {
  367.                 strcpy (speak_path, p);
  368.  
  369.                 if (verbose)
  370.                     printf ("talk: found %s from PATH\n",
  371.                         speak_path);
  372.             }
  373.         }
  374. #else /*! SEARCH_PATH*/
  375.         else
  376.         {
  377. printf ("talk: %s not found\n", SPEAK_PROG);
  378. printf ("Either set environment variable SPEAK to the full path of %s\n", SPEAK_PROG);
  379. printf ("or make sure %s is in current directory.\n", SPEAK_PROG);
  380.             exit(1);
  381.         }
  382. #endif /*SEARCH_PATH*/
  383.     }
  384.  
  385.  
  386.  
  387.     /*
  388.      *   do load/nogo
  389.      */
  390.     base = (long) Pexec ((short) 3, (long) speak_path, (long) 0, (long) 0);
  391.     if (base < 0)
  392.     {
  393.         printf ("talk: Pexec failure\n");
  394.         exit (1);
  395.     }
  396.  
  397.  
  398.  
  399.     /*
  400.      *   mark program start 256 bytes after basepage...
  401.      */
  402.     program = (long) (base + 0x00000100L);
  403.  
  404.  
  405.  
  406.     /*
  407.      *   fix the 2 subs by adding returns...
  408.      */
  409.     strncpy ((char *) (program+0x0e), rts, 2);
  410.     strncpy ((char *) (program+0x6c), rts, 2);
  411.  
  412.     return;
  413. }
  414.  
  415.  
  416.  
  417.  
  418. /*------------------------------*/
  419. /*    speak_stream        */
  420. /*------------------------------*/
  421. void speak_stream (FILE *stream)
  422. {
  423.     /*
  424.      *   read lines from stream calling speak_line on every one...
  425.      */
  426.     while (1)
  427.     {
  428.         /*
  429.          *   read a line. speak_line eliminates newline, etc.
  430.          */
  431.         fgets (line_buf, MAXLINE-1, stream);
  432.         if (feof (stream))
  433.         {
  434.             break;
  435.         }
  436.  
  437.  
  438.         /*
  439.          *   do it! (printf allows ^C to terminate)
  440.          */
  441.         if (verbose)
  442.             printf ("%s\n", line_buf);
  443.  
  444.         speak_line (line_buf);
  445.     }
  446.  
  447.     return;
  448. }
  449.  
  450.  
  451.  
  452. /*------------------------------*/
  453. /*    speak_line        */
  454. /*------------------------------*/
  455. void speak_line (char *ps)
  456. {
  457.     register char  *buffer;
  458.     register char  *pstart;
  459.     long        save_ssp;
  460.  
  461.  
  462.  
  463.     /*
  464.      *   clean up the line. clean_line ret NULL if line is empty (ie
  465.      *   devoid of readable text).
  466.      *
  467.      *   this can get more sophisticated.
  468.      */
  469.     if ((pstart = clean_line (ps)) == (char *) NULL)
  470.         return;
  471.  
  472.  
  473.  
  474.     /*
  475.      *   check for nothing to say...
  476.      */
  477.     if (strlen (pstart) == 0)
  478.         return;
  479.  
  480.  
  481.  
  482.     /*
  483.      *   force the length of the the string not to exceed 125
  484.      */
  485.     pstart[125] = '\0';
  486.  
  487.  
  488.  
  489.     /*
  490.      *   note location of speak.tos input buffer
  491.      */
  492.     buffer = (char *) (program + 0x6EEEL);
  493.  
  494.  
  495.  
  496.     /*
  497.      *   this is a Cconrs-type buffer so our string has to be modified
  498.      *   by having the first byte the length of the buffer and the second
  499.      *   the length of the actual string. we copy directly to speak.tos
  500.      *   buffer here...
  501.      */
  502.     strcpy (buffer+2, pstart);        /* data to speak */
  503.     *(buffer+1) = strlen (pstart);        /* and its length */
  504.     *buffer     = (char) 0xFE;        /* size of entire buffer */
  505.  
  506.  
  507.  
  508.     /* 
  509.      *   SPEAK will respeak the last line if the current
  510.      *   input line is a '\n'. The '\n' is replaced by a 
  511.      *   space to defeat this redundant speech on double spaced
  512.      *   files.
  513.      */
  514.     if (!*(buffer+1))
  515.     {
  516.         buffer[1] = (char) 1;
  517.         buffer[2] = ' ';
  518.         buffer[3] = '\0';
  519.     }
  520.  
  521.  
  522.  
  523.     /*
  524.      *   Call speak.
  525.      */
  526. #if defined(__GNUC__) && defined(INLINE_ASM)
  527.     __asm__ volatile                        \
  528.     ("\
  529.         movml    d0-d7/a0-a6,sp@-;    /* save all regs */    \
  530.         moveq    #50,d0;                        \
  531.         addl    %0,d0;                        \
  532.         movel    d0,a2;                        \
  533.         jbsr    a2@;                        \
  534.         moveq    #136,d0;                    \
  535.         addl    %0,d0;                        \
  536.         movel    d0,a2;                        \
  537.         jbsr    a2@;                        \
  538.         movml    sp@+, d0-d7/a0-a6"                \
  539.     :                    /* outputs */        \
  540.     : "g"(program)                /* inputs */        \
  541.     : "d0", "a2"                /* clobbered regs */    \
  542.     );
  543. #else
  544.     c_speak ();
  545. #endif /*__GNUC__&&INLINE_ASM*/
  546.  
  547.  
  548.  
  549.     /*
  550.      *   slight delay...then return. delay is needed to make a smooth
  551.      *   transition between continued lines. delay is in milliseconds.
  552.      */
  553. #ifdef NEED_DELAY
  554.     wait_ms (200L);
  555. #endif /*NEED_DELAY*/
  556.  
  557.     return;
  558. }
  559.  
  560.  
  561.  
  562. /*------------------------------*/
  563. /*    clean_line        */
  564. /*------------------------------*/
  565. char *clean_line (char *ps)
  566. {
  567.  
  568. /*
  569.  *    here we can get more sophisticated than this. we only kill newlines
  570.  *    and leading/trailing whitespace but could also delete punctuation,
  571.  *    expand numbers, abbreviations, etc.
  572.  */
  573.  
  574.     register char  *pstart;
  575.     register char  *pend;
  576.  
  577.  
  578.  
  579.     /*
  580.      *   kill any newlines just in case
  581.      */
  582.     pstart = ps;
  583.     while (*pstart && ((*pstart == '\n') || (*pstart == '\r')))
  584.     {
  585.         *pstart = ' ';
  586.         pstart++;
  587.     }
  588.  
  589.  
  590.  
  591.     /*
  592.      *   kill leading whitespace
  593.      */
  594.     pstart = ps;
  595.     while (*pstart && ((*pstart == ' ') || (*pstart == '\t')))
  596.         pstart++;
  597.  
  598.  
  599.  
  600.     /*
  601.      *   kill trailing whitespace
  602.      */
  603.     pend = &pstart[strlen(pstart)-1];
  604.     while (((long)pend > (long)pstart) && ((*pend==' ') || (*pend=='\t')))
  605.     {
  606.         *pend = '\0';
  607.         pend--;
  608.     }
  609.  
  610.  
  611.     return (pstart);
  612. }
  613.  
  614.  
  615.  
  616. #ifdef NEED_DELAY
  617.  
  618. /*------------------------------*/
  619. /*    wait_ms            */
  620. /*------------------------------*/
  621.  
  622. #define MSLOOP        125
  623.  
  624. void wait_ms (long ms)
  625. {
  626.  
  627. /*
  628.  *    wait prescribed number of miliseconds (approx).
  629.  *    inner loop takes about 1 ms on normal 8Mhz ST.
  630.  */
  631.  
  632.     int    i;
  633.  
  634.     if (ms <= 0)
  635.         return;
  636.  
  637.     for ( ; ms > 0; ms--)
  638.         for (i = MSLOOP; i > 0; i--)
  639.             ;
  640.  
  641.     return;
  642. }
  643.  
  644. #endif /*NEED_DELAY*/
  645.  
  646.  
  647. #ifdef SEARCH_PATH
  648.  
  649. /*
  650.  * NAME
  651.  *    which - search PATH directories for given file
  652.  *
  653.  *    called by: anything
  654.  *
  655.  *    calls:     strpbrk, strtok, getenv, strcpy, access, strncpy, sprintf
  656.  *
  657.  *    returns:   ptr to full pathname of file or NULL if not found
  658.  *
  659.  *    notes:
  660.  *
  661.  *    file should be simple filename (i.e. nnnnnnnn.eee). if it contains
  662.  *    any / or \ characters and the file cannot be found in the given path,
  663.  *    a null ptr is returned. delim is list of possible path component
  664.  *    seperator (eg ", "). env_name should be "PATH" or "path" typically,
  665.  *    but can be anything that would be in the environment.
  666.  *
  667.  *    ptr returned, if valid, points to static array maintained here. use
  668.  *    it or (potentially) loose it...
  669.  *
  670.  *    typical call:
  671.  *
  672.  *        file_full_path = (char *) which (filename, "PATH", ",");
  673.  */
  674.  
  675. #include <stdio.h>
  676. #include <stdlib.h>
  677. #include <strings.h>
  678. #ifdef HAS_ACCESS
  679. #include <unistd.h>
  680. #endif /*HAS_ACCESS*/
  681.  
  682. #ifdef DBG
  683. # undef DBG
  684. #endif
  685. #ifdef DEBUG
  686. # define DBG(x)        printf x
  687. #else
  688. # define DBG(x)
  689. #endif
  690.  
  691. /*------------------------------*/
  692. /*    which            */
  693. /*------------------------------*/
  694. char *which (char *file, char *env_name, char *delim)
  695. {
  696.     static char    pathname[MAXPATH];
  697.     char        pbuf[MAXENV];
  698.     char           *p;
  699. #ifndef HAS_ACCESS
  700.     FILE           *fd;
  701. #endif /*HAS_ACCESS*/
  702.  
  703.  
  704.  
  705.     strcpy (pathname, file);
  706.  
  707.  
  708.     /*
  709.      *   check the obvios: cwd
  710.      */
  711. #ifdef HAS_ACCESS
  712.     if (access (pathname, 0) != -1)
  713.         return (pathname);
  714. #else /*! HAS_ACCESS*/
  715.     if ((fd = fopen (pathname, "r")) != NULL)
  716.     {
  717.         fclose (fd);
  718.         return (pathname);
  719.     }
  720. #endif /*HAS_ACCESS*/
  721.  
  722.  
  723.     /*
  724.      *   file not in cwd. if file contains a specific path (i.e. contains
  725.      *   a \ (or /) or if PATH environment is not set, return a NULL.
  726.      *   else search for file along PATH.
  727.      */
  728.     if (strpbrk (file, "\\/") || !(p = getenv (env_name)))
  729.     {
  730.         DBG (("which: env= %s\n", p));
  731.         return ((char *) NULL);
  732.     }
  733.     DBG (("which: env= %s\n", p));
  734.     
  735.  
  736.     /*
  737.      *   copy value of env_name
  738.      */
  739.     if (strlen (p) > MAXENV)
  740.         strncpy (pbuf, p, MAXENV);
  741.     else
  742.         strcpy (pbuf, p);
  743.  
  744.  
  745.     /*
  746.      *   start breaking up the string...
  747.      */
  748.     if (p = strtok (pbuf, delim))
  749.     {
  750.         do
  751.         {
  752. #define lastchar(s)    (p)[strlen(p)-1]
  753.  
  754.             DBG (("which: token= %s\n", p));
  755.             if ((lastchar(p) == '\\') || (lastchar(p) == '/'))
  756.                 sprintf (pathname, "%0.50s%0.20s", p, file);
  757.             else if (index (p, '\\'))
  758.                 sprintf (pathname, "%0.50s\\%0.20s", p, file);
  759.             else if (index (p, '/'))
  760.                 sprintf (pathname, "%0.50s/%0.20s", p, file);
  761.             else
  762.                 sprintf (pathname, "%0.50s\\%0.20s", p, file);
  763.             DBG (("which: pathname= %s\n", pathname));
  764.  
  765. #ifdef HAS_ACCESS
  766.             if (access (pathname, 0) != -1)
  767.                 return (pathname);
  768. #else /*! HAS_ACCESS*/
  769.             if ((fd = fopen (pathname, "r")) != (FILE *) NULL)
  770.             {
  771.                 fclose (fd);
  772.                 return (pathname);
  773.             }
  774. #endif /*HAS_ACCESS*/
  775.         } while (p = strtok ((char *)0L, delim));
  776.     }
  777.  
  778.  
  779.     /*
  780.      *   if we get here, we did not find it...
  781.      */
  782.     return ((char *) NULL);
  783. }
  784.  
  785. #endif /*SEARCH_PATH*/
  786.  
  787.  
  788.  
  789.  
  790.  
  791.  
  792.  
  793.  
  794. #if 0
  795.  
  796. /*
  797.  *    c_speak.c - stub to invoke SPEAK.TOS
  798.  *
  799.  *    this doe NOT work unless registers are saved before (*f)() is
  800.  *    invoked and restored after return. GNU C does not do this.
  801.  */
  802.  
  803. #ifndef lint
  804. static char *rcsid_c_speak_c = "$Id$";
  805. #endif
  806.  
  807. /*
  808.  * $Log$
  809.  */
  810.  
  811. /*
  812.  *    offsets from program start to where we jump...
  813.  */
  814. #define CALL_1_OFFSET    0x32
  815. #define CALL_2_OFFSET    0x88
  816.  
  817. /*
  818.  *    this is actually a pointer to the start of the loaded program
  819.  */
  820. extern long    program;
  821.  
  822.  
  823. /*------------------------------*/
  824. /*    c_speak            */
  825. /*------------------------------*/
  826. void c_speak ()
  827. {
  828.     register void (*f)();
  829.  
  830.     /*
  831.      *   first call, set up phonemes, make call...
  832.      */
  833.     f = (void (*)()) (program + CALL_1_OFFSET);
  834.     (*f)();
  835.  
  836.     /*
  837.      *   second call, speak...
  838.      */
  839.     f = (void (*)()) (program + CALL_2_OFFSET);
  840.     (*f)();
  841.  
  842.     return;
  843. }
  844.  
  845.  
  846. #endif
  847.  
  848.  
  849.