#include <ctype.h>

char *next_arg();
char *skip_delim();
char *strip_path();

/*
;;
;; Command argument and DOS path manipulation functions. 
;; T. Jennings 7 June 83
;;
;; --------------- Command Tail Processing Functions ---------------
;;
;;	This next set of functions are meant to be used together. Examples
;;on their use follows.
;;
;;
;;int num_args(string)	Returns the number of args in the string, seperated
;;			by delims (see delim(), below). Leading delimiters
;;			are ignored.
;;
;;char *next_arg(string) Returns a pointer to the next arg, delimited 
;;			by a delim, skipping over the current arg. Use via
;;			ptr= nextarg(ptr) to skip to each argument. All 
;;			switches at the end of the current arg are skipped.
;;
;;
;;char *skip_delim(string) Skips leading delims in a string. returns a pointer.
;;
;;cpyarg(to,from)	Copies a string, up to the next delim or switch.
;;			Leading and trailing delimiters are stripped (from 
;;			the output string) and a null terminator is added.
;;
;;			after cpyarg()		FROM: foo/b foobar fipple
;;						TO: foo
;;
;;delim(c)		Returns true if the character is a delimiter.
;;			Nulls are not considered a delimiter. The list of
;;			delimiters is contained in the array '_dlmlst', and
;;			can be changed via newdelim().
;;
;;newdelim(s)		Replace the list of delimiters. The string 's' must
;;			be less than 20 chars. (Not checked.)
;;
;;char filtchar(c)	Convert a character to one legal for an MSDOS filename.
;;			Illegal characters such as switch or path seperators,
;;			control characters, etc are changed to '$'. Bit 7 is
;;			masked off. (Disallows foreign language support??)
;;
;;wild(string)		Returns true if the string contains a star or question.
;;
;;char *strip_path(out,in) Copies the disk specifier or pathname to the output
;;			array, and returns a pointer to the name in the input
;;			string.	Drive specs are considered a path, and are
;;			treated as such by DOS. Stripping "a:foo" and
;;			"bin/foo/framis.asm" result in:
;;
;;				IN:	"A:"
;;				IN:	"bin\foo"
;;
;;				OUT:	"A:"
;;				OUT:	"bin\"
;;
;;strip_switch(out,in)	Copy the switches from the in string, remove the switch
;;			character and put all the characters in the out array.
;;			Each is converted to upper case, and the string is null
;;			terminated.
;;
;;			strip_switch(s,"foo/b/f/z");
;;			s is now: "BFZ"
;;
;;ispath_delim(c)	Returns true if the character is a legal pathname
;;char c;		component seperator. 
;;
;;
;; --------- Command Tail Processing Examples ----------
;;
;;	This is an example of one way to use the above functions to process
;;an MSDOS program command tail. You do not need to know what the system switch
;;character or legal path seperators are. If you can't handle paths, strip them
;;off. Assume there is a pointer, p, that points to a command tail string:
;;
;;	p= "  source.ext abc.asm/v+\bin\def.com   /x/y/z"
;;
;;	p= skip_delim(p);		 p= "source.exe abc...... 
;;
;;	p= next_arg(p);			 p= "abc.asm/v.... "  
;;	cpyarg(work,p);			 work= "abc.asm"  
;;	s= strip_path(work,p));		 s= "abc.asm"   path= ""  
;;	strip_switch(sw,p);		 sw= "V"  
;;
;;	p= next_arg(p);			 p= "\bin\def.com"  
;;	cpyarg(work,p);			 work= "\bin\def.com"  
;;	s= strip_path(path,p);		 s= "def.com"  path= "\bin\"  
;;	strip_switch(sw,p);		 sw= ""  
;;
;;	p= next_arg(p);			 p= "/x/y/z"  
;;	cpyarg(work,p);			 work= ""  
;;	s= strip_path(path,p);		 s= ""  path= ""  
;;	strip_switch(sw,p);		 sw= "XYZ"  
;;
;;	p= next_arg(p);			 p= ""  
;;
;;	while (num_args(p))		 while not end of string ... 
;;	while (*p)			 another way ... 
;;
;;
;;char *name,sw[4],path[40];
;;
;;	p= skip_delim(p);
;;	while (num_args(p) > 0) {	 *p points to the current arg, 
;;		name= strip_path(path,p);
;;		strip_switch(sw,p);
;;		printf("Path= %s, Name= %s, Switches= %s\n",path,name,sw);
;;	}
;;
*/
/* Return the number of args left in the string. */

