home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright (C) 1987 by George W. Jolly.
-
- QUOTEARG VERSION 1.0, March 15, 1987
-
- Routine QUOTEARG scans the command image in the PSP and
- creates a new argument vector. New features not
- included in the standard DeSmet argument scanner are
- implemented. A program using QUOTEARG need only add one
- line of code to obtain the new features.
-
- New features implemented:
-
- 1) Simple quoting. An argument which begins with any of
- the three quote characters ' ` " is taken to be a
- quoted argument. All characters up to a matching
- quote are kept in the argument, including blanks.
- The quote used for a given argument cannot be included
- within the argument, so choose accordingly.
-
- 2) File Name Wildcard Expansion. An argument which is
- NOT quoted as described above is eligible for wildcard
- processing. The DOS 'find first' / 'find next' calls are
- used to scan for matching file names. If none are found
- the argument is kept as-is. If one or more file names
- are found the original argument is discarded and the
- file names are placed in the argument list as separate
- arguments. (note: if the argument contains a drive or
- directory path, they are prepended to each argument generated.)
-
- 3) Program Name in Argument Zero. Routine PGM_NAME, by
- Dan Lewis, is used to obtain the name of the calling
- program. This name is provided in the first argument.
-
- An example call follows:
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- quotearg(&argc,&argv);
- <... other processing ...>
- }
-
- NOTE: This code has been tested under DeSmet C 2.61 in both
- small and large case. When compiling large case, use the
- option -NLARGE_CASE=1 so the conditional #ifdef's will know
- you are using large case. ASM88 provides such automatically,
- but C88 does not.
-
- *** Acknowledgement ***
-
- Back in my CP/M days I used BDS C by Leor Zolman. It included
- a routine, called the same way as this one, which handled wildcard
- substitution for file names. I was just learning C then, and that
- routine really came in handy. Many times I've wished I still had
- it available. Although this routine is new code, I remain grateful
- to Leor Zolman for his fine product.
-
- History...
- changes by Jim Van Zandt, Sept 88...
- Checking for MS-DOS versions 1 or 2 before looking for pgm name.
- Fewer arguments.
- */
-
- unsigned _rax, _rds, _rdx, _rcx, _rbx;
-
- #define strdup(s) (char *)malloc(strlen(s)+1)
-
- /*
- MAXARG defines the maximum number of arguments. you might want
- to tune this to your needs to conserve memory.
- */
-
- #define MAXARG 100
- static char *argvec[MAXARG];
- static int argcnt;
- extern char *malloc();
-
-
- quotearg( argc, argv )
- int *argc;
- char ***argv;
- {
- int k, cmdptr, quoteflag;
- char cmdbuf[130], argbuf[130], *cb;
- char *pgm_name();
- static void getcmd(char *);
- static int getarg( char **, char *, int *);
-
- cmdptr = 0;
- getcmd(cmdbuf);
-
- argcnt = 0;
- argvec[argcnt++] = pgm_name(); /* program name first */
-
- cb = cmdbuf;
- while(getarg( &cb, argbuf, "eflag ))
- {
- if (quoteflag)
- k = 0;
- else
- k = read_dir( argbuf, argvec+argcnt, MAXARG-argcnt );
-
- if (k)
- {
- argcnt += k;
- }
- else
- { /* get some space */
- argvec[argcnt] = (char *)malloc(strlen(argbuf)+1);
- strcpy( argvec[argcnt++], argbuf ); /* and save the name in it */
- }
- }
- *argc = argcnt;
- *argv = argvec;
- }
-
-
- static int getarg( bp, arg, quoteflag )
- char **bp;
- char *arg;
- int *quoteflag;
- {
- char *buf;
- int rf;
-
- buf = *bp; /* grab the input buffer pointer */
- *quoteflag = 0; /* assume is not quoted */
-
- while(isspace(*buf)) buf++; /* skip leading whitespace */
-
- rf = 0; /* initialize return flag */
- if (*buf)
- {
- rf = 1; /* set return flag (an argument was found) */
- if (*buf == '\'' || *buf == '\"' || *buf == '`') /* if quoted */
- {
- *quoteflag = *buf++; /* remember what it was */
- while (*buf && *buf != *quoteflag)
- *arg++ = *buf++; /* copy the quoted arg over */
- if (*buf == *quoteflag) /* then find whitespace */
- while (!isspace(*buf) && (*buf != 0))
- buf++;
- }
- else /* if not quoted */
- {
- while (!isspace(*buf) && *buf)
- *arg++ = *buf++; /* copy the unquoted arg over */
- }
- }
- *arg = 0; /* terminate the output string */
- *bp = buf; /* update buffer pointer */
- return(rf);
- }
-
-
- static int read_dir( s, argv, max )
- char *s;
- char **argv;
- int max;
- {
- int i, func, attr;
- char buf[50], path[150], temp[300];
- static void strlower(char *);
-
- get_path( s, path );
-
- /* if no wild cards, don't bother looking */
- if(strpbrk( s, "*?") == 0) return 0;
-
- attr = 0; /* no directories or hidden files */
- func = 0x4E; /* search for first entry */
- i = 0;
- while (i<max && (n_dir_srch( s, func, buf, attr )==0))
- {
- func = 0x4F; /* search for next entry next time */
- strcpy( temp, path ); /* first put path in */
- strcat( temp, buf+21+1+2+2+2+2 ); /* then put name.ext in */
- argv[i] = (char *)malloc(strlen(temp)+1); /* get some space */
- strlower(temp); /* make lower case */
- strcpy( argv[i], temp ); /* save the name in it */
- i++;
- }
- return i;
- }
-
-
- static void getcmd(buf) /* get parameter string from PSP */
- char *buf;
- {
- char len;
- unsigned pspseg;
- extern unsigned _pcb ; /* defined by DeSmet C: PSP's segment */
- int bufseg;
- int bufoff;
- int lenseg;
- int lenoff;
-
- pspseg = _pcb;
-
- #ifdef LARGE_CASE
- bufseg = ((long)buf) >> 16;
- bufoff = ((long)buf) & 0xFFFF;
- lenseg = ((long)(&len)) >> 16;
- lenoff = ((long)(&len)) & 0xFFFF;
- #else
- bufseg = _showds();
- bufoff = buf;
- lenseg = _showds();
- lenoff = &len;
- #endif
- len = 0;
- _lmove( 127, 0x81, pspseg, bufoff, bufseg );
- /*
- the following code would be correct if the PSP still looked like
- DOS made it look. However, DeSmet C initialization seems to
- put a blank on the length byte and a CR after the string. This
- is done before we get control, so we must live with it.
-
- _lmove( 1, 0x80, pspseg, lenoff, lenseg );
- buf[len] = 0;
- */
- while (*buf != 0x0D) buf++; /* find the CR */
- *buf = 0; /* null out the CR */
- }
-
-
- static int n_dir_srch( s, func, buf, attr )
- char *s, *buf;
- int func, attr;
- {
- #ifndef LARGE_CASE
- _rax = 0x1A00; _rds = _showds(); _rdx = buf; _doint(0x21);
- _rax = func<<8; _rds = _showds(); _rdx = s; _rcx = attr; _doint(0x21);
- #else
- _rax = 0x1A00; _rds = ((long)buf)>>16;
- _rdx = buf & 0xFFFF; _doint(0x21);
- _rax = func<<8; _rds = ((long)s)>>16;
- _rdx = s & 0xFFFF; _rcx = attr; _doint(0x21);
- #endif
- return(_rax);
- }
-
- static int get_path( s, path )
- char *s, *path;
- {
- int len;
- char *p1;
- char *rindex();
-
- len = strlen(s); /* grab the length */
- path[0] = '\0'; /* empty the path string */
- p1 = rindex( s, '\\' ); /* seek end of path string */
- if (p1)
- {
- *path++ = *s; /* copy first byte of directory string */
- while (s++ != p1)
- *path++ = *s; /* copy the path string */
- *path = '\0'; /* terminate the string */
- }
- else
- {
- if (s[1] == ':')
- {
- *path++ = s[0];
- *path++ = s[1];
- *path++ = 0;
- }
- }
- return;
- }
-
- static void strlower(s)
- char *s;
- {
- while(*s)
- {
- *s = tolower(*s);
- s++;
- }
- }
-
- /*
- PGM_NAME.C: Function to retrieve a program's name
- --------------------------------------------------
- This simple function retrieves the name that was used to
- invoke the program that contains it. Even if you simply
- rename the executable file without recompiling it, this
- function will properly return the new name. In effect,
- this function returns what should (but is NOT) supplied
- by argv[0].
-
- The name includes not only the filename and extension of
- the EXE (or COM) file; DOS also prepends the name of the
- subdirectory where it was found. If found in the current
- directory, this prefix will begin with the drive designator.
- Otherwise, if DOS had to invoke the PATH processing to find
- the program, the prefix will come from one of the strings of
- the PATH environment variable (which may or may not include
- the drive designator - it depends on you).
-
- One useful characteristic of the name is that the name
- returned is NOT always the same. In particular, if a
- program named ABC loads and executes program XYZ which
- calls this function, the name returned will be ABC, not
- XYZ. This can be used to detect the manner of invocation
- of the program - i.e., direct or chained.
-
- This program was written in DeSmet C based on the code found
- in a public domain program written in Turbo Pascal called
- MAPMEM.PAS, written by K. Kokkonen of TurboPower Software.
-
- Dan Lewis, Key Software Products Sept. 9, 1986
- */
-
- static char *pgm_name() /* routine made static by gwj */
- {
- int i ;
- unsigned off = 0 ;
- extern unsigned _pcb ; /* defined by DeSmet C: PSP's segment */
- union
- {
- unsigned seg ; /* environment segment */
- char byte[2] ; /* unpacked form */
- } env ;
- char *name ;
- char *ptr ;
- static char bfr[200] ;
- static char empty[] = "";
-
- /* program name isn't available under MS-DOS 1 or 2 */
- _rax = 0x3000;
- _doint(0x21);
- if((_rax & 0x00ff) < 3) return empty;
-
- /* retrieve paragraph address of environment strings */
- env.byte[0] = _peek( 0x2C, _pcb ) ;
- env.byte[1] = _peek( 0x2D, _pcb ) ;
-
- /* Skip past environment strings */
- while (_peek( off++, env.seg ))
- {
- while (_peek( off++, env.seg ))
- {
- }
- }
-
- /* Look for start of program pathname */
- while (_peek( ++off, env.seg ) == 0)
- {
- }
-
- /* Copy program pathname */
- ptr = bfr ;
- while (*ptr++ = toupper(_peek( off++, env.seg )))
- {
- }
-
- return (name = bfr);
- }
-