Relay-Version: version B 2.10.3 beta 11/15/85; site seismo.CSS.GOV Posting-Version: version B 2.10.2 9/3/84; site panda.UUCP Path: seismo!harvard!talcott!panda!sources-request From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: head(1), and ctags(1) for AT&T type systems Message-ID: <1289@panda.UUCP> Date: 10 Jan 86 23:25:57 GMT Sender: jpn@panda.UUCP Reply-To: itkin@luke.UUCP (Steven List) Organization: Benetics Corp, Mt. View, CA Lines: 470 Approved: jpn@panda.UUCP Mod.sources: Volume 3, Issue 87 Submitted by: Steven List # I've recently had the pleasure (?) of working with an AT&T # 3B2/300. Among the many differences I encountered are the # absences of the Berkeley commands head(1) and ctags(1). I'd # gotten used to those command due to the generosity of Plexus in # providing them on their System III and V systems. Needless to # say I immediately sat down and wrote them. # # My version of head(1) adds a command line option to the standard: # +n. In this case, +n means "skip n lines before displaying". # Yes, I'm aware that I could use sed(1) for this. But sed(1) # doesn't stop when it has done what you asked. It still processes # to the end of file. So, I figured that I'd just add this one # little feature. # # My version of ctags(1) is pretty much the same as the Berkeley # one, as far as I can tell. It uses some code to recognize # function declarations that I borrowed from `cpr' (I don't have # the original author's name). It is simple, straightforward, and # readily modified. # # As always, comments, changes, and corrections are welcome. # # Steven # ### # Steven List @ Benetics Corporation, Mt. View, CA # Just part of the stock at "Uncle Bene's Farm" # {cdp,engfocus,greipa,idi,oliveb,plx,sun,tolerant}!bene!luke!itkin ### #! /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: # head.c # ctags.c # This archive created: Sat Dec 14 17:38:46 1985 export PATH; PATH=/bin:$PATH echo shar: extracting "'head.c'" '(4938 characters)' if test -f 'head.c' then echo shar: will not over-write existing file "'head.c'" else sed 's/^ZZ//' << \SHAR_EOF > 'head.c' ZZ/* head - replace head command */ ZZ/* ZZ * call: head [ +n ] [ -n ] [ file ... ] ZZ * ZZ * +n = number of lines to skip before starting display ZZ * default = 0 ZZ * -n = number of lines to display, starting with top of file ZZ * default = 10 ZZ * file = any number of files may be present ZZ * if name is `-', read from standard input ZZ */ ZZ#include ZZ ZZ#define FALSE 0 ZZ#define TRUE 1 ZZ ZZvoid dofile (); ZZ ZZmain (ac, av) ZZint ac; ZZchar **av; ZZ{ ZZ register FILE *in = stdin; /* default is standard input */ ZZ ZZ register int header = FALSE; /* TRUE if multiple files */ ZZ ZZ register char *cp; /* general purpose pointer */ ZZ ZZ register long nlines = 10; /* number of lines to display */ ZZ register long skip = 0; /* number of lines to skip */ ZZ ZZ register char *pgm; /* program name */ ZZ ZZ if (pgm = strrchr (av[0], '/')) pgm++; ZZ else pgm = av[0]; ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* Adjust args to skip program name */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ av++; ac--; ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* process arguments/options */ ZZ /* it is assumed that the options will precede all file names */ ZZ /* on the command line */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ while (ac) ZZ { ZZ if (*av[0] == '+') /* lines to skip */ ZZ { ZZ skip = atoi (&av[0][1]); ZZ ac--; av++; ZZ } ZZ else if (*av[0] == '-') /* lines to display */ ZZ { ZZ nlines = atoi (&av[0][1]); ZZ ac--; av++; ZZ } ZZ else break; ZZ } ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* If any files, then process each */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ if (ac) ZZ { ZZ /* ------------------------------------------------------------ */ ZZ /* If more than one file name specified, display headers */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ header = ac > 1; ZZ while (ac--) ZZ { ZZ if (!strcmp (*av, "-")) ZZ { ZZ dofile (stdin, "standard input", skip, nlines, header); ZZ } ZZ else if (!(in = fopen (*av, "r"))) ZZ { ZZ fprintf (stderr, ZZ "head: cannot read file %s - skipping\n", *av); ZZ } ZZ else ZZ { ZZ dofile (in, *av, skip, nlines, header); ZZ fclose (in); ZZ } ZZ av++; ZZ } ZZ } ZZ else dofile (stdin, "standard input", skip, nlines, FALSE); ZZ ZZ exit (0); ZZ} ZZ/* ------------------------------------------------------------ */ ZZ/* Process a file, skipping and displaying as necessary */ ZZ/* ------------------------------------------------------------ */ ZZvoid ZZdofile (in, inname, skip, nlines, dohead) ZZregister FILE *in; /* input stream */ ZZregister char *inname; /* input file name */ ZZregister long skip; /* number of lines to skip */ ZZregister long nlines; /* number of lines to display */ ZZ int dohead; /* TRUE if header is to be displayed */ ZZ{ ZZ register char *c; /* convenient local pointer */ ZZ register long lineno = 0; /* line number in file */ ZZ ZZ char inbuf[1024]; /* line buffer */ ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* Print header if necessary */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ if (dohead) ZZ { ZZ printf ("\ ZZ+-----------------------------------------------------------------+\n\ ZZ+ %-40.40s +\n\ ZZ+-----------------------------------------------------------------+\n", ZZ inname); ZZ } ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* Skip lines */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ while (lineno++ < skip && fgets (inbuf, sizeof inbuf, in)); ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* Display lines */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ lineno = 0; ZZ ZZ while (lineno++ < nlines && fgets (inbuf, sizeof inbuf, in)) ZZ fputs (inbuf, stdout); ZZ ZZ return; ZZ} SHAR_EOF if test 4938 -ne "`wc -c < 'head.c'`" then echo shar: error transmitting "'head.c'" '(should have been 4938 characters)' fi fi # end of overwriting check echo shar: extracting "'ctags.c'" '(6771 characters)' if test -f 'ctags.c' then echo shar: will not over-write existing file "'ctags.c'" else sed 's/^ZZ//' << \SHAR_EOF > 'ctags.c' ZZ/*T ctags - generate VI tags file from C sources */ ZZ/*S globals and stuff */ ZZ#include ZZ#include ZZ ZZ#define EQ == ZZ#define NE != ZZ#define GT > ZZ#define GE >= ZZ#define LT < ZZ#define LE <= ZZ#define OR || ZZ#define AND && ZZ ZZ#define TRUE 1 ZZ#define FALSE 0 ZZ ZZ#define SPACE ' ' ZZ#define NUL '\0' ZZ ZZtypedef short BOOL; ZZ ZZchar FunctionName[40]; ZZ ZZchar *ReservedWord[] = { ZZ "BOOL", "auto", "bool", "break", "case", "char", "continue", ZZ "default", "do", "double", "else", "entry", "enum", ZZ "extern", "float", "for", "goto", "if", ZZ "int", "long", "register", "return", "short", ZZ "sizeof", "static", "struct", "switch", ZZ "typedef", "union", "unsigned", "void", "while", ZZ NULL }; ZZ ZZchar *pgm; ZZchar inbuf[512]; ZZ ZZextern char *strchr (); /* index on BSD */ ZZextern char *strrchr (); /* rindex on BSD */ ZZextern char *strpbrk (); /* ??? */ ZZ ZZint skiptoend (); /* skip to end of function */ ZZchar ckfunc (); /* check for function declaration */ ZZ/*Page Eject*/ ZZmain (ac, av) ZZint ac; ZZchar *av[]; ZZ{ ZZ register FILE *in; /* input file stream */ ZZ register FILE *tagfile; /* `tags' file being created */ ZZ ZZ register char *cp; /* convenient character pointers */ ZZ register char *ep; /* */ ZZ ZZ register int i; /* loop index and such */ ZZ register int index = FALSE; /* if true, produce a functions */ ZZ /* index instead of tags file */ ZZ register int line_number = 0; /* line number of declaration */ ZZ register int optind = 1; /* like getopt - command arg */ ZZ ZZ char *funcname; /* function name */ ZZ ZZ char filename[15]; /* like it says */ ZZ ZZ if (pgm = strrchr (av[0], '/')) pgm++; ZZ else pgm = av[0]; ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* Create the tags file */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ tagfile = fopen ("tags", "w"); ZZ if (!tagfile) ZZ { ZZ perror ("tags"); ZZ fprintf (stderr, ZZ "%s: cannot create file tags\n", pgm); ZZ exit (1); ZZ } ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* If selected, write a function index to stdout instead */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ if (!strncmp (av[1], "-x", 2)) ZZ { ZZ index = TRUE; ZZ optind++; ZZ } ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* Process each file specified on the command line */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ for (i = optind; i LT ac; i++) ZZ { ZZ if (!(in = fopen (av[i], "r"))) ZZ { ZZ perror (av[i]); ZZ fprintf (stderr, ZZ "%s: unable to read file %s\n", pgm, av[i]); ZZ } ZZ else ZZ { ZZ while (fgets (inbuf, sizeof inbuf, in)) ZZ { ZZ line_number++; ZZ if (ckfunc (inbuf)) ZZ { ZZ /* ------------------------------------------------------------ */ ZZ /* Found a function declaration */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ inbuf[strlen(inbuf)-1] = NUL; ZZ if (index) ZZ { ZZ printf ("%-20.20s %6d %s\t%s\n", ZZ FunctionName, line_number, av[i], inbuf); ZZ } ZZ /* ------------------------------------------------------------ */ ZZ /* Special case function name `main' */ ZZ /* ------------------------------------------------------------ */ ZZ else if (!strcmp (FunctionName, "main")) ZZ { ZZ cp = strrchr (av[i], '/'); ZZ if (cp) cp++; ZZ else cp = av[i]; ZZ strcpy (filename, cp); ZZ ep = strrchr (filename, '.'); ZZ if (ep) *ep = NUL; ZZ fprintf (tagfile, "M%s\t%s\t?^%s$?\n", ZZ filename, av[i], inbuf); ZZ } ZZ else ZZ { ZZ fprintf (tagfile, "%s\t%s\t?^%s$?\n", ZZ FunctionName, av[i], inbuf); ZZ } ZZ line_number += skiptoend (in); ZZ } ZZ } ZZ fclose (in); ZZ } ZZ } ZZ fclose (tagfile); ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* Tags file must be sorted alphabetically on tag */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ system ("sort -u -t'\t' +0 -1 -o tags tags"); ZZ ZZ exit (0); ZZ} ZZ/*S ckfunc - check line for function declaration */ ZZ/*H ckfunc */ ZZ/*E*/ ZZ ZZ#define isidchr(c) (isalnum(c) OR (c EQ '_')) ZZ ZZchar ZZckfunc (s) ZZregister char *s; /* string to check for declaration */ ZZ{ ZZ register char *p; /* convenient character pointer */ ZZ register int i; /* useful loop index */ ZZ register int result; /* used to terminate search loop */ ZZ register char found = FALSE; /* true if declaration found */ ZZ ZZ static char *_fnm = "ckfunc"; ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* There's GOT to be a left paren for there to be a declaration */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ if (strchr (s, '(')) ZZ { ZZ found = TRUE; ZZ ZZ while (found) ZZ { ZZ found = FALSE; ZZ p = FunctionName; ZZ for (s; isascii (*s) AND isspace (*s) AND *s; s++); ZZ if( *s EQ '*' ) ZZ { ZZ for (++s; isascii (*s) AND isspace (*s) AND *s; s++); ZZ } ZZ ZZ if ((*s EQ '_') OR isalpha(*s)) ZZ { ZZ while (isidchr (*s)) *p++ = *s++; ZZ ZZ *p = NUL; ZZ ZZ for (found = FALSE, i = 0; ZZ !found AND ReservedWord[i]; i++) ZZ { ZZ if (!(result = strcmp (FunctionName, ReservedWord[i]))) ZZ found = TRUE; ZZ else if (result LT 0) break; ZZ } ZZ } ZZ } ZZ } ZZ ZZ for (s; isascii (*s) AND isspace (*s) AND *s; s++); ZZ ZZ if (*s EQ '(') ZZ { ZZ for (found = FALSE; *s AND !found; s++) ZZ found = *s EQ ')'; ZZ ZZ if (found) ZZ { ZZ for (; *s AND isspace (*s); s++); ZZ ZZ found = *s NE ';'; ZZ } ZZ } ZZ ZZ return found; ZZ} ZZ/* ------------------------------------------------------------ */ ZZ/* Skiptoend is called after a function declaration is found */ ZZ/* to skip to the end of the function. */ ZZ/* ------------------------------------------------------------ */ ZZint ZZskiptoend (in) ZZregister FILE *in; /* file being processed */ ZZ{ ZZ register int nest = 0; /* nesting level - zero means end */ ZZ register int c; /* character being checked */ ZZ register int line_number = 0; /* like it says */ ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* Simpleminded search for the starting brace */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ while (((c = getc (in)) NE EOF) AND c NE '{') ZZ if (c EQ '\n') line_number++; ZZ ZZ nest++; ZZ ZZ /* ------------------------------------------------------------ */ ZZ /* Keep going until the paired brace is found */ ZZ /* ------------------------------------------------------------ */ ZZ ZZ while (nest AND ((c = getc (in)) NE EOF)) ZZ { ZZ switch (c) ZZ { ZZ case '{': nest++; break; ZZ case '}': nest--; break; ZZ case '\n': line_number++; ZZ } ZZ } ZZ ZZ return line_number; ZZ} SHAR_EOF if test 6771 -ne "`wc -c < 'ctags.c'`" then echo shar: error transmitting "'ctags.c'" '(should have been 6771 characters)' fi fi # end of overwriting check # End of shell archive exit 0