/*  This is a hack of a hack - a VERY QUICK mod to ctohtml       */

/*    "included *"s in strings"                                  */
/*    Does BCPL use '''' or '*'' ?                               */
/*    Probably need to fix '**'                                  */
/*     - I haven't handled either as my program doesn't use them */


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define QUOTE_COLOR "#ff0000"
#define COMMENT_COLOR "#408080"
#define PREPROC_COLOR "#008000"
#define NUMBER_COLOR "#000080"
#ifndef FALSE
#define TRUE (0==0)
#define FALSE (0!=0)
#endif

/*
 * BCPL to HTML converter. Converts BCPL code to HTML with syntax hilighting...
 * Assumes any words in UPPER CASE must be keywords to print in bold.
 * Works for my programs, probably no-one elses...
 */

int peekchar = -1;

int 
IsReservedWord(char *word)
{
  char c;
  char *s=word;
  int isword = TRUE;
  if (word[1] == '\0') return(FALSE);
  for (;;) {
    c = *word++;
    if (c == '\0') break;
    if (isalpha(c) && islower(c)) return(FALSE); /* Not */
    if (!isalpha(c)) isword = FALSE;
  }
  if (isword) {  /* HACK!!! reduce to lower-case */
    for (;;) {
      if (*s == '\0') break;
      if ((isalpha(*s)) && (isupper(*s))) *s = tolower(*s);
      s += 1;
    }
  }

  return(isword); /* It's a word, and there's no lower-case in it */
}

int 
fpeek(FILE * f)
{
	int             ch;

	ch = fgetc(f);
	ungetc(ch, f);
	return ch;
}


void 
printchar(char inchar, FILE * fstream)
{
static int lastch = '\n', lineno = 1;
	if (lastch == '\n') fprintf(fstream, "<a name=\"%0d\"><font color=black><em>%05d</em></font>   ", lineno, lineno);
	if (inchar == '&')
		fprintf(fstream, "&amp;");
	else if (inchar == '>')
		fprintf(fstream, "&gt;");
	else if (inchar == '<')
		fprintf(fstream, "&lt;");
	else
		if (inchar != 0) fputc(inchar, fstream);
	if (inchar == '\n') lineno += 1;

	lastch = inchar;
}

