/*
 *  Copyright (c) 1994 John E. Davis  (davis@amy.tch.harvard.edu)
 *  All Rights Reserved.
 */
#include <stdio.h>
#include "buffer.h"
#include "screen.h"

static unsigned char Symbol_Colors[128] = 
{
   JNORMAL_COLOR,	/* 0 */
   JNORMAL_COLOR,	/* 1 */
   JNORMAL_COLOR,	/* 2 */
   JNORMAL_COLOR,	/* 3 */
   JNORMAL_COLOR,	/* 4 */
   JNORMAL_COLOR,	/* 5 */
   JNORMAL_COLOR,	/* 6 */
   JNORMAL_COLOR,	/* 7 */
   JNORMAL_COLOR,	/* 8 */
   JNORMAL_COLOR,	/* 9 */
   JNORMAL_COLOR,	/* 10 */
   JNORMAL_COLOR,	/* 11 */
   JNORMAL_COLOR,	/* 12 */
   JNORMAL_COLOR,	/* 13 */
   JNORMAL_COLOR,	/* 14 */
   JNORMAL_COLOR,	/* 15 */
   JNORMAL_COLOR,	/* 16 */
   JNORMAL_COLOR,	/* 17 */
   JNORMAL_COLOR,	/* 18 */
   JNORMAL_COLOR,	/* 19 */
   JNORMAL_COLOR,	/* 20 */
   JNORMAL_COLOR,	/* 21 */
   JNORMAL_COLOR,	/* 22 */
   JNORMAL_COLOR,	/* 23 */
   JNORMAL_COLOR,	/* 24 */
   JNORMAL_COLOR,	/* 25 */
   JNORMAL_COLOR,	/* 26 */
   JNORMAL_COLOR,	/* 27 */
   JNORMAL_COLOR,	/* 28 */
   JNORMAL_COLOR,	/* 29 */
   JNORMAL_COLOR,	/* 30 */
   JNORMAL_COLOR,	/* 31 */
   JNORMAL_COLOR,	/* 32 */
   JOP_COLOR,	/* ! */
   JSTR_COLOR,	/* " */
   JOP_COLOR,	/* # */
   JKEY_COLOR,	/* $ */
   JOP_COLOR,	/* % */
   JOP_COLOR,	/* & */
   JSTR_COLOR,	/* ' */
   JDELIM_COLOR,	/* ( */
   JDELIM_COLOR,	/* ) */
   JOP_COLOR,	/* * */
   JOP_COLOR,	/* + */
   JDELIM_COLOR,	/* , */
   JNUM_COLOR,	/* - */
   JDELIM_COLOR,	/* . */
   JOP_COLOR,	/* / */
   JNUM_COLOR,	/* 0 */
   JNUM_COLOR,	/* 1 */
   JNUM_COLOR,	/* 2 */
   JNUM_COLOR,	/* 3 */
   JNUM_COLOR,	/* 4 */
   JNUM_COLOR,	/* 5 */
   JNUM_COLOR,	/* 6 */
   JNUM_COLOR,	/* 7 */
   JNUM_COLOR,	/* 8 */
   JNUM_COLOR,	/* 9 */
   JOP_COLOR,	/* : */
   JDELIM_COLOR,	/* ; */
   JOP_COLOR,	/* < */
   JOP_COLOR,	/* = */
   JOP_COLOR,	/* > */
   JOP_COLOR,	/* ? */
   JKEY_COLOR,	/* @ */
   JKEY_COLOR,	/* A */
   JKEY_COLOR,	/* B */
   JKEY_COLOR,	/* C */
   JKEY_COLOR,	/* D */
   JKEY_COLOR,	/* E */
   JKEY_COLOR,	/* F */
   JKEY_COLOR,	/* G */
   JKEY_COLOR,	/* H */
   JKEY_COLOR,	/* I */
   JKEY_COLOR,	/* J */
   JKEY_COLOR,	/* K */
   JKEY_COLOR,	/* L */
   JKEY_COLOR,	/* M */
   JKEY_COLOR,	/* N */
   JKEY_COLOR,	/* O */
   JKEY_COLOR,	/* P */
   JKEY_COLOR,	/* Q */
   JKEY_COLOR,	/* R */
   JKEY_COLOR,	/* S */
   JKEY_COLOR,	/* T */
   JKEY_COLOR,	/* U */
   JKEY_COLOR,	/* V */
   JKEY_COLOR,	/* W */
   JKEY_COLOR,	/* X */
   JKEY_COLOR,	/* Y */
   JKEY_COLOR,	/* Z */
   JDELIM_COLOR,	/* [ */
   JDELIM_COLOR,	/* \ */
   JDELIM_COLOR,	/* ] */
   JOP_COLOR,	/* ^ */
   JKEY_COLOR,	/* _ */
   JKEY_COLOR,	/* ` */
   JKEY_COLOR,	/* a */
   JKEY_COLOR,	/* b */
   JKEY_COLOR,	/* c */
   JKEY_COLOR,	/* d */
   JKEY_COLOR,	/* e */
   JKEY_COLOR,	/* f */
   JKEY_COLOR,	/* g */
   JKEY_COLOR,	/* h */
   JKEY_COLOR,	/* i */
   JKEY_COLOR,	/* j */
   JKEY_COLOR,	/* k */
   JKEY_COLOR,	/* l */
   JKEY_COLOR,	/* m */
   JKEY_COLOR,	/* n */
   JKEY_COLOR,	/* o */
   JKEY_COLOR,	/* p */
   JKEY_COLOR,	/* q */
   JKEY_COLOR,	/* r */
   JKEY_COLOR,	/* s */
   JKEY_COLOR,	/* t */
   JKEY_COLOR,	/* u */
   JKEY_COLOR,	/* v */
   JKEY_COLOR,	/* w */
   JKEY_COLOR,	/* x */
   JKEY_COLOR,	/* y */
   JKEY_COLOR,	/* z */
   JDELIM_COLOR,	/* { */
   JOP_COLOR,	/* | */
   JDELIM_COLOR,	/* } */
   JOP_COLOR,	/* ~ */
   JNORMAL_COLOR,
};

