[net.sources] mkprog, a program to make skeleton of programs

mohamedr@hscfvax.UUCP (03/20/87)

The following program is a first cut at producing a program generator that
will produce the boiler plate needed at the beginning of most programs.
Unpack the archive, make the program, and type, for example

	mkprog -o ab

and look at the program generated in prog.c.  EXAMPLE contains a commented
output.

I hope to work further on it and produce something worth archiving in
mod.sources.  I will appreciate comments and, above all, code to improve
this version.

Enjoy!

Mohamed el Lozy				ellozy@harvard
Health Sciences Computing Facility	mohamed@hscfvax
Harvard School of Public Health		(617) 732-0762
665 Huntington Avenue
Boston, MA 02115

------------------------------ CUT HERE ------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	TODO
#	EXAMPLE
#	Makefile
#	mkprog.h
#	constant.c
#	do_mkprog.c
#	efopen.c
#	getopt.c
#	mkprog.c
#	mkprog.1
#	efopen.3s
# This archive created: Fri Mar 20 13:00:29 1987
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(870 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^	X//' << \SHAR_EOF > 'README'
	XMkprog will make a skeleton of a program, which includes the
	X"boiler-plate" that almost all programs contain.  That includes certain
	Xexternal declarations, the code for interpreting specified command line
	Xoptions, and the code for for looping over named files, with standard
	Xinput as the default.  The generated program will interpret command
	Xline arguments using getopt(3).  Many options exist.
	X
	XI am posting this preliminary version to net.sources and hope to get ideas
	Xfor improvements as well as bug fixes.  I hope to incorporate as many
	Xsuggestions as possible, and to post a new version to mod.sources later.
	X
	XI can be reached as ellozy@harvard, which is on most nets known to man or
	Xbeast.
	X
	XMohamed el Lozy				ellozy@harvard
	XHealth Sciences Computing Facility	mohamed@hscfvax
	XHarvard School of Public Health		(617) 732-0762
	X665 Huntington Avenue
	XBoston, MA 02115
SHAR_EOF
if test 870 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 870 characters)'
fi
chmod +x 'README'
fi # end of overwriting check
echo shar: extracting "'TODO'" '(890 characters)'
if test -f 'TODO'
then
	echo shar: will not over-write existing file "'TODO'"
else
sed 's/^	X//' << \SHAR_EOF > 'TODO'
	X1.  It should be possible to specify whether you want your programs to
	Xhave RCS or SCCS stuff, and what your favorite tab indent is, in an
	Xenvironmental variable.  Easy to do, but I have temporarily run out of
	Xenergy.
	X
	X2.  While on the subject of environmental variables, the generated code should
	Xbe able to search for options first in an environmental variable, then on
	Xthe command line.
	X
	X3.  It would be nice to be able to say, for example:
	X
	X	mkprog -i l,page_len,66 ...
	X
	Xto mean that there should be a -l flag, setting the value of the int variable
	Xpage_len, with a default (if no -l flag) of 66.  Trickier (not really difficult)
	Xand I am not sure how necessary.
	X
	XComments will be appreciated, code even more so.
	X
	XMohamed el Lozy				ellozy@harvard
	XHealth Sciences Computing Facility	mohamed@hscfvax
	XHarvard School of Public Health		(617) 732-0762
	X665 Huntington Avenue
	XBoston, MA 02115
SHAR_EOF
if test 890 -ne "`wc -c < 'TODO'`"
then
	echo shar: error transmitting "'TODO'" '(should have been 890 characters)'
fi
chmod +x 'TODO'
fi # end of overwriting check
echo shar: extracting "'EXAMPLE'" '(2249 characters)'
if test -f 'EXAMPLE'
then
	echo shar: will not over-write existing file "'EXAMPLE'"
