[comp.lang.c] Comment viewer

robert@duttnph.tudelft.nl (Robert de Vries) (10/10/89)

Richard O'Keefe posted recently an article with the source of a program
to highlight comments in a C program.
I liked it, so I enhanced it a little bit and made it a little more
intelligent about strings. It also highlights the comments by reversing
the text and background colors.

There is one catch to this program: scarcely documented sources are VERY
easily spotted. Obfuscated C programmers beware! :-)

    	Robert.

---------------------- Cut here ------------------------------------
/*
    seecom.c -- highlight comments in C programs
    Usage: seecom <foobaz.c | more
    Original version by: Richard O'Keefe (ok@cs.mu.oz.au)
    Changed to highlight using reversed characters and to handle
    quoted strings with comment.
    Changed by: Robert de Vries (robert@duttnph.tudelft.nl)

    Compile:
       cc -o seecom seecom.c -ltermcap
*/
#include <stdio.h>

main()
{
    int state = 0;
    int c, prev_c = 0;
    char bp[1024], area[100], *parea, *start, *end, *term;
    extern char *tgetstr(), *getenv();
    
    term = getenv("TERM");
    if (term == NULL)
    {
	fprintf(stderr, "No TERM environment variable.\n");
	exit(1);
    }
    
    if (tgetent(bp, term) != 1)
    {
	fprintf(stderr, "tgetent failed.\n");
	exit(1);
    }
    
    parea = area;
    start = tgetstr("so", &parea);
    end = tgetstr("se", &parea);
    if ((start == NULL) || (end == NULL))
    {
	fprintf(stderr, "This terminal type cannot highlight.\n");
	exit(1);
    }
    
    
    while (c = getchar(), c != EOF)
    {
	switch (state)
	{
	  case 0:
	    /* we are not inside a comment */
	    /* check for '/*' '"' and ''' */
		switch(c)
		{
		  case '/':
		    c = getchar();
		    if (c == '*')
		    {
			printf("%s/*", start);
			state = 1;
		    }
		    else
		    {
			ungetc(c, stdin);
			putchar('/');
		    }
		    break;
		  case '"':
		    putchar(c);
		    if (prev_c != '\\') state = 2;
		    break;
		  case '\'':
		    putchar(c);
		    if (prev_c != '\\') state = 3;
		    break;
		  default:
		    putchar(c);
		    break;
		}
	    break;
	  case 1:
	    /* we are inside a comment */
	    /* check for '*' '/' */
	    putchar(c);
	    if (c == '*')
	    {
		c = getchar();
		if (c == '/')
		{
		    printf("/%s", end);
		    state = 0;
		}
		else
		    ungetc(c, stdin);
	    }
	    break;
	  case 2:
	    /* we are inside double quotes */
	    putchar(c);
	    if ((c == '"') && (prev_c != '\\'))
		state = 0;
	    break;
	  case 3:
	    /* we are inside single quotes */
	    putchar(c);
	    if ((c == '\'') && (prev_c != '\\'))
		state = 0;
	    break;
	}
	/* in case the backslash is an escape one, put a dummy character
	   in prev_c */
	if ((prev_c == '\\') && (c == '\\')) prev_c = ' ';
	else prev_c = c;
    }	

    switch (state)
    {
      case 1:
	fprintf(stderr, "Unterminated comment.\n");
	exit(1);
	break;
      case 2:
	fprintf(stderr, "Unterminated string (missing \").\n");
        exit(1);
	break;
      case 3:
	fprintf(stderr, "Unterminated character constant (missing ').\n");
	exit(1);
	break;
    }
    exit(0);
}