/* These are the C++ keywords:
 * asm auto
 * break
 * case catch char class const continue
 * default delete do double
 * else enum extern
 * float for friend
 * goto
 * if inline int
 * long
 * new
 * operator
 * private protected public
 * register return
 * short signed sizeof static struct switch
 * template this throw try typedef
 * union unsigned
 * virtual void volatile
 * while
 */

static char *Keywords[] = /* length 2 to 9 */
{
   "doif",			       /* di */
   "asmforintnewtry",		       /* afint */
   "autocasecharelseenumgotolongthisvoid",    /* acceegltv */
   "breakcatchclassconstfloatshortthrowunionwhile",   /* bcccfstuw */
   "deletedoubleexternfriendinlinepublicreturnsignedsizeofstaticstructswitch",
   				       /* ddefiprsssss */
   "defaultprivatetypedefvirtual",     /* dptv */
   "continueoperatorregistertemplateunsignedvolatile",   /* cortuv */
   "protected",			       /* p */
};

unsigned short *highlight_token(register unsigned short *p, unsigned short *pmax)
{
   register char *t;
   register unsigned short *q;
   unsigned char ch = (unsigned char) *p;
   int color, skip = 0, n;
   
   q = p;
   while (q < pmax)
     {
	ch = (unsigned char) *q & 0x7F;
	color = Symbol_Colors[ch];
	if (color == JNUM_COLOR) skip = 1;
	else if (color != JKEY_COLOR) break;
	q++;
     }

   if (skip) return q;
   n = (int) (q - p);
   if ((n < 2) || (n > 9)) return q;
   
   t = Keywords[n - 2];
   while (*t)
     {
	p = q - n;
	while ((p < q) && (*t == (char) *p))
	  {
	     p++; t++;
	  }
	if (p == q)
	  {
	     p = q - n;
	     while (p < q) *p++ |= JKEY_COLOR << 8;
	     return q;
	  }
	if (*t > (char) *p) break;/* alphabetical */
	t += (int) (q - p);
     }
   return q;
}

	