else
sed 's/^	X//' << \SHAR_EOF > 'EXAMPLE'
	XThe following program was generated by
	X    mkprog -h -n junk -o 'ab$c#'
	XComments were added manually to explain some of the design decisions in
	Xmkprog.
	X
	XThis is junk.h:
	X
	X    #include <stdio.h>
	X    #include <ctype.h>	/* I use ctype so often I prefer to always include it */
	X
	X    typedef enum {false=0, true=1} bool;
	X
	X    char *progname;	/* for error messages */
	X
	X    bool a_flag;	/* bools, then */
	X    int c_val;		/* ints, and finally */
	X    char *b_string;	/* char pointers */
	X
	XThis is junk.c:
	X
	X    #include "junk.h"
	X
	X    main(argc, argv)
	X    int argc;
	X    char *argv[];
	X    {
	X	extern int optind;	/* for getopt(3) */
	X	extern int opterr;
	X	extern char *optarg;
	X	int c;			/* for switch */
	X	int i;			/* for looping aver file names */
	X	bool used_stdin = false;	/* so as not to use stdin twice */
	X	FILE *fp, *efopen();
	X
	X	opterr = 1;		/* for getopt again, might well be 0 */
	X	progname = argv[0];
	X
	X	c_val = 0;		/* initialize explicitly so that you will */
	X	b_string = (char *) 0;	/* know where to put default vaules */
	X
	X	while ((c = getopt(argc, argv, "ac:b:")) != EOF)
	X	    switch(c) {
	X	    case 'a':
	X		a_flag = true;
	X		break;
	X	    case 'c':
	X		c_val = atoi(optarg);
	X		break;
	X	    case 'b':
	X		b_string = optarg;
	X		break;
	X	    case '?':
	X		usage();
	X		break;
	X	    }
	X
	X	argc -= optind;		/* reset argc and argv after dealing with */
	X	argv += optind;		/* options */
	X
	X	for (i = 0; i < argc; i++) {	/* loop over files names checking */
	X					/* access first */
	X	    if (strcmp(argv[i], "-") == 0) {
	X		if (used_stdin) {
	X		    fprintf(stderr, "standard input used twice\n");
	X		    exit(1);
	X		}
	X		else {
	X		    used_stdin = true;
	X		}
	X	    }
	X    #ifdef unix
	X	    else if (access(argv[i], 4) == -1) {	/* check access */
	X		fprintf(stderr, "%s: cannot access %s: ", progname, argv[i]);
	X		perror("");
	X		exit(1);
	X	    }
	X    #endif unix
	X	}
	X
	X	fp = stdin;
	X	i = 0;
	X
	X	do {		/* now loop over file names doing program */
	X	    if (argc > 0)
	X		fp = efopen(argv[i], "r");	/* efopen will exit */
	X						/* on failure */
	X	    do_junk(fp);	/* this does the real work */
	X	    (void) fclose(fp);	/* remember to close files! */
	X	} while (++i < argc);
	X	exit(0);
	X    }
	X
	X    usage()
	X    {
	X	fprintf(stderr, "Usage: %s [ -a ] [ -c c_val ] [ -b b_string ] [ file ... ]\n", progname);
	X	exit(1);
	X    }
SHAR_EOF
if test 2249 -ne "`wc -c < 'EXAMPLE'`"
then
	echo shar: error transmitting "'EXAMPLE'" '(should have been 2249 characters)'
fi
chmod +x 'EXAMPLE'
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(1797 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^	X//' << \SHAR_EOF > 'Makefile'
	X# Change the following defaults to suit your taste
	XTABS          = 4
	XRCS           = true
	XSCCS          = false
	X
	XCFLAGS        = -g -DTABS=$(TABS) -DRCS=$(RCS) -DSCCS=$(SCCS)
	X
	XDEST	      = /usr/local
	X
	XEXTHDRS	      = /usr/include/ctype.h \
	X		/usr/include/stdio.h
	X
	XHDRS	      = mkprog.h
	X
	XLINKER	      = cc -g
	X
	XMAKEFILE      = Makefile
	X
	XGETOPT        =
	X# if you do not have getopt(3) in your library uncomment the following
	X# statement:
	X# GETOPT      = getopt.o
	XOBJS	      = constant.o \
	X		do_mkprog.o \
	X		efopen.o \
	X		$(GETOPT) \
	X		mkprog.o
	X
	XPRINT	      = pr
	X
	XPROGRAM	      = mkprog
	X
	XSRCS	      = constant.c \
	X		do_mkprog.c \
	X		efopen.c \
	X		getopt.c \
	X		mkprog.c
	X
	XMANPAGE       =	mkprog.1 efopen.3s
	X
	XSHAR_OBJECTS  =	README TODO EXAMPLE Makefile $(HDRS) $(SRCS) $(MANPAGE)
	X
	XSHARFILE      = mkprog.shar
	X
	Xall:		$(PROGRAM)
	X
	X$(PROGRAM):     $(OBJS) $(LIBS)
	X		@echo -n "Loading $(PROGRAM) ... "
	X		@$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
	X		@echo "done"
	X
	Xlint:;		lint $(SRCS)
	X
	Xclean:;		@rm -f $(OBJS) $(PROGRAM) $(SHARFILE) prog prog.? a.out core
	X
	Xdepend:;	@mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST)
	X
	Xindex:;		@ctags -wx $(HDRS) $(SRCS)
	X
	Xinstall:	$(PROGRAM)
	X		@echo Installing $(PROGRAM) in $(DEST)
	X		@install -s $(PROGRAM) $(DEST)
	X
	Xprint:;		@$(PRINT) $(HDRS) $(SRCS)
	X
	Xprogram:        $(PROGRAM)
	X
	Xtags:           $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)
	X
	Xupdate:		$(DEST)/$(PROGRAM)
	X
	X$(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS)
	X		@make -f $(MAKEFILE) DEST=$(DEST) install
	X
	Xshar:;		@shar -a $(SHAR_OBJECTS) > $(SHARFILE)
	X###
	Xconstant.o: mkprog.h /usr/include/stdio.h /usr/include/ctype.h
	Xdo_mkprog.o: mkprog.h /usr/include/stdio.h /usr/include/ctype.h
	Xefopen.o: /usr/include/stdio.h
	Xgetopt.o: /usr/include/stdio.h
	Xmkprog.o: mkprog.h /usr/include/stdio.h /usr/include/ctype.h
