/* ########################################################################
   
   SMAC FILE USED BY XCORAL EDITOR
   
   File: color.sc
   Path: /home/emery/Xcoral/color.sc
   Description: 
   Created: Mon Nov 21 17:43:37 MET 1994
   Author: Lionel Fournigault
   Modified: Mon Jun 7 1999
   Last maintained by: Bruno Pages
   
   RCS $Revision$ $State$
   
   
   ########################################################################
   
   Note: First I would like to say that regexp for LaTeX, Perl, Ada
   Fortran, Shell-script and make, are derived from emacs19 hilight.el
   
   Requires: utilities.sc lex.sc
   
   Defines: color_region, color_buffer.
   
   Suggested bindings: 
   
   Procedure: 
   
   ########################################################################
   
   Copyright (c) : Lionel Fournigault
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

   ######################################################################## */
/*
 * ###########################################################################
 *                       Generics colors for all modes
 * ###########################################################################
 */

{
  if (! function("delete_chars"))
    load_file("utilities.sc");
  if (! function("lex_add"))
    load_file("lex.sc");
}

char *gen_comment_color = "limegreen";
char *gen_include_color = "goldenrod";
char *gen_define_color = "darkgoldenrod";
char *gen_keyword_color = "purple";
char *gen_string_color = "slategray";

/*char *gen_varfunc_color = "yellow";*/
char *gen_varfunc_color = "orange";
char *gen_decl_color = "palegreen";
char *gen_class_color = "orange";

char *gen_del_new_color = "red";
char *gen_return_color = "lightsteelblue";
char *gen_link_color = "tan";
char *gen_makefile_color = "plum";

char *gen_string = "[^']\\(\"[^\\\"]*\\(\\\\\\(.\\|\n\\)[^\\\"]*\\)*\"\\)";

/*
 * ###########################################################################
 *                       C/C++ colors
 * ###########################################################################
 */
char *cpp_comment_color = gen_comment_color;
char *cpp_keyword_color = gen_keyword_color;
char *cpp_define_color = gen_define_color;
char *cpp_string_color = gen_string_color;

/*
 * ###########################################################################
 *                       java colors
 * ###########################################################################
 */
char *java_comment_color = gen_comment_color;
char *java_category_color = gen_del_new_color;
char *java_result_color = gen_return_color;
char *java_class_color = gen_class_color;
char *java_modifier_color = gen_keyword_color;
char *java_keyword_color = gen_keyword_color;
char *java_import_color = gen_define_color;
char *java_string_color = gen_string_color;
char *java_package_color = gen_include_color;

/*
 * ###########################################################################
 *                       LaTeX colors
 * ###########################################################################
 */
char *latex_comment_color = gen_comment_color;
char *latex_keyword_color = gen_keyword_color;
char *latex_defun_color = gen_decl_color;
char *latex_define_color = gen_define_color;
char *latex_decl_color = gen_decl_color;
char *latex_label_color = gen_keyword_color; 
char *latex_include_color = gen_include_color;
char *latex_italic_color = gen_decl_color;
char *latex_bold_color = gen_varfunc_color;
char *latex_ref_color = gen_comment_color;

/*
 * ###########################################################################
 *                       HTML colors
 * ###########################################################################
 */
char *html_title_color = gen_comment_color;
char *html_ibtt_color = gen_keyword_color;
char *html_pre_color = gen_define_color;
char *html_img_color = gen_decl_color;
char *html_ref_color = gen_varfunc_color;
char *html_list_color = gen_define_color;
char *html_forms_color = gen_include_color;
char *html_hds_color = gen_keyword_color;
char *hltml_string_color = gen_string_color;

/*
 * ###########################################################################
 *                       Edir (edit directory) colors
 * ###########################################################################
 */
char *edir_directory_color = gen_comment_color;
char *edir_link_color = gen_link_color;
char *edir_c_file_color = gen_decl_color;
char *edir_tex_file_color = gen_decl_color;
char *edir_sc_file_color = gen_decl_color;
char *edir_h_file_color = gen_class_color;
char *edir_makefile_color = "plum";
char *edir_readme_color = gen_del_new_color;

/*
 * ###########################################################################
 *                       Fortran colors
 * ###########################################################################
 */
char *fortran_comment_color = gen_comment_color;
char *fortran_include_color = gen_include_color;
char *fortran_keyword_color = gen_keyword_color;
char *fortran_func_color = gen_varfunc_color;
char *fortran_decl_color = gen_decl_color;
char *fortran_string_color = gen_string_color;
char *fortran_type_color = gen_decl_color;

/*
 * ###########################################################################
 *                       Fortran 90 colors
 * Thanks to Joerg Stiller
 * ###########################################################################
 */
char *f90_comment_color = gen_comment_color;
char *f90_string_color  = gen_string_color;
char *f90_unit_color    = gen_class_color;
char *f90_include_color = gen_include_color;
char *f90_type_color    = gen_decl_color;
char *f90_decl_color    = gen_decl_color;
char *f90_keyword_color = gen_keyword_color;

/*
 * ###########################################################################
 *                       Ada colors
 * ###########################################################################
 */
char *ada_comment_color = gen_comment_color;
char *ada_glob_struct_color = gen_varfunc_color;
char *ada_struct_color = gen_keyword_color;
char *ada_decl_color = gen_decl_color;
char *ada_include_color = gen_include_color;
char *ada_string_color = gen_string_color;

/*
 * ###########################################################################
 *                       Perl colors
 * ###########################################################################
 */
