cincl : dump c #include files

Download cincl.zip

Synopsis:

cincl.cpp


cincl.cpp

Synopsis
/* -----------------------------------------------------------------------
-- --------  (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);
}








Contact me about content on this page using john_web-at-arrizza-dot-com
For Web Master or site problems contact: webadmin-at-arrizza-dot-com
Copyright John Arrizza (c) 2001-2010