SHAR_EOF
if test 1797 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 1797 characters)'
fi
chmod +x 'Makefile'
fi # end of overwriting check
echo shar: extracting "'mkprog.h'" '(652 characters)'
if test -f 'mkprog.h'
then
	echo shar: will not over-write existing file "'mkprog.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'mkprog.h'
	X/*	 "$Header: mkprog.h,v 1.1 86/05/19 16:32:46 root Exp $"	*/
	X#include <stdio.h>
	X#include <ctype.h>
	X
	Xtypedef enum {false=0, true=1} bool;
	X
	Xint optind;
	Xint opterr;
	Xchar *optarg;
	X
	Xchar *progname;
	X
	Xbool f_flag;	/* true if program does not read files */
	Xbool h_flag;	/* true if want to generate .h file */
	Xbool R_flag;	/* true if want RCS header, default set in Makefile */
	Xbool S_flag;	/* true if want SCCS header, default set in Makefile */
	X
	Xint t_val;	/* spaces indented or size of tab, default set in Makefile */
	X
	Xchar *h_string;	/* pointer to name of .h file */
	Xchar *n_string;	/* pointer to name of .c file */
	Xchar *o_string;	/* string of options */
SHAR_EOF
if test 652 -ne "`wc -c < 'mkprog.h'`"
then
	echo shar: error transmitting "'mkprog.h'" '(should have been 652 characters)'
fi
chmod +x 'mkprog.h'
fi # end of overwriting check
echo shar: extracting "'constant.c'" '(3805 characters)'
if test -f 'constant.c'
then
	echo shar: will not over-write existing file "'constant.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'constant.c'
	X#ifndef lint
	Xstatic char rcsid[] = "$Header: constant.c,v 1.3 87/03/02 17:51:28 root Exp $";
	Xstatic char rcswhere[] = "$Source: /usr/src/local/local/mkprog/RCS/constant.c,v $";
	X#endif
	X
	X/*  This file contains top(), middle() and bottom().
	X *  The first two print out constant boilerplate, while bottom()
	X *  prints out constant stuff plus one line with the name of
	X *  the program being made.
	X *
	X *  It also contains out(), the function that actually prints the
	X *  lines with a suitable indent.  It, too, is independent of the
	X *  options and of the data structure used for them
	X */
	X
	X#include "mkprog.h"
	X
	Xtop(fp_h, fp_p)
	XFILE *fp_h, *fp_p;
	X{
	X    extern char h_file[];
	X
	X    if (R_flag || S_flag) {		/* rcsid and sccsid headers in prog */
	X	out(fp_p, 0, "#ifndef lint\n");
	X	if (R_flag)
	X	    out(fp_p, 0, "static char rcsid[] = \"$Header$\";\n");
	X	if (S_flag)
	X	    out(fp_p, 0, "static char sccsid[] = \"$Header$\";\n");
	X	out(fp_p, 0, "#endif\n\n");
	X
	X	if (fp_h != fp_p) {		/* and in header */
	X	if (R_flag)
	X	    out(fp_h, 0, "/*\t \"$Header$\"\t*/\n");
	X	if (S_flag)
	X	    out(fp_h, 0, "/*\t \"$Header$\"\t*/\n");
	X	}
	X    }
	X
	X    if (h_flag)
	X	out(fp_p, 0, "#include \"%s\"\n", h_file);
	X
	X    out(fp_h, 0, "#include <stdio.h>\n");
	X    out(fp_h, 0, "#include <ctype.h>\n");
	X    out(fp_h, 0, "\n");
	X    if (o_string) {
	X	out(fp_h, 0, "typedef enum {false=0, true=1} bool;\n");
	X	out(fp_h, 0, "\n");
	X    }
	X    out(fp_h, 0, "char *progname;\n");
	X}
	X
	Xmiddle(fp_p, args)
	Xbool args;
	XFILE *fp_p;
	X{
	X    out(fp_p, 0, "\nmain(argc, argv)\n");
	X    out(fp_p, 0, "int argc;\n");
	X    out(fp_p, 0, "char *argv[];\n");
	X    out(fp_p, 0, "{\n");
	X    if (!f_flag)
	X	out(fp_p, 1, "extern int optind;\n");
	X    out(fp_p, 1, "extern int opterr;\n");
	X    if (args)
	X	out(fp_p, 1, "extern char *optarg;\n");
	X    if (o_string)
	X	out(fp_p, 1, "int c;\n");
	X    if (!f_flag) {
	X	out(fp_p, 1, "int i;\n");
	X	out(fp_p, 1, "bool used_stdin = false;\n");
	X	out(fp_p, 1, "FILE *fp, *efopen();\n");
	X    }
	X    out(fp_p, 0, "\n");
	X    out(fp_p, 1, "opterr = 1;\n");
	X    out(fp_p, 1, "progname = argv[0];\n\n");
	X}
	X
	Xbottom(progname, fp_p)
	Xchar *progname;
	XFILE *fp_p;
	X{
	X    if (o_string) {
	X	out(fp_p, 1, "argc -= optind;\n");
	X	out(fp_p, 1, "argv += optind;\n");
	X    }
	X    else {
	X	out(fp_p, 1, "argc--;\n");
	X	out(fp_p, 1, "argv++;\n");
	X    }
	X    out(fp_p, 0, "\n");
	X    out(fp_p, 1, "for (i = 0; i < argc; i++) {\n");
	X    out(fp_p, 2, "if (strcmp(argv[i], \"-\") == 0) {\n");
	X    out(fp_p, 3, "if (used_stdin) {\n");
	X    out(fp_p, 4, "fprintf(stderr, \"standard input used twice\\n\");\n");
	X    out(fp_p, 4, "exit(1);\n");
	X    out(fp_p, 3, "}\n");
	X    out(fp_p, 3, "else {\n");
	X    out(fp_p, 4, "used_stdin = true;\n");
	X    out(fp_p, 3, "}\n");
	X    out(fp_p, 2, "}\n");
	X    out(fp_p, 0, "#ifdef unix\n");
	X    out(fp_p, 2, "else if (access(argv[i], 4) == -1) {\n");
	X    out(fp_p, 3, "fprintf(stderr, \"%%s: cannot access %%s: \", progname, argv[i]);\n");
	X    out(fp_p, 3, "perror(\"\");\n");
	X    out(fp_p, 3, "exit(1);\n");
	X    out(fp_p, 2, "}\n");
	X    out(fp_p, 0, "#endif unix\n");
	X    out(fp_p, 1, "}\n");
	X    out(fp_p, 0, "\n");
	X    out(fp_p, 1, "fp = stdin;\n");
	X    out(fp_p, 1, "i = 0;\n");
	X    out(fp_p, 0, "\n");
	X    out(fp_p, 1, "do {\t\t\n");
	X    out(fp_p, 2, "if (argc > 0)\n");
	X    out(fp_p, 3, "fp = efopen(argv[i], \"r\");\n");
	X    out(fp_p, 0, "\n");
	X    out(fp_p, 2, "do_%s(fp);\n", progname);
	X    out(fp_p, 2, "(void) fclose(fp);\n");
	X    out(fp_p, 1, "} while (++i < argc);\n");
	X    out(fp_p, 1, "exit(0);\n");
	X    out(fp_p, 0, "}\n");
	X}
	X
	X	/* VARARGS3 */
	X
	Xout(fp, n, s1, s2, s3, s4, s5)
	XFILE *fp;
	Xint n;
	Xchar *s1, *s2, *s3, *s4, *s5;
	X{
	X    int n_tabs, n_spaces;
	X
	X    n_spaces = n*t_val;
	X
	X    n_tabs = n_spaces/8;
	X    while (n_tabs--)
	X	putc('\t', fp);
	X
	X    n_spaces %= 8;
	X    while (n_spaces--)
	X	putc(' ', fp);
	X    fprintf(fp, s1, s2, s3, s4, s5);
	X}
