arnold@gatech.UUCP (Arnold Robbins) (02/23/84)
This is a suite of programs (in shell archive format) which produces a cross reference listing of identifiers, and character, string, integer, and floating point constants in C programs. The man page explains how to use it. The makefile should need only a little bit of editing to tailor it to your local system. please tear at the dotted line (don't forget to remove my .signature too!) ------------------------------------------------------------------------- echo 'extracting --- README' cat >README <<'!!FUNKY STUFF!!' README: This directory contains the files for 'cxref', a C language cross referencing program. The makefile will build the program, use 'make install' to put a copy in in the destination directory. You should set the destination inside the makefile. I have it set to use my BIN. BIN is taken from the environment, since I use the UNIX 4.0 make. The cxref driver depends on the destination. The cxref driver will you show the flow of information between programs. I suggest that you run the programs separately, successively adding the next program in a particular pipeline, to see how the information is transformed. With some work in the cscan.l and cxref.c files, this program could be easily made to cross reference other languages. Here is a list of the files, and what they contain: README --- this file. cxref.1 --- man page. makefile --- the makefile. cxref.c --- driver, calls all the other programs, does arg handling. constdefs.h --- header file, used by cscan.l and filter.c. cscan.l --- does the work of finding indentifiers and contsants. docxref.c --- main program and some other stuff to drive lex. filter.c --- filters int and floats to their own files. fmtxref.c --- formats output for printing. numfilter.c --- formats integers and floats to pass to fmtxref. SORT[1-3] --- shell files to save typing during testing and development. Arnold Robbins, Information and Computer Science, Georgia Tech gatech!arnold February 1984. Copyright (c) 1984 by Arnold Robbins All rights reserved !!FUNKY STUFF!! echo 'extracting --- SORT1' cat >SORT1 <<'!!FUNKY STUFF!!' # SORT1 -- do the first sorting job for cxref. # # the purpose of this file is to save typing during testing and development. # # Arnold Robbins, Information and Computer Science, Georgia Tech # gatech!arnold # Copyright (c) 1984 by Arnold Robbins # All rights reserved # This program may not be sold, but may be distributed # provided this header is included. # sort -u +0b -2 +2n !!FUNKY STUFF!! echo 'extracting --- SORT2' cat >SORT2 <<'!!FUNKY STUFF!!' # SORT2 -- do the second sorting job for cxref. # # the purpose of this file is to save typing during testing and development. # # Arnold Robbins, Information and Computer Science, Georgia Tech # gatech!arnold # Copyright (c) 1984 by Arnold Robbins # All rights reserved # This program may not be sold, but may be distributed # provided this header is included. # sort -u +0n -1 +1b -2 +2n !!FUNKY STUFF!! echo 'extracting --- SORT3' cat >SORT3 <<'!!FUNKY STUFF!!' # SORT3 -- do the third sorting job for cxref. # # the purpose of this file is to save typing during testing and development. # # Arnold Robbins, Information and Computer Science, Georgia Tech # gatech!arnold # Copyright (c) 1984 by Arnold Robbins # All rights reserved # This program may not be sold, but may be distributed # provided this header is included. # sort -u +0n +1n -2 +2b -3 +3n !!FUNKY STUFF!! echo 'extracting --- basename.c' cat >basename.c <<'!!FUNKY STUFF!!' /* ** basename.c ** ** return the last portion of a path name. ** included by several of the cxref component programs. ** ** Arnold Robbins, Information and Computer Science, Georgia Tech ** gatech!arnold ** Copyright (c) 1984 by Arnold Robbins ** All rights reserved ** This program may not be sold, but may be distributed ** provided this header is included. ** */ char *basename(str) /* return last portion of a path name */ char *str; { char *cp, *rindex(); if((cp = rindex(str, '/')) == NULL) return(str); else return(++cp); } !!FUNKY STUFF!! echo 'extracting --- constdefs.h' cat >constdefs.h <<'!!FUNKY STUFF!!' /* ** constdefs.h ** ** definitions of keyletters for different constants. ** arbitrary, as long as char < string < int < float. ** ** used by several of the cxref component programs. ** ** Arnold Robbins, Information and Computer Science, Georgia Tech ** gatech!arnold ** Copyright (c) 1984 by Arnold Robbins ** All rights reserved ** This program may not be sold, but may be distributed ** provided this header is included. ** */ #define CHAR 'a' #define STRING 'b' #define INT 'c' #define FLOAT 'd' !!FUNKY STUFF!! echo 'extracting --- cscan.l' cat >cscan.l <<'!!FUNKY STUFF!!' /* ** cscan.l ** ** Does the major work of removing identifiers and constants ** from the input stream, for Cxref. Its output is then extensively ** postprocessed. ** ** Arnold Robbins, Information and Computer Science, Georgia Tech ** gatech!arnold ** Copyright (c) 1984 by Arnold Robbins ** All rights reserved ** This program may not be sold, but may be distributed ** provided this header is included. ** */ %{ extern int line_no; %} letter [A-Za-z_] digit [0-9] %% int | char | float | double | struct | union | long | short | unsigned | auto | extern | register | typedef | static | goto | return | sizeof | break | continue | if | else | for | do | while | switch | case | default | entry | enum | void | define | undef | include | ifdef | ifndef | endif ; /* ignore C and cpp keywords */ "<".+">" ; /* forget about include-file names */ "\n" line_no++; "/*" { /* get rid of comments */ register char c, c1; loop: while((c = input()) != '*' && c != 0) if(c == '\n') line_no++; if(c == 0) { fprintf(stderr, "unexpected EOF in comment at line %d\n", line_no); exit(1); } if((c1 = input()) != '/') { unput(c1); /* could be '*' before '/' */ goto loop; } } {letter}({letter}|{digit})* outid(); /* what we actually want */ '[^\\']' | '\\{digit}{1,3}' | '\\[\\bfrnlt']' outchar(); \" { /* collect then delete quoted strings */ register char c; register int i; for(i = 1, c = input(); ; i++, c = input()) switch (c) { case '"': yytext[i] = c; yytext[++i] = '\0'; yyleng = i - 1; goto fini; case '\\': yytext[i] = '\\'; yytext[++i] = input(); if (yytext[i] == '\n') { line_no++; yytext[i] = 'n'; /* make visible */ } break; case 0: fprintf(stderr, "unexpected EOF inside string at line %d\n", line_no); exit(1); break; default: yytext[i] = c; break; } fini: outstring(); } [+-]?{digit}+[lL]? | [+-]?0[Xx]({digit}|[a-fA-F])+[lL]? outint(); [+-]?{digit}*"."{digit}+([Ee][+-]?{digit}+)? | [+-]?{digit}+"."{digit}*([Ee][+-]?{digit}+)? | [+-]?{digit}+[Ee][+-]?{digit}+ outfloat(); . ; /* everything else */ %% yywrap() /* wrap up for lex, return 1 */ { return(1); } #include "constdefs.h" extern char *fname; extern char *basename(); outchar() { outtext(CHAR); } outstring() { outtext(STRING); } outint() { int i = strlen(yytext); if (yytext[i-1] == 'l' || yytext[i-1] == 'L') yytext[i-1] = '\0'; outtext(INT); } outfloat() { outtext(FLOAT); } outtext(type) char type; { printf("~%c%s\t%s\t%d\n", type, yytext, basename(fname), line_no); } !!FUNKY STUFF!! echo 'extracting --- cxref.1' cat >cxref.1 <<'!!FUNKY STUFF!!' .TH CXREF 1 local .SH NAME cxref \- cross reference C source files .SH SYNOPSIS .I cxref [-Scfis] [files] .SH DESCRIPTION .PP .I Cxref reads the named C source files and produces on the standard output a cross reference of all the identifiers and constants in the files. Constants are integer constants (12, 0421, 0x1A), floating point constants (123.45, 0.2e-4), string constants ("this is a string\en"), and character constants ('a', '\e033'). Identifiers, character constants, and string constants are sorted lexicographically, i.e. according to the machine collating sequence (7-bit ASCII on the Vax). Integer and floating point constants are sorted numerically. .PP If no files are named, .I cxref reads the standard input. For multiple files, the argument "\-" (a single dash) indicates that the standard input should be read at that point. .PP If Arguments are given, they must come before any file names. .PP .I Cxref recognizes the following arguments: .RS .TP S Cross reference all files separately. The default action is to cross reference all named files together. .TP c Leave character constants out of the cross reference listing. .TP f Leave floating point constants out of the cross reference listing. .TP i Leave integer constants out of the cross reference listing. .TP s Leave string constants out of the cross reference listing. .RE By default, all types of constants are included in the cross reference. .PP .I Cxref does .I not include #include files, or expand macro definitions. Files named in #include lines can be listed on the command line if they should also be cross referenced. .PP .I Cxref is best run in the background, with its output redirected into a file or the line printer spooler lpr(1), since it reads all the named files, using sort(1) as an intermediate pass. The sorting can take time which the user can probably put to more productive use. .SH DIAGNOSTICS .PP Self explanatory. .SH BUGS .PP Systems running UNIX 4.0 and later already have a program named .IR cxref . Therefore, on those systems, this program should be renamed. .PP .I Cxref does not do any formatting on its output (other than to insure that it writes no more than 80 columns), so it should probably be run piping its output into pr(1). .PP Floating point constants are converted to a common format for sorting, therefore they may appear in the output in a format different from (but numerically equivalent to) their form in the original source code. .SH "SEE ALSO" lex(1), lpr(1), pr(1), sort(1) .SH AUTHOR .PP .nf Arnold Robbins School of Information and Computer Science Georgia Institute of Technology Atlanta, Geogia 30332 UUCP: gatech!arnold CSNET: Arnold@Gatech ARPANET: Arnold.Gatech@Csnet-Relay .br .fi Copyright (c) 1984 by Arnold Robbins. All rights reserved. This program may not be sold, but may be distributed provided this notice is included. !!FUNKY STUFF!! echo 'extracting --- cxref.c' cat >cxref.c <<'!!FUNKY STUFF!!' /* ** cxref.c ** ** C driver for Cxref program. ** does argument handling, then builds the right ** shell commands for passing to the system() routine. ** ** A possible but difficult speed improvement would be to ** set up the argument vectors ourselves, the i/o with a pipe() ** call, and do all the forking and execing ourselves. ** But, in keeping w/the philosophy of "Let someone else do ** the hard part", we leave well enough alone and let the shell do it. ** ** Arnold Robbins, Information and Computer Science, Georgia Tech ** gatech!arnold ** Copyright (c) 1984 by Arnold Robbins ** All rights reserved ** This program may not be sold, but may be distributed ** provided this header is included. ** */ #include <stdio.h> #include <ctype.h> #ifdef DEBUG #define system(str) printf("%s\n", str) #endif #define TRUE 1 #define FALSE 0 char *name; char **xargv; int xargc; int sflag = FALSE; /* do each one separately */ int iflag = TRUE; /* print out ints */ int fflag = TRUE; /* print out floats */ int cflag = TRUE; /* print out chars */ int strflag = TRUE; /* print out strings */ main(argc, argv) int argc; char **argv; { int i, j; name = argv[0]; for(argv++, argc--; argc > 0; argv++, argc--) if (argv[0][0] != '-') break; else if(argv[0][1] == '\0') /* filename of "-" */ break; else for(i = 1; argv[0][i] != '\0'; i++) switch(argv[0][i]) { case 'S': sflag = TRUE; break; case 'c': cflag = FALSE; break; case 'i': iflag = FALSE; break; case 'f': fflag = FALSE; break; case 's': strflag = FALSE; break; default: usage(); break; } xargc = argc; xargv = argv; runprogs(); } char command[BUFSIZ * 10]; /* may need LOTS of room */ char commandbuf[BUFSIZ * 10]; char *docxref(); char *filter(); char *intout(); char *floatout(); #define ONLYONE 1 #define ALLOFTHEM 2 runprogs() /* execute the programs */ { int i; if (sflag) { for (i = 0; i < xargc; i++) { printf("\tC Cross Refence Listing of %s\n", xargv[i]); fflush(stdout); /* send to ouput before commands start */ sprintf(command, "%s | sort -u +0b -2 +2n | %s | %s/fmtxref", docxref(i, ONLYONE), filter(), SRCDIR); system(command); if (iflag) { sprintf(commandbuf, "sort -u +0n -1 +1b -2 +2n < /tmp/cxr.%d.1 | %s/intfilter | %s/fmtxref", getpid(), SRCDIR, SRCDIR); sprintf(command, "if [ -s /tmp/cxr.%d.1 ] ; then %s ; fi", getpid(), commandbuf); system(command); } if (fflag) { sprintf(commandbuf, "sort -u +0n +1n -2 +2b -3 +3n < /tmp/cxr.%d.2 | %s/floatfilter | %s/fmtxref", getpid(), SRCDIR, SRCDIR); sprintf(command, "if [ -s /tmp/cxr.%d.2 ] ; then %s ; fi", getpid(), commandbuf); system(command); } fflush(stdout); } } else { if (xargc == 1) printf("\tC Cross Reference Listing of %s\n\n", xargv[0]); else printf("\tC Cross Reference Listing\n\n"); fflush(stdout); sprintf(command, "%s | sort -u +0b -2 +2n | %s | %s/fmtxref", docxref(0, ALLOFTHEM), filter(),SRCDIR); system (command); if (iflag) { sprintf(commandbuf, "sort -u +0n -1 +1b -2 +2n < /tmp/cxr.%d.1 | %s/intfilter | %s/fmtxref", getpid(), SRCDIR, SRCDIR); sprintf(command, "if [ -s /tmp/cxr.%d.1 ] ; then %s ; fi", getpid(), commandbuf); system(command); } if (fflag) { sprintf(commandbuf, "sort -u +0n +1n -2 +2b -3 +3n < /tmp/cxr.%d.2 | %s/floatfilter | %s/fmtxref", getpid(), SRCDIR, SRCDIR); sprintf(command, "if [ -s /tmp/cxr.%d.2 ] ; then %s ; fi", getpid(), commandbuf); system(command); } fflush(stdout); } if (! isatty(fileno(stdout))) putchar('\f'); sprintf(command, "rm -f /tmp/cxr.%d.[12]", getpid()); system(command); } char *docxref(index, howmany) int index, howmany; { static char buf[BUFSIZ]; int i, j, k; if (howmany == ONLYONE) sprintf(buf, "%s/docxref %s", SRCDIR, xargv[index]); else { sprintf(buf, "%s/docxref ", SRCDIR); i = strlen(buf); for(; xargc > 0; xargc--, xargv++) { for(j = 0; xargv[0][j] != '\0'; j++) buf[i++] = xargv[0][j]; buf[i++] = ' '; } buf[i] = '\0'; } return (buf); } char *filter() { static char buf[40]; if (! cflag && strflag) sprintf(buf, "%s/filter -c %d", SRCDIR, getpid()); else if (cflag && ! strflag) sprintf(buf, "%s/filter -s %d", SRCDIR, getpid()); else if (! cflag && ! strflag) sprintf(buf, "%s/filter -cs %d", SRCDIR, getpid()); else sprintf(buf, "%s/filter %d", SRCDIR, getpid()); return (buf); } usage() { fprintf(stderr, "usage: %s [-Scsif] [files]\n", name); exit (1); } !!FUNKY STUFF!! echo 'extracting --- docxref.c' cat >docxref.c <<'!!FUNKY STUFF!!' /* ** docxref.c ** ** Driver for lex based scanner. Arranges for stdin to be each named ** file in turn, so that yylex() never has to know about files. ** Some of this code is not pretty, but it's not too bad. ** ** Arnold Robbins, Information and Computer Science, Georgia Tech ** gatech!arnold ** Copyright (c) 1984 by Arnold Robbins ** All rights reserved ** This program may not be sold, but may be distributed ** provided this header is included. ** */ #include <stdio.h> #include <ctype.h> #define TRUE 1 #define FALSE 0 extern char yytext[]; extern int yyleng; int line_no = 1; /* current line number */ char *fname = NULL; /* current file name */ main(argc,argv) int argc; char **argv; { FILE saved_in, *fp; char *name; int more_input = FALSE; /* more files to process */ int read_stdin = FALSE; name = argv[0]; /* save command name */ fname = "stdin"; if(argc == 1) { yylex(); exit(0); } if(argv[1][0] == '-') usage(argv[0]); /* will exit */ saved_in = *stdin; /* save stdin in case "-" is found on command line */ for(--argc, argv++; argc > 0; --argc, argv++) { if(fileno(stdin) != fileno(&saved_in) || read_stdin) fclose(stdin); /* free unix file descriptors */ if(strcmp(*argv, "-") == 0) { *stdin = saved_in; fname = "stdin"; read_stdin = TRUE; more_input = (argc - 1 > 0); } else if((fp = fopen(*argv,"r")) == NULL) { fprintf(stderr,"%s: can't open %s\n", name, *argv); continue; } else { *stdin = *fp; /* do it this way so that yylex() */ /* never knows about files etc. */ more_input = (argc - 1 > 0); fname = *argv; } yylex(); /* do the work */ if(more_input) line_no = 1; } } outid() { char *basename(); printf("%s\t%s\t%d\n", yytext, basename(fname), line_no); } usage(name) char *name; { fprintf(stderr,"usage: %s [files]\n", name); exit(1); } #include "basename.c" !!FUNKY STUFF!! echo 'extracting --- filter.c' cat >filter.c <<'!!FUNKY STUFF!!' /* ** filter.c ** ** separate out integer and floating point constants into ** their own files, pass char and string constants on through. ** ** input: sorted output of docxref, contains identifiers and constants. ** output: identifiers, char and string constants, depending on flags. ** output goes to fmtxref. ** ** Arnold Robbins, Information and Computer Science, Georgia Tech ** gatech!arnold ** Copyright (c) 1984 by Arnold Robbins ** All rights reserved ** This program may not be sold, but may be distributed ** provided this header is included. ** */ #include <stdio.h> #include "constdefs.h" #define MAXFILE 120 #define MAXLINE 120 FILE *fp1, *fp2; int cflag = 0; int sflag = 0; char *name; main(argc, argv) int argc; char **argv; { char buf[BUFSIZ]; char file1[MAXFILE], file2[MAXFILE]; if (argc <= 1) usage(); if(argv[1][0] == '-') { if (argc == 2) usage(); if (argv[1][1] == 'c' || argv[1][2] == 'c') cflag = 1; if (argv[1][1] == 's' || argv[1][2] == 's') sflag = 1; if (!cflag && !sflag) /* bad option given */ usage(); argv++; } sprintf(file1, "/tmp/cxr.%d.1", atoi(argv[1])); sprintf(file2, "/tmp/cxr.%d.2", atoi(argv[1])); if ((fp1 = fopen(file1, "w")) == NULL) { fprintf(stderr,"%s: couldn't create tempfile 1\n"); exit (2); } if ((fp2 = fopen(file2, "w")) == NULL) { fprintf(stderr,"%s: couldn't create tempfile 2\n"); exit (3); } while (gets(buf) != NULL) { if (buf[0] != '~') printf("%s\n", buf); else switch (buf[1]) { case CHAR: if (! cflag) printf("%s\n", &buf[2]); break; case STRING: if (! sflag) printf("%s\n", &buf[2]); break; case INT: outint(buf); break; case FLOAT: outfloat(buf); break; default: fprintf(stderr,"%s: bad input line '%s'\n", name, buf); exit (4); } } fclose(fp1); fclose(fp2); } #define OCTAL 1 #define HEX 2 #define DEC 3 outint(buf) char *buf; { char file[MAXLINE], line[MAXLINE]; int val; int type = 0; buf += 2; /* skip leading ~INT */ file[0] = line[0] = '\0'; if (buf[0] == '0') /* octal or hex */ { if (buf[1] == 'x' || buf[1] == 'X') /* hex */ { type = HEX; buf += 2; /* skip leading 0x */ sscanf(buf, "%x %s %s", &val, file, line); } else { type = OCTAL; sscanf(buf, "%o %s %s", &val, file, line); } } else { type = DEC; sscanf(buf, "%d %s %s", &val, file, line); /* decimal */ } /* * strategy is to convert to decimal for numeric sorting, * then have output filter convert back to right base. */ switch (type) { case OCTAL: fprintf(fp1, "%d\t%s\t%s\t1\n", val, file, line); break; case DEC: fprintf(fp1, "%d\t%s\t%s\t2\n", val, file, line); break; case HEX: fprintf(fp1, "%d\t%s\t%s\t3\n", val, file, line); break; } } outfloat(buf) char *buf; { char file[MAXLINE], line[MAXLINE]; char mantissa[MAXLINE], exponent[MAXLINE]; char strval[MAXLINE]; char controlstr[MAXLINE]; double val; int i, j; buf += 2; /* skip ~FLOAT */ mantissa[0] = exponent[0] = file[0] = line[0] = '\0'; sscanf(buf, "%lf %s %s", &val, file, line); for (i = 0; buf[i] != '\t'; i++) if (buf[i] == '.') break; for (j = i + 1; buf[j] != 'E' && buf[j] != 'e' && buf[j] != '\t'; j++) ; j -= i - 1; /* j is now num digits to right decimal point. */ if (j < 6) j = 6; /* default */ sprintf(controlstr, "%%1.%dg", j); sprintf(strval, controlstr, val); /* * strategy is a follows: * 1) convert all floats to a common printed format (%g) * 2) split up mantissa and exponent into separate parts for sorting * 3) a float filter will put them back together. */ for(i = j = 0; strval[j] != 'e' && strval[j] != 'E' && strval[j] != '\0'; i++, j++) mantissa[i] = strval[j]; mantissa[i] = '\0'; if (strval[j] == 'e' || strval[j] == 'E') { j++; for(i = 0; strval[j] != '\0'; i++, j++) exponent[i] = strval[j]; exponent[i] = '\0'; } else exponent[0] = '\0'; fprintf(fp2, "%s\t%s\t%s\t%s\n", mantissa, exponent[0] != '\0' ? exponent : "0", file, line); } usage() { fprintf(stderr, "usage: %s [-cs] pid\n", name); exit (1); } !!FUNKY STUFF!! echo 'extracting --- fmtxref.c' cat >fmtxref.c <<'!!FUNKY STUFF!!' /* ** fmtxref.c ** ** format the output of the C cross referencer. ** this program relies on the fact that its input ** is sorted and uniq-ed. ** ** Arnold Robbins, Information and Computer Science, Georgia Tech ** gatech!arnold ** Copyright (c) 1984 by Arnold Robbins ** All rights reserved ** This program may not be sold, but may be distributed ** provided this header is included. ** */ #include <stdio.h> #include <ctype.h> #define TRUE 1 #define FALSE 0 #define MAXID 121 /* maximum lengths of identifiers, file names, etc. */ #define MAXFILE 15 #define MAXLINE 121 #define MAXNUM 7 #define ID 1 /* return codes to indicate what is new on input line */ #define NEWFILE 2 #define LINE 3 #define ERROR 4 char prev_id[MAXID] = ""; char prev_file[MAXFILE] = ""; char id[MAXID] = ""; char file[MAXFILE] = ""; char line[MAXNUM] = ""; main(argc, argv, envp) int argc; char **argv, **envp; { char inline[BUFSIZ]; char *gets(); int val; if(gets(inline) == NULL) { fprintf(stderr, "%s: standard input is empty.\n", argv[0]); exit(1); } if((val = breakup(inline)) == ERROR) { fprintf(stderr, "malformed input '%s'\n", inline); exit(2); } output(val); /* does proper formatting */ while(gets(inline) != NULL && val != ERROR) { val = breakup(inline); output(val); } if(val == ERROR) { fprintf(stderr, "malformed input '%s'\n", inline); exit(2); } putchar('\n'); } breakup(text) char *text; { int retval; int i, j; if(text[0] == '"' || text[0] == '\'') { /* break the line up by hand */ i = 0; id[i++] = text[0]; for(j = 1; text[j] != text[0]; i++, j++) { id[i] = text[j]; if(id[i] == '\\') id[++i] = text[++j]; /* e.g. \" */ } id[i++] = text[0]; id[i] = '\0'; j++; /* skip close quote */ while(isspace(text[j])) j++; for(i = 0; !isspace(text[j]); i++, j++) file[i] = text[j]; file[i] = '\0'; while(isspace(text[j])) j++; for(i = 0; !isspace(text[j]) && text[j] != '\0'; i++, j++) line[i] = text[j]; line[i] = '\0'; } else { if(sscanf(text, "%s %s %s", id, file, line) != 3) return(ERROR); } /* now decide about return code for formatting */ if(strcmp(prev_id, id) != 0) /* different identifiers */ { strcpy(prev_id, id); strcpy(prev_file, file); retval = ID; } else if(strcmp(prev_file, file) != 0) /* different files */ { strcpy(prev_file, file); retval = NEWFILE; } else retval = LINE; return(retval); } output(val) int val; { static int curpos = 1; static int first = TRUE; int line_len = strlen(line); switch(val) { case ID: if(! first) putchar('\n'); else first = FALSE; printf("%-20.20s\t%-14.14s\t%s", id, file, line); curpos = 40 + line_len; break; case NEWFILE: printf("\n\t\t\t%-14.14s\t%s", file, line); curpos = 40 + line_len; break; case LINE: if(curpos + line_len + 2 < 80) { printf(", %s", line); /* same output line */ curpos += 2 + line_len; } else { printf(",\n\t\t\t\t\t%s", line); /* new line */ curpos = 40 + line_len; } break; case ERROR: /* shouldn't come to here */ fprintf(stderr, "internal error: output() called with %s\n", "a value of ERROR"); fprintf(stderr, "id == '%s'\tfile == '%s'\tline == '%s'\n", id, file, line); break; default: /* shouldn't come to here either */ fprintf(stderr, "internal error: output() called with %s %d\n", "the unknown value", val); break; } } !!FUNKY STUFF!! echo 'extracting --- makefile' cat >makefile <<'!!FUNKY STUFF!!' # makefile for cxref -- C cross referencing program # # Arnold Robbins, Information and Computer Science, Georgia Tech # gatech!arnold # Copyright (c) 1984 by Arnold Robbins # All rights reserved # This program may not be sold, but may be distributed # provided this header is included. SCANOBJS= docxref.o cscan.o SCANSRCS= docxref.c cscan.l INCLS= constdefs.h basename.c PROGS= docxref fmtxref filter numfilter cxref SRCS= $(SCANSRCS) fmtxref.c filter.c numfilter.c cxref.c DOCS= README makefile cxref.1 PRINTS= $(INCLS) $(SRCS) $(DOCS) CFLAGS= -O # for my use during development, put in my bin DESTDIR=$(BIN) # when installing, use the line below # DESTDIR=/ics/bin all: $(PROGS) @echo " all" done docxref: $(SCANOBJS) cc $(SCANOBJS) -ll -o $@ cscan.o docxref.o filter.o: $(INCLS) fmtxref: fmtxref.c $(CC) $(CFLAGS) fmtxref.c $(LDFLAGS) -o fmtxref filter: filter.c $(CC) $(CFLAGS) filter.c $(LDFLAGS) -o filter numfilter: numfilter.c $(INCLS) $(CC) $(CFLAGS) numfilter.c $(LDFLAGS) -o numfilter cxref: cxref.c $(CC) $(CFLAGS) -DSRCDIR='"$(DESTDIR)"' cxref.c $(LDFLAGS) -o cxref print: prt $(PRINTS) | lpr -b 'Cxref New Source' touch print2 print2: $(PRINTS) prt $? | lpr -b 'Cxref New Source' touch print2 install: $(PROGS) rm -f $(DESTDIR)/cxref $(DESTDIR)/docxref $(DESTDIR)/fmtxref rm -f $(DESTDIR)/filter $(DESTDIR)/intfilter $(DESTDIR)/floatfilter cp cxref $(DESTDIR)/cxref cp docxref $(DESTDIR)/docxref cp fmtxref $(DESTDIR)/fmtxref cp filter $(DESTDIR)/filter cp numfilter $(DESTDIR)/intfilter ln $(DESTDIR)/intfilter $(DESTDIR)/floatfilter # cp cxref.1 /usr/man/man.l # cd $(DESTDIR); chmod 711 $(PROGS) clean: rm -f $(SCANOBJS) clobber: clean rm -f $(PROGS) print2 !!FUNKY STUFF!! echo 'extracting --- numfilter.c' cat >numfilter.c <<'!!FUNKY STUFF!!' /* ** numfilter.c ** ** Convert input back to proper form, depending on how called. ** Output is passed to the fmtxref program. ** ** Arnold Robbins, Information and Computer Science, Georgia Tech ** gatech!arnold ** Copyright (c) 1984 by Arnold Robbins ** All rights reserved ** This program may not be sold, but may be distributed ** provided this header is included. ** */ #include <stdio.h> #define MAXLINE 120 char *name; main(argc, argv) int argc; char **argv; { char *basename(); name = basename(argv[0]); /* remove leading path */ if (strcmp(name, "intfilter") == 0) /* turn ints back to normal */ intfilter(); else if (strcmp(name, "floatfilter") == 0) floatfilter(); /* turn floats back to normal */ else { fprintf(stderr, "%s: must be named floatfilter or intfilter\n", name); exit(1); } exit(0); } intfilter() { char buf[BUFSIZ]; char file[MAXLINE], number[MAXLINE]; int val; int type; while (gets(buf) != NULL) { sscanf(buf, "%d %s %s %d", &val, file, number, &type); switch (type) { case 1: /* octal */ if (val == 0) /* don't print 00 */ printf("0\t%s\t%s\n", file, number); else printf("0%o\t%s\t%s\n", val, file, number); /* supply leading 0 */ break; case 2: /* decimal */ printf("%d\t%s\t%s\n", val, file, number); break; case 3: /* hex */ printf("0x%x\t%s\t%s\n", val, file, number); break; default: fprintf(stderr,"%s: bad input line '%s'\n", name, buf); exit (4); } } } floatfilter() { char buf[BUFSIZ]; char file[MAXLINE], number[MAXLINE]; char mantissa[MAXLINE], exponent[MAXLINE]; while (gets(buf) != NULL) { sscanf(buf, "%s %s %s %s", mantissa, exponent, file, number); if (strcmp(exponent, "0") == 0) printf("%s\t", mantissa); else printf("%sE%s\t", mantissa, exponent); printf("%s\t%s\n", file, number); } } #include "basename.c" !!FUNKY STUFF!! -- Arnold Robbins CSNET: arnold@gatech ARPA: arnold.gatech@CSNet-relay UUCP: ...!{akgua,allegra,rlgvax,sb1,ut-sally}!gatech!arnold Did'ja ever have one of those re-incarnations?