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