home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / INTERNET / UPC2S1.ZIP / EXECUTE.C < prev    next >
C/C++ Source or Header  |  1993-10-03  |  26KB  |  787 lines

  1. /*--------------------------------------------------------------------*/
  2. /*       e x e c u t e . C                                            */
  3. /*                                                                    */
  4. /*       Execute an external command for UUPC/extended functions      */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*       Changes Copyright (c) 1989-1993 by Kendra Electronic         */
  9. /*       Wonderworks.                                                 */
  10. /*                                                                    */
  11. /*       All rights reserved except those explicitly granted by       */
  12. /*       the UUPC/extended license agreement.                         */
  13. /*--------------------------------------------------------------------*/
  14.  
  15. /*--------------------------------------------------------------------*/
  16. /*                          RCS Information                           */
  17. /*--------------------------------------------------------------------*/
  18.  
  19. /*
  20.  *    $Id: execute.c 1.11 1993/10/03 22:09:09 ahd Exp $
  21.  *
  22.  *    Revision history:
  23.  *    $Log: execute.c $
  24.  * Revision 1.11  1993/10/03  22:09:09  ahd
  25.  * Change debugging messages
  26.  *
  27.  * Revision 1.10  1993/10/02  22:56:59  ahd
  28.  * Suppress compile warning
  29.  *
  30.  * Revision 1.9  1993/10/02  19:07:49  ahd
  31.  * Suppress compiler warning
  32.  *
  33.  * Revision 1.8  1993/09/27  00:45:20  ahd
  34.  * Fix Windows compile, add debug to OS/2 and DOS version
  35.  *
  36.  * Revision 1.7  1993/09/26  03:32:27  dmwatt
  37.  * Use Standard Windows NT error message module
  38.  *
  39.  * Revision 1.6  1993/09/23  03:26:51  ahd
  40.  * Use common file search routine
  41.  *
  42.  * Revision 1.5  1993/09/20  04:38:11  ahd
  43.  * TCP/IP support from Dave Watt
  44.  * 't' protocol support
  45.  * OS/2 2.x support
  46.  *
  47.  * Revision 1.4  1993/08/08  17:39:09  ahd
  48.  * Denormalize path for opening on selected networks
  49.  *
  50.  * Revision 1.3  1993/08/03  03:11:49  ahd
  51.  * Further Windows 3.x fixes
  52.  *
  53.  * Revision 1.2  1993/08/02  03:24:59  ahd
  54.  * Further changes in support of Robert Denny's Windows 3.x support
  55.  *
  56.  * Revision 1.1  1993/07/31  16:22:16  ahd
  57.  * Initial revision
  58.  *
  59.  */
  60.  
  61. /*--------------------------------------------------------------------*/
  62. /*                        System include files                        */
  63. /*--------------------------------------------------------------------*/
  64.  
  65. #include <errno.h>
  66. #include <stdio.h>
  67. #include <stdlib.h>
  68. #include <string.h>
  69. #include <ctype.h>
  70. #include <time.h>
  71. #include <process.h>
  72. #include <io.h>
  73.  
  74. #ifdef WIN32
  75. #include <windows.h>
  76. #include <signal.h>
  77. #elif defined(_Windows)
  78. #include <windows.h>
  79. #include <shellapi.h>
  80. #endif
  81.  
  82. #include <direct.h>
  83.  
  84. /*--------------------------------------------------------------------*/
  85. /*                    UUPC/extended include files                     */
  86. /*--------------------------------------------------------------------*/
  87.  
  88. #include "lib.h"
  89. #include "hlib.h"
  90. #include "execute.h"
  91.  
  92. #ifdef _Windows
  93. #include "winutil.h"
  94. #endif
  95.  
  96. #ifdef WIN32
  97. #include "pnterr.h"
  98. #endif
  99.  
  100. /*--------------------------------------------------------------------*/
  101. /*                          Local variables                           */
  102. /*--------------------------------------------------------------------*/
  103.  
  104. currentfile();
  105.  
  106. /*--------------------------------------------------------------------*/
  107. /*                    Internal function prototypes                    */
  108. /*--------------------------------------------------------------------*/
  109.  
  110. static boolean internal( const char *command );
  111.  
  112. static boolean batch( const char *input, char *output);
  113.  
  114. #ifdef _Windows
  115.  
  116. /*--------------------------------------------------------------------*/
  117. /*       e x e c u t e                       (Windows 3.x version)    */
  118. /*                                                                    */
  119. /*       execute external command under Windows                       */
  120. /*--------------------------------------------------------------------*/
  121.  
  122. int execute( const char *command,
  123.              const char *parameters,
  124.              const char *input,
  125.              const char *output,
  126.              const boolean synchronous,
  127.              const boolean foreground )
  128. {
  129.    int result;
  130.  
  131.    boolean useBat = (input != NULL) || (output != NULL );
  132.  
  133.    char path[FILENAME_MAX];         /* String for executable file   */
  134.    char batchFile[FILENAME_MAX];    /* String for batch driver file */
  135.    char perfect[FILENAME_MAX];      /* String for results test file */
  136.  
  137. /*--------------------------------------------------------------------*/
  138. /*                          Locate the command                        */
  139. /*--------------------------------------------------------------------*/
  140.  
  141.    if ( internal( command ) )
  142.    {
  143.       strcpy( path , command );
  144.       useBat = TRUE;
  145.    }
  146.    else if (batch( command, path ))
  147.    {
  148.       if (useBat)                      // Using redirection?
  149.       {
  150.          printmsg(0,"Cannot use redirection with batch file %s",
  151.                      path );
  152.          return -2;
  153.       }
  154.    } /* else */
  155.    else if ( !*path )                  // Error returned from search?
  156.       return -1;                       // Yes --> Error already reported
  157.  
  158. /*--------------------------------------------------------------------*/
  159. /*     Generate a batch file for redirected DOS programs, if needed   */
  160. /*--------------------------------------------------------------------*/
  161.  
  162.    if ( useBat )
  163.    {
  164.       FILE *stream ;
  165.  
  166.       mktempname( batchFile, "BAT");
  167.       mktempname( perfect, "TMP");
  168.       stream = FOPEN( batchFile, "w", TEXT_MODE );
  169.  
  170.       if ( stream == NULL )
  171.       {
  172.          printerr( batchFile );
  173.          panic();
  174.       }
  175.  
  176.       fprintf( stream ,
  177.                "@echo off\n%s %s",
  178.                path,
  179.                parameters == NULL ? "" : parameters );
  180.  
  181.       if ( input != NULL )
  182.          fprintf( stream, " < %s", input );
  183.  
  184.       if ( output != NULL )
  185.          fprintf( stream, " < %s", output );
  186.  
  187.       fprintf( stream,
  188.               "\nif errorlevel 1 erase %s\n",
  189.                perfect );
  190.  
  191.       fclose ( stream );
  192.  
  193.       stream = FOPEN( perfect, "w", TEXT_MODE );
  194.       if ( stream == NULL )
  195.       {
  196.          printerr( perfect );
  197.          panic();
  198.       }
  199.       fclose( stream );
  200.  
  201.       strcpy( path, batchFile );             // Run the batch command
  202.  
  203.    } /* if ( useBat ) */
  204.  
  205. /*--------------------------------------------------------------------*/
  206. /*                       Actually run the command                     */
  207. /*--------------------------------------------------------------------*/
  208.  
  209.    result = SpawnWait( path,
  210.                        parameters,
  211.                        synchronous,
  212.                        foreground ? SW_MAXIMIZE : SW_SHOWMINNOACTIVE );
  213.  
  214. /*--------------------------------------------------------------------*/
  215. /*       For batch files, we can only report zero/non-zero            */
  216. /*       results.  Do so, and clean up our input file at the same     */
  217. /*       time.                                                        */
  218. /*--------------------------------------------------------------------*/
  219.  
  220.    if ( useBat )
  221.    {
  222.       int unlinkResult = unlink( perfect );
  223.  
  224.       if (( result == 0 ) && (unlinkResult != 0))
  225.          result = 255;
  226.  
  227.       if (unlink( batchFile ))
  228.          printerr( batchFile );
  229.  
  230.    } /* if ( useBat ) */
  231.  
  232. /*--------------------------------------------------------------------*/
  233. /*                     Report results of command                      */
  234. /*--------------------------------------------------------------------*/
  235.  
  236.    printmsg( 4,"Result of spawn %s is ... %d", command, result);
  237.  
  238.    return result;
  239.  
  240. } /* execute */
  241.  
  242. #elif defined(WIN32)
  243.  
  244. /*--------------------------------------------------------------------*/
  245. /*    e x e c u t e                             (Windows NT version)  */
  246. /*                                                                    */
  247. /*    Execute an external program                                     */
  248. /*--------------------------------------------------------------------*/
  249.  
  250. int execute( const char *command,
  251.              const char *parameters,
  252.              const char *input,
  253.              const char *output,
  254.              const boolean synchronous,
  255.              const boolean foreground )
  256. {
  257.    int result;
  258.    char path[BUFSIZ];
  259.  
  260. /*--------------------------------------------------------------------*/
  261. /*               Redirect STDIN and STDOUT as required                */
  262. /*--------------------------------------------------------------------*/
  263.  
  264.    if ((input != NULL) && (freopen(input , "rb", stdin) == NULL))
  265.    {
  266.       printerr(input);
  267.       return -2;
  268.    }
  269.  
  270.    if ((output != NULL) && (freopen(output, "wt", stdout) == NULL))
  271.    {
  272.       printerr( output );
  273.       if ( input != NULL )
  274.       {
  275.          FILE *temp = freopen("con", "rt", stdin);
  276.  
  277.          if ( (temp == NULL) && (errno != 0) )
  278.          {
  279.             printerr("stdin");
  280.             panic();
  281.          }
  282.          setvbuf( stdin, NULL, _IONBF, 0);
  283.  
  284.       } /* if ( input != NULL ) */
  285.       return -2;
  286.    }
  287.  
  288. /*--------------------------------------------------------------------*/
  289. /*                  Execute the command in question                   */
  290. /*--------------------------------------------------------------------*/
  291.  
  292.    if (internal(strcpy(path,command)) ||
  293.        batch(command, path))        // Internal or batch command?
  294.    {
  295.  
  296.       if ( parameters == NULL )
  297.          result = system( path );
  298.       else {
  299.  
  300.          strcat( path, " ");
  301.          strcat( path, parameters );
  302.  
  303.          result = system( path );
  304.  
  305.       } /* else */
  306.  
  307.    } /* if (internal(command)) */
  308.    else  {                       /* No --> Invoke normally           */
  309.       STARTUPINFO si;
  310.       PROCESS_INFORMATION pi;
  311.       void *oldCtrlCHandler;
  312.  
  313.       if ( ! *path )                // Did search fail?
  314.          return -2;                 // Yes --> Msg issued, just return
  315.  
  316.       memset(&si, 0, sizeof(STARTUPINFO));
  317.       si.cb = sizeof(STARTUPINFO);
  318.       si.lpTitle = (LPSTR)command;
  319.       si.dwFlags = STARTF_USESHOWWINDOW;
  320.       si.wShowWindow = foreground ? SW_MAXIMIZE : SW_SHOWMINNOACTIVE;
  321.  
  322.  
  323.       if (parameters != NULL)
  324.       {
  325.          strcat( path, " ");
  326.          strcat( path, parameters );
  327.       }
  328.  
  329.       result = CreateProcess(NULL,
  330.                              path,
  331.                              NULL,
  332.                              NULL,
  333.                              TRUE,
  334.                              0,
  335.                              NULL,
  336.                              NULL,
  337.                              &si,
  338.                              &pi);
  339.  
  340.       if (!result)                  // Did CreateProcess() fail?
  341.       {                             // Yes --> Report error
  342.          DWORD dwError = GetLastError();
  343.          printmsg(0, "execute:  CreateProcess failed");
  344.          printNTerror("CreateProcess", dwError);
  345.       }
  346.       else {
  347.  
  348.          if (synchronous)
  349.          {
  350.  
  351. /*--------------------------------------------------------------------*/
  352. /*       Set things up so that we ignore Ctrl-C's coming in to the    */
  353. /*       child, and wait for other application to finish.             */
  354. /*--------------------------------------------------------------------*/
  355.  
  356.             oldCtrlCHandler = signal(SIGINT, SIG_IGN);
  357.  
  358.             WaitForSingleObject(pi.hProcess, INFINITE);
  359.             GetExitCodeProcess(pi.hProcess, &result);
  360.  
  361.             signal(SIGINT, oldCtrlCHandler); // Re-enable Ctrl-C handling
  362.  
  363.          }  /* if (synchronous) */
  364.          else
  365.             result = 0;
  366.  
  367. /*--------------------------------------------------------------------*/
  368. /*       If we're spawning asynchronously, we assume that we don't    */
  369. /*       care about the exit code from the spawned process.           */
  370. /*       Closing these makes it impossible to get at the old          */
  371. /*       process's exit code.                                         */
  372. /*--------------------------------------------------------------------*/
  373.  
  374.          CloseHandle(pi.hProcess);
  375.          CloseHandle(pi.hThread);
  376.  
  377.       } /* else !result */
  378.  
  379.    } /* else internal command */
  380.  
  381. /*--------------------------------------------------------------------*/
  382. /*                  Re-open our standard i/o streams                  */
  383. /*--------------------------------------------------------------------*/
  384.  
  385.    if ( output != NULL )
  386.    {
  387.       freopen("con", "wt", stdout);
  388.       setvbuf( stdout, NULL, _IONBF, 0);
  389.    }
  390.  
  391.    if ( input != NULL )
  392.    {
  393.       FILE *temp = freopen("con", "rt", stdin);
  394.  
  395.       if ( (temp == NULL) && (errno != 0) )
  396.       {
  397.          printerr("stdin");
  398.          panic();
  399.       }
  400.  
  401.       setvbuf( stdin, NULL, _IONBF, 0);
  402.  
  403.    } /* if ( input != NULL ) */
  404.  
  405. /*--------------------------------------------------------------------*/
  406. /*                     Report results of command                      */
  407. /*--------------------------------------------------------------------*/
  408.  
  409.    printmsg( 4 ,"Result of spawn %s is ... %d", command, result);
  410.  
  411.    return result;
  412.  
  413. } /* execute */
  414.  
  415. #else
  416.  
  417. #ifdef __TURBOC__
  418. #pragma argsused
  419. #endif
  420.  
  421. /*--------------------------------------------------------------------*/
  422. /*       e x e c u t e                       (OS/2 + DOS version)     */
  423. /*                                                                    */
  424. /*       Generic execute external command with optional redirection   */
  425. /*       of standard input and output                                 */
  426. /*--------------------------------------------------------------------*/
  427.  
  428. int execute( const char *command,
  429.              const char *parameters,
  430.              const char *input,
  431.              const char *output,
  432.              const boolean synchronous,
  433.              const boolean foreground )
  434. {
  435.    int result;
  436.    char path[BUFSIZ];
  437.  
  438. /*--------------------------------------------------------------------*/
  439. /*               Redirect STDIN and STDOUT as required                */
  440. /*--------------------------------------------------------------------*/
  441.  
  442.    if ((input != NULL) && (freopen(input , "rb", stdin) == NULL))
  443.    {
  444.       printerr(input);
  445.       return -2;
  446.    }
  447.  
  448.    if ((output != NULL) && (freopen(output, "wt", stdout) == NULL))
  449.    {
  450.       printerr( output );
  451.       if ( input != NULL )
  452.       {
  453.          FILE *temp = freopen("con", "rt", stdin);
  454.  
  455.          if ( (temp == NULL) && (errno != 0) )
  456.          {
  457.             printerr("stdin");
  458.             panic();
  459.          }
  460.          setvbuf( stdin, NULL, _IONBF, 0);
  461.  
  462.       } /* if ( input != NULL ) */
  463.  
  464.       return -2;
  465.    }
  466.  
  467. /*--------------------------------------------------------------------*/
  468. /*                  Execute the command in question                   */
  469. /*--------------------------------------------------------------------*/
  470.  
  471.    if (internal(strcpy(path,command)) ||
  472.        batch(command,path))         // Internal command or batch file?
  473.    {
  474.  
  475.       if ( parameters == NULL )
  476.          result = system( path );
  477.       else {
  478.  
  479.          strcat( path, " ");
  480.          strcat( path, parameters );
  481.  
  482.          result = system( path );
  483.       } /* else */
  484.  
  485.    } /* if (internal(command)) */
  486.    else  {                       /* No --> Invoke normally           */
  487.  
  488.       if ( *path )
  489.       {
  490.          printmsg(4,"execute: spawnlp(%d, %s, %s%s%s)",
  491.                               synchronous ? P_WAIT : P_NOWAIT,
  492.                               path,
  493.                               command,
  494.                               parameters == NULL ? "" : ", ",
  495.                               parameters == NULL ? "" : parameters );
  496.  
  497.          result = spawnlp( synchronous ? P_WAIT : P_NOWAIT,
  498.                            (char *) path,
  499.                            (char *) command,
  500.                            (char *) parameters,
  501.                            NULL);
  502.  
  503.          if (result == -1)       /* Did spawn fail?                  */
  504.             printerr(command);   /* Yes --> Report error             */
  505.       } /* else */
  506.       else
  507.          result = -3;            // Flag we never ran command
  508.  
  509.    } /* else */
  510.  
  511. /*--------------------------------------------------------------------*/
  512. /*                  Re-open our standard i/o streams                  */
  513. /*--------------------------------------------------------------------*/
  514.  
  515.    if ( output != NULL )
  516.    {
  517.       freopen("con", "wt", stdout);
  518.       setvbuf( stdout, NULL, _IONBF, 0);
  519.    }
  520.  
  521.    if ( input != NULL )
  522.    {
  523.       FILE *temp = freopen("con", "rt", stdin);
  524.  
  525.       if ( (temp == NULL) && (errno != 0) )
  526.       {
  527.          printerr("stdin");
  528.          panic();
  529.       }
  530.       setvbuf( stdin, NULL, _IONBF, 0);
  531.  
  532.    } /* if ( input != NULL ) */
  533.  
  534. /*--------------------------------------------------------------------*/
  535. /*                     Report results of command                      */
  536. /*--------------------------------------------------------------------*/
  537.  
  538.    printmsg( 4,"Result of spawn %s is ... %d", command, result);
  539.  
  540.    return result;
  541.  
  542. } /* execute */
  543.  
  544. #endif
  545.  
  546. /*--------------------------------------------------------------------*/
  547. /*       e x e c u t e C o m m a n d                                  */
  548. /*                                                                    */
  549. /*       Split command from its parameters for execute                */
  550. /*--------------------------------------------------------------------*/
  551.  
  552. int executeCommand( const char *command,
  553.                     const char *input,
  554.                     const char *output,
  555.                     const boolean synchronous,
  556.                     const boolean foreground )
  557. {
  558.    char *cmdname;
  559.    char *parameters;
  560.    char buffer[FILENAME_MAX];
  561.    int result;
  562.  
  563.    strcpy( buffer, command );
  564.  
  565.    cmdname = strtok( buffer, WHITESPACE );
  566.    parameters = strtok( NULL, "\r\n" );
  567.  
  568.    if ( parameters != NULL )
  569.    {
  570.       while (isspace( *parameters ) || iscntrl( *parameters ))
  571.          parameters++;
  572.  
  573.       if ( !strlen( parameters ))
  574.          parameters = NULL;
  575.    }
  576.  
  577.    result = execute( cmdname,
  578.                      parameters,
  579.                      input,
  580.                      output,
  581.                      synchronous,
  582.                      foreground );
  583.  
  584.    return result;
  585.  
  586. } /* executeCommand */
  587.  
  588. /*--------------------------------------------------------------------*/
  589. /*    i n t e r n a l                                                 */
  590. /*                                                                    */
  591. /*    Determine if command is internal DOS command                    */
  592. /*--------------------------------------------------------------------*/
  593.  
  594. static boolean internal( const char *command )
  595. {
  596.    static char *commands[] = { "break",   "cd",    "chdir",    "copy",
  597.                                "ctty",    "date",  "del",      "dir",
  598.                                "echo",    "erase", "for",      "md",
  599.                                "mkdir",   "rd",    "rem",      "ren",
  600.                                "rename",  "rmdir", "time",     "ver",
  601.                                "verify",  "vol",
  602.                                NULL };
  603.    char **list;
  604.  
  605. /*--------------------------------------------------------------------*/
  606. /*                   Determine command list to use                    */
  607. /*--------------------------------------------------------------------*/
  608.  
  609.    if (E_internal == NULL )
  610.       list = commands;
  611.    else
  612.       list = E_internal;
  613.  
  614. /*--------------------------------------------------------------------*/
  615. /*                   Scan the list for the command                    */
  616. /*--------------------------------------------------------------------*/
  617.  
  618.    while( *list != NULL )
  619.    {
  620.       printmsg(5,"Searching for \"%s\", comparing to \"%s\"",
  621.                   *list, command);
  622.  
  623.       if (equali(*list++,command))
  624.       {
  625.          printmsg(4,"\"%s\" is an internal command",command);
  626.          return TRUE;
  627.       } /* if */
  628.  
  629.    } /* while( *list != NULL ) */
  630.  
  631. /*--------------------------------------------------------------------*/
  632. /*       The command is not in the list; return FALSE (external       */
  633. /*       command)                                                     */
  634. /*--------------------------------------------------------------------*/
  635.  
  636.    printmsg(4,"\"%s\" is an external command",command);
  637.    return FALSE;
  638.  
  639. } /* internal */
  640.  
  641. /*--------------------------------------------------------------------*/
  642. /*    b a t c h                                                       */
  643. /*                                                                    */
  644. /*    Determine if a command is batch file                            */
  645. /*--------------------------------------------------------------------*/
  646.  
  647. static boolean batch( const char *input, char *output)
  648. {
  649.    char *search = getenv("PATH");
  650.    char *gotPath;
  651.    char *period;
  652.  
  653.    static const char *extensions[] = { ".exe",
  654.                                        ".com",
  655. #if !defined(_DOS) && !defined(_Windows)
  656.                                        ".cmd",
  657. #endif
  658.                                        ".bat",
  659.                                        NULL };
  660.  
  661. /*--------------------------------------------------------------------*/
  662. /*                  Validate the search path exists                   */
  663. /*--------------------------------------------------------------------*/
  664.  
  665.    if ( search == NULL )
  666.    {
  667.       printmsg(0,"batch: Unable to retrieve PATH environment variable!");
  668.       panic();
  669.    }
  670.  
  671. /*--------------------------------------------------------------------*/
  672. /*        Determine if we have path, and if we have an extension      */
  673. /*--------------------------------------------------------------------*/
  674.  
  675.    gotPath = strchr( input, '/');
  676.    if ( gotPath == NULL )
  677.       gotPath = strchr( input, '\\');
  678.  
  679.    period = strchr( (gotPath == NULL) ? input : gotPath, '.');
  680.  
  681.    if ( period != NULL )         //    We have extension?
  682.    {
  683.       if ( gotPath )             // Extension + path?
  684.       {                          // Yes --> Just look for the file
  685.  
  686.          char *fname = normalize( input );
  687.  
  688.          if ( access( input, 00))
  689.             *output = '\0';
  690.          else
  691.             strcpy( output, fname );
  692.  
  693.       } /* if ( gotPath ) */
  694.       else
  695.          _searchenv( input, "PATH", output );
  696.  
  697.       if ( ! *output )           // No file found?
  698.       {
  699.  
  700.          printerr( input );
  701.          return FALSE;
  702.  
  703.       }  /* if ( ! *output ) */
  704.  
  705. #if defined(_DOS) || defined(_Windows)
  706.       return equal( period, ".bat" );
  707. #else
  708.       return equali( period, ".cmd" ) || equali( period, ".bat" );
  709. #endif
  710.  
  711.    } /* if ( p != NULL ) */
  712.  
  713. /*--------------------------------------------------------------------*/
  714. /*       Walk the path looking for the file's possible types in       */
  715. /*       the path's directories                                       */
  716. /*--------------------------------------------------------------------*/
  717.  
  718.    while( *search )
  719.    {
  720.       char base[FILENAME_MAX];
  721.       int extension = 0;
  722.  
  723.       if ( gotPath )
  724.       {
  725.          strcpy( base, input );
  726.          search = "";                        // Force this to be last pass
  727.       }
  728.       else {
  729.  
  730.          char *next = strchr(search,';');    // Find next path component
  731.          size_t len;
  732.  
  733.          if ( next == NULL )
  734.             len = strlen( search );
  735.          else
  736.             len = (size_t) (next - search);
  737.  
  738.          memcpy( base, search, len );        // Path for search ...
  739.          search += len + 1;                  // Step past semicolon
  740.          if ( base[len - 1 ] != '\\' )       // Ending in back slash?
  741.             base[len++] = '\\';              // No --> Add one
  742.          strcpy( base + len , input );       // ... plus file name
  743.  
  744.       } /* else */
  745.  
  746.       printmsg(8,
  747.                "Searching for extension of %s",
  748.                base );
  749.  
  750. /*--------------------------------------------------------------------*/
  751. /*       Search a single directory in a path for a file with          */
  752. /*       various extensions.                                          */
  753. /*--------------------------------------------------------------------*/
  754.  
  755.       while( extensions[extension] != NULL )
  756.       {
  757.          strcpy( output, base );
  758.          strcat( output, extensions[extension] );
  759.  
  760.          if ( ! access(output, 00 ))
  761.          {
  762.  
  763. #if defined(_DOS) || defined(_Windows)
  764.             return equal( extensions[extension] , ".bat" );
  765. #else
  766.             return equal( extensions[extension] , ".cmd" ) ||
  767.                    equal( extensions[extension] , ".bat" );
  768. #endif
  769.          } /* if ( result != NULL ) */
  770.  
  771.          extension++;
  772.  
  773.       }  /* while( extensions[extension] != NULL ) */
  774.  
  775.    } /* while( *search ) */
  776.  
  777. /*--------------------------------------------------------------------*/
  778. /*       We could not find the file, report failure to the caller     */
  779. /*--------------------------------------------------------------------*/
  780.  
  781.    printmsg(0, "batch: Unable to locate %s in search path", input);
  782.  
  783.    *output = '\0';                  // Flag no file found!
  784.    return FALSE;
  785.  
  786. } /* batch */
  787.