char *perl_comment_color = gen_comment_color;
char *perl_string_color = gen_string_color;
char *perl_label_color = gen_define_color;
char *perl_include_color = gen_include_color;
char *perl_decl_color = gen_varfunc_color;
char *perl_defun_color = gen_class_color;
char *perl_keyword_color = gen_keyword_color;

/*
 * ###########################################################################
 *                       Shell script colors
 * ###########################################################################
 */
char *shell_comment_color = gen_comment_color;
char *shell_string_color = gen_string_color;
char *shell_include_color = gen_include_color;
char *shell_define_color = gen_define_color;
char *shell_var_color = gen_varfunc_color;
char *shell_keyword_color = gen_keyword_color;

/*
 * ###########################################################################
 *                 Makefile makefile and Imakefile colors
 * ###########################################################################
 */
char *make_comment_color = gen_comment_color;
char *make_rules_color = gen_varfunc_color;
char *make_define_color = gen_define_color;
char *make_keyword_color = gen_keyword_color;
char *make_defun_color = gen_varfunc_color;
char *make_include_color = gen_include_color;

/*
 * ###########################################################################
 *                       Internal color functions.
 * ###########################################################################
 */
/*
**	Function name : color_regexp_in_region
**
**	Description : Fonction de colorisation d'une regexp entre les positions
**         Smac start et end.
**	Input : La regexp, le numero de la re_substring, debut et fin de la
**         region et la couleur.  
**	Output :
*/
void color_regexp_in_region ( char *regexp, int nsub, int start, int end, char *color)
{
    int orig = current_position();
    int pos, re_begin, re_end;

    goto_char(start);
    while (1) {
	pos = re_forward_search (regexp);
	if ((pos == -1) || (pos == -2) || (pos > end))
	  break;
	re_begin = re_match_beginning(nsub);
	re_end = re_match_end(nsub);
	color_area (re_begin, (re_end > end) ? end : re_end, color);

/*	goto_char (re_match_end(nsub)); */
	goto_char(re_end+1);
/*	goto_next_char(); */

	if (current_position() >= end)
	  break;
    }
    goto_char (orig);
}

/*
**	Function name : color_comment_in_region
**
**	Description : Fonction speciale pour les commentaires car
**         la recherche se fait en 2 fois (debut et fin du commentaire).
**
**	Input : Le debut et la fin de la region et la couleur.
**	Output :
*/
void color_comment_in_region ( char * re_cpp_begin_comment, char * re_cpp_end_comment, int start, int end, char * color)
{
    int orig = current_position ();
    int begin_comment, end_comment, pos;

    /* Les commentaires sur plusieurs lignes */
    goto_char(start);
    while (1) {
	pos = re_forward_search (re_cpp_begin_comment);
	if ((pos == -1) || (pos == -2) || (pos > end))
	  break;

	begin_comment = re_match_beginning(0);
	if (begin_comment >= end)
	  break;
	goto_char (begin_comment);
	
	/* Recherche de la fin du commentaire */
	pos = re_forward_search (re_cpp_end_comment);
	if ((pos == -1) || (pos == -2) || (pos > end))
	  break;
	
	end_comment = (re_match_end(0) > end) ? end : re_match_end(0);
	color_area (begin_comment, end_comment, color);
	goto_char (end_comment);

	if (current_position() >= end)
	  break;
    }
    goto_char (orig);
}

/*
 * ###########################################################################
 *                       C/C++ Regexp
 * ###########################################################################
 */

/* for performance reason and to have a proper
   result, one does not use regexp here */

/* memorize the c c++ keywords */

char ** c_cpp_all_keyworks[26];

{
  c_cpp_all_keyworks['b' - 'a'] = lex_add("reak", 0);
  c_cpp_all_keyworks['c' - 'a'] =
    lex_add("ase", lex_add("atch", lex_add("har", lex_add("lass", lex_add("onst", 0)))));
  c_cpp_all_keyworks['d' - 'a'] =
    lex_add("efault", lex_add("elete", lex_add("o", lex_add("ouble", 0))));
  c_cpp_all_keyworks['e' - 'a'] =
    lex_add("lse", lex_add("num", lex_add("xtern", 0)));
  c_cpp_all_keyworks['f' - 'a'] =
    lex_add("loat", lex_add("or", lex_add("riend", 0)));
  c_cpp_all_keyworks['g' - 'a'] = lex_add("oto", 0);
  c_cpp_all_keyworks['i' - 'a'] =
    lex_add("f", lex_add("nline", lex_add("nt", 0)));
  c_cpp_all_keyworks['l' - 'a'] = lex_add("ong", 0);
  c_cpp_all_keyworks['n' - 'a'] = lex_add("ew", 0);
  c_cpp_all_keyworks['o' - 'a'] = lex_add("perator", 0);
  c_cpp_all_keyworks['p' - 'a'] =
    lex_add("rivate", lex_add("rotected", lex_add("ublic", 0)));
  c_cpp_all_keyworks['r' - 'a'] = lex_add("egister", lex_add("eturn", 0));
  c_cpp_all_keyworks['s' - 'a'] =
    lex_add("hort", lex_add("izeof", lex_add("tatic", lex_add("truct", lex_add("witch", 0)))));
  c_cpp_all_keyworks['t' - 'a'] =
    lex_add("his", lex_add("emplate", lex_add("ypedef", 0)));  
  c_cpp_all_keyworks['u' - 'a'] = lex_add("nion", lex_add("nsigned", 0));
  c_cpp_all_keyworks['v' - 'a'] =
    lex_add("irtual", lex_add("oid", lex_add("olatile", 0)));
  c_cpp_all_keyworks['w' - 'a'] = lex_add("hile", 0);
}