SHAR_EOF
if test 3805 -ne "`wc -c < 'constant.c'`"
then
	echo shar: error transmitting "'constant.c'" '(should have been 3805 characters)'
fi
chmod +x 'constant.c'
fi # end of overwriting check
echo shar: extracting "'do_mkprog.c'" '(5101 characters)'
if test -f 'do_mkprog.c'
then
	echo shar: will not over-write existing file "'do_mkprog.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'do_mkprog.c'
	X#ifndef lint
	Xstatic char rcsid[] = "$Header: do_mkprog.c,v 1.4 87/03/02 17:54:52 root Exp $";
	Xstatic char rcswhere[] = "$Source: /usr/src/local/local/mkprog/RCS/do_mkprog.c,v $";
	X#endif
	X
	X/*  do_mkprog.c contains those parts of the program that depend on
	X *  the data representation used.  On the other hand, constant.c
	X *  contains material that is independent of the data representation
	X *  and, in almost all cases, of the actual data themselves.
	X */
	X
	X#include "mkprog.h"
	X#define MAX_OPTS 20
	X
	Xchar b_opts[MAX_OPTS], i_opts[MAX_OPTS], s_opts[MAX_OPTS];
	X
	Xdo_mk_prog(fp_h, fp_p)
	XFILE *fp_h, *fp_p;
	X{
	X    bool args;			/* any string or int args? */
	X
	X    if (o_string)
	X	mk_arrays();		/* make b_opts[] etc and check on duplicates */
	X
	X    top(fp_h, fp_p);		/* boiler plate at top */
	X
	X    if (o_string)
	X	mk_decl(fp_h);		/* external declarations */
	X
	X    if (i_opts[0] != '\0' || s_opts[0] != '\0')
	X	args = true;
	X    else
	X	args = false;
	X    middle(fp_p, args);		/* main(argc, argv) ... etc. */
	X
	X    if (o_string)
	X	mk_switch(fp_p);	/* switch statement */
	X
	X    if (!f_flag)
	X	bottom(n_string, fp_p);	/* file processing statements */
	X    else {
	X#ifdef undefined
	X	out(fp_p, 0, "\n");
	X#endif undefined
	X	out(fp_p, 1, "do_%s();\n", n_string);
	X	out(fp_p, 1, "exit(0);\n");
	X	out(fp_p, 0, "}\n");
	X    }
	X    mk_usage(fp_p);
	X}
	X
	X/* break up the options in *o_string into three arrays: b_opt for
	X * the binary options, i_opt for the integers, and s_opt for the strings,
	X * then sort each of these arrays.
	X */
	X
	Xmk_arrays()
	X{
	X    char *b_ptr = b_opts;
	X    char *i_ptr = i_opts;
	X    char *s_ptr = s_opts;
	X    char *cp;
	X    char *index();
	X
	X    for (cp = o_string; *cp; cp++) {
	X	if ((index(b_opts, *cp) != (char *) 0)  ||
	X	    (index(i_opts, *cp) != (char *) 0)  ||
	X	    (index(s_opts, *cp) != (char *) 0)) {
	X		fprintf(stderr, "%s: '%c' found twice in options string\n",
	X		  progname, *cp);
	X		exit(1);
	X	}
	X	switch (*(cp + 1)) {
	X	case '$':
	X	    *s_ptr++ = *cp++;
	X	    *cp = ':';
	X	    break;
	X	case '#':
	X	    *i_ptr++ = *cp++;
	X	    *cp = ':';
	X	    break;
	X	default:
	X	    *b_ptr++ = *cp;
	X	    break;
	X	}
	X    }
	X    
	X    *b_ptr = *i_ptr = *s_ptr = '\0';
	X
	X    /*  Then sort the strings made */
	X
	X    strsort(b_opts);
	X    strsort(i_opts);
	X    strsort(s_opts);
	X
	X    /* then put the options back into o_string in order:
	X     * binaries, then integers, then strings, each group
	X     * sorted.
	X     */
	X
	X    cp = o_string;
	X
	X    b_ptr = b_opts;
	X    while (*cp++ = *b_ptr++)
	X	;
	X    cp--;
	X
	X    i_ptr = i_opts;
	X    while (*cp++ = *i_ptr++)
	X	*cp++ = ':';
	X    cp--;
	X
	X    s_ptr = s_opts;
	X    while (*cp++ = *s_ptr++)
	X	*cp++ = ':';
	X    cp--;
	X}
	X
	X/* use the sorted arrays to make the external declarations.  They
	X * are arranged in order: booleans then integers than character pointers,
	X * sorted alphabetically within each category.
	X */
	X
	Xmk_decl(fp_h)
	XFILE *fp_h;
	X{
	X    char *cp;
	X
	X    putc('\n', fp_h);
	X
	X    for (cp = b_opts; *cp; cp++)
	X	out(fp_h, 0, "bool %c_flag;\n", *cp);
	X    for (cp = i_opts; *cp; cp++)
	X	out(fp_h, 0, "int %c_val;\n", *cp);
	X    for (cp = s_opts; *cp; cp++)
	X	out(fp_h, 0, "char *%c_string;\n", *cp);
	X}
	X
	Xmk_switch(fp_p)	/* make switch in same order, precede by initializing */
	XFILE *fp_p;
	X{
	X    char *cp;
	X
	X    for (cp = i_opts; *cp; cp++)
	X	out(fp_p, 1, "%c_val = 0;\n", *cp);
	X    for (cp = s_opts; *cp; cp++)
	X	out(fp_p, 1, "%c_string = (char *) 0;\n", *cp);
	X    putc('\n', fp_p);
	X
	X    out(fp_p, 1, "while ((c = getopt(argc, argv, \"%s\")) != EOF)\n", o_string);
	X    out(fp_p, 2, "switch(c) {\n");
	X
	X    for (cp = b_opts; *cp; cp++) {
	X	out(fp_p, 2, "case '%c':\n", *cp);
	X	out(fp_p, 3, "%c_flag = true;\n", *cp);
	X	out(fp_p, 3, "break;\n");
	X    }
	X
	X    for (cp = i_opts; *cp; cp++) {
	X	out(fp_p, 2, "case '%c':\n", *cp);
	X	out(fp_p, 3, "%c_val = atoi(optarg);\n", *cp);
	X	out(fp_p, 3, "break;\n");
	X    }
	X
	X    for (cp = s_opts; *cp; cp++) {
	X	out(fp_p, 2, "case '%c':\n", *cp);
	X	out(fp_p, 3, "%c_string = optarg;\n", *cp);
	X	out(fp_p, 3, "break;\n");
	X    }
	X
	X    out(fp_p, 2, "case '?':\n");
	X    out(fp_p, 3, "usage();\n");
	X    out(fp_p, 3, "break;\n");
	X    out(fp_p, 2, "}\n\n");
	X}
	X
	X/*  Simple string sort, sorts a string in situ.  For current
	X *  purpose simple interchange is all we need.
	X */
	X
	Xstrsort(s)
	Xchar *s;
	X{
	X    char *out_ptr, *in_ptr, tmp;
	X
	X    if (s == (char *) 0 || *s == '\0')
	X	return;
	X
	X    for (out_ptr = s + 1; *out_ptr; out_ptr++)
	X	for (in_ptr = out_ptr - 1; *in_ptr > *(in_ptr + 1) && in_ptr >= s; in_ptr--) {
	X	    tmp = *in_ptr;
	X	    *in_ptr = *(in_ptr + 1);
	X	    *(in_ptr + 1) = tmp;
	X	}
	X}
	X
	Xmk_usage(fp_p)	/* make usage() with options and files, as appropriate. */
	XFILE *fp_p;
	X{
	X    char *cp;
	X
	X    out(fp_p, 0, "\nusage()\n{\n");
	X    out(fp_p, 1, "fprintf(stderr, \"Usage: %%s");
	X
	X    if (*b_opts) {
	X	fputs(" [ -", fp_p);
	X	for (cp = b_opts; *cp; cp++)
	X	    putc(*cp, fp_p);
	X	fputs(" ]", fp_p);
	X    }
	X
	X    if (*i_opts)
	X	for (cp = i_opts; *cp; cp++)
	X	    fprintf(fp_p, " [ -%c %c_val ]", *cp, *cp);
	X
	X    if (*s_opts)
	X	for (cp = s_opts; *cp; cp++)
	X	    fprintf(fp_p, " [ -%c %c_string ]", *cp, *cp);
	X
	X    if (!f_flag)
	X	fprintf(fp_p, " [ file ... ]");
	X    fprintf(fp_p, "\\n\", progname);\n");
	X
	X    out(fp_p, 1, "exit(1);\n}\n");
	X}
