home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / sysutils / msshell / stdargv.c < prev    next >
C/C++ Source or Header  |  1992-06-20  |  13KB  |  593 lines

  1. /* MS-DOS stdargv Function
  2.  *
  3.  * MS-DOS stdargv - Copyright (c) 1990,1,2 Data Logic Limited.
  4.  *
  5.  * This code is subject to the following copyright restrictions:
  6.  *
  7.  * 1.  Redistribution and use in source and binary forms are permitted
  8.  *     provided that the above copyright notice is duplicated in the
  9.  *     source form.
  10.  *
  11.  *    $Header: c:/usr/src/shell/rcs/stdargv.c 2.0 1992/04/13 17:39:09 Ian_Stewartson Exp $
  12.  *
  13.  *    $Log: stdargv.c $
  14.  *    Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
  15.  *    MS-Shell 2.0 Baseline release
  16.  *
  17.  *
  18.  *
  19.  * MODULE DEFINITION:
  20.  *
  21.  * This function expandes the command line parameters in a UNIX like manner.
  22.  * Wild character *?[] are allowed in file names. @filename causes command lines
  23.  * to be read from filename.  Strings between " or ' are not expanded.  All
  24.  * entries in the array are malloced.
  25.  *
  26.  * This function replaces the standard Microsoft C5.1 & C6.0 C Run-Time
  27.  * start up line processing function (_setargv in stdargv.obj).
  28.  *
  29.  * To get the OS2 version, compile with -DOS2
  30.  *
  31.  * Author:
  32.  *    Ian Stewartson
  33.  *    Data Logic, Queens House, Greenhill Way
  34.  *    Harrow, Middlesex  HA1 1YR, UK.
  35.  *    istewart@datlog.co.uk or ukc!datlog!istewart
  36.  */
  37.  
  38. #include <sys/types.h>            /* MS-DOS type definitions      */
  39. #include <sys/stat.h>            /* File status definitions    */
  40. #include <stdio.h>            /* Standard I/O delarations     */
  41. #include <stdlib.h>            /* Standard library functions   */
  42. #include <errno.h>            /* Error number declarations    */
  43. #ifdef OS2
  44. #define INCL_DOSSESMGR
  45. #define INCL_DOSMEMMGR
  46. #define INCL_DOSPROCESS
  47. #define INCL_WINSWITCHLIST
  48. #include <os2.h>            /* OS2 functions declarations   */
  49. #else
  50. #include <dos.h>            /* DOS functions declarations   */
  51. #include <bios.h>            /* BIOS functions declarations  */
  52. #endif
  53. #include <ctype.h>            /* Character type declarations  */
  54. #include <string.h>            /* String library functions     */
  55. #include <limits.h>            /* String library functions     */
  56. #include <fcntl.h>            /* File Control Declarations    */
  57. #include <dirent.h>            /* Direction I/O functions    */
  58. #include <unistd.h>
  59. #include <glob.h>            /* Globbing functions        */
  60.  
  61. /*
  62.  *  DATA DEFINITIONS:
  63.  */
  64.  
  65. #define MAX_LINE    160        /* Max line length        */
  66. #define S_ENTRY        sizeof (char *)
  67.  
  68. /*
  69.  *  DATA DECLARATIONS:
  70.  */
  71. #ifdef MSDOS
  72.  
  73. extern void    _setargv (void);
  74. static void    _Ex_CommandLine (char *);    /* Expand file        */
  75. static void    _Ex_ExpandIndirectFile (char *);
  76. static char    *_Ex_GetSpace (int, char *);    /* Get space        */
  77. static void    _Ex_AddArgument (char *);    /* Add argument        */
  78. static char    *_Ex_SkipWhiteSpace (char *);    /* Skip spaces        */
  79. static char    *_Ex_ConvertToUnixFormat (char *);
  80. static void    _Ex_ExpandField (char *);    /* Split file name    */
  81. static void    _Ex_FatalError (int, char *, char *);
  82. static char    *_Ex_ConvertEnvVariables (char *);
  83. static char    *_EX_OutOfMemory = "%s: %s\n";
  84.  
  85. extern char far    *_pgmptr;         /* Program name            */
  86. extern char    **__argv;         /* Current argument address    */
  87. extern int    __argc;         /* Current argument count    */
  88.  
  89. #ifdef OS2
  90. extern ushort    _aenvseg;        /* Environment seg        */
  91. extern ushort    _acmdln;        /* Command line offset        */
  92. #endif
  93.  
  94. /*
  95.  *  MODULE ABSTRACT: _setargv
  96.  *
  97.  *  UNIX like command line expansion
  98.  */
  99.  
  100. void    _setargv ()
  101. {
  102.     char far        *s;         /* Temporary string pointer        */
  103.  
  104. #  ifndef M_I86LM
  105.     char        buf[MAX_LINE];    /* Temporary space        */
  106. #  endif
  107.  
  108. #ifdef OS2
  109.     char far        *argvp = (char far *)((((long)_aenvseg) << 16));
  110.     ushort        off = _acmdln;
  111.     HSWITCH        hswitch;
  112.     SWCNTRL        swctl;
  113.     PIDINFO        PidInfo;
  114.     char        *cp;
  115.  
  116.     while (--off)
  117.     {
  118.     if (argvp[off - 1] == 0)
  119.          break;
  120.     }
  121.  
  122. /* Add program name */
  123.  
  124.     _pgmptr =  &argvp[off];
  125.  
  126.     if (argvp[_acmdln] == 0)
  127.     {
  128. #  ifndef M_I86LM
  129.     cp = buf;
  130.     s = _pgmptr;
  131.     while (*(cp++) = *(s++))
  132.         continue;
  133.  
  134.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (buf));
  135. #  else
  136.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (_pgmptr));
  137. #  endif
  138.     }
  139.  
  140.     else
  141.     {
  142.     argvp += _acmdln;
  143.  
  144. #  ifndef M_I86LM
  145.     cp = buf;
  146.     s = argvp;
  147.     while (*(cp++) = *(s++))
  148.         continue;
  149.  
  150.     off = strlen (buf);
  151.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (buf));
  152.     argvp += off + 1;
  153.  
  154.     cp = buf;
  155.     s = argvp;
  156.     while (*(cp++) = *(s++))
  157.         continue;
  158.  
  159.     _Ex_CommandLine (buf);
  160. #  else
  161.  
  162.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (argvp));
  163.     argvp += strlen (argvp) + 1;
  164.     _Ex_CommandLine (argvp);
  165.  
  166. #  endif
  167.  
  168. /* Set up the Window name.  Give up if it does not work.  */
  169.  
  170.     if (!DosGetPID (&PidInfo) &&
  171.         ((hswitch = WinQuerySwitchHandle (0, PidInfo.pid))) &&
  172.         (!WinQuerySwitchEntry (hswitch, &swctl)))
  173.     {
  174.         if ((cp = strrchr (__argv[0], '/')) == (char *)NULL)
  175.         cp = __argv[0];
  176.  
  177.         else
  178.             ++cp;
  179.  
  180.  
  181.         strncpy (swctl.szSwtitle, cp, MAXNAMEL);
  182.         swctl.szSwtitle[MAXNAMEL] = 0;
  183.  
  184.         if ((cp = strrchr (swctl.szSwtitle, '.')) != (char *)NULL)
  185.         *cp = 0;
  186.  
  187.         WinChangeSwitchEntry (hswitch, &swctl);
  188.     }
  189.     }
  190. #else
  191.                     /* Set up pointer to command line */
  192.     char far        *argvp = (char far *)((((long)_psp) << 16) + 0x081L);
  193.     unsigned int    envs = *(int far *)((((long)_psp) << 16) + 0x02cL);
  194.  
  195. /* Command line can be null or 0x0d terminated - convert to null */
  196.  
  197.     s = argvp;
  198.  
  199.     while (*s && (*s != 0x0d))
  200.     ++s;
  201.  
  202.     if (*s == 0x0d)
  203.     *s = 0;
  204.  
  205. /* Set up global parameters and expand */
  206.  
  207.     __argc = 0;
  208.  
  209. /* Get the program name */
  210.  
  211.     if ((_osmajor <= 2) || (envs == 0))
  212.     s = "unknown";
  213.  
  214. /* In the case of DOS 3+, we look in the environment space */
  215.  
  216.     else
  217.     {
  218.     s = (char far *)(((long)envs) << 16);
  219.  
  220.     while (*s)
  221.     {
  222.         while (*(s++) != 0)
  223.         continue;
  224.     }
  225.  
  226.     s += 3;
  227.     }
  228.  
  229. /* Add the program name        */
  230.  
  231.     _pgmptr = s;
  232.  
  233. #  ifndef M_I86LM
  234.     cp = buf;
  235.     while (*(cp++) = *(s++))
  236.     continue;
  237.  
  238.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (buf));
  239.  
  240.     s  = argvp;
  241.     cp = buf;
  242.     while (*(cp++) = *(s++))
  243.     continue;
  244.  
  245.     _Ex_CommandLine (buf);
  246. #  else
  247.     _Ex_AddArgument (_Ex_ConvertToUnixFormat (s));
  248.     _Ex_CommandLine (argvp);
  249. #  endif
  250. #endif
  251.  
  252.     _Ex_AddArgument ((char *)NULL);
  253.     --__argc;
  254. }
  255.  
  256. /*
  257.  * Expand the DOS Command line
  258.  */
  259.  
  260. static void    _Ex_CommandLine (argvp)
  261. char        *argvp;            /* Line to expand            */
  262. {
  263.     char    *spos;            /* End of string pointer    */
  264.     char    *cpos;            /* Start of string pointer    */
  265.     char    *fn;            /* Extracted file name string    */
  266.  
  267. /* Search for next separator */
  268.  
  269.     spos = argvp;
  270.  
  271.     while (*(cpos = _Ex_SkipWhiteSpace (spos)))
  272.     {
  273.  
  274. /* Extract string argument */
  275.  
  276.     if ((*cpos == '"') || (*cpos == '\''))
  277.     {
  278.         spos = cpos + 1;
  279.  
  280.         do
  281.         {
  282.         if ((spos = strchr (spos, *cpos)) != NULL)
  283.         {
  284.             spos++;
  285.             if (spos[-2] != '\\')
  286.             break;
  287.         }
  288.  
  289.         else
  290.             spos = &spos[strlen (cpos)];
  291.  
  292.         } while (*spos);
  293.  
  294.         fn    = _Ex_GetSpace (spos - cpos - 2, cpos + 1);
  295.     }
  296.  
  297. /* Extract normal argument */
  298.  
  299.     else
  300.     {
  301.         spos = cpos;
  302.         while (!isspace (*spos) && *spos)
  303.         spos++;
  304.  
  305.         fn = _Ex_GetSpace (spos - cpos, cpos);
  306.     }
  307.  
  308. /* Process argument */
  309.  
  310.     if (*cpos != '\'')
  311.         fn = _Ex_ConvertEnvVariables (fn);
  312.  
  313.     switch (*cpos)
  314.     {
  315.         case '@':        /* Expand file                    */
  316.         _Ex_ExpandIndirectFile (fn);
  317.         break;
  318.  
  319.         case '"':        /* Expand string                */
  320.         case '\'':
  321.         _Ex_AddArgument (fn);
  322.         break;
  323.  
  324.         default:        /* Expand field                    */
  325.         _Ex_ExpandField (fn);
  326.     }
  327.  
  328.     free (fn);
  329.     }
  330. }
  331.  
  332. /* Expand an indirect file Argument */
  333.  
  334. static void    _Ex_ExpandIndirectFile (file)
  335. char        *file;        /* Expand file name                */
  336. {
  337.     FILE        *fp;        /* File descriptor                */
  338.     char    *EoLFound;    /* Pointer                */
  339.     int        c_maxlen = MAX_LINE;
  340.     char    *line;        /* Line buffer                    */
  341.     char    *eolp;
  342.  
  343. /* If file open fails, expand as a field */
  344.  
  345.     if ((fp = fopen (file + 1, "rt")) == NULL)
  346.     {
  347.     _Ex_ExpandField (file);
  348.     return;
  349.     }
  350.  
  351. /* Grab some memory for the line */
  352.  
  353.     if ((line = malloc (c_maxlen)) == (char *)NULL)
  354.     _Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);
  355.  
  356. /* For each line in the file, remove EOF characters and add argument */
  357.  
  358.     while (fgets (line, c_maxlen, fp) != (char *)NULL)
  359.     {
  360.     EoLFound = strchr (line, '\n');
  361.     eolp = line;
  362.  
  363. /* Handle continuation characters */
  364.  
  365.     while (TRUE)
  366.     {
  367.  
  368. /* Check for a continuation character */
  369.  
  370.         if (((EoLFound = strchr (eolp, '\n')) != (char *)NULL) &&
  371.         (*(EoLFound - 1) == '\\'))
  372.         {
  373.         *(EoLFound - 1) = '\n';
  374.         *EoLFound = 0;
  375.         EoLFound = (char *)NULL;
  376.         }
  377.  
  378.         else if (EoLFound == (char *)NULL)
  379.         EoLFound = strchr (line, 0x1a);
  380.  
  381.         if (EoLFound != (char *)NULL)
  382.         break;
  383.  
  384. /* Find the end of the line */
  385.  
  386.         c_maxlen = strlen (line);
  387.  
  388. /* Get some more space */
  389.  
  390.         if ((line = realloc (line, c_maxlen + MAX_LINE)) == (char *)NULL)
  391.         _Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);
  392.  
  393.         eolp = &line[c_maxlen];
  394.  
  395.         if (fgets (eolp, MAX_LINE, fp) == (char *)NULL)
  396.         break;
  397.     }
  398.  
  399. /* Terminate the line and add it to the argument list */
  400.  
  401.     if (EoLFound != (char *)NULL)
  402.         *EoLFound = 0;
  403.  
  404.     _Ex_AddArgument (line);
  405.     }
  406.  
  407.     if (ferror(fp))
  408.     _Ex_FatalError (errno, "%s: %s (%s)\n", file + 1);
  409.  
  410.     free (line);
  411.     fclose (fp);
  412.  
  413. /* Delete tempoary files */
  414.  
  415.     if (((line = strrchr (file + 1, '.')) != (char *)NULL) &&
  416.     (stricmp (line, ".tmp") == 0))
  417.     unlink (file + 1);            /* Delete it        */
  418. }
  419.  
  420. /* Get space for an argument name */
  421.  
  422. static char    *_Ex_GetSpace (length, in_s)
  423. int        length;            /* String length                */
  424. char        *in_s;                  /* String address        */
  425. {
  426.     char    *out_s;            /* Malloced space address       */
  427.  
  428.     if ((out_s = malloc (length + 1)) == (char *)NULL)
  429.     _Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);
  430.  
  431. /* Copy string for specified length */
  432.  
  433.     strncpy (out_s, in_s, length);
  434.     out_s[length] = 0;
  435.  
  436.     return (out_s);
  437. }
  438.  
  439. /* Append an argument to the array */
  440.  
  441. static void    _Ex_AddArgument (Argument)
  442. char        *Argument;            /* Argument to add        */
  443. {
  444.     if (__argc == 0)
  445.     __argv = (char **)malloc (50 * S_ENTRY);
  446.  
  447.     else if ((__argc % 50) == 0)
  448.     __argv = (char **)realloc (__argv, (__argc + 50) * S_ENTRY);
  449.  
  450.     if (__argv == (char **)NULL)
  451.     _Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);
  452.  
  453.     if (Argument == (char *)NULL)
  454.     __argv[__argc++] = (char *)NULL;
  455.  
  456.     else
  457.     __argv[__argc++] = _Ex_GetSpace (strlen (Argument), Argument);
  458. }
  459.  
  460. /*  Skip over spaces */
  461.  
  462. static char    *_Ex_SkipWhiteSpace (a)
  463. char        *a;            /* String start address        */
  464. {
  465.     while (isspace(*a))
  466.         a++;
  467.  
  468.     return (a);
  469. }
  470.  
  471. /* Convert name to Unix format */
  472.  
  473. static char    *_Ex_ConvertToUnixFormat (a)
  474. char        *a;
  475. {
  476.     char    *sp = a;
  477.  
  478.     while ((a = strchr (a, '\\')) != (char *)NULL)
  479.     *(a++) = '/';
  480.  
  481. #ifndef OS2
  482.     return strlwr (sp);
  483. #else
  484.     if (!IsHPFSFileSystem (sp))
  485.     strlwr (sp);
  486.  
  487.     return sp;
  488. #endif
  489.  
  490. }
  491.  
  492. /* Find the location of meta-characters.  If no meta, add the argument and
  493.  * return NULL.  If meta characters, return position of end of directory
  494.  * name.  If not multiple directories, return -1
  495.  */
  496.  
  497. static void    _Ex_ExpandField (file)
  498. char        *file;
  499. {
  500.     int        i = 0;
  501.     glob_t    gp;
  502.  
  503.     if (strpbrk (file, "?*[]\\") == (char *)NULL)
  504.     {
  505.     _Ex_AddArgument (file);
  506.     return;
  507.     }
  508.  
  509.     if (glob (file, GLOB_NOCHECK, (int (*)())NULL , &gp))
  510.     _Ex_FatalError (ENOMEM, _EX_OutOfMemory, (char *)NULL);
  511.  
  512.     i = 0;
  513.  
  514.     while (i < gp.gl_pathc)
  515.     _Ex_AddArgument (gp.gl_pathv[i++]);
  516.  
  517.     globfree (&gp);
  518. }
  519.  
  520. /* Fatal errors */
  521.  
  522. static void    _Ex_FatalError (ecode, format, para)
  523. int        ecode;
  524. char        *format;
  525. char        *para;
  526. {
  527.     fprintf (stderr, format, "stdargv", strerror (ecode), para);
  528.     exit (1);
  529. }
  530.  
  531. /* Process Environment - note that field is a malloc'ed field */
  532.  
  533. static char    *_Ex_ConvertEnvVariables (field)
  534. char        *field;
  535. {
  536.     char    *sp, *cp, *np, *ep;
  537.     char    save;
  538.     int        b_flag;
  539.  
  540.     sp = field;
  541.  
  542. /* Replace any $ strings */
  543.  
  544.     while ((sp = strchr (sp, '$')) != (char *)NULL)
  545.     {
  546.  
  547. /* If ${...}, find the terminating } */
  548.  
  549.     if (*(cp = ++sp) == '{')
  550.     {
  551.         b_flag = 1;
  552.         ++cp;
  553.  
  554.         while (*cp && (*cp != '}'))
  555.         cp++;
  556.     }
  557.  
  558. /* Else must be $..., find the terminating non-alphanumeric */
  559.  
  560.     else
  561.     {
  562.         b_flag = 0;
  563.  
  564.         while (isalnum (*cp))
  565.         cp++;
  566.     }
  567.  
  568. /* Grab the environment variable */
  569.  
  570.     if (cp == sp)
  571.         continue;
  572.  
  573. /* Get its value */
  574.  
  575.     save = *cp;
  576.     *cp = 0;
  577.     ep = getenv (sp + b_flag);
  578.     *cp = save;
  579.  
  580.     if (ep != (char *)NULL)
  581.     {
  582.         np = _Ex_GetSpace (strlen(field) - (cp - sp) + strlen (ep) - 1, field);
  583.         strcpy (&np[sp - field - 1], ep);
  584.         free (field);
  585.         strcpy ((sp = &np[strlen(np)]), cp + b_flag);
  586.         field = np;
  587.     }
  588.     }
  589.  
  590.     return field;
  591. }
  592. #endif
  593.