/*
**	Function name : c_cpp_color_region
**
**	Description : colorize the specified area in c c++ mode
**         suposes that the start position is not into a string or
**         a comment, else the result will be strange !
**
**	Input :
**	Output :
*/
void forward_word();

void c_cpp_color_region (int start, int end) 
{
  int here = current_position();
  int begin;
  
  uncolor_area(start, end);
  
  goto_char(start);
  
  while (msearch("abcdefghijklmnopqrstuvwxyz'#\"/", end, 1)) {
    /* the current character may be the beginning of a coloration case */
    begin = current_position();
    
    switch (current_char()) {
    case '"' :
      goto_next_char();
      while (msearch("\\\"", end, 1) && (current_char() != '\"')) {
	goto_next_char();
	goto_next_char();
      }
      color_area(begin, current_position(), cpp_string_color);
      if (current_char() == '"')
	goto_next_char();
      break;
    case '\'' :
      goto_next_char();
      while (msearch("\\'", end, 1) && (current_char() != '\'')) {
	goto_next_char();
	goto_next_char();
      }
      color_area(begin, current_position(), cpp_string_color);
      if (current_char() == '\'')
	goto_next_char();
      break;
    case '/' :
      switch (next_char()) {
      case '*' :
	goto_next_char();
	goto_next_char();
	while (msearch("*", end, 1) && (next_char() != '/'))
	  goto_next_char();
	goto_next_char();	  
	color_area(begin, current_position(), cpp_comment_color);
	goto_next_char();	  
	break;
      case '/' :
	goto_end_of_line();
	color_area(begin, current_position(), cpp_comment_color);
	goto_next_char();
	break;
      default:
	goto_next_char();
      }
      break;
    case '#':
      goto_next_char();
      forward_word();
      color_area(begin, current_position() - 1, cpp_define_color);
      break;
    default:
      goto_next_char();
      if (match_identifier(c_cpp_all_keyworks[previous_char() - 'a']))
	color_area(begin, current_position() - 1, cpp_keyword_color);
      else
	/* go after the word */
	while ((current_position() < end) &&
	       strchr("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
		      current_char()))
	  goto_next_char();
    }
  }
  
  goto_char(here);
}


/*
 * ###########################################################################
 *                       Regexp for LaTeX
 * ###########################################################################
 */
char *re_latex_comment = "\\(^\\|[^\\]\\)\\(%.*\\)$";
char *re_latex_keyword = "\\(\
\\\\\\(sub\\)*\\(paragraph\\|section\\)\\(\\*\\|\\[.*\\]\\)?{[^}]*}\
\\|\
\\\\\\(address\\|signature\\|opening\\|closing\\|chapter\\|part\\|cleardoublepage\\|multicolumn\\|multirow\\)\\(\\*\\|\\[.*\\]\\)?{[^}]*}\
\\|\
\\\\footnote\\(mark\\|text\\)?{[^}]*}\
\\|\
\\\\[a-z]+box{[^}]*}\
\\|\
\\\\\\(v\\|h\\)space\\(\\*\\)?{[^}]*}\
\\)";
char *re_latex_defun = "\\(\
\\\\\\(re\\)?new\\(environment\\|command\\)\
\\|\
\\\\new\\(length\\|theorem\\|counter\\)\
\\)";
char *re_latex_define = "\\(\
\\\\\\(setlength\\|hline\\|hrule\\|cline\\|settowidth\\|addtolength\\|setcounter\\|addtocounter\\)\
\\|\
\\\\\\(title\\|author\\|date\\|thanks\\)";
char *re_latex_decl = "\\(\
\\\\documentclass\\(\\[.*\\]\\)?{[^}]*}\
\\|\
\\\\\\(begin\\|end\\|nofiles\\|includeonly\\){[^}]*}\
\\|\
\\\\\\(raggedright\\|makeindex\\|makeglossary\\|maketitle\\)\\b\
\\|\
\\\\\\(pagestyle\\|bibliographystyle\\|usepackage\\|thispagestyle\\|pagenumbering\\){[^}]*}\
\\|\
\\\\\\(normalsize\\|small\\|footnotesize\\|scriptsize\\|tiny\\|large\\|Large\\|LARGE\\|huge\\|Huge\\)\\b\
\\|\
\\\\\\(appendix\\|tableofcontents\\|listoffigures\\|listoftables\\)\\b\
\\|\
\\\\\\(bf\\|em\\|it\\|rm\\|sf\\|sl\\|sc\\|ss\\|tt\\)\\b\
\\)";
char *re_latex_label = "\\(\
\\\\item\\[\" \"\\]\
\\|\
\\\\item\\b\
\\|\
\\\\caption\\(\\[.*\\]\\)?{[^}]*}\
\\)";
char *re_latex_include = "\\\\\\(include\\|input\\|bibliography\\){[^}]*}";
char *re_latex_italic = "{\\\\\\(em\\|it\\|sl\\){[^}]*}";
char *re_latex_bold = "{\\\\bf{[^}]*}";
char *re_latex_ref = "\\\\\\(\\(no\\)?cite\\|\\(page\\)?ref\\|refer\\|label\\|index\\|glossary\\){[^}]*}";