SHAR_EOF
if test 5101 -ne "`wc -c < 'do_mkprog.c'`"
then
	echo shar: error transmitting "'do_mkprog.c'" '(should have been 5101 characters)'
fi
chmod +x 'do_mkprog.c'
fi # end of overwriting check
echo shar: extracting "'efopen.c'" '(803 characters)'
if test -f 'efopen.c'
then
	echo shar: will not over-write existing file "'efopen.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'efopen.c'
	X#ifndef lint
	Xstatic char rcsid[] = "$Header: efopen.c,v 1.2 87/03/02 17:45:15 root Exp $";
	Xstatic char rcswhere[] = "$Source: /usr/src/local/local/mkprog/RCS/efopen.c,v $";
	X#endif
	X
	X#include <stdio.h>
	X
	XFILE *
	Xefopen(file, mode)	/* fopen file, die if cannot */
	Xchar *file, *mode;	/* from K & P with addition of perror() and handling
	X			   of "-" as stdin */
	X{
	X    FILE *fp;
	X    extern char *progname;
	X
	X    if (strcmp(file, "-") == 0)
	X	return(stdin);
	X
	X    if ((fp = fopen(file, mode)) != NULL)
	X	return (fp);
	X
	X    if (progname)
	X	fprintf(stderr, "%s: ", progname);
	X    fprintf(stderr, "can't open file %s mode %s: ", file, mode);
	X    perror("");
	X    exit(1);
	X	/* NOTREACHED */
	X}
	X
	X/* This makes it more portable to a non-unix environment */
	X
	X#ifndef unix
	Xperror(s)
	Xchar *s;
	X{
	X    putc('\n', stderr);
	X}
	X#endif
