home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / c / getf.arc / QUOTEARG.C < prev   
C/C++ Source or Header  |  1988-11-20  |  10KB  |  362 lines

  1. /*
  2.     Copyright (C) 1987 by George W. Jolly.
  3.  
  4.     QUOTEARG VERSION 1.0, March 15, 1987
  5.  
  6.     Routine QUOTEARG scans the command image in the PSP and
  7.     creates a new argument vector.  New features not
  8.     included in the standard DeSmet argument scanner are
  9.     implemented.  A program using QUOTEARG need only add one
  10.     line of code to obtain the new features.
  11.  
  12.     New features implemented:
  13.  
  14.     1) Simple quoting.  An argument which begins with any of
  15.        the three quote characters ' ` " is taken to be a
  16.        quoted argument.  All characters up to a matching
  17.        quote are kept in the argument, including blanks.
  18.        The quote used for a given argument cannot be included
  19.        within the argument, so choose accordingly.
  20.  
  21.     2) File Name Wildcard Expansion.  An argument which is
  22.        NOT quoted as described above is eligible for wildcard
  23.        processing.  The DOS 'find first' / 'find next' calls are
  24.        used to scan for matching file names.  If none are found
  25.        the argument is kept as-is.  If one or more file names
  26.        are found the original argument is discarded and the
  27.        file names are placed in the argument list as separate
  28.        arguments.  (note: if the argument contains a drive or
  29.        directory path, they are prepended to each argument generated.)
  30.  
  31.     3) Program Name in Argument Zero.  Routine PGM_NAME, by
  32.        Dan Lewis, is used to obtain the name of the calling
  33.        program.  This name is provided in the first argument.
  34.  
  35.     An example call follows:
  36.  
  37.             main(argc,argv)
  38.             int argc;
  39.             char **argv;
  40.             {
  41.                 quotearg(&argc,&argv);
  42.                 <... other processing ...>
  43.             }
  44.  
  45.     NOTE: This code has been tested under DeSmet C 2.61 in both
  46.     small and large case.  When compiling large case, use the
  47.     option -NLARGE_CASE=1 so the conditional #ifdef's will know
  48.     you are using large case.  ASM88 provides such automatically,
  49.     but C88 does not.
  50.  
  51.                      *** Acknowledgement ***
  52.  
  53.     Back in my CP/M days I used BDS C by Leor Zolman.  It included
  54.     a routine, called the same way as this one, which handled wildcard
  55.     substitution for file names.  I was just learning C then, and that
  56.     routine really came in handy.  Many times I've wished I still had
  57.     it available.  Although this routine is new code, I remain grateful
  58.     to Leor Zolman for his fine product.
  59.  
  60.     History...
  61.         changes by Jim Van Zandt, Sept 88...
  62.             Checking for MS-DOS versions 1 or 2 before looking for pgm name.
  63.             Fewer arguments.
  64. */
  65.  
  66. unsigned _rax, _rds, _rdx, _rcx, _rbx;
  67.  
  68. #define strdup(s) (char *)malloc(strlen(s)+1)
  69.  
  70. /*
  71.    MAXARG defines the maximum number of arguments.  you might want
  72.    to tune this to your needs to conserve memory.
  73. */
  74.  
  75. #define MAXARG 100
  76. static char *argvec[MAXARG];
  77. static int   argcnt;
  78. extern char *malloc();
  79.  
  80.  
  81. quotearg( argc, argv )
  82. int *argc;
  83. char ***argv;
  84. {
  85.     int k, cmdptr, quoteflag;
  86.     char cmdbuf[130], argbuf[130], *cb;
  87.     char *pgm_name();
  88.     static void getcmd(char *);
  89.     static int getarg( char **, char *, int *);
  90.  
  91.     cmdptr = 0;
  92.     getcmd(cmdbuf);
  93.  
  94.     argcnt = 0;
  95.     argvec[argcnt++] = pgm_name();       /* program name first */
  96.  
  97.     cb = cmdbuf;
  98.     while(getarg( &cb, argbuf, "eflag ))
  99.     {
  100.         if (quoteflag)
  101.             k = 0;
  102.         else
  103.             k = read_dir( argbuf, argvec+argcnt, MAXARG-argcnt );
  104.  
  105.         if (k)
  106.         {
  107.             argcnt += k;
  108.         }
  109.         else
  110.         {                                          /* get some space */
  111.             argvec[argcnt] = (char *)malloc(strlen(argbuf)+1);
  112.             strcpy( argvec[argcnt++], argbuf );  /* and save the name in it */
  113.         }
  114.     }
  115.     *argc = argcnt;
  116.     *argv = argvec;
  117. }
  118.  
  119.  
  120. static int getarg( bp, arg, quoteflag )
  121. char **bp;
  122. char *arg;
  123. int *quoteflag;
  124. {
  125.     char *buf;
  126.     int  rf;
  127.  
  128.     buf = *bp;       /* grab the input buffer pointer */
  129.     *quoteflag = 0;  /* assume is not quoted */
  130.  
  131.     while(isspace(*buf)) buf++;     /* skip leading whitespace */
  132.  
  133.     rf = 0;      /* initialize return flag */
  134.     if (*buf)
  135.     {
  136.         rf = 1;  /* set return flag (an argument was found) */
  137.         if (*buf == '\'' || *buf == '\"' || *buf == '`')   /* if quoted */
  138.         {
  139.             *quoteflag = *buf++;                /* remember what it was */
  140.             while (*buf && *buf != *quoteflag)
  141.                 *arg++ = *buf++;                /* copy the quoted arg over */
  142.             if (*buf == *quoteflag)             /* then find whitespace */
  143.                while (!isspace(*buf) && (*buf != 0))
  144.                     buf++;
  145.         }
  146.         else                                    /* if not quoted */
  147.         {
  148.             while (!isspace(*buf) && *buf)
  149.                 *arg++ = *buf++;        /* copy the unquoted arg over */
  150.         }
  151.     }
  152.     *arg = 0;        /* terminate the output string */
  153.     *bp = buf;       /* update buffer pointer */
  154.     return(rf);
  155. }
  156.  
  157.  
  158. static int read_dir( s, argv, max )
  159. char *s;
  160. char **argv;
  161. int  max;
  162. {
  163.     int i, func, attr;
  164.     char buf[50], path[150], temp[300];
  165.     static void strlower(char *);
  166.  
  167.     get_path( s, path );
  168.  
  169.                             /* if no wild cards, don't bother looking */
  170.     if(strpbrk( s, "*?") == 0) return 0;
  171.  
  172.     attr = 0;                /* no directories or hidden files */
  173.     func = 0x4E;            /* search for first entry   */
  174.     i = 0;
  175.     while (i<max && (n_dir_srch( s, func, buf, attr )==0))
  176.     {
  177.         func = 0x4F;               /* search for next entry next time */
  178.         strcpy( temp, path );                      /* first put path in */
  179.         strcat( temp, buf+21+1+2+2+2+2 );          /* then put name.ext in */
  180.         argv[i] = (char *)malloc(strlen(temp)+1);  /* get some space */
  181.         strlower(temp);                            /* make lower case */
  182.         strcpy( argv[i], temp );                   /* save the name in it */
  183.         i++;
  184.     }
  185.     return i;
  186. }
  187.  
  188.  
  189. static void getcmd(buf)       /* get parameter string from PSP */
  190. char *buf;
  191. {
  192.     char len;
  193.     unsigned pspseg;
  194.     extern unsigned _pcb ;  /* defined by DeSmet C: PSP's segment */
  195.     int  bufseg;
  196.     int  bufoff;
  197.     int  lenseg;
  198.     int  lenoff;
  199.  
  200.     pspseg = _pcb;
  201.  
  202. #ifdef LARGE_CASE
  203.     bufseg = ((long)buf) >> 16;
  204.     bufoff = ((long)buf) & 0xFFFF;
  205.     lenseg = ((long)(&len)) >> 16;
  206.     lenoff = ((long)(&len)) & 0xFFFF;
  207. #else
  208.     bufseg = _showds();
  209.     bufoff = buf;
  210.     lenseg = _showds();
  211.     lenoff = &len;
  212. #endif
  213.     len = 0;
  214.     _lmove( 127, 0x81, pspseg, bufoff, bufseg );
  215. /*
  216.     the following code would be correct if the PSP still looked like
  217.     DOS made it look.   However, DeSmet C initialization seems to
  218.     put a blank on the length byte and a CR after the string.  This
  219.     is done before we get control, so we must live with it.
  220.  
  221.            _lmove( 1, 0x80, pspseg, lenoff, lenseg );
  222.            buf[len] = 0;
  223. */
  224.     while (*buf != 0x0D) buf++;    /* find the CR */
  225.     *buf = 0;                      /* null out the CR */
  226. }
  227.  
  228.  
  229. static int n_dir_srch( s, func, buf, attr )
  230. char *s, *buf;
  231. int func, attr;
  232. {
  233. #ifndef LARGE_CASE
  234.     _rax = 0x1A00;   _rds = _showds();  _rdx = buf;              _doint(0x21);
  235.     _rax = func<<8;  _rds = _showds();  _rdx = s;  _rcx = attr;  _doint(0x21);
  236. #else
  237.     _rax = 0x1A00;   _rds = ((long)buf)>>16;  
  238.                      _rdx = buf & 0xFFFF;                 _doint(0x21);
  239.     _rax = func<<8;  _rds = ((long)s)>>16;  
  240.                      _rdx = s & 0xFFFF;      _rcx = attr; _doint(0x21);
  241. #endif
  242.     return(_rax);
  243. }
  244.  
  245. static int get_path( s, path )
  246. char *s, *path;
  247. {
  248.     int len;
  249.     char *p1;
  250.     char *rindex();
  251.  
  252.     len = strlen(s);            /* grab the length */
  253.     path[0] = '\0';                /* empty the path string */
  254.     p1 = rindex( s, '\\' );        /* seek end of path string */
  255.     if (p1)
  256.     {
  257.         *path++ = *s;            /* copy first byte of directory string */
  258.         while (s++ != p1)
  259.             *path++ = *s;        /* copy the path string    */
  260.         *path = '\0';            /* terminate the string    */
  261.     }
  262.     else
  263.     {
  264.         if (s[1] == ':')
  265.         {
  266.             *path++ = s[0];
  267.             *path++ = s[1];
  268.             *path++ = 0;
  269.         }
  270.     }
  271.     return;
  272. }
  273.  
  274. static void strlower(s)
  275. char *s;
  276. {
  277.     while(*s)
  278.     {
  279.         *s = tolower(*s);
  280.         s++;
  281.     }
  282. }
  283.  
  284. /*
  285.         PGM_NAME.C:  Function to retrieve a program's name
  286.         --------------------------------------------------
  287.         This simple function retrieves the name that was used to
  288.         invoke the program that contains it.  Even if you simply
  289.         rename the executable file without recompiling it, this
  290.         function will properly return the new name.  In effect, 
  291.         this function returns what should (but is NOT) supplied
  292.         by argv[0].
  293.  
  294.         The name includes not only the filename and extension of
  295.         the EXE (or COM) file; DOS also prepends the name of the
  296.         subdirectory where it was found.  If found in the current
  297.         directory, this prefix will begin with the drive designator.
  298.         Otherwise, if DOS had to invoke the PATH processing to find 
  299.         the program, the prefix will come from one of the strings of
  300.         the PATH environment variable (which may or may not include
  301.         the drive designator - it depends on you).
  302.  
  303.         One useful characteristic of the name is that the name
  304.         returned is NOT always the same.  In particular, if a
  305.         program named ABC loads and executes program XYZ which
  306.         calls this function, the name returned will be ABC, not
  307.         XYZ.  This can be used to detect the manner of invocation
  308.         of the program - i.e., direct or chained.
  309.  
  310.         This program was written in DeSmet C based on the code found
  311.         in a public domain program written in Turbo Pascal called
  312.         MAPMEM.PAS, written by K. Kokkonen of TurboPower Software.
  313.  
  314.         Dan Lewis, Key Software Products      Sept. 9, 1986
  315. */
  316.  
  317. static char *pgm_name()         /* routine made static by gwj */
  318. {
  319.     int i ;
  320.     unsigned off = 0 ;
  321.     extern unsigned _pcb ;  /* defined by DeSmet C: PSP's segment */
  322.     union
  323.         {
  324.         unsigned seg ;  /* environment segment */
  325.         char byte[2] ;  /* unpacked form */
  326.         } env ;
  327.     char *name ;
  328.     char *ptr ;
  329.     static char bfr[200] ;
  330.     static char empty[] = "";
  331.  
  332.             /* program name isn't available under MS-DOS 1 or 2 */
  333.     _rax = 0x3000;
  334.     _doint(0x21);
  335.     if((_rax & 0x00ff) < 3) return empty;
  336.  
  337.             /* retrieve paragraph address of environment strings */
  338.     env.byte[0] = _peek( 0x2C, _pcb ) ;
  339.     env.byte[1] = _peek( 0x2D, _pcb ) ;
  340.  
  341.     /* Skip past environment strings */
  342.     while (_peek( off++, env.seg ))
  343.     {
  344.         while (_peek( off++, env.seg ))
  345.         {
  346.         }
  347.     }
  348.  
  349.     /* Look for start of program pathname */
  350.     while (_peek( ++off, env.seg ) == 0)
  351.     {
  352.     }
  353.  
  354.     /* Copy program pathname */
  355.     ptr = bfr ;
  356.     while (*ptr++ = toupper(_peek( off++, env.seg )))
  357.     {
  358.     }
  359.  
  360.     return (name = bfr);
  361. }
  362.