unsigned short *highlight_string (unsigned short *p, unsigned short *pmax)
{
   unsigned char ch;
   unsigned char q = (unsigned char) *p;

   *p++ |= JSTR_COLOR << 8;
   while (p < pmax)
     {
	ch = (unsigned char) *p;
	*p++ |= JSTR_COLOR << 8;
	if (ch == q) break;
	if ((ch == '\\') && (p < pmax))
	  {
	     *p++ |= JSTR_COLOR << 8;
	  }
     }
   return p;
}

unsigned short *highlight_number (unsigned short *p, unsigned short *pmax)
{
   unsigned short *p1;
   unsigned char ch;
   unsigned char color;
   
   ch = (unsigned char) *p;
   if (ch == '-')
     {
	p1 = p + 1;
	if ((p1 < p) && (JNUM_COLOR == Symbol_Colors[(unsigned char) *p1]))
	  {
	     *p |= JNUM_COLOR << 8;
	     *p1 |= JNUM_COLOR << 8;
	     p += 2;
	  }
	else 
	  {
	     *p |= JOP_COLOR;
	     return p + 1;
	  }
     }
   while (p < pmax)
     {
	ch = (unsigned char) *p;
	color = Symbol_Colors[ch & 0x7F];
	/* here I miss a minus sign in the exponent but so what */
	if ((color != JNUM_COLOR) && (color != JKEY_COLOR)
	    && (ch != '.'))
	  break;
	*p++ |= JNUM_COLOR << 8;
     }
   return p;
}
	  
unsigned short *highlight_comment (unsigned short *p, unsigned short *pmax)
{
   char ch;
   while (p < pmax)
     {
	ch = (char) *p;
	*p++ |= JCOM_COLOR << 8;
	if ((ch == '*') && (p < pmax) && (*p == '/'))
	  {
	     *p++ |= JCOM_COLOR << 8;
	     break;
	  }
     }
   return p;
}



void syntax_highlight (register unsigned short *p, register unsigned short *pmax)
{
   register unsigned char ch = 0;
   unsigned short *pmin;
   register unsigned int color;
   
/* Skip the whitespace and if we find a '*' with a followed by whitespace,
 * highlight it as a comment-- like these lines
 */
   
   while (p < pmax)
     {
	ch = (unsigned char) *p;
	if (ch > ' ') break;
	p++;
     }
   
   pmin = p;
   
   if ((p + 1 < pmax) &&
       (((ch == '*') && (*(p + 1) <= ' '))
	|| ((ch == '%') && (CBuf->modes & SL_MODE))))
     p = highlight_comment (p, pmax);
   
   while (p < pmax)
     {
	ch = (unsigned char) *p;
	if ((ch > 32) && (ch < 127))
	  {	     
	     color = (unsigned int) Symbol_Colors[ch];
	     if (color == JKEY_COLOR) p = highlight_token (p, pmax);
	     else if (color == JSTR_COLOR) p = highlight_string(p, pmax);
	     else if (color == JNUM_COLOR) p = highlight_number (p, pmax);
	     else if (color == JDELIM_COLOR) *p++ |= color << 8; 
	     else if ((ch == '/') && (p + 1 < pmax))
	       {
		  ch = *(p + 1);
		  if (ch == '/')
		    {
		       while (p < pmax)
			 {
			    *p++ |= JCOM_COLOR << 8;
			 }
		       return;
		    }
		  else if (ch == '*') 
		    {
		       *p++ |= JCOM_COLOR << 8; *p++ |= JCOM_COLOR << 8;
		       p = highlight_comment (p, pmax);
		    }
		  else *p++ |= JOP_COLOR << 8;
	       }
	     else if ((ch == '*') && (p + 1 < pmax) && (*(p + 1) == '/'))
	       {
		  /* missed the comment.  This means it was started on a 
		   * previous line and the person did not follow the 
		   * rules like this comment does. 
		   */
		  
		  p += 2;
		  while (pmin < p) 
		    {
		       *pmin &= 0xFF;
		       *pmin |= JCOM_COLOR << 8;
		       pmin++;
		    }
	       }
	     else if ((ch == '%') && (CBuf->modes & SL_MODE))
	       p = highlight_comment (p, pmax);
	     else *p++ |= color << 8; 
	  }
	else p++;
     }
}
	       
	