SHAR_EOF
if test 803 -ne "`wc -c < 'efopen.c'`"
then
	echo shar: error transmitting "'efopen.c'" '(should have been 803 characters)'
fi
chmod +x 'efopen.c'
fi # end of overwriting check
echo shar: extracting "'getopt.c'" '(1729 characters)'
if test -f 'getopt.c'
then
	echo shar: will not over-write existing file "'getopt.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'getopt.c'
	X#ifndef lint
	Xstatic char rcsid[] = "$Header: getopt.c,v 1.1 87/03/04 10:33:18 root Exp $";
	Xstatic char rcswhere[] = "$Source: /usr/src/local/local/mkprog/RCS/getopt.c,v $";
	X#endif
	X
	X/* Slightly modified from Keith Bostik's submission to mod.sources */
	X#include <stdio.h>
	X
	X/*
	X * get option letter from argument vector
	X */
	Xint	opterr = 1,	/* if set to zero no message for bad option */
	X	optind = 1,	/* index into parent argv vector */
	X	optopt;		/* character checked for validity */
	Xchar	*optarg;	/* argument associated with option */
	X
	X#define BADCH	(int)'?'
	X#define EMSG	""
	X
	Xgetopt(nargc,nargv,ostr)
	Xint	nargc;
	Xchar	**nargv,
	X	*ostr;
	X{
	X    static char	*place = EMSG;	/* option letter processing */
	X    register char	*oli;		/* option letter list index */
	X    char	*index();
	X
	X    if(!*place) {			/* update scanning pointer */
	X	if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place)
	X	    return(EOF);
	X	if (*place == '-') {	/* found "--" */
	X	    ++optind;
	X	    return(EOF);
	X	}
	X    }				/* option letter okay? */
	X    if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
	X	if(!*place) ++optind;
	X	if (opterr)
	X	    fprintf(stderr, "%s: illegal option -- %c\n", *nargv, optopt);
	X	return(BADCH);
	X    }
	X    if (*++oli != ':') {		/* don't need argument */
	X	optarg = NULL;
	X	if (!*place) ++optind;
	X    }
	X    else {				/* need an argument */
	X	if (*place) optarg = place;	/* no white space */
	X	else if (nargc <= ++optind) {	/* no arg */
	X	    place = EMSG;
	X	    if (opterr)
	X		fprintf(stderr, "%s: option requires an argument -- %c\n",
	X		    *nargv, optopt);
	X	    return(BADCH);
	X	}
	X	 else optarg = nargv[optind];	/* white space */
	X	place = EMSG;
	X	++optind;
	X    }
	X    return(optopt);			/* dump back option letter */
	X}
