home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
c
/
getf.arc
/
QUOTEARG.C
< prev
Wrap
C/C++ Source or Header
|
1988-11-20
|
10KB
|
362 lines
/*
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);
}