void latex_color_region(int start, int end)
{
    color_regexp_in_region ( re_latex_comment, 2, start, end, latex_comment_color );
    color_regexp_in_region ( re_latex_keyword, 0, start, end, latex_keyword_color );
    color_regexp_in_region ( re_latex_defun, 0, start, end, latex_defun_color );
    color_regexp_in_region ( re_latex_define, 0, start, end, latex_define_color );
    color_regexp_in_region ( re_latex_decl, 0, start, end, latex_decl_color );
    color_regexp_in_region ( re_latex_label, 0, start, end, latex_label_color );
    color_regexp_in_region ( re_latex_include, 0, start, end, latex_include_color );
    color_regexp_in_region ( re_latex_italic, 0, start, end, latex_italic_color );
    color_regexp_in_region ( re_latex_bold, 0, start, end, latex_bold_color );
    color_regexp_in_region ( re_latex_ref, 0, start, end, latex_ref_color );
}

/*
 * ###########################################################################
 *                       Regexp for Html 3.0
 * ###########################################################################
 */
char *re_html_ibtt = 
  "<EM>\\|</EM>||\<B>\\|</B>\\|<I>\\|</I>\\|<TT>\\|</TT>\\|<CENTER>\\|</CENTER>\\|\
<em>\\|</em>||\<b>\\|</b>\\|<i>\\|</i>\\|<tt>\\|</tt>\\|<center>\\|</center>";

char *re_html_pre = 
  "<PRE>\\|</PRE>\\|<BLOCKQUOTE>\\|</BLOCKQUOTE>\\|\
<pre>\\|</pre>\\|<blockquote>\\|</blockquote>";

char *re_html_img = 
  "<IMG SRC=\\|<IMG ALIGN=TOP SRC=\\|<IMG ALIGN=MIDDLE SRC=\\|\
<img src=\\|<img align=top src=\\|<img align=middle src=";

char *re_html_title = 
  "<HTML>\\|</HTML>\\|<TITLE>\\|</TITLE>\\|<HEAD>\\|</HEAD>\\|<BODY\\|</BODY>\\|\
<ADDRESS>\\|</ADDRESS>\\|<html>\\|</html>\\|<title>\\|</title>\\|<head>\\|\
</head>\\|<body>\\|</body\\|<address>\\|</address>";

char *re_html_ref = "<A\\| HREF=\\|</A>\\|<a\\|href=\\|</a>";

char *re_html_hds = 
  "<HR>\\|<BR>\\|<H1>\\|</H1>\\|<H2>\\|</H2>\\|<H3>\\|</H3>\\|<H4>\\|</H4>\\|\
<H5>\\|</H5>\\|<H6>\\|</H6>\\|<CENTER>\\|</CENTER>\\|<P>\\|</P>\\|\
<hr>\\|<br>\\|<h1>\\|</h1>\\|<h2>\\|</h2>\\|<h3>\\|</h3>\\|<h4>\\|</h4>\\|\
<h5>\\|</h5>\\|<h6>\\|</h6>\\|<center>\\|</center>\\|<p>\\|</p>";

char *re_html_list = 
  "<TR>\\|</TR>\\|<UL>\\|</UL>\\|<LI>\\|<OL>\\|</OL>\\|<DL>\\|</DL>\\|<DT>\\|<DD>\\|\
<tr>\\|</tr>\\|<ul>\\|</ul>\\|<li>\\|<ol>\\|</ol>\\|<dl>\\|</dl>\\|<dt>\\|<dd>";

char *re_html_forms =
  "<INPUT\\|TYPE=\\|SRC=\\|<SELECT\\|</SELECT>\\|\
<OPTION>\\|<TEXTAREA\\|</TEXTAREA>\\|\
<TABLE\\|</TABLE>\\|<CAPTION>\\|</CAPTION>\\|\
<FORM\\|</FORM>\\|\
<input\\|type=\\|src=\\|<select\\|</select>\\|\
<option>\\|<textarea\\|</textarea>\\|\
<table\\|</table>\\|<caption>\\|</caption>\\|\
<form\\|</form>";

void html_color_region(int start, int end)
{
  color_regexp_in_region (re_html_title, 0, start, end, html_title_color);
  color_regexp_in_region (re_html_ibtt, 0, start, end, html_ibtt_color);
  color_regexp_in_region (re_html_pre, 0, start, end, html_pre_color);
  color_regexp_in_region (re_html_img, 0, start, end, html_img_color);
  color_regexp_in_region (re_html_ref, 0, start, end, html_ref_color);
  color_regexp_in_region (re_html_list, 0, start, end, html_list_color);
  color_regexp_in_region (re_html_forms, 0, start, end, html_forms_color);
  color_regexp_in_region (re_html_hds, 0, start, end, html_hds_color);
  color_regexp_in_region (gen_string, 0, start, end, hltml_string_color);
}

/*
 * ###########################################################################
 *                       Regexp for edit directory 
 * ###########################################################################
 */
char *re_edir_directory = "^d.*$";
char *re_edir_link = "^l.*$";
char *re_edir_c_file = "^-.* \\([^ \n\t]*\\.c\\)$";
char *re_edir_tex_file = "^-.* \\([^ \n\t]*\\.tex\\)$";
char *re_edir_sc_file = "^-.* \\([^ \n\t]*\\.sc\\)$";
char *re_edir_h_file = "^-.* \\([^ \n\t]*\\.h\\)$";
/*
   char *re_edir_o_file = "^-.* \\([^ \n\t]*\\.o\\)$";
   char *re_edir_tilde_file = "^-.* \\([^ \n\t]*~\\)$";
*/
char *re_edir_makefile = "^-.* \\(makefile\\|Makefile\\|MAKEFILE\\|Imakefile\\)";
char *re_edir_readme = "^-.* \\(readme\\|Readme\\|README\\)";

