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