SHAR_EOF
if test 1729 -ne "`wc -c < 'getopt.c'`"
then
	echo shar: error transmitting "'getopt.c'" '(should have been 1729 characters)'
fi
chmod +x 'getopt.c'
fi # end of overwriting check
echo shar: extracting "'mkprog.c'" '(1473 characters)'
if test -f 'mkprog.c'
then
	echo shar: will not over-write existing file "'mkprog.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'mkprog.c'
	X#ifndef lint
	Xstatic char rcsid[] = "$Header: mkprog.c,v 1.3 87/03/02 17:55:39 root Exp $";
	Xstatic char rcswhere[] = "$Source: /usr/src/local/local/mkprog/RCS/mkprog.c,v $";
	X#endif
	X
	X#include "mkprog.h"
	X
	Xchar h_file[256];	/* name of .h file, used in constant.c */
	X
	Xmain(argc, argv)
	Xint argc;
	Xchar *argv[];
	X{
	X    int c;
	X    FILE *fp_p, *fp_h, *efopen();
	X    char p_file[256];	/* name of .c file */
	X
	X    /*  The following symbols are defined in the Makefile */
	X
	X    t_val = TABS;
	X    R_flag = RCS;
	X    S_flag = SCCS;
	X
	X    n_string = "prog";
	X    progname = argv[0];
	X    opterr = 1;
	X    while ((c = getopt(argc, argv, "RSfhn:o:p:t:")) != EOF)
	X	switch(c) {
	X	case'R':
	X	    R_flag = true;
	X	    break;
	X	case'S':
	X	    S_flag = true;
	X	    break;
	X	case'f':
	X	    f_flag = true;
	X	    break;
	X	case'h':
	X	    h_flag = true;
	X	    break;
	X	case'n':
	X	    n_string = optarg;
	X	    break;
	X	case'o':
	X	    o_string = optarg;
	X	    break;
	X	case't':
	X	    t_val = atoi(optarg);
	X	    break;
	X	case '?':
	X	    usage();
	X	    break;
	X	}
	X
	X    argc -= optind;
	X    argv += optind;
	X
	X    if (argc != 0)
	X	usage();
	X
	X    (void) sprintf(p_file, "%s%s", n_string, ".c");
	X    fp_p = efopen(p_file, "w");
	X
	X    if (h_flag) {
	X	(void) sprintf(h_file, "%s%s", n_string, ".h");
	X	fp_h = efopen(h_file, "w");
	X    }
	X    else
	X	fp_h = fp_p;	/* "header" stuff gets written into .c file */
	X
	X    do_mk_prog(fp_h, fp_p);
	X}
	X
	Xusage()
	X{
	X    fprintf(stderr, "Usage: %s [ -RSfh ] [ -t t_val ] [ -n n_string ] [ -o o_string ]\n", progname);
	X}
SHAR_EOF
if test 1473 -ne "`wc -c < 'mkprog.c'`"
then
	echo shar: error transmitting "'mkprog.c'" '(should have been 1473 characters)'
fi
chmod +x 'mkprog.c'
fi # end of overwriting check
echo shar: extracting "'mkprog.1'" '(3485 characters)'
if test -f 'mkprog.1'
then
	echo shar: will not over-write existing file "'mkprog.1'"