void edir_color_region(int start, int end)
{
    color_regexp_in_region ( re_edir_directory, 0, start, end, edir_directory_color);
    color_regexp_in_region ( re_edir_link, 0, start, end, edir_link_color);
    color_regexp_in_region ( re_edir_c_file, 1, start, end, edir_c_file_color);
    color_regexp_in_region ( re_edir_tex_file, 1, start, end, edir_tex_file_color);
    color_regexp_in_region ( re_edir_sc_file, 1, start, end, edir_sc_file_color);
    color_regexp_in_region ( re_edir_h_file, 1, start, end, edir_h_file_color);
/*
   color_regexp_in_region ( re_edir_o_file, 1, start, end, edir_o_file_color);
   color_regexp_in_region ( re_edir_tilde_file, 1, start, end, edir_tilde_file_color);
*/   
    color_regexp_in_region ( re_edir_makefile, 1, start, end, edir_makefile_color);
    color_regexp_in_region ( re_edir_readme, 1, start, end, edir_readme_color);
}

/*
 * ###########################################################################
 *                       Regexp for Fortran.
 * ###########################################################################
 */
char *re_fortran_comment = "^[*Cc].*$";
char *re_fortran_include = "[ \t]\\(\
call\\|stop\\|return\\|end\\|include\\|\
CALL\\|STOP\\|RETURN\\|END\\|INCLUDE\
\\)[' \t\n]";

char *re_fortran_func = "[ \t]\\(\
program\\|subroutine\\|function\\|\
PROGRAM\\|SUBROUTINE\\|FUNCTION\
\\)[ \t\n]";

char *re_fortran_type = "\\([ \t]\\|implicit[ \t]*\\|IMPLICIT[ \t]*\\)\\(\
dimension\\|integer\\|real\\|double[ \t]*precision\\|character\\|logical\\|complex\\|double[ \t]*complex\\|\
DIMENSION\\|INTEGER\\|REAL\\|DOUBLE[ \t]*PRECISION\\|CHARACTER\\|LOGICAL\\|COMPLEX\\|DOUBLE[ \t]*COMPLEX\
\\)\\(\\*[0-9]*\\|[ \t\n]\\)";

char *re_fortran_decl = "implicit[ \t]*none\\|\
[ \t]\\(parameter[\t\n ]*([^)]*)\\|data\\|save\\|common[ \t\n]*/[^/]*/\\)";

char *re_fortran_string = concat3("\\(",gen_string,"\\|'.*'\\)");

char *re_fortran_keyword = "\\([ \t]\\(\
do\\|do[ \t]*[0-9]+\\|go[ \t]*to[ \t]*[0-9]+\\|end[ \t]*do\\|if\\|else[ \t]*if\\|then\\|else\\|end[ \t]*if\\|\
DO\\|DO[ \t]*[0-9]+\\|GO[ \t]*TO[ \t]*[0-9]+\\|END[ \t]*DO\\|IF\\|ELSE[ \t]*IF\\|THEN\\|ELSE\\|END[ \t]*IF\
\\)[ \t\n(]\\|\\(^[ \t]*[0-9]+\\|[ \t]\\(continue\\|CONTINUE\\)[ \t\n]\\|format\\|FORMAT\\)\\)";

void fortran_color_region(int start, int end)
{
   color_regexp_in_region ( re_fortran_include, 0, start, end,
			   fortran_include_color); 
   color_regexp_in_region ( re_fortran_func, 1, start, end,
			   fortran_func_color); 
   color_regexp_in_region ( re_fortran_string, 1, start, end, 
                           fortran_string_color);
   color_regexp_in_region ( re_fortran_decl, 1, start, end, 
			   fortran_decl_color);
   color_regexp_in_region ( re_fortran_keyword, 0, start, end, 
			   fortran_keyword_color);
   color_regexp_in_region ( re_fortran_type, 0, start, end, 
			   fortran_type_color);
   color_regexp_in_region ( re_fortran_comment, 0, start, end, 
			   fortran_comment_color);
}

/*
 * ###########################################################################
 *                  Regexp for Fortran 90 free source form.
 * Thanks to Joerg Stiller
 * ###########################################################################
 */
/* Fortran 90 identifier */
char *re_f90_identifier = "[a-zA-Z][a-zA-Z_0-9]*";

/* optional Fortran 90 identifier */
char *re_f90_opt_identifier = "[a-zA-Z_]*[a-zA-Z_0-9]*";

/* Fortran 90 comment */
char *re_f90_comment1 = "^[ \t]*!.*$";
char *re_f90_comment2 = "[ \t][ \t][ \t]*!.*$";
  
/* Fortran 90 strings (enclosed in ' ' or " ") */
char *re_f90_string1 = "[ \t\\,=(]\\(\"[^\\\"]*.\"\\)[ \n\t\\);,]";
char *re_f90_string2 = "[ \t\\,=(]\\('[^']*.'\\)[ \n\t\\);,]";

/* Fortran 90 include statement */
char *re_f90_include = "^[ \t]*\\(include\\|INCLUDE\\)[ \n\t'\\\"]";

/* Fortran 90 program units and related statements */
char *re_f90_program = "^[ \t]*\\(\
\\(program\\|end[ \t]*[ \t]*program\\|stop\
\\|PROGRAM\\|END[ \t]*[ \t]*PROGRAM\\|STOP\\)\
[ \t][a-zA-Z_]*[a-zA-Z_0-9]*\\)[ \t\n]";

