[mod.sources] head

sources-request@panda.UUCP (01/11/86)

Mod.sources:  Volume 3, Issue 87
Submitted by: Steven List <bene!luke!itkin>


# 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    <stdio.h>
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	<stdio.h>
ZZ#include	<ctype.h>
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