1/*
2 * States definitions file for GNU Enscript.
3 * Copyright (c) 1997-2003 Markku Rossi.
4 * Author: Markku Rossi <mtr@iki.fi>
5 *
6 * The latest version of this file can be downloaded from URL:
7 *
8 *     http://www.iki.fi/~mtr/genscript/enscript.st
9 */
10
11/*
12 * This file is part of GNU Enscript.
13 *
14 * Enscript is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Enscript is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Enscript.  If not, see <http://www.gnu.org/licenses/>.
26 */
27
28/*
29 * $Id: enscript.st,v 1.3 2003/03/05 08:31:31 mtr Exp $
30 */
31
32/*
33 * Guildelines for writing new highlighting rules for the GNU Enscript.
34 *
35 * - all highlighting states should have a document comment like this:
36 *
37 *   /**
38 *    * Name: c
39 *    * Description: C programming language.
40 *    * Author: Author Name <author@email.address>
41 *    * ...
42 *
43 *   It is used by enscript's --help-pretty-print option to print
44 *   description about supported highlighting modes.
45 *
46 * - the main entry state (for example, for the C, the state `c') must
47 *   be inherited from state `HighlightEntry':
48 *
49 *   state c extends HighlightEntry
50 *   {
51 *     ...
52 *
53 * - all help-states smust be inherited from state `Highlight':
54 *
55 *   state c_string extends Highlight
56 *   {
57 *     ...
58 *
59 * - all printing should be done with the language_print() procedure
60 *   instead of the print() primitive.
61 *
62 * - using enscript.el to build regular expressions:
63 *
64 *      M-x load-file RET enscript.el RET
65 *
66 *   Move in the buffer to the point where the (build-re '()) ends,
67 *   that is, after the last closing parenthesis ')'.  Then, type:
68 *
69 *      C-x C-e
70 *
71 *   Magic should happen.
72 *
73 * These rules ensures that enscript's --help-pretty-print option and
74 * the different output languages (HTML, RTF, etc.) work.
75 */
76
77/* This script needs at least this version of the States program. */
78prereq ("1.6.2");
79
80/*
81 * Constants, fonts, etc.
82 */
83
84debug = "0";
85
86/* Boolean values. */
87true = 1;
88false = 0;
89
90font_spec = "Courier@10";
91
92/* These components are resolved from <font_spec>. */
93font = "";
94ptsize = "";
95
96/*
97 * Generatel table of contents?  This is not supported by all output
98 * languages.
99 */
100toc = "0";
101
102/*
103 * The Highlight style.  The default style is `emacs' to imitate
104 * Emacs' font lock mode.
105 */
106style = "emacs";
107
108/*
109 * Create color outputs?
110 */
111color = "1";
112
113/*
114 * Use verbose highlighting rules?
115 */
116verbose_highlighting = false;
117
118/*
119 * Target language.  Possible values are:
120 * - enscript		generate enscript special escapes
121 * - html		generate HTML
122 * - overstrike		generate overstrike (line printers, less)
123 * - texinfo		generate Texinfo
124 * - rtf                generate Rich Text Format (rtf - MS Word, WordPerfect)
125 *                      This code can be souched into MS Word or PowerPoint
126 *                      for a pretty version of the code
127 */
128language = "enscript";
129
130/*
131 * How many input files we have.
132 */
133num_input_files = "1";
134current_input_file = 0;
135
136/*
137 * Document title.
138 */
139document_title = "Enscript Output";
140
141/*
142 * Global variables for nested highlighting `nested.st'.
143 */
144nested_start = "^-+(([ \t]*)([a-zA-Z_0-9]*)([ \t]*))-+$";
145nested_start_re = 0;
146nested_end = "^-+$";
147nested_end_re_cached = 0;
148nested_end_re = 0;
149nested_default = "passthrough";
150
151/*
152 * Color definitions.
153 */
154
155cindex = 0;
156rgb_values = list ();
157
158sub define_color (name, r, g, b)
159{
160  rgb_values[cindex] = list (name, r, g, b);
161  cindex = cindex + 1;
162}
163
164sub color_index (name)
165{
166  local i;
167
168  for (i = 0; i < length (rgb_values); i = i + 1)
169    if (strcmp (rgb_values[i][0], name) == 0)
170      return i;
171
172  return -1;
173}
174
175sub language_color (name)
176{
177  local idx;
178
179  idx = color_index (name);
180  if (idx < 0)
181    panic ("unknown color `", name, "'");
182
183  /*
184   * The map_color() subroutine is language specific and defined in
185   * *_faces() subroutine.
186   */
187  map_color (rgb_values[idx][1], rgb_values[idx][2], rgb_values[idx][3]);
188}
189
190/* RGB definitions for colors.	These are borrowed from X's rgb.txt file. */
191
192define_color ("black",			0, 0, 0);
193define_color ("gray25",			64, 64, 64);
194define_color ("gray50",			127, 127, 127);
195define_color ("gray75",			191, 191, 191);
196define_color ("gray85",			217, 217, 217);
197define_color ("gray90",			229, 229, 229);
198define_color ("gray95",			242, 242, 242);
199define_color ("blue",			0, 0, 255);
200define_color ("cadet blue",		95, 158, 160);
201define_color ("dark goldenrod",		184, 134, 11);
202define_color ("dark olive green",	85, 107, 47);
203define_color ("firebrick",		178, 34, 34);
204define_color ("forest green",		34, 139, 34);
205define_color ("green",			0, 255, 0);
206define_color ("orchid",			218, 112, 214);
207define_color ("purple",			160, 32, 240);
208define_color ("red",			255, 0, 0);
209define_color ("rosy brown",		188, 143, 143);
210
211define_color ("DarkSeaGreen",		143, 188, 143);
212define_color ("DarkSeaGreen1",		193, 255, 193);
213define_color ("DarkSeaGreen2",		180, 238, 180);
214define_color ("DarkSeaGreen3",		155, 205, 155);
215define_color ("DarkSeaGreen4",		105, 139, 105);
216define_color ("Goldenrod",		237, 218, 116);
217define_color ("Aquamarine",		67, 183, 186);
218define_color ("SeaGreen2",		100, 233, 134);
219define_color ("Coral",			247, 101,  65);
220define_color ("DarkSlateGray1",		154, 254, 255);
221define_color ("LightGrey",		211, 211, 211);
222
223
224/*
225 * General helpers.
226 */
227
228sub debug (msg)
229{
230  if (debug_level)
231    print ("DEBUG: ", msg, "\n");
232}
233
234sub is_prefix (prefix, string)
235{
236  return strncmp (prefix, string, length (prefix)) == 0;
237}
238
239sub strchr (string, ch)
240{
241  local len = length (string), i;
242
243  for (i = 0; i < len; i = i + 1)
244    if (string[i] == ch)
245      return i;
246
247  return -1;
248}
249
250sub need_version (major, minor, beta)
251{
252  local r, v, i;
253
254  regmatch (version, (/([0-9]+)\.([0-9]+)\.([0-9]+)/));
255  v = list (int ($1), int ($2), int ($3));
256  r = list (major, minor, beta);
257
258  for (i = 0; i < 3; i = i + 1)
259    if (v[i] > r[i])
260      return 1;
261    else if (v[i] < r[i])
262      return 0;
263
264  /* Exact match. */
265  return 1;
266}
267
268/* Highlight types which match expression <re> from string <data>. */
269sub highlight_types (data, re)
270{
271  local match_len;
272
273  while (regmatch (data, re))
274    {
275      language_print ($B);
276      type_face (true);
277      language_print ($0);
278      type_face (false);
279
280      match_len = length ($B, $0);
281
282      data = substring (data, match_len, length (data));
283    }
284
285  language_print (data);
286}
287
288
289/*
290 * The supported faces.  These functions are used in the highlighting
291 * rules to mark different logical elements of the code.  The
292 * different faces and their properties (face_*) are defined in the
293 * style definition files.  The face_on() and face_off() functions are
294 * defined in the output language definition files.
295 */
296
297sub bold (on)
298{
299  if (on)
300    face_on (face_bold);
301  else
302    face_off (face_bold);
303}
304
305sub italic (on)
306{
307  if (on)
308    face_on (face_italic);
309  else
310    face_off (face_italic);
311}
312
313sub bold_italic (on)
314{
315  if (on)
316    face_on (face_bold_italic);
317  else
318    face_off (face_bold_italic);
319}
320
321sub comment_face (on)
322{
323  if (on)
324    face_on (face_comment);
325  else
326    face_off (face_comment);
327}
328
329sub function_name_face (on)
330{
331  if (on)
332    face_on (face_function_name);
333  else
334    face_off (face_function_name);
335}
336
337sub variable_name_face (on)
338{
339  if (on)
340    face_on (face_variable_name);
341  else
342    face_off (face_variable_name);
343}
344
345sub keyword_face (on)
346{
347  if (on)
348    face_on (face_keyword);
349  else
350    face_off (face_keyword);
351}
352
353sub reference_face (on)
354{
355  if (on)
356    face_on (face_reference);
357  else
358    face_off (face_reference);
359}
360
361sub string_face (on)
362{
363  if (on)
364    face_on (face_string);
365  else
366    face_off (face_string);
367}
368
369sub builtin_face (on)
370{
371  if (on)
372    face_on (face_builtin);
373  else
374    face_off (face_builtin);
375}
376
377sub type_face (on)
378{
379  if (on)
380    face_on (face_type);
381  else
382    face_off (face_type);
383}
384
385sub highlight_face (on)
386{
387  if (on)
388    face_on (face_highlight);
389  else
390    face_off (face_highlight);
391}
392
393
394/*
395 * Initializations.
396 */
397
398start
399{
400  /* Set debug level. */
401  debug_level = int (debug);
402
403  /* Use colors? */
404  color = int (color);
405
406  /* Increment input file count. */
407  current_input_file = current_input_file + 1;
408
409  /* Resolve fonts. */
410  idx = strchr (font_spec, '@');
411  if (idx < 0)
412    panic ("malformed font spec: `", font_spec, "'");
413
414  font = substring (font_spec, 0, idx);
415  ptsize = substring (font_spec, idx + 1, length (font_spec));
416
417  debug (concat ("start: ", font, "@", ptsize));
418
419  /* Construct bold, italic, etc. fonts for our current body font. */
420  if (is_prefix ("AvantGarde", font))
421    {
422      bold_font = "AvantGarde-Demi";
423      italic_font = "AvantGarde-BookOblique";
424      bold_italic_font = "AvantGarde-DemiOblique";
425    }
426  else if (regmatch (font, /^Bookman|Souvenir/))
427    {
428      bold_font = concat ($0, "-Demi");
429      italic_font = concat ($0, "-LightItalic");
430      bold_italic_font = concat ($0, "-DemiItalic");
431    }
432  else if (regmatch (font, /^Lucida(Sans-)?Typewriter/))
433    {
434      bold_font = concat ($0, "Bold");
435      italic_font = concat ($0, "Oblique");
436      bold_italic_font = concat ($0, "BoldOblique");
437    }
438  else if (regmatch (font, /^(.*)-Roman$/))
439    {
440      bold_font = concat ($1, "-Bold");
441      italic_font = concat ($1, "-Italic");
442      bold_italic_font = concat ($1, "-BoldItalic");
443    }
444  else
445    {
446      bold_font = concat (font, "-Bold");
447      italic_font = concat (font, "-Oblique");
448      bold_italic_font = concat (font, "-BoldOblique");
449    }
450
451  /* Create regular expressions for nested highlighting. */
452  nested_start_re = regexp (nested_start);
453  nested_end_re_cached = regexp (nested_end);
454
455  /* Define output faces. */
456  calln (concat ("lang_", language));
457
458  /* Define our highlight style. */
459  calln (concat ("style_", style));
460
461  /* Resolve start state. */
462  if (check_startrules ())
463    debug ("startstate from startrules");
464  if (check_namerules ())
465    debug ("startstate from namerules");
466}
467
468namerules
469{
470  /\.(c|h)$/					c;
471  /\.(c++|C|H|cpp|cc|cxx)$/			cpp;
472  /\.m$/					matlab;
473  /\.(mpl|mp|maple)$/				maple;
474  /\.(scm|scheme)$/				scheme;
475  /\b\.emacs$|\.el$/				elisp;
476  /\.ad(s|b|a)$/				ada;
477  /\.[Ss]$/					asm;
478  /\.st$/					states;
479  /(M|m)akefile.*/				makefile;
480  /\.(MOD|DEF|mi|md)$/				modula_2;
481  /\.tcl$/					tcl;
482  /\.(v|vh)$/					verilog;
483  /\.html?$/					html;
484  /\bChangeLog$/				changelog;
485  /\.(vhd|vhdl)$/				vhdl;
486  /\.(scr|.syn|.synth)$/			synopsys;
487  /\.idl$/					idl;
488  /\.(hs|lhs|gs|lgs)$/				haskell;
489  /\.(pm|pl)$/					perl;
490  /\.(eps|EPS|ps|PS)$/				postscript;
491  /\.py$/					python;
492  /\.pyx$/					pyrex;
493  /\.js$/					javascript;
494  /\.java$/					java;
495  /\.([Pp][Aa][Ss]|[Pp][Pp]|[Pp])$/		pascal;
496  /\.[fF]$/					fortran;
497  /\.f90$/					f90;
498  /\.awk$/					awk;
499  /\.sh$/					sh;
500  /\.vba$/					vba;
501  /\.(cshrc|login|logout|history|csh)$/		csh;
502  /\.tcshrc$/					tcsh;
503  /\.(zshenv|zprofile|zshrc|zlogin|zlogout)$/	zsh;
504  /\.(bash_profile|bashrc|inputrc)$/		bash;
505  /\.m4$/					m4;
506  /\.il$/					skill;
507  /\.wrl$/					vrml;
508  /\b(rfc.*\.txt|draft-.*\.txt)$/		rfc;
509  /\.inf$/i					inf;
510  /\.tex$/					tex;
511  /\.wmlscript$/				wmlscript;
512  /\.wmls$/					wmlscript;
513  /^.*$/					passthrough;
514}
515
516startrules
517{
518  /.\010.\010.\010./					nroff;
519  /-\*- [Cc] -\*-/					c;
520  /-\*- [Cc]\+\+ -\*-/					cpp;
521  /-\*- [Aa][Dd][Aa] -\*-/				ada;
522  /-\*- [Aa][Ss][Mm] -\*-/				asm;
523  /-\*- [Oo][Bb][Jj][Cc] -\*-/				objc;
524  /-\*- [Ss][Cc][Hh][Ee][Mm][Ee] -\*-/			scheme;
525  /-\*- [Ee][Mm][Aa][Cc][Ss] [Ll][Ii][Ss][Pp] -\*-/	elisp;
526  /-\*- [Tt][Cc][Ll] -\*-/				tcl;
527  /-\*- [Vv][Hh][Dd][Ll] -\*-/				vhdl;
528  /-\*- [Hh][Aa][Ss][Kk][Ee][Ll][Ll] -\*-/		haskell;
529  /-\*- [Ii][Dd][Ll] -\*-/				idl;
530  /-\*- [Pp][Ee][Rr][Ll] -\*-/				perl;
531  /^#![ \t]*\/.*\/perl/					perl;
532  /^From:/						mail;
533  /^#![ \t]*(\/usr)?\/bin\/[ngmt]?awk/			awk;
534  /^#![ \t]*(\/usr)?\/bin\/sh/				sh;
535  /^#![ \t]*(\/usr)?\/bin\/csh/				csh;
536  /^#![ \t]*(\/usr)?(\/local)?\/bin\/tcsh/		tcsh;
537  /^#![ \t]*(\/usr)?(\/local)?\/bin\/zsh/		zsh;
538  /^#![ \t]*(\/usr)?(\/local)?\/bin\/bash/		bash;
539  /^#![ \t]*(\/usr)?(\/ccs)?\/bin\/m4/			m4;
540  /^#VRML/						vrml;
541  /^\04?%!/						postscript;
542}
543
544
545/*
546 * The global super states.
547 */
548
549state Highlight
550{
551  /* If you want to preserve enscript's escape sequences in the state
552     highlighting, uncomment the following rule.  It passes all
553     enscript's escape sequences to the output.
554
555       /^\0[^{]+{[^}]+}/ {
556        language_print ($0);
557       }
558  */
559
560  /* If we are doing nested highlighting (same document can contain
561     multiple highlighting styles), the variable `nested_end_re'
562     specifies the end of the nesting highlight state. */
563  nested_end_re {
564    language_print($0);
565    return;
566  }
567
568  /* Skip output language's special characters. */
569  LANGUAGE_SPECIALS {
570    language_print ($0);
571  }
572}
573
574/* How many nesting HighlightEntry states are currently active.  The
575   header and trailer will be printed at the nesting level 0. */
576highlight_entry_nesting = 0;
577
578state HighlightEntry extends Highlight
579{
580  BEGIN {
581    if (highlight_entry_nesting++ == 0)
582      header();
583  }
584  END {
585    if (--highlight_entry_nesting == 0)
586      trailer();
587  }
588}
589
590
591
592/*
593 * Helper subroutines and states.
594 */
595
596state match_balanced_block extends Highlight
597{
598  match_balanced_block_start {
599    language_print ($0);
600    match_balanced_block_count = match_balanced_block_count + 1;
601  }
602
603  match_balanced_block_end {
604    match_balanced_block_count = match_balanced_block_count - 1;
605    if (match_balanced_block_count == 0)
606      return $0;
607
608    language_print ($0);
609  }
610}
611
612sub match_balanced_block (starter, ender)
613{
614  match_balanced_block_count = 1;
615  match_balanced_block_start = starter;
616  match_balanced_block_end = ender;
617  return call (match_balanced_block);
618}
619
620state eat_one_line
621{
622  /.*\n/ {
623    language_print ($0);
624    return;
625  }
626}
627
628
629/*
630Local variables:
631mode: c
632End:
633*/
634