char *re_f90_module = "^[ \t]*\\(\
\\(module\\|end[ \t]*[ \t]*module\\|contains\
\\|MODULE\\|END[ \t]*[ \t]*MODULE\\|CONTAINS\\)\
[ \t]*[a-zA-Z_]*[a-zA-Z_0-9]*\\)[ \n\t]";

char *re_f90_subprog = "[ \t]*\\(\
\\(end[ \t]*[ \t]*subroutine\\|subroutine\\|function\\|end[ \t]*[ \t]*function\\|return\
\\|SUBROUTINE\\|END[ \t]*[ \t]*SUBROUTINE\\|FUNCTION\\|END[ \t]*[ \t]*FUNCTION\\|RETURN\\)\
[ \t][a-zA-Z]*[a-zA-Z_0-9]*[ \t]*\\)[ \n\t(&]";

char *re_f90_func_result = "^[ \t]*.*[ \t,]\\(\
\\([ \t]*result\
\\|[ \t]*RESULT\\)\
\\)[ \n\t(&]";

/* Fortran 90 derived type definitions */
char *re_f90_type = "^[ \t]*\\(\
\\(type\\|end[ \t]*type\
\\|TYPE\\|END[ \t]*TYPE\\)\
[ \t]*[a-zA-Z]*[a-zA-Z_0-9]*\\)";

/* Fortran 90 declarations */
char *re_f90_decl_0 = "\\([ \t]*.*::\\)";
char *re_f90_decl_1 = "^[ \t]*\
\\(character\\|common\\|complex\\|data\\|implicit[ none]*\\|integer\\|logical\\|parameter\\|real\\|recursive\\|type\
\\|CHARACTER\\|COMMON\\|COMPLEX\\|DATA\\|IMPLICIT[ NONE]*\\|INTEGER\\|LOGICAL\\|PARAMETER\\|REAL\\|RECURSIVE\\|TYPE\
\\)[ \t\n,(&*]";

char *re_f90_decl_2 = "[ \t\n ,;]\
\\(character\\|complex\\|data\\|implicit[ none]*\\|integer\\|logical\\|parameter\\|private\\|public\\|real\\|recursive\\|sequence\\|type\
\\|CHARACTER\\|COMPLEX\\|DATA\\|IMPLICIT[ NONE]*\\|INTEGER\\|LOGICAL\\|PARAMETER\\|PRIVATE\\|PUBLIC\\|REAL\\|RECURSIVE\\|SEQUENCE\\|TYPE\
\\)[ \t\n,(&*]";

/* Some Fortran 90 keywords */
char *re_f90_keyword1 = "[ \t\n:;]\
\\(case\\|case default\\|cycle\\|do\\|else\\|else[ \t]*if\\|exit\\|go[ \t]*to\\|if\\|only\\|select case\\|then\\|use\\|where\\|elsewhere\
\\|CASE\\|CASE DEFAULT\\|CYCLE\\|DO\\|ELSE\\|ELSE[ \t]*IF\\|EXIT\\|GO[ \t]*TO\\|IF\\|ONLY\\|SELECT CASE\\|THEN\\|USE\\|WHERE\\|ELSEWHERE\
\\)[ \t\n(]";

char *re_f90_keyword2 = "[ \t\n;]\
\\(end[ \t]*do\\|end[ \t]*if\\|end[ \t]*select\\|end[ \t]*where\
\\|END[ \t]*DO\\|END[ \t]*IF\\|END[ \t]*SELECT\\|END[ \t]*WHERE\
\\)[ \t\n(]";

/* Fortran 90 special characters */
char *re_f90_special = "\\(; \\|  &\\)";


void fortran90_color_region(int start, int end)
{
   color_regexp_in_region ( re_f90_include,     0, start, end, f90_include_color); 
   color_regexp_in_region ( re_f90_program,     1, start, end, f90_unit_color); 
   color_regexp_in_region ( re_f90_module,      1, start, end, f90_unit_color);
   color_regexp_in_region ( re_f90_subprog,     1, start, end, f90_unit_color);
   color_regexp_in_region ( re_f90_func_result, 1, start, end, f90_unit_color);
   color_regexp_in_region ( re_f90_type,        1, start, end, f90_type_color);
   color_regexp_in_region ( re_f90_decl_0,      1, start, end, f90_decl_color);
   color_regexp_in_region ( re_f90_decl_1,      1, start, end, f90_decl_color);
   color_regexp_in_region ( re_f90_decl_2,      1, start, end, f90_decl_color);
   color_regexp_in_region ( re_f90_keyword1,    1, start, end, f90_keyword_color);
   color_regexp_in_region ( re_f90_keyword2,    1, start, end, f90_keyword_color);
   color_regexp_in_region ( re_f90_special,     1, start, end, f90_keyword_color);
   color_regexp_in_region ( re_f90_string1,     1, start, end, f90_string_color);
   color_regexp_in_region ( re_f90_string2,     1, start, end, f90_string_color);
   color_regexp_in_region ( re_f90_comment1,    0, start, end, f90_comment_color);
   color_regexp_in_region ( re_f90_comment2,    0, start, end, f90_comment_color);
}

/*
 * ###########################################################################
 *                       Regexp for Ada.
 * ###########################################################################
 */