short num_args(string)
char *string;
{
int count;

	count= 0;
	string= skip_delim(string);		/* skip leading blanks, */
	while (*string) {
		++count;			/* count one, */
		string= next_arg(string);	/* find next, */
	}
	return(count);
}

/* Return a pointer to the next argument in the string. */

char *next_arg(string)
char *string;
{
	while ((!delim(*string)) && *string)		/* skip this one, */
		++string;				/* up to delim, */
	string= skip_delim(string);			/* then skip delims, */
	return(string);
}

/* Skip over the leading delimiters in a string. */

char *skip_delim(string)
char *string;
{
	while (delim(*string) && *string) {
		++string;
	}
	return(string);
}
/* Copy the string to the destination array, stopping if we find one
of our delimiters. */

void cpyatm(to,from)
char *to;
char *from;
{
	while ( (!delim(*from)) && *from) 
		*to++= *from++;
	*to= '\0';
}

/* Copy the string to the destination array, stopping if we find one
of our delimiters or switches. */

void cpyarg(to,from)
char *to;
char *from;
{
	while ( (!delim(*from)) && (*from != '/') && *from) 
		*to++= *from++;
	*to= '\0';
}

/* Strip any switches from the input string, put into the output array. */

void strip_switch(out,in)
char *out;
char *in;
{
	while (*in && (*in != '/'))		/* skip to end of string */
		++in;				/* or first switch, */

	while (*in && (*in == '/')) {		/* copy switch args while */
		++in;
		*out++ = toupper(*in);		/* stripping switch chars, */
		++in;
	}
	*out= '\0';				/* terminate it, */
}

/* ----- List of legal delimiters. This is the default list ----- */

static char _dlmlst[20] = {" \t,"};	/* space, tab, comma */

/* Return true if the character is a delimiter from the list above. */

delim(c)
char c;
{
char *cp;

	for (cp= _dlmlst; *cp;) if (c == *cp++) return(1);
	return(0);
}

/* Change the list of delimiters. */

void newdelim(s)
char *s;
{
	strcpy(_dlmlst,s);
}

/* Clean up the character for a legal MSDOS filename. Convert undesireable
characters to a dollar. */

char filtchar(c)
char c;
{
	c&= 0x7f;			/* strip bit 7, */
	if ((c == '/') || ispath_delim(c) || (c < ' ') || (c > '~') )
		c= '$';			/* dont allow illegal chars */
	c= toupper(c);			/* all uppercase, */
	return(c);
}
/* Return 1 if the string is a wild filespec. */

short wild(string)
char *string;
{
char *p;

	p= string;
	while (*p) {
		if (*p == '?') return(1);
		if (*p == '*') return(1);
		++p;
	}
	return(0);				/* not wild. */
}

/* Strip the pathname or disk specifier from a filename, return it in a
seperate array. We do this by initially copying the entire name in, then
searching for the colon or slash. Right after the last one we find,
stuff a null, removing the name part. 

Also return a pointer to the name part in the input name. */

char *strip_path(out,in)
char *out;
char *in;
{
char *name;
char *endpath;

	cpyarg(out,in);			/* duplicate, for working, */
	name= in;			/* point to name, */
	endpath= out;			/* and end of path part, */

	while (*in) {			/* look for slashes or colons, */
		if (*in == ':')	{	/* if a colon, */
			endpath= ++out;	/* point to name, */
			name= ++in;

		} else if (ispath_delim(*in)) {
			endpath= ++out;	/* move the pointer up, */
			name= ++in;

		} else {
			++in;
			++out;
		}
	}
	*endpath= '\0';			/* delete the name part, */
	return(name);			/* return ptr to name part. */
}

/* Return true if the character is a legal path name component seperator. */

ispath_delim(c)
char c;
{
	return(c == '\\');
}

/* Convert a string to lower case. */

stolower(s)
char *s;
{
	while (*s) {
		*s= tolower(*s);
		++s;
	}
}
/* Convert a string to upper case. */

stoupper(s)
char *s;
{
	while (*s) {
		*s= toupper(*s);
		++s;
	}
}