else
sed 's/^	X//' << \SHAR_EOF > 'mkprog.1'
	X.TH MKPROG 1 local
	X.SH NAME
	Xmkprog \- make skeleton of program
	X.SH SYNOPSIS
	X.B mkprog
	X[
	X.B \-RSfi
	X] [
	X.B -o
	Xoption_string ] [
	X.B \-n
	Xprog_name ] [
	X.B \-t
	Xtab_indent]
	X.SH DESCRIPTION
	X.I mkprog
	Xwill make a skeleton of a program, which includes the ``boiler-plate''
	Xthat almost all programs contain.  That includes certain external
	Xdeclarations, the code for interpreting specified command line options,
	Xand the code for for looping over named files, with standard input as
	Xthe default.
	X.PP
	XThe generated program will interpret command line arguments using
	Xgetopt(3).  It will interpret the file '-' as being standard input,
	Xand will accept it (once) in any position among the files to be read.
	XIf compiled on a UNIX system it will check that all files are readable,
	Xusing access(2), before opening any of them.  Files are opened using a
	Xmodified form of efopen(3h), modified from Kernighan and Pike to recognize
	X\&'-' as representing standard input.
	X.PP
	XThe program so made is normally placed in
	X.IR prog.c .
	XTo get a feel for the generated code, give the command:
	X.IP
	Xmkprog \-o ab
	X.PP
	Xand look at the program produced in
	X.IR prog.c .
	X.PP
	XThe most important flag is the
	X.B \-o
	Xflag, which is followed by a string containing the flags that the
	Xgenerated program is to interpret.  Flags must be a single letter
	Xeach.  If they represent a binary option the letter is followed by
	Xnothing, if they precede a numerical valued option the flag must be
	Xfollowed by a
	X.BR # ,
	Xand if they introduce a string value the flag must be followed by a
	X.BR $ .
	XSo
	X.IP
	Xmkprog \-o \'ab#c$\'
	X.PP
	Xwill produce a program which interprets a binary flag,
	X.IR a ,
	Xa flag followed by a numerical argument,
	X.IR b ,
	Xand a flag followed by a string argument,
	X.IR c .
	XThat program would be invoked, for example, as
	X.IP
	Xprog \-a \-b 17 \-c string
	X.PP
	XInternally, a binary option like a sets a variable that would be
	Xcalled
	X.IR a_flag ,
	Xa flag followed by a numerical argument would assign its value to an
	Xint variable called
	X.IR b_value ,
	Xwhile a flag followed by a string value will make a character pointer called
	X.I c_string
	Xpoint to it.
	X.PP
	XSuch variables are initialized explicitly to zero in the case of
	X.I ints
	Xand to the null pointer in the case of
	X.IR *char 's.
	X.PP
	XThe binary flags interpreted are:
	X.TP
	X.B \-R
	Xproduce a header for
	X.IR rcs (1).
	X.TP
	X.B \-S
	Xproduce a header for 
	X.IR sccs (1).
	X.TP
	X.B \-f
	XProduce a skeleton for a program that does not read files.
	X.TP
	X\-h
	XProduce an include file, called
	X.I prog.h
	Xby default, containing the global declarations.  A suitable include
	Xstatement is generated in the source file.
	X.PP
	XThe flags introducing arguments are:
	X.TP
	X.BI \-n " prog_name"
	XProduces a program called
	X.I prog_name.c
	Xrather than the default
	X.IR prog.c .
	XAlso, if the
	X.I \-h
	Xflag is present, the include file will be named
	X.IR prog_name.h .
	X.TP
	X.BI \-t " tab_indent"
	XThe program is indented in increments of
	X.IR tab_indent .
	XThe default is 4.
	X.SH LIMITATIONS
	XThe most serious limitation is in the naming of the variables that
	Xrelate to the string and numerical options, and in the assignment of
	Xdefault values.  It is easy to write a program that will accept, for
	Xeach flag, a name and initial value for the corresponding variable.  It
	Xis not clear how much easier such a program would be in practice.
	XVariable names can (and usually should) be changed with global
	Xsubstitutions, and the initialization statements stand out where they
	Xcan be conveniently edited.
	X.SH SEE ALSO
	Xgetopt(3), efopen(3h)
SHAR_EOF
if test 3485 -ne "`wc -c < 'mkprog.1'`"
then
	echo shar: error transmitting "'mkprog.1'" '(should have been 3485 characters)'
fi
chmod +x 'mkprog.1'
fi # end of overwriting check
echo shar: extracting "'efopen.3s'" '(929 characters)'
if test -f 'efopen.3s'
then
	echo shar: will not over-write existing file "'efopen.3s'"
else
sed 's/^	X//' << \SHAR_EOF > 'efopen.3s'
	X.TH EFOPEN 3S  "11 May 1986"
	X.SH NAME
	Xefopen \- open a stream, exiting with message in case of failure
	X.SH SYNOPSIS
	X.B #include <stdio.h>
	X.br
	X.B extern char *progname;
	X.PP
	X.SM
	X.B FILE
	X.B *efopen(filename, type)
	X.br
	X.B char *filename, *type;
	X.SH DESCRIPTION
	X.I Efopen
	Xcalls
	X.IR fopen (3S)
	Xto open the file named by
	X.IR filename ,
	Xand if successful returns a pointer to be used to identify the stream in
	Xsubsequent operations.
	X.PP
	XIf
	X.I filename
	Xis the string \-
	X.I efopen
	Xwill return
	X.IR stdin .
	X.PP
	X.I Type
	Xis a character string as in
	X.IR fopen (3S).
	X.PP
	XOn failure,
	X.I efopen
	Xexits, after printing out the name of the program (if a value has been
	Xgiven to
	X.B progname
	Xby main), the name of the file, and calling
	X.IR perror (3).
	X.SH "SEE ALSO"
	Xfopen(3S),
	Xopen(2),
	Xfclose(3),
	Xperror(3)
	X.SH "AUTHOR"
	XModified by Mohamed el Lozy from program given in
	X.I "The UNIX Programming Environment"
	Xby Brian W. Kernighan and Rob Pike, p 182.
SHAR_EOF
if test 929 -ne "`wc -c < 'efopen.3s'`"
then
	echo shar: error transmitting "'efopen.3s'" '(should have been 929 characters)'
fi
chmod +x 'efopen.3s'
fi # end of overwriting check
#	End of shell archive
exit 0