/*
 * slashes.c - process C source where // indicates comment to end-of-line.
 *
 * Usage:  slashes [ infile [outfile] ]
 */

#include <stdio.h>

#define FALSE 0
#define BUFFERSIZE 1024

// define state names for findslashes()
#define LOOKING 0		// looking for //'s
#define INDQUOTE 1		// inside double quotes
#define INSQUOTE 2		// inside single quotes
#define INCOMMENT 3		// inside comment delimiters

char buf [ BUFFERSIZE ];

FILE *in, *out, *freopen();

char version[] = "V1.0b";

char *findslashes(), *getline(), *fgets();

main( argc, argv )
int argc;
char *argv[];
{

if ( argc > 3 )
    showusage();

if ( argc == 2 || argc == 3 )
    {
    in = freopen ( argv[1], "r", stdin ); // this makes stdin = argv[1]
    if ( !in )
       {
       fprintf ( stderr, "Can't open file %s for input.\n", argv[1] );
       showusage();
       }
    }

if ( argc == 3 )
    {
    out = freopen ( argv[2], "w", stdout ); // this makes stdout = argv[2]
    if ( !out )
       {
       fprintf ( stderr, "Can't open file %s for output.\n", argv[2] );
       showusage();
       }
    }

// process the data

while ( getline ( buf ) )	// get line from stdin into buf
    {
    char *pos;
    pos = findslashes ( buf );	// find those slashes
    if ( pos != NULL )
       fix ( pos );		// fix up the comment for this line
    printf ( "%s", buf );
    }

exit ( 0 );
}

/*
 * findslashes() returns a pointer to the first occurrence of // in string
 * s, or NULL if not found.  // inside comments and quotes are ignored.
 * findslashes is implemented as a state machine with four states (see
 * defines at the beginning of this file).
 */

char *
findslashes ( s )
    char *s;
    {
    static int state = LOOKING;
    if ( state != INCOMMENT )		// only comments can bridge lines
	state = LOOKING;
    while ( *s )
	{
	if ( *s == '\\' )
	    {
	    s += 2;             	// skip escaped character
	    continue;
	    }
	switch ( state )
	    {
	    case INDQUOTE :
		if ( *s == '"' )	// found closing double quote
		    state = LOOKING;
		break;
	    case INSQUOTE :
		if ( *s == '\'' )	// found closing single quote
		    state = LOOKING;
		break;
	    case INCOMMENT :
		if ( *s == '*' && *(s+1) == '/' ) // found closing comment
		    state = LOOKING;		  //   delimiter
		break;
	    case LOOKING :		// we're looking for //'s
		switch ( *s )
		    {
		    case '"'  :
			state = INDQUOTE;  // found opening double quote
			break;
		    case '\'' :
			state = INSQUOTE;
			break;
		    case '/'  :
			if ( *(s+1) == '/' )
			    return ( s );  // found //
			else if (  *(s+1) == '*' ) // found comment start
			    state = INCOMMENT;

			break;
		    }
		break;
	    }
	++s;
	}
    return ( NULL );		// if we get to here then there is no //
    }

/*
 * fix() takes a pointer to the first slash in //, converts // to a opening
 * comment delimiter, and adds a closing comment delimiter at the end of 
 * the string.
 */
fix ( where )
    char *where;
    {
    char *end;
    *(where+1) = '*';         // convert '/' to '*' 
    end = where + strlen ( where ) - 1;   // end points at newline
    strcpy ( end, " */\n" );
    }


showusage ()
  {
  fprintf ( stderr,"slashes (%s) - Process C source where // indicates ",
			version );
  fprintf ( stderr,"comment to end-of-line.\n" );
  fprintf ( stderr,"  Usage:  slashes [ infile [outfile] ]\n\n" );
  exit ( 20 );
  }

// get a line that is no longer than BUFFERSIZE.
char *
getline ( s )
    char *s;
    {
    return ( fgets ( s, BUFFERSIZE - 3, stdin ) ); // to allow for comment
    }
