[comp.sources.misc] A C version of the lint driver script

rsalz@pineapple.bbn.com (02/06/88)

Comp.sources.misc: Volume 2, Issue 45

Submitted-By: "Rich $alz" <rsalz@pineapple.BBN.COM>

Archive-Name: lint-c-front


Comp.sources.misc: Volume 2, Issue 45
Submitted-By: "Rich $alz" <rsalz@pineapple.BBN.COM>
Archive-Name: lint-c-front

A couple of jobs ago I worked on SysV UniSoft machines, and shell scripts
were painfully slow.  To make sure I knew pipe/fork/exec/wait semantics, I
rewrote the lint script into C code.  The games with exit and _exit helped
shrink program size; a colleague printf/sprinf library that didn't use
standard I/O, so this whole program was under 8K.
As a minimum, some folks might find the transliteration of
	(/lib/cpp $O $A | $L/lint1 $X -H$H $A >>$T) 2>&1
useful, amusing, or maybe even buggy.  I know it worked back then...

Enjoy,
	/r$

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'lint.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lint.c'\"
else
echo shar: Extracting \"'lint.c'\" \(6486 characters\)
sed "s/^X//" >'lint.c' <<'END_OF_FILE'
X/*
X**  If only for hack value, a C version of the old-fashioned lint script.
X*/
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <signal.h>
X
X/* Fundamental constants of the universe. */
X#define ARG_CNT		30
X#define TRUE		1
X#define FALSE		0
X
X/* Argument lists. */
Xchar	*Lint1[ARG_CNT]	= {
X    "/usr/lib/lint/lint1"
X};
Xint	 Lint1C		= 1;
X
Xchar	*Lint2[ARG_CNT]	= {
X    "/usr/lib/lint/lint2"
X};
Xint	 Lint2C		= 1;
X
Xchar	*Cpp[ARG_CNT]	= {
X    "/lib/cpp",
X    "-DLINT",
X    "-Dlint",
X    "-C"
X};
Xint	 CppC		= 4;
X
X/* Other global variables. */
Xchar	 Htemp[]	= "/tmp/lintHXXXXXX";
Xchar	 Ttemp[]	= "/tmp/lintTXXXXXX";
Xint	 Libstat;
Xint	 Tfid;
X
X/* Linked in later. */
Xextern int	 errno;
Xextern char	*calloc();
Xextern char	*mktemp();
Xextern char	*strcpy();
Xextern char	*strchr();
Xextern char	*strrchr();
X/*+GETOPT ROUTINE
X *
X * A hacked-over version of the one in the standard library.
X */
X
Xint	 optind = 1;
Xchar	*optarg;
X
Xint
Xgetopt(ac, av, opts)
X    int			  ac;
X    char		**av;
X    char		 *opts;
X{
X    static int		  sp = 1;
X    register int	  c;
X    register char	 *cp;
X
X    if (sp == 1)
X	if (optind >= ac || av[optind][0] != '-' || av[optind][1] == '\0')
X	    return('\0');
X	else if (strcmp(av[optind], "--") == 0)
X	{
X	    optind++;
X	    return('\0');
X	}
X
X    c = av[optind][sp];
X    if (c == ':' || (cp = strchr(opts, c)) == NULL)
X	yelp("illegal option \"%c\"", c);
X    if (*++cp == ':')
X    {
X	if (av[optind][sp + 1] != '\0')
X	    optarg = &av[optind++][sp + 1];
X	else if (++optind >= ac)
X	    yelp("option \"%c\" requires an argument", c);
X	else
X	    optarg = av[optind++];
X	sp = 1;
X    }
X    else
X    {
X	if (av[optind][++sp] == '\0')
X	{
X	    sp = 1;
X	    optind++;
X	}
X	optarg = NULL;
X    }
X    return(c);
X}
X/*+SIGNAL CATCHERS AND EXITS
X */
X
X
X#ifdef	LINT
Xextern void	 exit();
X#else
Xexit(X)	int X;	 { _exit(X); }
X#endif	LINT
X
X
X/* VARARGS1 */
Xyelp(A, B)
X    char	*A;
X    char	*B;
X{
X    int		 E;
X
X    E = errno;
X    printf(A, B);
X    printf(" (errno = %d).\n", E);
X    exit(1);
X}
X
X
XRupt()
X{
X    (void)unlink(Htemp);
X    (void)unlink(Ttemp);
X    yelp("\r\nInterrupted!\r\n");
X    /* NOTREACHED */
X}
X/*+UTILITY ROUTINES
X */
X
X
X/*
X * This routine appends a lint library to the T file.
X */
XLib(N, Flag)
X    char		*N;
X    int			 Flag;
X{
X    register int	 F;
X    register int	 i;
X    char		 Buff[BUFSIZ];
X
X    if (Flag)
X	sprintf(Buff, "/usr/lib/lint/llib-l%s.ln", N);
X    else
X	(void)strcpy(Buff, N);
X
X    if ((F = open(Buff, O_RDONLY)) < 0)
X	printf("cannot open \"%s\" lint library (errno=%d)", Buff, errno);
X    else
X    {
X	while ((i = read(F, Buff, sizeof Buff)) > 0)
X	    (void)write(Tfid, Buff, (unsigned int)i);
X	(void)close(F);
X    }
X}
X
X
X/*
X * This routine concats an argument to an arglist, perhaps preceeding
X * it with a minus sign and a letter.
X */
XAdd(C, Alist, Arg, Simple)
X    int		  C;
X    char	**Alist;
X    char	 *Arg;
X    char	  Simple;
X{
X    int			  L;
X    register char	 *p;
X
X    if (C >= ARG_CNT - 2)
X	yelp("too many arguments");
X	/* NOTREACHED */
X
X    L = strlen(Arg) + 1;
X    if (Simple)
X	L += 2;
X    p = Alist[C] = calloc((unsigned int)L, 1);
X    if (Simple)
X    {
X	*p++ = '-';
X	*p++ = Simple;
X    }
X    (void)strcpy(p, Arg);
X}
X/*!*/
X/*
X *  This routine is implements this line from the script:
X *	(/lib/cpp $O $A | $L/lint1 $X -H$H $A >>$T) 2>&1
X */
XDo(N)
X    char	*N;
X{
X    int		 P[2];
X
X    if (fork() == 0)
X    {
X	/* The kids run "... 2>&1" */
X	(void)close(2);
X	(void)dup(1);
X	(void)pipe(P);
X
X	Cpp[CppC]	= N;
X	Lint1[Lint1C]	= N;
X
X	if (fork() == 0)
X	{
X	    /* Younger child runs "cpp | ..." */
X	    (void)close(1);
X	    (void)dup(P[1]);
X	    (void)close(P[1]);
X	    (void)close(P[0]);
X	    (void)close(Tfid);
X	    (void)execv(Cpp[0], Cpp);
X	    yelp("No cpp?");
X	    /* NOTREACHED */
X	}
X	else
X	{
X	    /* Older child runs "... | lint >> Tfid" */
X	    (void)close(0);
X	    (void)dup(P[0]);
X	    (void)close(P[0]);
X	    (void)close(P[1]);
X	    (void)close(1);
X	    (void)dup(Tfid);
X	    (void)close(Tfid);
X	    (void)execv(Lint1[0], Lint1);
X	    yelp("No lint1?");
X	    /* NOTREACHED */
X	}
X    }
X    else
X	(void)wait((int *)0);
X}
X/*+MAIN ROUTINE
X */
X
X
Xmain(ac, av)
X    register int	 ac;
X    register char	*av[];
X{
X    register char	*p;
X    register int	 c;
X    struct stat		 Sb;
X
X    (void)mktemp(Htemp);
X    (void)mktemp(Ttemp);
X    Tfid = open(Ttemp, O_RDWR | O_CREAT | O_APPEND, 0666);
X    Add(Lint2C++, Lint2, Ttemp, 'T');
X
X    /* Parse JCL. */
X    while (c = getopt(ac, av, "abhuvxI:D:U:Nnpl:o:"))
X	switch (c)
X	{
X	    /* [abhuvx] -- standard lint flags. */
X	    case 'a': case 'b': case 'h': case 'u': case 'v': case 'x':
X		Add(Lint1C++, Lint1, "", c);
X		Add(Lint2C++, Lint2, "", c);
X		break;
X	    /* [DIU] -- standard cpp flags. */
X	    case 'D': case 'I': case 'U':
X		Add(CppC++, Cpp, optarg, c);
X		break;
X	    /* p -- portable library. */
X	    case 'p':
X		Add(Lint1C++, Lint1, "", c);
X		Add(Lint2C++, Lint1, "", c);
X	    /* [Nn] -- net or no library. */
X	    case 'N': case 'n':
X		Libstat = c;
X		break;
X	    /* l -- lint library. */
X	    case 'l':
X		Lib(optarg, TRUE);
X		break;
X	    /* o -- output file (redirection without meta chars). */
X	    case 'o':
X		(void)close(1);
X		(void)open(optarg, O_WRONLY | O_CREAT | O_TRUNC, 0666);
X		break;
X	}
X
X    Add(Lint1C++, Lint1, Htemp, 'H');
X    Add(Lint2C++, Lint2, Htemp, 'H');
X    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
X	(void)signal(SIGINT, Rupt);
X
X    /* Did flags; do filenames and libraries. */
X    for (; optind < ac; optind++)
X    {
X	/* Check for -l.. argument. */
X	if (*(p = av[optind]) == '-' && *++p == 'l')
X	{
X	    Lib(++p, TRUE);
X	    continue;
X	}
X
X	/* Check for *.c for *.ln arguments. */
X	if (p = strrchr(av[optind], '.'))
X	{
X	    if (*++p == 'c' && p[1] == '\0')
X	    {
X		Do(av[optind]);
X		continue;
X	    }
X	    if (p[0] == 'l' && p[1] == 'n' && p[2] == '\0')
X	    {
X		Lib(av[optind], FALSE);
X		continue;
X	    }
X	}
X	printf("Not grokked -- \"%s\" -- ignored\n", av[optind]);
X    }
X
X    /* Any standard C library? */
X    switch (Libstat)
X    {
X	case '\0':	Lib("c", TRUE);		break;
X	case 'N':	Lib("netc", TRUE);
X			Lib("net", TRUE);	break;
X	case 'p':	Lib("port", TRUE);	break;
X    }
X
X    (void)close(Tfid);
X
X    /* If lint1 created anything, run lint2. */
X    if (stat(Htemp, &Sb) >= 0 && Sb.st_size >= 0)
X    {
X	Add(Lint2C, Lint2, Htemp, 'H');
X	if (fork() == 0)
X	{
X	    (void)execv(Lint2[0], Lint2);
X	    yelp("No lint2?");
X	    /* NOTREACHED */
X	}
X	(void)wait((int *)0);
X    }
X
X    /* That's all she wrote. */
X    (void)unlink(Htemp);
X    (void)unlink(Ttemp);
X    exit(0);
X}
END_OF_FILE
if test 6486 -ne `wc -c <'lint.c'`; then
    echo shar: \"'lint.c'\" unpacked with wrong size!
fi
# end of 'lint.c'
fi
echo shar: End of shell archive.
exit 0