/*
 *			G E T C M D
 */

/*)BUILD	$(TKBOPTIONS) = {
			TASK	= ...GTC
		}	
*/

#ifdef	DOCUMENTATION

title	getcmd	Build command files for Decus C
index		Build command files for Decus C

synopsis

	getcmd >result -options pattern file_list

description

	Getcmd was written to aid in maintaining the Decus C compiler.
	It is used to generate command files for building the run-time
	library, for example.  It is probably of limited use in other
	areas.
	.s
	The following options are defined:
	.lm +16
	.s.i-16;-c		Macro command file, (for run-time library
	build.  This prevents compiling RSX.MAC and RT11.MAC.
	.s.i-16;-d		Enable debug code.
	.s.i-16;-m model	"model" replaces '?' in a pattern string.
	.s.i-16;-r		For RT11, preface the output file with
	"R MACRO" and end it with "^C".
	.s.lm-16
	If no pattern is present, patterns and wild-card descriptions will
	be read from the standard input.  The input format is:
	.s
		output_file pattern input_spec.
	.s
	If the pattern begins with a blank, the current output_file
	(or stdout) will be used.  If the pattern contains blanks,
	enclose it in quotes.
	.s
	If no input_spec is present, the line is copied to the output with no
	changes other than substitution for the model string.
	.s
	Within a pattern, the following strings have special meaning:
	.lm +8
	.s.i -8;?	Replaced by the last model string
	.s.i -8;*.*	Replaced by the filename + extension
	.s.i -8;*	Replaced by the filename only
	.s.lm -8
	Note that the disk and [UIC,PPN] is never output.
	.s
	Unflagged arguments are wild-card file specifications.
	.s
	For example:
	.s
	getcmd >rilbas.cmd -c OBJ:*,LST:*=SRC:RT11,SRC:* *.MAC
	.s
	The above command line builds the assembly command file for the I/O
	library in RT11 mode.
	.s
	getcmd >tov.cmd VAX::[C.OTSIO]*.*/VA=[5,5]*.* [5,5]*.*
	.s
	The above command generates an indirect command file for RSTS/E DECnet.

bugs

	getcmd was written to aid in maintaining the Decus C run-time
	library.  It is fairly
	useless in other situations.  The build program may be more
	generally useful.

author

	Martin Minow

#endif

/*
 * Edit history
 * 0.0 ??-???-??  MM	Invention
 * 0.1  5-May-81 JSL	If no filespec on a line, just copy the pattern
 * 0.2  5-May-81 JSL	If no model, leave ? alone instead of deleting it
 * 0.3  4-Jun-81 MM	Changed iovtoa to fgetname
 */

char	*documentation[] = {
"Getcmd builds command files, writing them to the standard output.  Usage:",
"	getcmd >result [flag] pattern wild_card_descriptions",
"The following switches are defined:",
"    -c		Macro command file, delete reference to RSX.MAC and RT11.MAC",
"    -d		Debug mode",
"    -m	model	\"Model\" replaces '?' in the pattern string",
"    -r		RT11 switch, preface output with R MACRO, end with ^C",
"",
"If no pattern is present, patterns and wild-card descriptions will",
"be read from the standard input.  The input format is:",
"	output_file pattern input_spec.",
"If the pattern begins with a blank, the current output_file (or stdout)",
"will be used.  If the pattern contains blanks, enclose it in quotes.",
"",
"If no input_spec is present, the line is copied to the output with no",
"changes other than substitution for the model string.",
"",
"Within a pattern, the following strings have special meaning:",
"	?	Replaced by the last model string",
"	*.*	Replaced by the filename + extension",
"	*	Replaced by the filename only",
"Note that the disk and [UIC,PPN] is never output",
"",
"Unflagged arguments are wild-card file specifications",
"",
"For example:",
"  getcmd >[5,5]rilbas.cmd -c \"OBJ:*,LST:*=SRC:RT11,SRC:*\" [5,5]*.MAC",
"The above command line builds the assembly command file for the I/O",
"library in RT11 mode.",
"",
"  getcmd >iotovm.cmd \"RDVAX::DB0:[C.OTSIO]*.*/VA=[5,5]*.*\" [5,5]*.*",
" The above command generates an indirect command file for RSTS/E DECnet",
0 };

#include <stdio.h>
#ifdef vms
#include		<ssdef.h>
#include		<stsdef.h>
#define	IO_SUCCESS	(SS$_NORMAL | STS$M_INHIB_MSG)
#define	IO_ERROR	SS$_ABORT
#endif
/*
 * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
 */
#ifndef	IO_SUCCESS
#define	IO_SUCCESS	0
#endif
#ifndef	IO_ERROR
#define	IO_ERROR	1
#endif
#define	FALSE		0
#define	TRUE		1
#define	EOS		0
#define	MAX_NAMES	500		/* Max. file names		*/
int		debug;
int		macroflag;
int		rt11flag;
char		*model;
char		*pattern;
char		*wild_spec;
char		*out_spec;
char		fullname[81];
char		filename[81];
char		line[133];		/* Input text line		*/
char		*text[MAX_NAMES];	/* store file names here	*/
char		**ttop = text;		/* Top of text pointer		*/

FILE		*infd;

main(argc, argv)
int		argc;
char		*argv[];
{

	register int		c;
	register int		i;
	register char		*ap;

	if (argv[1][0] == '?' && argv[1][1] == EOS) {
		help();
		exit(IO_ERROR);
	}
	model = "?";
	for (i = 1; i < argc; i++) {
		if (*(ap = argv[i]) == '-') {
			while ((c = tolower(*++ap)) != EOS) {
				switch (c) {
				case 'd':
					debug++;
					break;

				case 'c':
					macroflag++;
					break;

				case 'm':
					if (++i >= argc)
						usage("No arg after -m");
					model = argv[i];
					goto loop;

				case 'r':
					rt11flag++;
					printf("R MACRO\n");
					break;

				default:
					bug("W", "Unknown switch", ap);
					break;
				}
			}
		}
		else {
			if (pattern == NULL) {
				pattern = argv[i];
				continue;
			}
			wild_spec = argv[i];
			ttop = text;
			if (process() > 0)
				doit();
		}
loop:;	}
	/*
	 * pattern will be NULL if none was provided by the command line
	 */
	if (pattern == NULL)
		getinput();
	if (rt11flag)
		printf("^C\n");
}

getinput()
/*
 * Read from stdin, process each line as it comes
 */
{
	register char	*lp;
	register int	c;
	register int	count;
	char		*skipbl();
	char		*findbl();
	int		fspecs;

	while (fgetss(line, sizeof line, stdin) != NULL) {
		/*
		 * Skip over leading blanks and get file spec.
		 */
		fspecs = count = 0;
		ttop = text;
		lp = line;
		if (*lp > ' ') {
			out_spec = lp = skipbl(line);
			lp = findbl(lp);
			if (debug)
				fprintf(stderr, "new stdout = \"%s\"\n",
						out_spec);
			if (freopen(out_spec, "w", stdout) == NULL) {
				bug("E", "Can't open output file", out_spec);
				error("Can't continue");
			}
		}
		/*
		 * Skip over blanks and get pattern
		 */
		lp = findqbl(lp, &pattern);
		lp = skipbl(lp);
		while (*lp != EOS) {
			lp = findqbl(lp, &wild_spec);
			count += process();
			fspecs++;
		}			
		if (fspecs == 0) {		/* No filespecs found */
			strcpy(fullname,"*.*");
			save(fullname);
		}
		if (count > 0 || fspecs == 0)
			doit();
	}
}
		

process()
/*
 * Find files, return how many
 */
{
	register int		count;		/* Count files		*/

	if (debug)
		fprintf(stderr, "Wild card spec = \"%s\"\n", wild_spec);
	if ((infd = fwild(wild_spec, "r")) == NULL) {
		bug("E", "Can't open", wild_spec);
		return(0);
	}
	for (count = 0; fnext(infd) != NULL; count++) {
		setname(infd);
		if (debug)
			fprintf(stderr, "Curr file = \"%s\"\n", fullname);
		if (macroflag &&
				(streq(fullname, "RSX.MAC")
				|| streq(fullname, "RT11.MAC")))
			continue;
		save(fullname);
	}
	if (debug)
		fprintf(stderr, "%d files processed\n\n", count);
	if (count == 0)
		bug("W", "No files matched", wild_spec);
	return(count);
}

doit()
{
	register char		**textp;	/* Pointer to names	*/
	register char		*pp;		/* Pattern pointer	*/
	register int		c;		/* Current character	*/

	for (textp = text; textp < ttop; textp++) {
		/*
		 * Get file name part, too
		 */
		strcpy(filename, *textp);
		for (pp = filename; (c = *pp) != EOS && c != '.'; pp++);
		*pp = EOS;
		for (pp = pattern; (c = *pp++) != EOS;) {
			switch (c) {

			case '*':
				if (*pp == '.' && pp[1] == '*') {
					printf(*textp);
					pp += 2;
				}
				else 
					printf(filename);
				break;

			case '?':
				printf(model);
				break;

			default:
				putchar(c);
			}
		}
		putchar('\n');
		free(*textp);
	}
}

setname(fd)
FILE 		*fd;
/*
 * Build file name
 */
{
	register char		*wp;
	register int		c;
	char			work[81];

	fgetname(fd, work);
	/*
	 * Skip backwards to the rightmost colon in the device name.
	 */
	for (wp = &work[strlen(work)]; wp > work && wp[-1] != ':'; wp--);
	/*
	 * Skip over [UIC] or [PPN] if present
	 */
	if (*wp == '[' || *wp == '(') {
		while ((c = *wp++) != EOS && c != ']' && c != ')');
		if (c == 0) {
			fprintf(stderr, "?GETCMD-bad file name \"%s\"\n",
					work);
			wp--;
		}
	}
	strcpy(fullname, wp);
	/*
	 * Don't include version
	 */
	for (wp = fullname; (c = *wp) != EOS && c != ';'; wp++);
	*wp = EOS;
}

save()
/*
 * Save fullname, add it to the text area (in sorted order)
 */
{
	register char	**textp;
	register char	**insert;
	register int	i;

	for (textp = text; textp < ttop; textp++) {
		if ((i = strcmp(*textp, fullname)) == 0) {
			fprintf("?GETCMD-E-Duplicate file name \"%s\"\n",
				fullname);
			return;
		}
		else if (i > 0)
			break;
	}
	insert = textp;
	textp = ttop;
	if (++ttop >= &text[MAX_NAMES])
		error("?GETCMD-F-Too many file names, %d max.\n", MAX_NAMES);

	while (textp >= insert) {
		textp[1] = *textp;
		textp--;
	}
	if ((*insert = malloc(strlen(fullname) + 1)) == NULL)
		error("?GETCMD-F-No room for \"%s\"\n", fullname);
	strcpy(*insert, fullname);
}
	

findqbl(text_ptr, start)
char		*text_ptr;
char		**start;
/*
 * Skip leading blanks, find text (handle quoted text strings)
 * return true start of text in start
 */
{
	register char	*lp;
	register int	c;
	char		*skipbl();
	char		*findbl();

	*start = lp = skipbl(text_ptr);
	if ((c = *lp) == EOS)
		return(lp);
	else if (c == '"') {
		lp++;
		*start = lp;
		while ((c = *lp) != EOS && c != '"')
			lp++;
		if (c == EOS) {
			bug("E", "Missing quote in pattern", pattern);
			return(lp);
		}
		*lp++ = EOS;
	}
	else lp = findbl(lp);
	if (debug)
		fprintf(stderr, "unscanned (return) = \"%s\"\n", lp);
	return(lp);
}

char *
skipbl(text_ptr)
char		*text_ptr;
/*
 * Skip over blanks
 */
{
	register char	*tp;
	register int	c;

	for (tp = text_ptr; (c = *tp) != EOS && c <= ' '; tp++);
	return(tp);
}

char *
findbl(text_ptr)
char		*text_ptr;
/*
 * Skip to the next blank, terminate the string and step the pointer
 */
{
	register char	*tp;

	for (tp = text_ptr; *tp > ' '; tp++);
	if (*tp)
		*tp++ = EOS;
	return(tp);
}

help()
/*
 * Give good help
 */
{
	register char	**dp;

	for (dp = documentation; *dp; dp++)
		fprintf(stderr, "%s\n", *dp);
}

usage(s)
char	*s;
{
	bug("E", s, NULL);
	fprintf(stderr, "For help, GETCMD ?\n");
	exit(IO_ERROR);
}

bug(severity, mess, arg)
char		*severity;
char		*mess;
char		*arg;
/*
 * Error messages
 */
{
	fprintf(stderr, "%cGETCMD-%s-%s",
		(*severity == 'W') ? '%' : '?', severity, mess);
	if (arg != NULL)
		fprintf(stderr, ": \"%s\"", arg);
	fprintf(stderr, "\n");
}
