home *** CD-ROM | disk | FTP | other *** search
- /* cgrind.c */
-
- /* Author:
- * Steve Kirkendall
- * 16820 SW Tallac Way
- * Beaverton, OR 97006
- * kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
- */
-
-
- /* This file contains the complete source-code for the cgrind program. */
-
- /* Cgrind underlines C's reserved words, and emboldens function names.
- * It does this by inserting "\fB", "\fU", and "\fR" into the file.
- * usage: cgrind [file.c]... >file
- */
-
- #include <stdio.h>
- #include <ctype.h>
-
- /* These store the fonts that are used for various parts of the source */
- char font_reserved = 'U';
- char font_function = 'B';
- char font_comment = '\0';
- char font_string = '\0';
-
- /* This array contains all C reserved words. The words are segregated
- * according to their first letter, to speed lookups
- */
- char *reserved[26][5] =
- {
- {"auto"},
- {"break"},
- {"case", "char", "continue"},
- {"default", "do", "double"},
- {"else", "enum", "extern"},
- {"far", "float", "for"},
- {"goto"},
- {(char *)0},
- {"if", "int"},
- {(char *)0},
- {(char *)0},
- {"long"},
- {(char *)0},
- {"near"},
- {(char *)0},
- {(char *)0},
- {(char *)0},
- {"register", "return"},
- {"short", "sizeof", "static", "struct", "switch"},
- {"typedef"},
- {"union", "unsigned"},
- {"void", "volatile"},
- {"while"},
- {(char *)0},
- {(char *)0},
- {(char *)0},
- };
-
- /* the program name, for diagnostics */
- char *progname;
-
- main(argc, argv)
- int argc; /* number of command-line args */
- char **argv; /* values of the command line args */
- {
- FILE *fp;
- int i;
-
- progname = argv[0];
-
- /* parse the flags */
- for (i = 1; i < argc && *argv[i] == '-'; i++)
- {
- switch (argv[i][1])
- {
- case 'r':
- font_reserved = argv[i][2];
- break;
-
- case 'f':
- font_function = argv[i][2];
- break;
-
- case 'c':
- font_comment = argv[i][2];
- break;
-
- case 's':
- font_string = argv[i][2];
- break;
-
- default:
- fputs(progname, stderr);
- fputs(": invalid flag (valid ones are -rC -fC -cC -sC)\n", stderr);
- exit(2);
- }
- }
-
- if (i == argc)
- {
- /* probably shouldn't read from keyboard */
- if (isatty(fileno(stdin)))
- {
- fputs("usage: ", stderr);
- fputs(progname, stderr);
- fputs(" [-rC] [-fC] [-cC] [-sC] [filename.c]...\n", stderr);
- exit(3);
- }
-
- /* no files named, so use stdin */
- cgrind(stdin);
- }
- else
- {
- for (; i < argc; i++)
- {
- fp = fopen(argv[i], "r");
- if (!fp)
- {
- perror(argv[i]);
- }
- else
- {
- cgrind(fp);
- if (i < argc - 1)
- {
- putchar('\f');
- }
- fclose(fp);
- }
- }
- }
- }
-
-
- /* This function does the cgrind thing to a single file */
- cgrind(fp)
- FILE *fp;
- {
- char linebuf[1025];
- char *fgets();
- char *ptr;
- int newfont;
-
- /* for each line ... */
- while (fgets(linebuf, sizeof linebuf, fp))
- {
- /* for each char of the line... */
- for (ptr = linebuf; *ptr; ptr++)
- {
- /* output a font string, if needed */
- newfont = grindchar(ptr);
- if (newfont)
- {
- putchar('\\');
- putchar('f');
- putchar(newfont);
- }
-
- /* output this character */
- putchar(*ptr);
- }
- }
- }
-
-
- /* This function detects when the font should change. It should be called
- * for each position in the line of text, including the '\n' or '\0' that
- * marks its end. This function returns '\0' normally, or one of 'B', 'U',
- * or 'R' to change the font.
- */
- grindchar(ptr)
- char *ptr; /* pointer to the char to process */
- {
- static font = 'R'; /* start in regular font */
- static context = '\0'; /* not in string, not in comment */
- static afternl = 0; /* after a newline in funny context? */
- static delay = 0; /* delay the emission of font? */
- int i, j, k;
-
- /* if we're in a funny context & get a '\n' or '\0', then make sure we
- * go out of its font during the newline and then go back into it
- */
- if ((*ptr == '\n' || *ptr == '\0') && context)
- {
- afternl = 1;
- delay = 0;
- if (font && font != 'R')
- return 'R';
- return '\0';
- }
- if (afternl && context)
- {
- afternl = 0;
- delay = 0;
- return font;
- }
-
- /* strings */
- if (!context && *ptr == '"')
- {
- context = '"';
- font = font_string;
- delay = 1;
- return '\0';
- }
- if (context == '"' && *ptr == '"')
- {
- context = '\0';
- font = 'R';
- delay = 0;
- return font_string ? 'R' : '\0';
- }
-
- /* comments */
- if (!context && *ptr == '/' && ptr[1] == '*')
- {
- context = '*';
- font = font_comment;
- delay = 0;
- return font;
- }
- if (context == '*' && *ptr == '*' && ptr[1] == '/')
- {
- context = '\0';
- font = 'R';
- if (font_comment)
- delay = 2;
- return '\0';
- }
-
- /* handle delayed output */
- if (delay > 0)
- {
- delay--;
- if (delay == 0)
- return font;
- }
-
- /* within funny contexts, don't look for reserved words or functions */
- if (context)
- {
- return '\0';
- }
-
- /* if this isn't alphanumeric, and font != 'R', then change to 'R' */
- if (!isalnum(*ptr) && *ptr != '_')
- {
- if (font != 'R')
- {
- font = 'R';
- return 'R';
- }
- return '\0';
- }
-
- /* if this *is* alphanumeric, and font != 'R', then it stays the same */
- if ((isalnum(*ptr) || *ptr == '_') && font != 'R')
- {
- return '\0';
- }
-
- /* if neither functions nor reserved words are used, skip! */
- if (!font_function && !font_reserved)
- {
- return '\0';
- }
-
- /* is this a reserved word? */
- if (islower(*ptr))
- {
- i = *ptr - 'a';
- for (j = 0; j < 5 && reserved[i][j]; j++)
- {
- k = strlen(reserved[i][j]);
- if (!strncmp(ptr, reserved[i][j], k) && !islower(ptr[k]))
- {
- if (font_reserved)
- font = font_reserved;
- return font_reserved;
- }
- }
- }
-
- /* is this word followed by a '(' ? */
- do
- {
- ptr++;
- } while (isalnum(*ptr) || *ptr == '_');
- while (*ptr == ' ')
- {
- ptr++;
- }
- if (*ptr == '(')
- {
- if (font_function)
- font = font_function;
- return font_function;
- }
-
- return '\0';
- }
-