#include <stdio.h>
#include <string.h>
#define STRLENGTH 262  /* room for massive name+ext or line */

/* All HTML tags used are here: */
#define HTMLSTR_HDGTOTITLE "<html>\n<head>\n<title>"
#define HTMLSTR_TITLE "Syntax coloring assignment \
by Laurie Sutherland"
#define HTMLSTR_CLOSEHDG "</title>\n</head>\n<body>\n<pre>\n"
#define HTMLSTR_CLOSEFILE "</pre>\n</body>\n</html>\n"
#define HTMLSTR_OPENSTR "<i>"
#define HTMLSTR_CLOSESTR "</i>"
#define HTMLSTR_OPENBOLD "<b>"
#define HTMLSTR_CLOSEBOLD "</b>"
   
/* ---------------------------------------
   change_ext()
   Takes in file name of C source file and
    converts it to a .html
   ----------------------------------------- */

static int change_ext(char * inputname, char * inputname_html)
{
 int i = 0;
 if (strlen(inputname) > STRLENGTH-3)
  return 1;
 else {
  while (inputname[i] != '.')  { 
   inputname_html[i] = inputname[i];
   i++;
  }
  inputname_html[i] = '\0';
  strcat(inputname_html, ".html");
  return 0;
 }
} 

/* ---------------------------------------
   change_ltgtamp()
   Takes in character streamed from file, and
    pointer to destination file.  Converts
    <, >, and & for HTML legibility
   ----------------------------------------- */
static void change_ltgtamp(int c, FILE * outputfile)  {
 if (c == '<')  
  fputs("&lt;", outputfile);
 else if (c == '>')   
  fputs("&gt;", outputfile);
 else if (c == '&')
  fputs("&amp;", outputfile);
}

/* ---------------------------------------
   output_word()
   Takes in pointers to buffer and destination 
    file.  Tests buffer word against C keywords;
    outputs word as bold if there's a match,  
    or plain if there is not a match.
   ----------------------------------------- */
static void output_word(char * buffer, FILE * outputfile)  {
 char * * ptr_key;
 char * keyword[] =
      { "auto",     "break",   "case",    "char",     "const",
        "continue", "double",  "default", "do",       "else",
        "enum",     "extern",  "float",   "for",      "goto",
        "if",       "int",     "long",    "register", "return",
        "short",    "signed",  "sizeof",  "static",   "struct",
        "switch",   "typedef", "union",   "unsigned", "void",
        "volatile", "while",     NULL };

 ptr_key = &keyword[0];

 while (*ptr_key != NULL)  {
  if (strcmp (*ptr_key, buffer) == 0)  {
   fputs(HTMLSTR_OPENBOLD, outputfile);
   fputs(buffer, outputfile);
   fputs(HTMLSTR_CLOSEBOLD, outputfile);
   break;
  }
 ptr_key++;
 }
 if (*ptr_key == NULL)
  fputs(buffer, outputfile);
}
 
/* ---------------------------------------
   Syntax Coloring, Project 6, CIT593 Fall 04
    by Laurie Sutherland
    
    Converts a C source file to an HTML file,
     with C keywords emboldened, and strings
     italicized.  Comments are set in "code"
     formatting.  Keywords in strings or comments
     are ignored. 
   ----------------------------------------- */