char *re_ada_comment = ";;\\|--.*$";
char *re_ada_glob_struct = "\\([ \t\n]procedure[ \t]+[^ \t\n]+[ \t]\
\\|[ \t\n]task[ \t]+[^ \t\n]+[ \t]\
\\|[ \t\n]function[ \t]+[^ \t\n]+[ \t]\
\\|[ \t\n]package[ \t]+[^ \t\n]+[ \t]\
\\|^[ \t]*private[ \t\n]\
\\|^end.*$\\)";

char *re_ada_struct = 
  "[ \n\t]\\(is\\|in\\|out\\|select\\|if\\|else\\|case\\|when\\|and\\|or\\|not\\|accept\\|\
loop\\|do\\|then\\|elsif\\|else\\|for\\|while\\|exit\\|begin\\|end\\|\
declare\\|exception\\|generic\\|raise\\|return\\|package\\|body\\)[ \n\t;]";

char *re_ada_decl = 
  "\\(^[ \t]*\\(type\\|subtype\\)[ \t\n]+[^ \t]+[ \t\n]\\|\
[ \t]+is record.*$\\)";

char *re_ada_include = "^[ \t]*\\(with\\|pragma\\|use\\)";
char *re_ada_string = gen_string;

void ada_color_region(int start, int end)
{
   color_regexp_in_region ( re_ada_string, 1, start, end, ada_string_color);
   color_regexp_in_region ( re_ada_include, 0, start, end, ada_include_color);
   color_regexp_in_region ( re_ada_glob_struct, 1, start, end, ada_glob_struct_color);
   color_regexp_in_region ( re_ada_struct, 1, start, end, ada_struct_color);
   color_regexp_in_region ( re_ada_decl, 0, start, end, ada_decl_color);
   color_regexp_in_region ( re_ada_comment, 0, start, end, ada_comment_color);
}

/*
 * ###########################################################################
 *                       Regexp for Perl.
 * ###########################################################################
 */
char *re_perl_comment = "^#.*\\|[ \t]#.*"; /*"\\s #.*$\\|^#.*$ ";*/
char *re_perl_string = gen_string;
char *re_perl_label = "^\\(__....?__\\|\\s *\\sw+:\\)";
char *re_perl_include = "^require.*$";
char *re_perl_decl = "^package.*$";
char *re_perl_defun = "^\\s *sub\\s +\\(\\w\\|[_']\\)+";
char *re_perl_keyword = "\\b\\(do\\|if\\|unless\\|while\\|until\\|else\\|elsif\\|for\\|foreach\\|continue\\|next\\|redo\\|last\\|goto\\|return\\|die\\|exit\\)\\b";

void perl_color_region(int start, int end)
{
   color_regexp_in_region ( re_perl_string , 1, start, end, perl_string_color);
    color_regexp_in_region ( re_perl_label , 0, start, end, perl_label_color);
    color_regexp_in_region ( re_perl_include , 0, start, end, perl_include_color);
    color_regexp_in_region ( re_perl_decl , 0, start, end, perl_decl_color);
    color_regexp_in_region ( re_perl_defun , 0, start, end, perl_defun_color);
    color_regexp_in_region ( re_perl_keyword , 0, start, end, perl_keyword_color);
    color_regexp_in_region ( re_perl_comment , 0, start, end, perl_comment_color);
}

/*
 * ###########################################################################
 *                       Regexp for java 
 *      Thanks to Jan Skibinski
 * ###########################################################################
 */

char *re_java_comment = "//.*$";
char *re_java_category = "^//[ \t]*category.*$";
    
char *re_java_string = gen_string;
char *re_java_result ="result\\|this\\new"; 

char *re_java_import = "^import.*$";
char *re_java_package = "^package.*$";

char *re_java_class = "\\(class\\|interface\\).*$";  

char *re_java_modifier = 
  "\\(abstract\\|static\\|public\\|protected\\|private\\|synchronized\\|native\\|final\
\\|extends\\|implements\\|throws\\)";

char *re_java_keyword = 
  "\\<\\(\
do\\|while\\|if\\|else\\|for\\|break\\|continue\\|case\\|return\\\
|switch\\|default\\|try\\|catch\\|throw\\|require\\|ensure\\|implies\
\\)\\>";

char * re_cpp_begin_comment = "/\\*";
char * re_cpp_end_comment = "\\*/";

void java_color_region(int start, int end)
{

  color_regexp_in_region ( re_java_string , 1, start, end, java_string_color);
  color_regexp_in_region ( re_java_result , 0, start, end, java_result_color);
  color_regexp_in_region ( re_java_import , 0, start, end, java_import_color);
  color_regexp_in_region ( re_java_package, 0, start, end, java_package_color);
  color_regexp_in_region ( re_java_class , 0, start, end, java_class_color);
  color_regexp_in_region ( re_java_modifier, 0, start, end, java_modifier_color);
  color_regexp_in_region ( re_java_keyword , 0, start, end, java_keyword_color);
  color_regexp_in_region ( re_java_comment , 0, start, end, java_comment_color);
  color_regexp_in_region ( re_java_category , 0, start, end, java_category_color);
  color_comment_in_region ( re_cpp_begin_comment, re_cpp_end_comment,start, end, java_comment_color );
}

/*
 * ###########################################################################
 *                       Regexp for Shell
 * ###########################################################################
 */
