home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / SH162_2S.ZIP / STDARGV.C < prev    next >
C/C++ Source or Header  |  1990-08-04  |  13KB  |  611 lines

  1. /*
  2.  *  MODULE NAME:     expand.c                        Revision: 1.0
  3.  *
  4.  *  AUTHOR:         Ian Stewartson
  5.  *
  6.  *  LOCATION:         Data Logic,
  7.  *             Greenford,
  8.  *             Middlesex,
  9.  *             England.
  10.  *
  11. #include <logo.h>
  12.  *  MODULE DEFINITION:    This function expandes the command line parameters
  13.  *            in a UNIX like manner.    Wild character *?[] are
  14.  *            allowed in file names. @filename causes command lines
  15.  *            to be read from filename.  Strings between " or ' are
  16.  *            not expanded.  All entries in the array are malloced.
  17.  *
  18.  *            This function replaces the standard MS-DOS command
  19.  *            line processing function (_setargv in stdargv.obj).
  20.  *
  21.  *  CALLING SEQUENCE:    The following calling sequences are used:
  22.  *
  23.  *            void    _setargv ();
  24.  *
  25.  *  ERROR MESSAGES:    Out of memory
  26.  *
  27.  *  INCLUDE FILES:
  28.  */
  29.  
  30. #include <sys/types.h>            /* MS-DOS type definitions          */
  31. #include <sys/stat.h>            /* File status definitions        */
  32. #include <stdio.h>            /* Standard I/O delarations         */
  33. #include <stdlib.h>            /* Standard library functions       */
  34. #include <errno.h>            /* Error number declarations        */
  35. #include <ctype.h>            /* Character type declarations      */
  36. #include <string.h>            /* String library functions         */
  37. #include <limits.h>            /* String library functions         */
  38. #include <fcntl.h>            /* File Control Declarations        */
  39. #include <io.h>                /* Input/Output Declarations        */
  40. #include <changes.h>
  41. #include <dir.h>            /* Direction I/O functions        */
  42.  
  43. #define INCL_NOPM
  44. #define INCL_DOS
  45. #include <os2.h>
  46.  
  47. /*
  48.  *  DATA DEFINITIONS:
  49.  */
  50.  
  51. #define MAX_LINE    256        /* Max line length        */
  52. #define S_ENTRY        sizeof (char *)
  53.  
  54. /*
  55.  *  DATA DECLARATIONS:
  56.  */
  57. #ifdef MSDOS
  58.  
  59. extern void    _setargv (void);
  60. static void    exp_line (char *);        /* Expand file        */
  61. static int    ex_pfield (char    *, char *);    /* Expand field        */
  62. static void    ex_pfile (char *);
  63. static char    *ex_gspace (int, char *);    /* Get space        */
  64. static void    ex_add_arg (char *);    /* Add argument            */
  65. static char    *ex_skip_sp (char *);    /* Skip spaces            */
  66. static char    *ex_tounix (char *);    /* Convert name to Unix format    */
  67. static int    ex_find (char*, int);    /* Split file name        */
  68. static void    ex_fatal (int, char *, char *);    /* Fatal error processing*/
  69. static char    *ex_environment (char *);    /* Process environment    */
  70. static char    *_ex_multi_drive (char *);    /* Check for multidrive    */
  71. static char    *ex_nomem = "%s: %s\n";
  72.  
  73. extern char far    *_pgmptr;         /* Program name            */
  74. extern char    **__argv;         /* Current argument address    */
  75. extern int    __argc;         /* Current argument count    */
  76.  
  77. extern unsigned _aenvseg;
  78. extern unsigned _acmdln;
  79.  
  80. /*
  81.  *  MODULE ABSTRACT: _setargv
  82.  *
  83.  *  UNIX like command line expansion
  84.  */
  85.  
  86. void    _setargv ()
  87. {
  88.                     /* Set up pointer to command line */
  89.     char far        *argvp = MAKEP(_aenvseg, _acmdln);
  90.     char far        *s;         /* Temporary string pointer        */
  91. #ifndef M_I86LM
  92.     char        buf[MAX_LINE];    /* Temporary space        */
  93.     char        *cp;
  94. #endif
  95.  
  96. /* Command line can be null or 0x0d terminated - convert to null */
  97.  
  98.     s = argvp;
  99.  
  100.     while (*s && (*s != 0x0d))
  101.     ++s;
  102.  
  103.     if (*s == 0x0d)
  104.     *s = 0;
  105.  
  106. /* Set up global parameters and expand */
  107.  
  108.     __argc = 0;
  109.  
  110. /* Get the program name */
  111.  
  112.     if (_osmajor <= 2)
  113.     s = "unknown";
  114.  
  115. /* In the case of DOS 3+, we look in the environment space */
  116.  
  117.     else
  118.     for ( s = argvp; *(s - 1); s-- );
  119.  
  120.     _pgmptr = s;
  121.  
  122. #ifndef M_I86LM
  123.     cp = buf;
  124.     while (*(cp++) = *(s++));
  125.  
  126.     ex_add_arg (ex_tounix (buf));    /* Add the program name        */
  127.  
  128.     s  = argvp;
  129.     cp = buf;
  130.     while (*(cp++) = *(s++));
  131.  
  132.     exp_line (buf);
  133. #else
  134.     ex_add_arg (ex_tounix (s));        /* Add the program name        */
  135.     exp_line (argvp);
  136. #endif
  137.  
  138.     ex_add_arg ((char *)NULL);
  139.     --__argc;
  140. }
  141.  
  142. /*
  143.  * Expand a line
  144.  */
  145.  
  146. static void    exp_line (argvp)
  147. char        *argvp;            /* Line to expand            */
  148. {
  149.     char    *spos;            /* End of string pointer    */
  150.     char    *cpos;            /* Start of string pointer    */
  151.     char    *fn;            /* Extracted file name string    */
  152.  
  153. /* Search for next separator */
  154.  
  155.     spos = argvp;
  156.  
  157.     while (*(cpos = ex_skip_sp (spos)))
  158.     {
  159.  
  160. /* Extract string argument */
  161.  
  162.     if ((*cpos == '"') || (*cpos == '\''))
  163.     {
  164.         spos = cpos + 1;
  165.  
  166.         do
  167.         {
  168.         if ((spos = strchr (spos, *cpos)) != NULL)
  169.         {
  170.             spos++;
  171.             if (spos[-2] != '\\')
  172.             break;
  173.         }
  174.  
  175.         else
  176.             spos = &spos[strlen (cpos)];
  177.  
  178.         }
  179.         while (*spos);
  180.  
  181.         fn    = ex_gspace (spos - cpos - 2, cpos + 1);
  182.     }
  183.  
  184. /* Extract normal argument */
  185.  
  186.     else
  187.     {
  188.         spos = cpos;
  189.         while (!isspace(*spos) && *spos)
  190.         spos++;
  191.  
  192.         fn = ex_gspace (spos - cpos, cpos);
  193.     }
  194.  
  195. /* Process argument */
  196.  
  197.     if (*cpos != '"')
  198.         fn = ex_environment (fn);
  199.  
  200.     switch (*cpos)
  201.     {
  202.         case '@':        /* Expand file                    */
  203.         ex_pfile (fn);
  204.         break;
  205.  
  206.         case '"':        /* Expand string                */
  207.         case '\'':
  208.         ex_add_arg (fn);
  209.         break;
  210.  
  211.         default:        /* Expand field                    */
  212.         if (!ex_find (fn, 0))
  213.             ex_add_arg (fn);
  214.     }
  215.  
  216.     free (fn);
  217.     }
  218. }
  219.  
  220. /* Expand a field if it has metacharacters in it */
  221.  
  222. static int    ex_pfield (prefix, postfix)
  223. char        *prefix;        /* Prefix field                */
  224. char        *postfix;        /* Postfix field            */
  225. {
  226.     int          count;        /* File path length        */
  227.     int         f_count = 0;    /* Number of files generated    */
  228.     int            slash_flag = 0;    /* slash required        */
  229.     char        fn[PATH_MAX + NAME_MAX + 2];/* Search file name */
  230.     char        *name;        /* Match string            */
  231.     char        *p, *p1;
  232.     DIR            *dp;
  233.     struct direct    *c_de;
  234.     unsigned int    c_drive;    /* Current drive        */
  235.     unsigned int    m_drive;    /* Max drive            */
  236.     unsigned int    s_drive;    /* Selected drive        */
  237.     unsigned int    x_drive, y_drive;    /* Dummies        */
  238.     char        *multi;        /* Multi-drive flag        */
  239.     char        t_drive[2];
  240.     ULONG               l_map;
  241.     int                 cnt;
  242.  
  243. /* Convert file name to lower case */
  244.  
  245.     strlwr (prefix);
  246.  
  247. /* Search all drives ? */
  248.  
  249.     if ((multi = _ex_multi_drive (prefix)) != (char *)NULL)
  250.     {
  251.         DosQCurDisk((PUSHORT) &c_drive, &l_map);
  252.     t_drive[1] = 0;
  253.  
  254.         for ( cnt = 1; cnt <= 26; cnt++, l_map >>= 1 )
  255.           if ( l_map & 1L )
  256.       {
  257.           t_drive[0] = (char)(cnt + 'a' - 1);
  258.               *multi = 0;
  259.  
  260.           if (pnmatch (t_drive, prefix, 0))
  261.           {
  262.                 *multi = ':';
  263.           fn[0] = t_drive[0];
  264.           strcpy (fn + 1, multi);
  265.           f_count += ex_pfield (fn, postfix);
  266.           }
  267.               else
  268.                 *multi = ':';
  269.       }
  270.  
  271.     return f_count;
  272.     }
  273.  
  274. /* Get the path length */
  275.  
  276.     p = strrchr (prefix, '/');
  277.     p1 = strchr (prefix, ':');
  278.  
  279.     if ((p1 == (char *)NULL) || (p1 < p))
  280.     {
  281.     if (p == (char *)NULL)
  282.     {
  283.         count = 0;
  284.         name = prefix;
  285.     }
  286.  
  287.     else
  288.     {
  289.         count = p - prefix;
  290.         name = p + 1;
  291.     }
  292.     }
  293.  
  294.     else if ((p == (char *)NULL) || (p < p1))
  295.     {
  296.     count = p1 - prefix;
  297.     name = p1 + 1;
  298.     }
  299.  
  300. /* Set up file name for search */
  301.  
  302.     if (((count == 2) && (strncmp (prefix + 1, ":/", 2) == 0)) ||
  303.     ((count == 0) && (*prefix == '/')))
  304.     {
  305.     strncpy (fn, prefix, ++count);
  306.     fn[count] = 0;
  307.     strcat (fn, ".");
  308.     }
  309.  
  310.     else
  311.     {
  312.     if ((count == 1) && (*(prefix + 1) == ':'))
  313.         count++;
  314.  
  315.     strncpy (fn, prefix, count);
  316.     fn[count] = 0;
  317.  
  318.     if (((count == 2) && (*(prefix + 1) == ':')) || (count == 0))
  319.         strcat (fn, ".");
  320.  
  321.     else
  322.         slash_flag = 1;
  323.     }
  324.  
  325. /* Search for file names */
  326.  
  327.     if ((dp = opendir (fn)) == (DIR *)NULL)
  328.     return 0;
  329.  
  330. /* Are there any matches */
  331.  
  332.     while ((c_de = readdir (dp)) != (struct direct *)NULL)
  333.     {
  334.     if ((*c_de->d_name == '.') && (*name != '.'))
  335.         continue;
  336.  
  337. /* Check for match */
  338.  
  339.     if (pnmatch (c_de->d_name, name, 0))
  340.     {
  341.         fn[count] = 0;
  342.  
  343.         if (slash_flag)
  344.         strcat (fn, "/");
  345.  
  346.         strcat (fn, c_de->d_name);
  347.  
  348. /* If the postfix is not null, this must be a directory */
  349.  
  350.         if (postfix != (char *)NULL)
  351.         {
  352.         struct stat        statb;
  353.  
  354.         if (stat (fn, &statb) < 0 ||
  355.             (statb.st_mode & S_IFMT) != S_IFDIR)
  356.             continue;
  357.  
  358.         strcat (fn, "/");
  359.         strcat (fn, postfix);
  360.         }
  361.  
  362.         f_count += ex_find (fn, 1);
  363.     }
  364.     }
  365.  
  366.     closedir (dp);
  367.     return f_count;
  368. }
  369.  
  370. /* Expand file name */
  371.  
  372. static void    ex_pfile (file)
  373. char        *file;        /* Expand file name                */
  374. {
  375.     FILE        *fp;        /* File descriptor                */
  376.     char    *p;        /* Pointer                */
  377.     int        c_maxlen = MAX_LINE;
  378.     char    *line;        /* Line buffer                    */
  379.  
  380. /* Grab some memory for the line */
  381.  
  382.     if ((line = malloc (c_maxlen)) == (char *)NULL)
  383.     ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
  384.  
  385. /* If file open fails, expand as a field */
  386.  
  387.     if ((fp = fopen (file + 1, "rt")) == NULL)
  388.     {
  389.     if (!ex_find (file, 0))
  390.         ex_add_arg (file);
  391.  
  392.     return;
  393.     }
  394.  
  395. /* For each line in the file, remove EOF characters and add argument */
  396.  
  397.     while (fgets (line, c_maxlen, fp) != (char *)NULL)
  398.     {
  399.     while ((p = strchr (line, '\n')) == (char *)NULL)
  400.     {
  401.         if ((p = strchr (line, 0x1a)) != (char *)NULL)
  402.         break;
  403.  
  404.         if ((line = realloc (line, c_maxlen + MAX_LINE)) == (char *)NULL)
  405.         ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
  406.  
  407.         if (fgets (&line[c_maxlen - 1], MAX_LINE, fp) == (char *)NULL)
  408.         break;
  409.  
  410.         c_maxlen += MAX_LINE - 1;
  411.     }
  412.  
  413.     if (p != (char *)NULL)
  414.         *p = 0;
  415.  
  416.     ex_add_arg (line);
  417.     }
  418.  
  419.     if (ferror(fp))
  420.     ex_fatal (errno, "%s: %s (%s)\n", file + 1);
  421.  
  422.     free (line);
  423.     fclose (fp);
  424. }
  425.  
  426. /* Get space for name */
  427.  
  428. static char    *ex_gspace (l, in_s)
  429. int        l;            /* String length                */
  430. char        *in_s;                  /* String address        */
  431. {
  432.     char    *out_s;            /* Malloced space address       */
  433.  
  434.     if ((out_s = malloc (l + 1)) == (char *)NULL)
  435.     ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
  436.  
  437. /* Copy string for specified length */
  438.  
  439.     strncpy (out_s, in_s, l);
  440.     out_s[l] = 0;
  441.  
  442.     return (out_s);
  443. }
  444.  
  445. /* Append an argument to the string */
  446.  
  447. static void    ex_add_arg (fn)
  448. char        *fn;            /* Argument to add        */
  449. {
  450.     if (__argc == 0)
  451.     __argv = (char **)malloc (50 * S_ENTRY);
  452.  
  453.     else if ((__argc % 50) == 0)
  454.     __argv = (char **)realloc (__argv, (__argc + 50) * S_ENTRY);
  455.  
  456.     if (__argv == (char **)NULL)
  457.     ex_fatal (ENOMEM, ex_nomem, (char *)NULL);
  458.  
  459.     __argv[__argc++] = (fn == (char *)NULL) ? fn : ex_gspace (strlen (fn), fn);
  460. }
  461.  
  462. /*  Skip over spaces */
  463.  
  464. static char    *ex_skip_sp (a)
  465. char        *a;            /* String start address        */
  466. {
  467.     while (isspace(*a))
  468.         a++;
  469.  
  470.     return (a);
  471. }
  472.  
  473. /* Convert name to Unix format */
  474.  
  475. static char    *ex_tounix (a)
  476. char        *a;
  477. {
  478.     char    *sp = a;
  479.  
  480.     while ((a = strchr (a, '\\')) != (char *)NULL)
  481.     *(a++) = '/';
  482.  
  483.     return strlwr (sp);
  484. }
  485.  
  486. /* Find the location of meta-characters.  If no meta, add the argument and
  487.  * return NULL.  If meta characters, return position of end of directory
  488.  * name.  If not multiple directories, return -1
  489.  */
  490.  
  491. static int    ex_find (file, must_exist)
  492. char        *file;
  493. int        must_exist;        /* FIle must exist flag        */
  494. {
  495.     char    *p;
  496.     int        i;
  497.     static char    ex_meta[] = "?*[]\\";    /* Metacharacters        */
  498.  
  499.     if ((p = strpbrk (file, ex_meta)) == (char *)NULL)
  500.     {
  501.     if (must_exist && (access (file, 0) < 0))
  502.         return 0;
  503.  
  504.     ex_add_arg (file);
  505.     return 1;
  506.     }
  507.  
  508.     else if ((p = strchr (p, '/')) != (char *)NULL)
  509.     *(p++) = 0;
  510.  
  511.     i = ex_pfield (file, p);
  512.  
  513.     if (p != (char *)NULL)
  514.        *(--p) = '/';
  515.  
  516.     return i;
  517. }
  518.  
  519. /* Fatal errors */
  520.  
  521. static void    ex_fatal (ecode, format, para)
  522. int        ecode;
  523. char        *format;
  524. char        *para;
  525. {
  526.     fprintf (stderr, format, "stdargv", strerror (ecode), para);
  527.     exit (1);
  528. }
  529.  
  530. /* Process Environment - note that field is a malloc'ed field */
  531.  
  532. static char    *ex_environment (field)
  533. char        *field;
  534. {
  535.     char    *sp, *cp, *np, *ep;
  536.     char    save;
  537.     int        b_flag;
  538.  
  539.     sp = field;
  540.  
  541. /* Replace any $ strings */
  542.  
  543.     while ((sp = strchr (sp, '$')) != (char *)NULL)
  544.     {
  545.     if (*(cp = ++sp) == '{')
  546.     {
  547.         b_flag = 1;
  548.         ++cp;
  549.  
  550.         while (*cp && (*cp != '}'))
  551.         cp++;
  552.     }
  553.  
  554.     else
  555.     {
  556.         b_flag;
  557.  
  558.         while (isalnum(*cp))
  559.         cp++;
  560.     }
  561.  
  562. /* Grab the environment variable */
  563.  
  564.     if (cp == sp)
  565.         continue;
  566.  
  567.     save = *cp;
  568.     *cp = 0;
  569.     ep = getenv (sp + b_flag);
  570.     *cp = save;
  571.  
  572.     if (ep != (char *)NULL)
  573.     {
  574.         np = ex_gspace (strlen(field) - (cp - sp) + strlen (ep) - 1, field);
  575.         strcpy (&np[sp - field - 1], ep);
  576.         ex_tounix (&np[sp - field - 1]);
  577.         free (field);
  578.         strcpy ((sp = &np[strlen(np)]), cp + b_flag);
  579.         field = np;
  580.     }
  581.     }
  582.  
  583.     return field;
  584. }
  585.  
  586. /* Check for multi_drive prefix */
  587.  
  588. static char    *_ex_multi_drive (prefix)
  589. char        *prefix;
  590. {
  591.     if (strlen (prefix) < 2)
  592.     return (char *)NULL;
  593.  
  594.     if (((*prefix == '*') || (*prefix == '?')) && (prefix[1] == ':'))
  595.     return prefix + 1;
  596.  
  597.     if (*prefix != '[')
  598.     return (char *)NULL;
  599.  
  600.     while (*prefix && (*prefix != ']'))
  601.     {
  602.     if ((*prefix == '\\') && (*(prefix + 1)))
  603.         ++prefix;
  604.  
  605.     ++prefix;
  606.     }
  607.  
  608.     return (*prefix && (*(prefix + 1) == ':')) ? prefix + 1 : (char *)NULL;
  609. }
  610. #endif
  611.