int main(int argc, char *argv[])
{
 char * inputname_c;       /* string name of input file */
 char inputname_html[STRLENGTH];  /* for converted name */ 
 FILE * inputfile;      /* file pointer for input file */
 FILE * outputfile;     /* file pointer for ouput file */
 char buffer[STRLENGTH]; /* holds words to be tested */
 int c = 0;              /* holds each input character */
 int i = 1;              /* loop increment */

/* Prepare input file - code adapted from Pat Palmer's
    hexdump assignment */
 if (argc > 1) { /* 1st arg should be filename */
  inputname_c = argv[1];
/* Only allow .c */
  if (strstr(inputname_c, ".c\0") == NULL) {
   printf("The input argument must be a C source file (.c)\n");
   return 0;
  }
/* Create output filename, exit if error */
  else { 
   if (change_ext(inputname_c, inputname_html) != 0) { 
    printf("Filename is too large\n");
    return 0;
   }
  }/* close else */ 
 } /* close filename if */

/* If no argument, exit */
 else {
  printf("filename argument required\n");
  return 0; /* quit now if no argument */
 }

/* Open the input file, to be read */
 inputfile = fopen(inputname_c,"r"); 
 if (inputfile == NULL) { /* file did not open */
  printf("%s could not be opened\n", inputname_c);
   return 0; /* quit now */
 }

/* If file opened OK, create output file */
 else { 
  outputfile = fopen(inputname_html, "w");   
/* Start file with opening HTML tags */
  fprintf(outputfile, "%s%s%s", HTMLSTR_HDGTOTITLE,
       HTMLSTR_TITLE, HTMLSTR_CLOSEHDG);

  while (1)  {
/* Stream until end of file */
   if ((c = fgetc(inputfile)) == EOF)  {
    break;
   }

/* Store alpha and test when word is completed */
   if (isalpha(c) != 0)  {
    for (i=0; i<STRLENGTH; i++)  {
     if (c == EOF)  {
      printf("\n***Error: Unclosed string\n");
      return 1;
     }
     else if (isalpha(c) == 0)  
      break;
     else
      buffer[i] = c;
     c = fgetc(inputfile);
    } /* end for loop */ 
/* Add null character to word, test */
    buffer[i] = '\0';
    output_word(buffer, outputfile);
   }
     
/* Stream comments without testing for
    anything except <, >, &  */
  if (c == '/')  {
   fputc(c, outputfile);
   c = fgetc(inputfile);
   if (c == '*')  {
    while (1) {
     if ((c=='<') || (c=='>') || (c=='&'))
      change_ltgtamp(c, outputfile);
     else
      fputc(c, outputfile);
     c = fgetc(inputfile);
     if (c == '*')  {
      fputc(c, outputfile);
      c = fgetc(inputfile);
      if (c == '/')  
       break;
     }
    }
   }
  }
     

/* Convert <, >, or & */
   if ((c=='<') || (c=='>') || (c=='&'))
    change_ltgtamp(c, outputfile);

/* Stream what follows ', to ensure that
** " following ' is not considered beginning of string */
   else if (c == '\'')  {
    fputc(c, outputfile); 
    i = 1; 
    while (1) { 
     c = fgetc(inputfile);
     if (c=='<' || c=='>' || c=='&')
      change_ltgtamp(c, outputfile);
     else
      fputc(c, outputfile); 
/* Stop when second ' is reached, or after 4 char (max 
** reference in single quotes) */
     if (c == '\'' || i > 4)  
      break;
     if (c == EOF)  {
      printf("\n***Error: Unclosed single quote\n");
      return 1;
     }
    i++;
    } /* end while */
   } /* end else */

/* Italicize and stream strings */
   else if (c == '"')  {
    fputs(HTMLSTR_OPENSTR, outputfile);
    fputc(c, outputfile); 
    while (1) { 
     c = fgetc(inputfile);
     if (c=='<' || c=='>' || c=='&')
      change_ltgtamp(c, outputfile);
     else
      fputc(c, outputfile); 
     if (c == EOF)  {
      printf("\n***Error: Unclosed string\n");
      return 1;
     }
     if (c == '"')  
      break;
    }
   fputs(HTMLSTR_CLOSESTR, outputfile);
  } /* end else if " */
 
/* Any non-special characters can be output */
   else
    fputc(c, outputfile);
  } /* close while */
  fprintf(outputfile, "%s", HTMLSTR_CLOSEFILE);
  fclose(outputfile);
 } /* close else */

 fclose(inputfile); 

 return 0;
} /* end main */