/* -----------------------------------------------------------------------
-- -------- (c) copyright 1993, 1994 -------------------------
-- -------- 555637 AB Ltd. -------------------------
-- -------- By: John Arrizza -------------------------
--------------------------------------------------------------------------
-- cincl scans c code for #includes and reports them
--
-- See readParms for a description of the input parms.
-- */
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <io.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* local defines */
#define FNAMEL 256 /* max. file name length */
/* Values for return codes */
#define RC_OK 0
#define RC_ERROR 1
#define RC_NOMSG 2
#define modname "CINCL"
/* structure containing input parms */
typedef struct _parms
{
int verbose;
int printlogo;
int printparms;
int includesys;
int recursivescan;
char infname[FNAMEL];
char TrcMskFile[9];
char TrcMskGrup[10];
char TrcMskLvl [80];
char TrcFile [256];
} PARMS;
/* linked list of include paths to search */
typedef struct _incpath
{
char *path;
struct _incpath *next;
} INCPATH;
/* linked list of source files to scan; usually one .c and then
a recursive list of all the .h's found within it
*/
typedef struct _scansource
{
char *path;
char *fname;
struct _scansource *next;
char slash[4];
} SCANSOURCE;
/* global private variables */
static char errmsg[1024];
static PARMS parms;
static FILE *infp;
static INCPATH *iphead;
static SCANSOURCE *sshead;
static long totnumlines;
static long totscanincludes;
static long totrepincludes;
static long totwarnings;
/* local function prototypes */
static int readParms (int argc, char **argv, PARMS *parms, INCPATH **iphead);
static int initEnv (INCPATH **iphead, SCANSOURCE **sshead);
static int openFiles (char *fname, FILE **infp);
static int cleanUp (FILE **f, INCPATH **iphead, SCANSOURCE **sshead);
static int closeFile (FILE **f);
static void printUsage (void);
static void printLogo (PARMS *parms);
static void printParms (PARMS *parms, INCPATH *iphead);
static void ErrMsgExit (int rc, char *errmsg);
static void ErrMsg (int rc, char *errmsg);
static void processFile (PARMS *parms, FILE *infp, INCPATH *iphead, SCANSOURCE **sshead);
static void addPath (INCPATH **iphead, char *path);
static void addSource (SCANSOURCE **sshead, char *path, char *fname);
static int isswitch (char *key, char *parm);
/* -----------------------------------------------------------------------
-- main:
-- read input parms
-- scan the file
-- cleanup
-- */
void
main(int argc, char **argv)
{
int rc;
SCANSOURCE *ss;
char *fqname;
totnumlines = 0;
totscanincludes = 0;
totrepincludes = 0;
totwarnings = 0;
rc = initEnv(&iphead, &sshead);
if (rc == RC_ERROR)
ErrMsgExit(rc, errmsg);
rc = readParms(argc, argv, &parms, &iphead);
if (rc != RC_OK)
ErrMsgExit(rc, errmsg);
addSource(&sshead, "", parms.infname);
/* while there is something to scan */
fqname = NULL;
for (ss = sshead; ss; ss = ss->next)
{
if (fqname)
free(fqname);
fqname = (char*) malloc(strlen(ss->path)+strlen(ss->slash)+strlen(ss->fname)+1);
strcpy(fqname, ss->path);
strcat(fqname, ss->slash);
strcat(fqname, ss->fname);
if (parms.verbose)
printf("Scanning '%s' ... \n", fqname);
rc = openFiles(fqname, &infp);
if (rc == RC_ERROR)
ErrMsgExit(rc, errmsg);
processFile(&parms, infp, iphead, &sshead);
closeFile(&infp);
}
if (fqname)
free(fqname);
if (parms.verbose)
printf("Total: Scanned %ld lines, found %ld includes, reported %ld includes\n",
totnumlines, totscanincludes, totrepincludes);
printf("\n");
for (ss = sshead; ss; ss = ss->next)
{
if (ss == sshead && ss->next == NULL)
printf("%s : \n", ss->fname);
else if (ss == sshead)
printf("%s : \\ \n", ss->fname);
else if (ss->next == NULL)
printf(" %s\n", ss->fname);
else
printf(" %s \\\n", ss->fname);
}
if (totwarnings)
printf("WARNINGS: %ld\n", totwarnings);
rc = cleanUp(&infp, &iphead, &sshead);
if (rc == RC_ERROR)
ErrMsgExit(rc, errmsg);
}
/* -----------------------------------------------------------------------
-- initEnv: creat
-- */
static int
initEnv(INCPATH **iphead, SCANSOURCE **sshead)
{
*iphead = NULL;
*sshead = NULL;
return RC_OK;
}
/* -----------------------------------------------------------------------
-- openFiles: open all of the files
-- */
static int
openFiles(char *fname, FILE **infp)
{
*infp = fopen(fname, "r");
if (!*infp)
{
sprintf(errmsg,"%s open failed: %s", fname, strerror(errno));
return RC_ERROR;
}
return RC_OK;
}
/* -----------------------------------------------------------------------
-- clean up like a good doobie
-- */
static int
cleanUp(FILE **infp, INCPATH **iphead, SCANSOURCE **sshead)
{
int rc;
INCPATH *ip;
SCANSOURCE *ss;
while(*iphead != NULL)
{
ip = *iphead;
*iphead = (*iphead)->next;
if (ip->path)
free(ip->path);
free(ip);
}
while(*sshead != NULL)
{
ss = *sshead;
*sshead = (*sshead)->next;
if (ss->path)
free(ss->path);
if (ss->fname)
free(ss->fname);
free(ss);
}
rc = closeFile(infp);
return rc;
}
/* -----------------------------------------------------------------------
-- closeFile: close a file and ensure the file pointer is null
-- */
static int
closeFile(FILE **f)
{
if (*f)
{
fclose(*f);
*f = NULL;
}
return RC_OK;
}
/* -----------------------------------------------------------------------
-- readParms: read the input parameters off the command line and response
-- file if any.
-- */
static int
readParms(int argc, char **argv, PARMS *parms, INCPATH **iphead)
{
FILE *f;
char l[FNAMEL];
char *p;
char tmp[FNAMEL];
int rc;
int curparm;
int done;
/* init the parms with defaults */
parms->verbose = 0;
parms->printlogo = TRUE;
parms->printparms = FALSE;
parms->includesys = FALSE;
parms->recursivescan = TRUE;
parms->infname[0] = '\0';
strcpy(parms->TrcMskFile, "null");
strcpy(parms->TrcMskGrup, "null");
strcpy(parms->TrcMskLvl, "e");
strcpy(parms->TrcFile, "trace");
f = NULL;
rc = RC_OK;
curparm = 0;
done = FALSE;
while (!done && (f || curparm < argc))
{
/* get the next parm from the input file or the next cmd line parm */
if (f)
{
p = fgets(l, FNAMEL, f);
if (!p)
{
fclose(f);
f = NULL;
continue;
}
p = strtok(l, " \n\r\t"); /* ignore everything after first white */
}
else
{
curparm++;
if (curparm >= argc)
continue;
strcpy(l, argv[curparm]);
}
#if 0
printf("Current parm = '%s'\n", l);
#endif
if (strcmp(l, "") == 0 ||
strcmp(l, "\n") == 0)
continue;
/* check to see what kind of parm it is */
if (l[0] == '-' || l[0] == '/')
{ /* it might be a switch */
l[0] = '-';
strlwr(l);
/* check for nologo switch */
if (isswitch(l, "-nol"))
{
parms->printlogo = FALSE;
continue;
}
/* no recursive scan */
if (isswitch(l, "-nor"))
{
parms->recursivescan = FALSE;
continue;
}
/* no recursive scan */
if (isswitch(l, "-r"))
{
parms->recursivescan = TRUE;
continue;
}
/* check for scan sys includes switch */
if (isswitch(l, "-nos"))
{
parms->includesys = FALSE;
continue;
}
/* check for scan sys includes switch */
if (isswitch(l, "-s"))
{
parms->includesys = TRUE;
continue;
}
/* verbose */
if (isswitch(l, "-vv")) /* must be before -v switch */
{
parms->verbose = 2;
continue;
}
if (isswitch(l, "-v"))
{
parms->verbose = 1;
continue;
}
if (isswitch(l, "-nov"))
{
parms->verbose = 0;
continue;
}
/* its an include declaration */
if (isswitch(l, "-i"))
{
addPath(iphead, &l[2]);
continue;
}
if (isswitch(l, "-e"))
{
char *e;
char *p;
strupr(&l[2]);
e = getenv(&l[2]);
if (!e)
{
printf("Environment variable not found '%s'\n", &l[2]);
continue;
}
for (p=strtok(e, ";"); p; p= strtok(NULL, ";"))
addPath(iphead, p);
continue;
}
/* check for scan sys includes switch */
if (isswitch(l, "-?") || isswitch(l, "-h"))
{
rc = RC_NOMSG;
done = TRUE;
continue;
}
/* check for print parms switch */
if (isswitch(l, "-p"))
{
parms->printparms = TRUE;
continue;
}
/* check for print parms switch */
if (isswitch(l, "-nop"))
{
parms->printparms = FALSE;
continue;
}
/* check for trace options */
if (l[1] == 't')
{
strcpy(tmp, l);
p = strtok(tmp, ":");
p = strtok(NULL, " ");
if (isswitch(l, "-tmfi"))
{ /* trace mask file */
strncpy(parms->TrcMskFile, p, sizeof(parms->TrcMskFile));
continue;
}
if (isswitch(l, "-tmgr"))
{ /* trace mask group name */
strncpy(parms->TrcMskGrup, p, sizeof(parms->TrcMskGrup));
continue;
}
if (isswitch(l, "-tmlv"))
{ /* trace mask level */
strncpy(parms->TrcMskLvl, p, sizeof(parms->TrcMskLvl));
continue;
}
if (isswitch(l, "-tf"))
{ /* trace file */
strncpy(parms->TrcFile, p, sizeof(parms->TrcFile));
continue;
}
/* -txxx parms will fall through to the switch and produce an error */
}
rc = RC_NOMSG;
printf("Error: Unknown switch: %s\n", l);
} /* endif a parm */
else if (l[0] == '@')
{
if (f)
fclose(f);
f = fopen(&l[1], "r");
if (!f)
{
rc = RC_NOMSG;
printf("Error: Can not open: %s : %s\n", &l[1], strerror(errno));
continue;
}
}
else
{ /* its a file name */
if (!parms->infname[0])
strcpy(parms->infname, l);
else /* too many file names */
{
rc = RC_NOMSG;
printf("Error: Unknown parameter: '%s'\n", l);
continue;
}
}
}
/* clean up */
if (f)
fclose(f);
if (!parms->infname[0])
{
rc = RC_NOMSG;
printf("Error: Missing input file name\n");
}
if (rc == RC_OK)
{
printLogo(parms);
printParms(parms, *iphead);
}
else
{
ErrMsg(rc, errmsg);
printUsage();
}
return rc;
}
/* -----------------------------------------------------------------------
-- isswitch: compares key and parm and returns if they match or not
--
-- */
static int
isswitch(char *key, char *parm)
{
if (strncmp(key, parm, strlen(parm)) == 0)
return TRUE;
return FALSE;
}
/* -----------------------------------------------------------------------
-- addPath: add path to linked list
-- */
static void
addPath(INCPATH **iphead, char *path)
{
INCPATH *ip;
INCPATH *last;
ip = (INCPATH*) malloc(sizeof(INCPATH));
ip->path = strdup(path);
ip->next = NULL;
if (*iphead == NULL)
*iphead = ip;
else
{
last = *iphead;
while(last->next != NULL)
last = last->next;
last->next = ip;
}
}
/* -----------------------------------------------------------------------
-- scanSource: add source to scan into linked list
-- only fnames are added
-- */
static void
addSource(SCANSOURCE **sshead, char *path, char *fname)
{
SCANSOURCE *ss;
SCANSOURCE *last;
for (last = *sshead; last && last->next != NULL; last = last->next)
{
/* if the entry is already there then we're done */
if (stricmp(last->fname, fname) == 0)
return;
}
ss = (SCANSOURCE*) malloc(sizeof(SCANSOURCE));
ss->path = strdup(path);
if (strlen(path) == 0 || path[strlen(path) - 1] == '\\')
strcpy(ss->slash, "");
else
strcpy(ss->slash, "\\");
ss->fname = strdup(fname);
ss->next = NULL;
if (last == NULL)
*sshead = ss;
else
last->next = ss;
}
/* -----------------------------------------------------------------------
-- printUsage: print usage report
-- */
static void
printUsage(void)
{
/*12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
printf("\nUsage: %s [parms] filename\n", modname);
printf("Input parms begin with '-' or '/'.\n");
printf(" -nol : don't print logo\n");
printf(" -p : dump parm summary\n");
printf(" -nop : don't dump parm summary (default)\n");
printf(" -r : scan found include files (default)\n");
printf(" -nor : don't scan found include files\n");
printf(" -v : verbose\n");
printf(" -vv : very verbose\n");
printf(" -nov : quiet mode (default)\n");
printf(" -s : scan system '<...>' includes\n");
printf(" -nos : don't scan system '<...>' includes (default)\n");
printf(" -txxxx : tracing\n");
printf(" -ipath : define include path 'path'\n");
printf(" -evrbl : use environment variable 'vrbl' for include paths\n");
printf(" -h -? : display this list\n");
printf(" @infname : read remaining parms from infname. 1 parm per line\n");
printf(" any chars after first blank in the line are ignored\n");
printf(" Any parms that do not start with @, - or / are file names\n\n");
}
/* -----------------------------------------------------------------------
-- printParms: print parm summary report
-- */
static void
printParms(PARMS *parms, INCPATH *iphead)
{
INCPATH *ip;
if (!parms->printparms)
return;
/*12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
printf("Input parameters are:\n");
printf(" TraceFile=%s TraceMask: file=%s grup=%s lvl=%s\n",
parms->TrcFile, parms->TrcMskFile,
parms->TrcMskGrup, parms->TrcMskLvl);
if (parms->verbose == 0)
printf(" Verbosity? : quiet\n");
else if (parms->verbose == 1)
printf(" Verbosity? : verbose\n");
else if (parms->verbose == 2)
printf(" Verbosity? : very verbose\n");
printf(" System includes? : %s\n", parms->includesys ? "yes" : "no");
printf(" Scan recursively? : %s\n", parms->recursivescan ? "yes" : "no");
printf(" Input file : %s\n", parms->infname);
printf(" Include paths: \n");
for (ip = iphead; ip; ip = ip->next)
printf(" %s\n", ip->path);
printf("\n");
}
/* -----------------------------------------------------------------------
-- printLogo: print logo
-- */
static void
printLogo(PARMS *parms)
{
if (!parms->printlogo)
return;
/*12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
printf("CINCL - (c) copyright 1996, 555637 Alberta Ltd.\n");
}
/* -----------------------------------------------------------------------
-- ErrMsgExit
-- */
static void
ErrMsg(int rc, char *errmsg)
{
if (rc != RC_NOMSG)
printf("%s: rc=%d %s\n", modname, rc, errmsg);
}
/* -----------------------------------------------------------------------
-- ErrMsgExit
-- */
static void
ErrMsgExit(int rc, char *errmsg)
{
ErrMsg(rc, errmsg);
exit(1);
}
/* -----------------------------------------------------------------------
-- processFile
-- */
static void
processFile(PARMS *parms, FILE *infp, INCPATH *iphead, SCANSOURCE **sshead)
{
#define LINESZ 1023
char *line;
char *fqpath;
char *p;
char *q;
char lbracket;
char rbracket;
long lineno;
int ok;
int sysincl;
INCPATH *ip;
int exists;
long scannedincludes;
long reportedincludes;
line = (char*) malloc(LINESZ + 1);
fqpath = (char*) malloc(FNAMEL + 1);
lineno = 0;
scannedincludes = 0;
reportedincludes = 0;
while(fgets(line, LINESZ, infp) != NULL)
{
p = line;
lineno++;
/* find first non-blank char */
while (*p == ' ' || *p == '\t')
p++;
/* not a pre-proc stmt, then keep going */
if (*p != '#')
continue;
/* it is, skip the hash */
p++;
/* find the next token, see if its an include */
q = strtok(p, " \t\n");
if (stricmp(q, "include") != 0)
continue;
/* it is, get the file */
q = strtok(NULL, " \t\n");
/* strip of the delimiters */
lbracket = *q;
q++;
rbracket = q[strlen(q) - 1];
q[strlen(q) - 1] = '\0';
/* check the form of the file */
ok = TRUE;
if (lbracket != '<' && lbracket != '"')
{
printf(" Warning (%ld): left delimiter '%c' should be angle bracket or double quote\n",
lineno, lbracket);
ok = FALSE;
}
if (rbracket != '>' && rbracket != '"')
{
printf(" Warning (%ld): right delimiter '%c' should be angle bracket or double quote\n",
lineno, rbracket);
ok = FALSE;
}
if (lbracket == '"' && lbracket != rbracket)
{
printf(" Warning (%ld): left delimiter is '%c', right is %c\n",
lineno, lbracket, rbracket);
ok = FALSE;
}
if (lbracket == '<' && rbracket != '>')
{
printf(" Warning (%ld): left delimiter is '%c', right is %c\n",
lineno, lbracket, rbracket);
ok = FALSE;
}
/* if there was a badly formed statement, just continue */
if (!ok)
{
totwarnings++;
continue;
}
scannedincludes++;
/* set flag to indicate if it is a system include or not */
sysincl = (lbracket == '<');
/* user doesn't want sys includes, don't scan them! */
if (sysincl && !parms->includesys)
continue;
for (ip = iphead; ip; ip=ip->next)
{
strcpy(fqpath, ip->path);
if (fqpath[strlen(fqpath) - 1] != '\\')
strcat(fqpath, "\\");
strcat(fqpath, q);
exists = access(fqpath, -1);
if (exists == 0)
break;
}
reportedincludes++;
if (ip)
{
if (parms->verbose == 2)
printf(" %-13.13s: line=%-4ld sys?=%s path=%s\n",
q, lineno, sysincl ? "yes": "no ", ip->path);
if (parms->recursivescan)
addSource(sshead, ip->path, q);
}
else
{
totwarnings++;
printf(" Warning (%ld): %s %sinclude file is not in path list\n",
lineno, q, sysincl ? "system ": "");
}
}
if (parms->verbose == 2)
printf(" Scanned %ld lines, found %ld includes, reported %ld includes\n",
lineno, scannedincludes, reportedincludes);
totnumlines += lineno;
totscanincludes += scannedincludes;
totrepincludes += reportedincludes;
free(line);
free(fqpath);
}
|