/*
 *                      ***************
 *                      * X R F 1 . C *
 *                      ***************
 *
 * Lexical processing for C xref'er. Sifts through C source code
 * and pulls out the identifiers. Recognizes reserved words and
 * disregards them. Returns non-zero integer (true) if an id was
 * successfully moved into 'idbuf', zero (false) if end-of-line
 * was reached. I took care to test the C compiler's reaction to
 * Formfeeds with respect to line numbers, and made sure the line
 * numbers assigned by xrf act the same.
 *
 * Version V1.3          9-May-80
 * Version V1.4		10-Jul-80 MM	Allow $ in identifiers, bummed code
 * Version V1.5		21-Jul-80 MM	Dropped newline from ctime()
 * Version V1.6		22-Jul-80 MM	'.' is not an alpha char.
 */

#include <stdio.h>
#include "xrf.h"

#define A 1             /* Alpha character */
#define C 2             /* Start of comment possibly */
#define L 3             /* Literal delimiter */
#define N 4             /* Numeric character */
#define Z 5             /* End of string */

#define NRW 28          /* # reserved words */

static int cmtflg = 0;	/* Comment flag */

static char ctype[] = {         /* Character action lookup */
                        Z,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,L,0,A,0,0,L,0,0,0,0,0,0,0,C,
                        N,N,N,N,N,N,N,N,N,N,0,0,0,0,0,0,
                        0,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,
                        A,A,A,A,A,A,A,A,A,A,A,0,0,0,0,A,
                        0,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,
                        A,A,A,A,A,A,A,A,A,A,A,0,0,0,0,0
                      };

static char *reswrd[NRW] = {
                        "auto", "break", "case", "char",
                        "continue", "default", "do", "double",
                        "else", "entry", "extern", "float",
                        "for", "goto", "if", "int",
                        "long", "register", "return", "short",
                        "sizeof", "static", "struct", "switch",
                        "typedef", "union", "unsigned", "while"
                        };























/*
 * Scan off a non reserved identifier. Put it into 'idbuf'.
 * Returns +1 if successful, 0 if end-of-line was reached.
 *
 */

getid()                         /* Get an identifier into idbuf */

   {
   register char *p ;                   /* Fast scan pointer */
   register char *i ;                   /* Fast id buf pointer */
   register int c;                      /* Dispatch code */

   if (debug) {printf("xrf: getting identifier\n");}
   p = scanp;                           /* Init fast pointers */
   i = idbuf;
   while ((c = *p) != 0)                /* Scan till end of string */
      {
      if(c == '\014')                   /* If formfeed, */
         {
         c = *p = ' ';                  /* Convert to harmless blank */
         newpage();                     /* Force new page */
         }
      if (cmtflg)                       /* If comment flag is on */
         {
         while(*p && *p++ != '*');	/* Scan to '*' or end of string */
         if(*p == '/')                  /* If we found end of comment */
            cmtflg = 0;                 /* Turn off comment flag */
         continue;                      /* and recycle */
         }
      switch(ctype[c])			/* Dispatch on the type */
         {
         case A:                        /* Start of an identifier */
            i = idbuf;                  /* Reset the id buffer pointer */
            do {
               if( i < &idbuf[NCPS] ) { /* Copy into idbuf */
                  *i++ = *p++;
               } else {                  /* Unless it gets full */
                  p++;
		}
            } while( (c=ctype[*p]) == A || c == N ); /* While alphanumeric */
            while( i < &idbuf[NCPS] ) {  /* Pad idbuf with nulls */
               *i++ = '\0';
	    }
            if(nonres(idbuf))           /* If it's not a reserved word */
               {
               scanp = p;               /* Update the scan pointer */
		if (debug) {printf("xrf: got identifier %s\n",idbuf);}
               return (1);              /* Return with success */
               }
            break;                      /* End of identifier processing */
         case N:                        /* Scan by a number string */
            do p++; while( (c=ctype[*p]) == N || c == A );
            break;
         case L:                        /* Scan by a literal */
	    while (*++p != c && *p) {	/* Scan to the matching trailing */
		if (*p == '\\') p++;	/* Quote, ignoring backslash quoted */
	    }				/* Characters.  If not at the end */
	    if (*p) p++;		/* Of the line, skip to the char. */
            break;			/* Following the trailing quote */
         case C:
            if(*++p == '*')             /* Start a comment */
              cmtflg = 1;               /* by setting comment flag */
            break;
         default:                       /* Otherwise just scan it off */
            p++;
            break;
         }                              /* End of switch statement */
      }                         /* If we exit here, end-of line. */
   if (debug) {printf("xrf: get identifier failed\n");}
   return(0);                   /* Return with failure indication */
   }



















/*
 * Search for reserved word. Return true (1) if NOT reserved word.
 * Uses binary search.
 */

nonres( bufp )                  /* Test if not reserved word */
char *bufp;
{
   register int low ;           /* Low pointer index */
   register int mid ;           /* Mid ... */
   register int hi  ;           /* hi ...  */
   int cond;                    /* Condition from strcmp */

   if (debug) {printf("xrf: check %s for reserved\n",bufp);}
   low = 0;
   hi  = NRW-1;
   while (low <= hi) {
       mid = (low + hi) / 2;
       if((cond = strcmp(bufp, reswrd[mid])) < 0) {
           hi = mid - 1;
       } else if (cond > 0) {
           low = mid + 1;
       } else {
	   if (debug) {printf("xrf: %s is reserved\n",bufp);}
           return(0);             /* False, it IS reserved */
       }
   }
   if (debug) {printf("xrf: %s not reserved\n",bufp);}
   return(1);                   /* True, it's NOT reserved */
}