int 
Print_HTML(FILE * fstream, char *Title)
{
	FILE           *InFile;
	int             inchar, i, newline = 1, WordIdx = 0; // currntly newline is NOT USED.
	char            word[280];

	for (i = 0; i < 280; ++i) word[i] = 0;
	/* Print out the HTML header. */
	fprintf(fstream, "<HTML>\n<HEAD>\n<TITLE> %s </TITLE>\n</HEAD>\n", Title);
	fprintf(fstream, "<BODY bgcolor=ffffff><pre>\n");

	/* Now we open the file for reading in text mode. */
	InFile = fopen(Title, "r");
	if (InFile == NULL)
		return -1;

	/* And start reading it in character by character. */
	inchar = fgetc(InFile); peekchar = fpeek(InFile);
	while (!feof(InFile)) {
		if (inchar == '\n') {
			newline = 1;
		} else if (!isspace(inchar)) {


		/* identifiers */
		if (isalpha(inchar) || (inchar == '_')) {
			for (i = 0; i < 280; ++i) word[i] = 0;
			WordIdx = 0;
			for (;;) {
				word[WordIdx++] = inchar;
				if (isdigit(peekchar) || isalnum(peekchar) || (peekchar == '_') || (peekchar == '.')) {
					inchar = fgetc(InFile);
					peekchar = fpeek(InFile);
				} else break;
			}
			if (IsReservedWord(word)) {
				printchar('\0', fstream); fprintf(fstream, "<b>%s</b>", word);
			} else {
				for (i = 0; i < WordIdx; ++i)
					printchar(word[i], fstream);
			}
			inchar = fgetc(InFile);
			peekchar = fpeek(InFile);
			continue;
		}

		if (isdigit(inchar)) {
			printchar('\0', fstream); fprintf(fstream, "<font color=%s>", NUMBER_COLOR);
			for (;;) {
				printchar(inchar, fstream);
				if (isdigit(peekchar)) {
					inchar = fgetc(InFile);
					peekchar = fpeek(InFile);
				} else break;
			}
			fprintf(fstream, "</font>");
			inchar = fgetc(InFile);
			peekchar = fpeek(InFile);
			continue;
		}

			/* numbers */
			if (inchar == '#') {
				printchar('\0', fstream); fprintf(fstream, "<font color=%s>", NUMBER_COLOR);
				printchar(inchar, fstream); // #
                                inchar = fgetc(InFile);
                                peekchar = fpeek(InFile);
				if (inchar == 'X') {
					printchar(inchar, fstream); // #X
                                        inchar = fgetc(InFile);
                                        peekchar = fpeek(InFile);
				}
				for (;;) { // assert first char must be a digit
					if (!isdigit(inchar)) break;
					printchar(inchar, fstream);  // #X0000000
                                       	inchar = fgetc(InFile);
                                       	peekchar = fpeek(InFile);
				}
				fprintf(fstream, "</font>");
				continue;
			/* Handle single line comments. */
			}
			else if (((inchar == '/') && (peekchar == '/'))
                            || ((inchar == '|') && (peekchar == '|'))) {
				printchar('\0', fstream); fprintf(fstream, "<font color=%s><i>", COMMENT_COLOR);
				while ((inchar != '\n') && (inchar > 0)) {
					printchar(inchar, fstream);
					inchar = fgetc(InFile);
					peekchar = fpeek(InFile);
				}
				fprintf(fstream, "</i></font>");
				newline = 1;
				continue;
			}
			/* Handle Multi-line comments. */
			else if ((inchar == '/') && (peekchar == '*')) {
				printchar('\0', fstream); fprintf(fstream, "<font color=%s><i>/", COMMENT_COLOR);
				for (;;) {
					inchar = fgetc(InFile);
					peekchar = fpeek(InFile);
					if ((inchar == '*') && (peekchar == '/')) break;
					printchar(inchar, fstream);
				}
				inchar = fgetc(InFile);
				peekchar = fpeek(InFile);
				fprintf(fstream, "*/</i></font>", COMMENT_COLOR);
				inchar = fgetc(InFile);
				peekchar = fpeek(InFile);
				continue; /* Now process next char */
			}
			else if (((inchar == '/') && (peekchar == '\\'))
                            || ((inchar == '\\') && (peekchar == '/'))) {
				printchar('\0', fstream); 
                                if (inchar == '/') {
					// not well supported - fprintf(fstream, "<b>&and;</b>");
					//fprintf(fstream, "<b>&cap;</b>");// poor approximation
					fprintf(fstream, "<b>%c%c</b>", inchar, peekchar);
				} else { // ditto
					//fprintf(fstream, "<b>&or;</b>");
					//fprintf(fstream, "<b>&cup;</b>");
					fprintf(fstream, "<b>%c%c</b>", inchar, peekchar);
				}
				(void)fgetc(InFile); // skip second char
				inchar = fgetc(InFile); // preload for next time around main loop
				peekchar = fpeek(InFile);
				continue;
			}
			/* Handle Blocks. */
			else if ((inchar == '$') &&
				 ((peekchar == '(') || (peekchar == ')'))) {
					printchar('\0', fstream); 
					fprintf(fstream, "<b>");
					printchar(inchar, fstream);
					inchar = fgetc(InFile);
					peekchar = fpeek(InFile);
					printchar(inchar, fstream);
					fprintf(fstream, "</b>");
					inchar = fgetc(InFile);
					peekchar = fpeek(InFile);
			}
			/* Handle Double Quotes. */
			else if (inchar == '"') {
				printchar('\0', fstream); fprintf(fstream, "<font color=%s>\"", QUOTE_COLOR);
				if (peekchar == '"') {
					/* Null string bug fix */
					inchar = fgetc(InFile);
					peekchar = fpeek(InFile);
					printchar(inchar, fstream);
				} else {
					inchar = fgetc(InFile);
					if (inchar == EOF) continue;
					peekchar = fpeek(InFile);
					for (;;) {
						if ((inchar != '*') && (peekchar == '"')) break;
						if ((inchar == '*') && (peekchar == '*')) {
							printchar(inchar, fstream);
							inchar = fgetc(InFile);
							peekchar = fpeek(InFile);
							if (peekchar == '"') break;
						}
						printchar(inchar, fstream);
						inchar = fgetc(InFile);
						if (inchar == EOF) break;
						peekchar = fpeek(InFile);
					}
					printchar(inchar, fstream);
					inchar = fgetc(InFile);
					peekchar = fpeek(InFile);
					printchar(inchar, fstream);
				}
				inchar = fgetc(InFile);
				peekchar = fpeek(InFile);
				fprintf(fstream, "</font>");
				newline = 0;
				continue;
			}
			/* Handle Single Quotes. */
			else if (inchar == '\'') {
				printchar('\0', fstream); fprintf(fstream, "<font color=%s>'", QUOTE_COLOR);
				inchar = fgetc(InFile);
				if (inchar == EOF) continue;
				peekchar = fpeek(InFile);
				printchar(inchar, fstream);
				if (inchar == '*') {
					inchar = fgetc(InFile);
					peekchar = fpeek(InFile);
					printchar(inchar, fstream);
				}
				/* inchar should be closing ' */
				inchar = fgetc(InFile);
				peekchar = fpeek(InFile);
				printchar(inchar, fstream);
				fprintf(fstream, "</font>");
				inchar = fgetc(InFile);
				peekchar = fpeek(InFile);
				newline = 0;
				continue;
			}
			newline = 0;
		} else {
			// it was a space...
		}
                // all drop through cases are single characters to be printed
		printchar(inchar, fstream);
		inchar = fgetc(InFile);
		peekchar = fpeek(InFile);
	}
	fprintf(fstream, "\n</pre></BODY></HTML>\n");
	fclose(InFile);
	return 1;
}

int 
main(int argc, char *argv[])
{
	if (argc < 2) {
		printf("Usage: %s [Filename]\n\n", argv[0]);
		return -1;
	}
	Print_HTML(stdout, argv[1]);
	return 0;
}