char *re_shell_comment = "^#.*\\|[ \t]#.*";
char *re_shell_string = gen_string;
char *re_shell_include = "^source[ \t].*$";
char *re_shell_define = "[^a-zA-Z0-9_#]set[ \t]+[a-zA-Z0-9_]+\\|[^a-zA-Z0-9_#]setenv[ \t]+[a-zA-Z0-9_]+";
char *re_shell_var = "\\$\\??[A-Za-z0-9_]+";
char *re_shell_keyword = 
  "[^_]\\<\\(if\\|then\\|else\\|fi\\|endif\\|case\\|default\\|switch\\|breaksw\\|endsw\\|continue\\|while\\|do\\|for\\)\\>[^_]\
\\|^\\(if\\|then\\|else\\|fi\\|endif\\|case\\|default\\|switch\\|breaksw\\|endsw\\|continue\\|while\\|do\\|for\\)\\>[^_]";

void shell_color_region(int start, int end)
{
    color_regexp_in_region ( re_shell_string , 1, start, end, shell_string_color);
    color_regexp_in_region ( re_shell_include , 0, start, end, shell_include_color);
    color_regexp_in_region ( re_shell_define , 0, start, end, shell_define_color);
    color_regexp_in_region ( re_shell_var , 0, start, end, shell_var_color);
    color_regexp_in_region ( re_shell_keyword , 0, start, end, shell_keyword_color);
    color_regexp_in_region ( re_shell_comment , 0, start, end, shell_comment_color);
}

/*
 * ###########################################################################
 *                       Regexp for Imake and Makefile.
 * ###########################################################################
 */
char *re_make_comment = "^#.*$\\|[^$]#.*$";
char *re_make_rules = 
  "^[^ \t\n]*%[^ \t\n]*[ \t]*::?[ \t]*[^ \t\n]*[ \t]*\\(#.*\\)?$\\|\
^[.][A-Za-z][A-Za-z]?\\..*$";

char *re_make_define = 
  "^[_A-Za-z0-9]+[ \t]*\\+?=\\|\
^[_A-Za-z0-9]+[ \t]*:[ \t]*sh[ \t]*=\\|\
\\( \\|:=\\)[_A-Za-z0-9]+[ \t]*\\+=";

char *re_make_keyword = "\\$\\([^ \t\n{(/]+\\|[{(]@?[_A-Za-z0-9:.,%/=]+[)}]\\)";
char *re_make_defun = "^[A-Za-z0-9.,/_-]+[ \t]*:[^=\n]*$";
char *re_make_include = "^include ";

void make_color_region(int start, int end)
{
   color_regexp_in_region ( re_make_rules , 0, start, end, make_rules_color);
    color_regexp_in_region ( re_make_define , 0, start, end, make_define_color);
    color_regexp_in_region ( re_make_keyword , 0, start, end, make_keyword_color);
    color_regexp_in_region ( re_make_defun , 0, start, end, make_defun_color);
    color_regexp_in_region ( re_make_include , 0, start, end, make_include_color);  
    color_regexp_in_region ( re_make_comment , 0, start, end, make_comment_color);
}

/*
 * ###########################################################################
 *                     Internal color switch  
 * ###########################################################################
 */
void color_internal(int start, int end)
{
    char *name = filename();
    char *file;
    char *mode_name = current_mode();
    
    file = basename(name);
    if ((strcmp(mode_name,"C-mode") == 0)
	||(strcmp(mode_name,"C++mode") == 0)) {
	c_cpp_color_region(start, end);
    }
    
    else if ((strcmp(mode_name,"Java") == 0)) {
	java_color_region(start, end);
    }
    else if ((strcmp(mode_name,"Edir") == 0)) {
	edir_color_region(start, end);
    }
    else if ((strcmp(mode_name,"Latex") == 0)) {
	latex_color_region(start, end);
    }
    else if ((strcmp(mode_name,"Html") == 0)) {
	html_color_region(start, end);
    }
    else if ((strcmp(mode_name,"Fortran") == 0)) {
      /* fortran_color_region(start, end); */
	fortran90_color_region(start, end);
    }
    else if ((strcmp(mode_name,"Ada") == 0)) {
	ada_color_region(start, end);
    }
    else if ((strcmp(mode_name,"Perl") == 0)) {
	perl_color_region(start, end);
    }
    else if ((strcmp(mode_name,"shell") == 0)) {
	shell_color_region(start, end);
    }
    
    else {
	if (file &&((strcmp(file, "Makefile")== 0)
	    || (strcmp(file, "MAKEFILE")== 0)
	    || (strcmp(file, "makefile")== 0)
	    || (strcmp(file, "Imakefile")== 0))) {
	    make_color_region(start, end);
	}
    }

    if (name)
      free(name);
    if(file)
      free(file);
    if(mode_name)
      free(mode_name);
}

/*
 * ###########################################################################
 *                     Smac user function.
 * ###########################################################################
 */
color_buffer()
{
    int orig = current_position ();

    if(monochrome())
      return;
    
    watch_on();
    remove_colors ();
    color_internal(0, end_of_file());
    goto_char(orig);
    watch_off();
}

/*
 * ###########################################################################
 *                     Smac user function.
 * ###########################################################################
 */
color_region()
{
    char *mode_name = current_mode();
    int orig = current_position ();
    int end, pos, start;
    
    if(monochrome())
      return;
    
    watch_on();
    goto_mark ();
    if ( (pos=current_position()) == orig ) {
	display_message ("Warning : no region defined");
	watch_off();
	return;
    }
    else if (pos > orig) {
	start = orig;
	end = pos;
    }
    else {
	start = pos;
	end = orig;
    }

    color_internal(start, end);

    goto_char (orig);
    watch_off();
}
