1 /* editor syntax highlighting.
2 
3    Copyright (C) 1996-2000 the Free Software Foundation
4 
5    Authors: 1998 Paul Sheer
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20    02111-1307, USA.
21 */
22 
23 #include <config.h>
24 #include <stdio.h>
25 #if defined(MIDNIGHT) || defined(GTK)
26 #include "edit.h"
27 #else
28 #include "coolwidget.h"
29 #endif
30 #if defined (HAVE_MAD) && ! defined (MIDNIGHT) && ! defined (GTK)
31 #include "mad.h"
32 #endif
33 
34 /* bytes */
35 #define SYNTAX_MARKER_DENSITY 512
36 
37 /*
38    Mispelled words are flushed from the syntax highlighting rules
39    when they have been around longer than
40    TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
41    chars per second and say 3 chars + a space per word, we can
42    accumulate 450 words absolute max with a value of 60. This is
43    below this limit of 1024 words in a context.
44  */
45 #define TRANSIENT_WORD_TIME_OUT 60
46 
47 #define UNKNOWN_FORMAT "unknown"
48 
49 #if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH)
50 
51 int option_syntax_highlighting = 1;
52 int option_auto_spellcheck = 1;
53 
54 /* these three functions are called from the outside */
55 void edit_load_syntax (WEdit * edit, char **names, char *type);
56 void edit_free_syntax_rules (WEdit * edit);
57 void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg);
58 
59 #ifdef HAVE_MAD
mad_syntax_malloc(size_t x,char * file,int line)60 static void *mad_syntax_malloc (size_t x, char *file, int line)
61 #define syntax_malloc(x) mad_syntax_malloc (x, __FILE__, __LINE__)
62 #else
63 static void *syntax_malloc (size_t x)
64 #endif
65 {
66     void *p;
67 #ifdef HAVE_MAD
68     p = mad_alloc (x, file, line);
69 #else
70     p = malloc (x);
71 #endif
72     memset (p, 0, x);
73     return p;
74 }
75 
76 #define syntax_free(x) {if(x){free(x);(x)=0;}}
77 
compare_word_to_right(WEdit * edit,long i,char * text,char * whole_left,char * whole_right,int line_start)78 static long compare_word_to_right (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start)
79 {
80     unsigned char *p, *q;
81     int c, d, j;
82     if (!*text)
83 	return -1;
84     c = edit_get_byte (edit, i - 1);
85     if (line_start)
86 	if (c != '\n')
87 	    return -1;
88     if (whole_left)
89 	if (strchr (whole_left, c))
90 	    return -1;
91     for (p = (unsigned char *) text, q = p + strlen ((char *) p); (unsigned long) p < (unsigned long) q; p++, i++) {
92 	switch (*p) {
93 	case '\001':
94 	    p++;
95 	    for (;;) {
96 		c = edit_get_byte (edit, i);
97 		if (!*p)
98 		    if (whole_right)
99 			if (!strchr (whole_right, c))
100 			    break;
101 		if (c == *p)
102 		    break;
103 		if (c == '\n')
104 		    return -1;
105 		i++;
106 	    }
107 	    break;
108 	case '\002':
109 	    p++;
110 	    j = 0;
111 	    for (;;) {
112 		c = edit_get_byte (edit, i);
113 		if (c == *p) {
114 		    j = i;
115 		    if (*p == *text && !p[1])	/* handle eg '+' and @+@ keywords properly */
116 			break;
117 		}
118 		if (j && strchr ((char *) p + 1, c))	/* c exists further down, so it will get matched later */
119 		    break;
120 		if (c == '\n' || c == '\t' || c == ' ') {
121 		    if (!*p) {
122 			i--;
123 			break;
124 		    }
125 		    if (!j)
126 			return -1;
127 		    i = j;
128 		    break;
129 		}
130 		if (whole_right)
131 		    if (!strchr (whole_right, c)) {
132 			if (!*p) {
133 			    i--;
134 			    break;
135 			}
136 			if (!j)
137 			    return -1;
138 			i = j;
139 			break;
140 		    }
141 		i++;
142 	    }
143 	    break;
144 	case '\003':
145 	    p++;
146 	    c = -1;
147 	    for (;; i++) {
148 		d = c;
149 		c = edit_get_byte (edit, i);
150 		for (j = 0; p[j] != '\003'; j++)
151 		    if (c == p[j])
152 			goto found_char2;
153 		break;
154 	      found_char2:
155 		j = c;		/* dummy command */
156 	    }
157 	    i--;
158 	    while (*p != '\003')
159 		p++;
160 	    if (p[1] == d)
161 		i--;
162 	    break;
163 	case '\004':
164 	    p++;
165 	    c = edit_get_byte (edit, i);
166 	    for (; *p != '\004'; p++)
167 		if (c == *p)
168 		    goto found_char3;
169 	    return -1;
170 	  found_char3:
171 	    for (; *p != '\004'; p++);
172 	    break;
173 #if 0
174 /* especially for LaTeX */
175 	case '\005': {
176                 int b = 0;
177 	        p++;
178 	        for (;;) {
179 		    c = edit_get_byte (edit, i);
180                     if (c == '\\') {
181                         i += 2;
182                         continue;
183                     }
184                     if (c == '{') {
185                     }
186 		    if (c == *p)
187 		        break;
188 		    if (c == '\n')
189 		        return -1;
190 		    i++;
191 	        }
192 	        break;
193             }
194 #endif
195 	default:
196 	    if (*p != (unsigned char) edit_get_byte (edit, i))
197 		return -1;
198 	}
199     }
200     if (whole_right)
201 	if (strchr (whole_right, edit_get_byte (edit, i)))
202 	    return -1;
203     return i;
204 }
205 
206 #define XXX							\
207 	    if (*s < '\005' || *s == (unsigned char) c)		\
208 		goto done;					\
209 	    s++;
210 
xx_strchr(const unsigned char * s,int c)211 static inline char *xx_strchr (const unsigned char *s, int c)
212 {
213   repeat:
214     XXX XXX XXX XXX XXX XXX XXX XXX;
215     XXX XXX XXX XXX XXX XXX XXX XXX;
216     goto repeat;
217   done:
218     return (char *) s;
219 }
220 
apply_rules_going_right(WEdit * edit,long i,struct syntax_rule rule)221 static inline struct syntax_rule apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule)
222 {
223     struct context_rule *r;
224     int contextchanged = 0, c;
225     int found_right = 0, found_left = 0, keyword_foundleft = 0, keyword_foundright = 0;
226     int is_end;
227     long end = 0;
228     struct syntax_rule _rule = rule;
229     if (!(c = edit_get_byte (edit, i)))
230 	return rule;
231     is_end = (rule.end == (unsigned char) i);
232 /* check to turn off a keyword */
233     if (_rule.keyword) {
234 	struct key_word *k;
235 	k = edit->rules[_rule.context]->keyword[_rule.keyword];
236 	if (edit_get_byte (edit, i - 1) == '\n')
237 	    _rule.keyword = 0;
238 	if (is_end) {
239 	    _rule.keyword = 0;
240 	    keyword_foundleft = 1;
241 	}
242     }
243 /* check to turn off a context */
244     if (_rule.context && !_rule.keyword) {
245 	long e;
246 	r = edit->rules[_rule.context];
247 	if (r->first_right == c && !(rule.border & RULE_ON_RIGHT_BORDER) && (e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) > 0) {
248 	    _rule.end = e;
249 	    found_right = 1;
250 	    _rule.border = RULE_ON_RIGHT_BORDER;
251 	    if (r->between_delimiters)
252 		_rule.context = 0;
253 	} else if (is_end && rule.border & RULE_ON_RIGHT_BORDER) {
254 /* always turn off a context at 4 */
255 	    found_left = 1;
256 	    _rule.border = 0;
257 	    if (!keyword_foundleft)
258 		_rule.context = 0;
259 	} else if (is_end && rule.border & RULE_ON_LEFT_BORDER) {
260 /* never turn off a context at 2 */
261 	    found_left = 1;
262 	    _rule.border = 0;
263 	}
264     }
265 /* check to turn on a keyword */
266     if (!_rule.keyword) {
267 	char *p;
268 	p = (r = edit->rules[_rule.context])->keyword_first_chars;
269 	while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
270 	    struct key_word *k;
271 	    int count;
272 	    long e;
273 	    count = (unsigned long) p - (unsigned long) r->keyword_first_chars;
274 	    k = r->keyword[count];
275 	    e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
276 	    if (e > 0) {
277 		end = e;
278 		_rule.end = e;
279 		_rule.keyword = count;
280 		keyword_foundright = 1;
281 		break;
282 	    }
283 	}
284     }
285 /* check to turn on a context */
286     if (!_rule.context) {
287 	if (!found_left && is_end) {
288 	    if (rule.border & RULE_ON_RIGHT_BORDER) {
289 		_rule.border = 0;
290 		_rule.context = 0;
291 		contextchanged = 1;
292 		_rule.keyword = 0;
293 	    } else if (rule.border & RULE_ON_LEFT_BORDER) {
294 		r = edit->rules[_rule._context];
295 		_rule.border = 0;
296 		if (r->between_delimiters) {
297 		    long e;
298 		    _rule.context = _rule._context;
299 		    contextchanged = 1;
300 		    _rule.keyword = 0;
301 		    if (r->first_right == c && (e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) >= end) {
302 			_rule.end = e;
303 			found_right = 1;
304 			_rule.border = RULE_ON_RIGHT_BORDER;
305 			_rule.context = 0;
306 		    }
307 		}
308 	    }
309 	}
310 	if (!found_right) {
311 	    int count;
312 	    struct context_rule **rules = edit->rules;
313 	    for (count = 1; rules[count]; count++) {
314 		r = rules[count];
315 		if (r->first_left == c) {
316 		    long e;
317 		    e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left);
318 		    if (e >= end && (!_rule.keyword || keyword_foundright)) {
319 			_rule.end = e;
320 			found_right = 1;
321 			_rule.border = RULE_ON_LEFT_BORDER;
322 			_rule._context = count;
323 			if (!r->between_delimiters)
324 			    if (!_rule.keyword) {
325 				_rule.context = count;
326 				contextchanged = 1;
327 			    }
328 			break;
329 		    }
330 		}
331 	    }
332 	}
333     }
334 /* check again to turn on a keyword if the context switched */
335     if (contextchanged && !_rule.keyword) {
336 	char *p;
337 	p = (r = edit->rules[_rule.context])->keyword_first_chars;
338 	while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
339 	    struct key_word *k;
340 	    int count;
341 	    long e;
342 	    count = (unsigned long) p - (unsigned long) r->keyword_first_chars;
343 	    k = r->keyword[count];
344 	    e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
345 	    if (e > 0) {
346 		_rule.end = e;
347 		_rule.keyword = count;
348 		break;
349 	    }
350 	}
351     }
352     return _rule;
353 }
354 
edit_get_rule(WEdit * edit,long byte_index)355 static struct syntax_rule edit_get_rule (WEdit * edit, long byte_index)
356 {
357     long i;
358     if (edit->syntax_invalidate) {
359 	struct _syntax_marker *s;
360 	while (edit->syntax_marker && edit->syntax_marker->offset >= edit->last_get_rule) {
361 	    s = edit->syntax_marker->next;
362 	    syntax_free (edit->syntax_marker);
363 	    edit->syntax_marker = s;
364 	}
365 	if (edit->syntax_marker) {
366 	    edit->last_get_rule = edit->syntax_marker->offset;
367 	    edit->rule = edit->syntax_marker->rule;
368 	} else {
369 	    edit->last_get_rule = -1;
370 	    memset (&edit->rule, 0, sizeof (edit->rule));
371 	}
372 	edit->syntax_invalidate = 0;
373     }
374     if (byte_index > edit->last_get_rule) {
375 	for (i = edit->last_get_rule + 1; i <= byte_index; i++) {
376 	    edit->rule = apply_rules_going_right (edit, i, edit->rule);
377 	    if (i > (edit->syntax_marker ? edit->syntax_marker->offset + SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY)) {
378 		struct _syntax_marker *s;
379 		s = edit->syntax_marker;
380 		edit->syntax_marker = syntax_malloc (sizeof (struct _syntax_marker));
381 		edit->syntax_marker->next = s;
382 		edit->syntax_marker->offset = i;
383 		edit->syntax_marker->rule = edit->rule;
384 	    }
385 	}
386     } else if (byte_index < edit->last_get_rule) {
387 	struct _syntax_marker *s;
388 	for (;;) {
389 	    if (!edit->syntax_marker) {
390 		memset (&edit->rule, 0, sizeof (edit->rule));
391 		for (i = -1; i <= byte_index; i++)
392 		    edit->rule = apply_rules_going_right (edit, i, edit->rule);
393 		break;
394 	    }
395 	    if (byte_index >= edit->syntax_marker->offset) {
396 		edit->rule = edit->syntax_marker->rule;
397 		for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++)
398 		    edit->rule = apply_rules_going_right (edit, i, edit->rule);
399 		break;
400 	    }
401 	    s = edit->syntax_marker->next;
402 	    syntax_free (edit->syntax_marker);
403 	    edit->syntax_marker = s;
404 	}
405     }
406     edit->last_get_rule = byte_index;
407     return edit->rule;
408 }
409 
translate_rule_to_color(WEdit * edit,struct syntax_rule rule,int * fg,int * bg)410 static void translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *fg, int *bg)
411 {
412     struct key_word *k;
413     k = edit->rules[rule.context]->keyword[rule.keyword];
414     *bg = k->bg;
415     *fg = k->fg;
416 }
417 
edit_get_syntax_color(WEdit * edit,long byte_index,int * fg,int * bg)418 void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
419 {
420     if (edit->rules && byte_index < edit->last_byte && option_syntax_highlighting) {
421 	translate_rule_to_color (edit, edit_get_rule (edit, byte_index), fg, bg);
422     } else {
423 #ifdef MIDNIGHT
424 	*fg = EDITOR_NORMAL_COLOR;
425 #else
426 	*fg = NO_COLOR;
427 	*bg = NO_COLOR;
428 #endif
429     }
430 }
431 
432 
433 /*
434    Returns 0 on error/eof or a count of the number of bytes read
435    including the newline. Result must be free'd.
436  */
437 #ifdef HAVE_MAD
mad_read_one_line(char ** line,FILE * f,char * file,int line_)438 static int mad_read_one_line (char **line, FILE * f, char *file, int line_)
439 #define read_one_line(a,b) mad_read_one_line(a,b,__FILE__,__LINE__)
440 #else
441 static int read_one_line (char **line, FILE * f)
442 #endif
443 {
444     char *p;
445     int len = 256, c, r = 0, i = 0;
446 #ifdef HAVE_MAD
447     p = mad_syntax_malloc (len, file, line_);
448 #else
449     p = syntax_malloc (len);
450 #endif
451     for (;;) {
452 	c = fgetc (f);
453 	if (c <= 0) {
454 	    if (!feof(f) && (c == -1 && errno == EINTR))
455 		continue;
456 	    r = 0;
457 	    break;
458 	} else if (c == '\n') {
459 	    r = i + 1;		/* extra 1 for the newline just read */
460 	    break;
461 	} else {
462 	    if (i >= len - 1) {
463 		char *q;
464 		q = syntax_malloc (len * 2);
465 		memcpy (q, p, len);
466 		syntax_free (p);
467 		p = q;
468 		len *= 2;
469 	    }
470 	    p[i++] = c;
471 	}
472     }
473     p[i] = 0;
474     *line = p;
475     return r;
476 }
477 
strdup_convert(char * s)478 static char *strdup_convert (char *s)
479 {
480     char *r, *p;
481     p = r = (char *) strdup (s);
482     while (*s) {
483 	switch (*s) {
484 	case '\\':
485 	    s++;
486 	    switch (*s) {
487 	    case ' ':
488 		*p = ' ';
489 		s--;
490 		break;
491 	    case 'n':
492 		*p = '\n';
493 		break;
494 	    case 'r':
495 		*p = '\r';
496 		break;
497 	    case 't':
498 		*p = '\t';
499 		break;
500 	    case 's':
501 		*p = ' ';
502 		break;
503 	    case '*':
504 		*p = '*';
505 		break;
506 	    case '\\':
507 		*p = '\\';
508 		break;
509 	    case '[':
510 	    case ']':
511 		*p = '\003';
512 		break;
513 	    case '{':
514 	    case '}':
515 		*p = '\004';
516 		break;
517 	    default:
518 		*p = *s;
519 		break;
520 	    }
521 	    break;
522 	case '*':
523 	    *p = '\001';
524 	    break;
525 	case '+':
526 	    *p = '\002';
527 	    break;
528 	default:
529 	    *p = *s;
530 	    break;
531 	}
532 	s++;
533 	p++;
534     }
535     *p = '\0';
536     return r;
537 }
538 
539 #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
540 
get_args(char * l,char ** args,int * argc)541 static void get_args (char *l, char **args, int *argc)
542 {
543     *argc = 0;
544     l--;
545     for (;;) {
546 	char *p;
547 	for (p = l + 1; *p && whiteness (*p); p++);
548 	if (!*p)
549 	    break;
550 	for (l = p + 1; *l && !whiteness (*l); l++);
551 	*l = '\0';
552 	*args = strdup_convert (p);
553 	(*argc)++;
554 	args++;
555     }
556     *args = 0;
557 }
558 
free_args(char ** args)559 static void free_args (char **args)
560 {
561     while (*args) {
562 	syntax_free (*args);
563 	*args = 0;
564 	args++;
565     }
566 }
567 
568 #define check_a {if(!*a){result=line;break;}}
569 #define check_not_a {if(*a){result=line;break;}}
570 
571 #ifdef MIDNIGHT
572 
573 int try_alloc_color_pair (char *fg, char *bg);
574 
this_try_alloc_color_pair(char * fg,char * bg)575 int this_try_alloc_color_pair (char *fg, char *bg)
576 {
577     char f[80], b[80], *p;
578     if (bg)
579 	if (!*bg)
580 	    bg = 0;
581     if (fg)
582 	if (!*fg)
583 	    fg = 0;
584     if (fg) {
585 	strcpy (f, fg);
586 	p = strchr (f, '/');
587 	if (p)
588 	    *p = '\0';
589 	fg = f;
590     }
591     if (bg) {
592 	strcpy (b, bg);
593 	p = strchr (b, '/');
594 	if (p)
595 	    *p = '\0';
596 	bg = b;
597     }
598     return try_alloc_color_pair (fg, bg);
599 }
600 #else
601 #ifdef GTK
602 int allocate_color (WEdit *edit, gchar *color);
603 
this_allocate_color(WEdit * edit,char * fg)604 int this_allocate_color (WEdit *edit, char *fg)
605 {
606     char *p;
607     if (fg)
608 	if (!*fg)
609 	    fg = 0;
610     if (!fg)
611 	return allocate_color (edit, 0);
612     p = strchr (fg, '/');
613     if (!p)
614 	return allocate_color (edit, fg);
615     return allocate_color (edit, p + 1);
616 }
617 #else
this_allocate_color(WEdit * edit,char * fg)618 int this_allocate_color (WEdit *edit, char *fg)
619 {
620     char *p;
621     if (fg)
622 	if (!*fg)
623 	    fg = 0;
624     if (!fg)
625 	return allocate_color (0);
626     p = strchr (fg, '/');
627     if (!p)
628 	return allocate_color (fg);
629     return allocate_color (p + 1);
630 }
631 #endif
632 #endif
633 
634 static char *error_file_name = 0;
635 
open_include_file(char * filename)636 static FILE *open_include_file (char *filename)
637 {
638     FILE *f;
639     char p[MAX_PATH_LEN];
640     syntax_free (error_file_name);
641     error_file_name = (char *) strdup (filename);
642     if (*filename == '/')
643 	return fopen (filename, "r");
644     strcpy (p, home_dir);
645     strcat (p, EDIT_DIR "/");
646     strcat (p, filename);
647     syntax_free (error_file_name);
648     error_file_name = (char *) strdup (p);
649     f = fopen (p, "r");
650     if (f)
651 	return f;
652     strcpy (p, LIBDIR "/syntax/");
653     strcat (p, filename);
654     syntax_free (error_file_name);
655     error_file_name = (char *) strdup (p);
656     return fopen (p, "r");
657 }
658 
659 /* returns line number on error */
edit_read_syntax_rules(WEdit * edit,FILE * f)660 static int edit_read_syntax_rules (WEdit * edit, FILE * f)
661 {
662     FILE *g = 0;
663     char *fg, *bg;
664     char last_fg[32] = "", last_bg[32] = "";
665     char whole_right[512];
666     char whole_left[512];
667     char *args[1024], *l = 0;
668     int save_line = 0, line = 0;
669     struct context_rule **r, *c = 0;
670     int num_words = -1, num_contexts = -1;
671     int argc, result = 0;
672     int i, j;
673 
674     args[0] = 0;
675 
676     strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
677     strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
678 
679     r = edit->rules = syntax_malloc (MAX_CONTEXTS * sizeof (struct context_rule *));
680 
681     for (;;) {
682 	char **a;
683 	line++;
684 	l = 0;
685 	if (!read_one_line (&l, f)) {
686 	    if (g) {
687 		fclose (f);
688 		f = g;
689 		g = 0;
690 		line = save_line + 1;
691 		syntax_free (error_file_name);
692 		if (l)
693 		    syntax_free (l);
694 		if (!read_one_line (&l, f))
695 		    break;
696 	    } else {
697 		break;
698 	    }
699 	}
700 	get_args (l, args, &argc);
701 	a = args + 1;
702 	if (!args[0]) {
703 	    /* do nothing */
704 	} else if (!strcmp (args[0], "include")) {
705 	    if (g || argc != 2) {
706 		result = line;
707 		break;
708 	    }
709 	    g = f;
710 	    f = open_include_file (args[1]);
711 	    if (!f) {
712 		syntax_free (error_file_name);
713 		result = line;
714 		break;
715 	    }
716 	    save_line = line;
717 	    line = 0;
718 	} else if (!strcmp (args[0], "wholechars")) {
719 	    check_a;
720 	    if (!strcmp (*a, "left")) {
721 		a++;
722 		strcpy (whole_left, *a);
723 	    } else if (!strcmp (*a, "right")) {
724 		a++;
725 		strcpy (whole_right, *a);
726 	    } else {
727 		strcpy (whole_left, *a);
728 		strcpy (whole_right, *a);
729 	    }
730 	    a++;
731 	    check_not_a;
732 	} else if (!strcmp (args[0], "context")) {
733 	    check_a;
734 	    if (num_contexts == -1) {
735 		if (strcmp (*a, "default")) {	/* first context is the default */
736 		    *a = 0;
737 		    check_a;
738 		}
739 		a++;
740 		c = r[0] = syntax_malloc (sizeof (struct context_rule));
741 		c->left = (char *) strdup (" ");
742 		c->right = (char *) strdup (" ");
743 		num_contexts = 0;
744 	    } else {
745 		c = r[num_contexts] = syntax_malloc (sizeof (struct context_rule));
746 		if (!strcmp (*a, "exclusive")) {
747 		    a++;
748 		    c->between_delimiters = 1;
749 		}
750 		check_a;
751 		if (!strcmp (*a, "whole")) {
752 		    a++;
753 		    c->whole_word_chars_left = (char *) strdup (whole_left);
754 		    c->whole_word_chars_right = (char *) strdup (whole_right);
755 		} else if (!strcmp (*a, "wholeleft")) {
756 		    a++;
757 		    c->whole_word_chars_left = (char *) strdup (whole_left);
758 		} else if (!strcmp (*a, "wholeright")) {
759 		    a++;
760 		    c->whole_word_chars_right = (char *) strdup (whole_right);
761 		}
762 		check_a;
763 		if (!strcmp (*a, "linestart")) {
764 		    a++;
765 		    c->line_start_left = 1;
766 		}
767 		check_a;
768 		c->left = (char *) strdup (*a++);
769 		check_a;
770 		if (!strcmp (*a, "linestart")) {
771 		    a++;
772 		    c->line_start_right = 1;
773 		}
774 		check_a;
775 		c->right = (char *) strdup (*a++);
776 		c->first_left = *c->left;
777 		c->first_right = *c->right;
778 		c->single_char = (strlen (c->right) == 1);
779 	    }
780 	    c->keyword = syntax_malloc (MAX_WORDS_PER_CONTEXT * sizeof (struct key_word *));
781 #if 0
782 	    c->max_words = MAX_WORDS_PER_CONTEXT;
783 #endif
784 	    num_words = 1;
785 	    c->keyword[0] = syntax_malloc (sizeof (struct key_word));
786 	    fg = *a;
787 	    if (*a)
788 		a++;
789 	    bg = *a;
790 	    if (*a)
791 		a++;
792 	    strcpy (last_fg, fg ? fg : "");
793 	    strcpy (last_bg, bg ? bg : "");
794 #ifdef MIDNIGHT
795 	    c->keyword[0]->fg = this_try_alloc_color_pair (fg, bg);
796 #else
797 	    c->keyword[0]->fg = this_allocate_color (edit, fg);
798 	    c->keyword[0]->bg = this_allocate_color (edit, bg);
799 #endif
800 	    c->keyword[0]->keyword = (char *) strdup (" ");
801 	    check_not_a;
802 	    num_contexts++;
803 	} else if (!strcmp (args[0], "spellcheck")) {
804 	    if (!c) {
805 		result = line;
806 		break;
807 	    }
808 	    c->spelling = 1;
809 	} else if (!strcmp (args[0], "keyword")) {
810 	    struct key_word *k;
811 	    if (num_words == -1)
812 		*a = 0;
813 	    check_a;
814 	    k = r[num_contexts - 1]->keyword[num_words] = syntax_malloc (sizeof (struct key_word));
815 	    if (!strcmp (*a, "whole")) {
816 		a++;
817 		k->whole_word_chars_left = (char *) strdup (whole_left);
818 		k->whole_word_chars_right = (char *) strdup (whole_right);
819 	    } else if (!strcmp (*a, "wholeleft")) {
820 		a++;
821 		k->whole_word_chars_left = (char *) strdup (whole_left);
822 	    } else if (!strcmp (*a, "wholeright")) {
823 		a++;
824 		k->whole_word_chars_right = (char *) strdup (whole_right);
825 	    }
826 	    check_a;
827 	    if (!strcmp (*a, "linestart")) {
828 		a++;
829 		k->line_start = 1;
830 	    }
831 	    check_a;
832 	    if (!strcmp (*a, "whole")) {
833 		*a = 0;
834 		check_a;
835 	    }
836 	    k->keyword = (char *) strdup (*a++);
837 	    k->first = *k->keyword;
838 	    fg = *a;
839 	    if (*a)
840 		a++;
841 	    bg = *a;
842 	    if (*a)
843 		a++;
844 	    if (!fg)
845 		fg = last_fg;
846 	    if (!bg)
847 		bg = last_bg;
848 #ifdef MIDNIGHT
849 	    k->fg = this_try_alloc_color_pair (fg, bg);
850 #else
851 	    k->fg = this_allocate_color (edit, fg);
852 	    k->bg = this_allocate_color (edit, bg);
853 #endif
854 	    check_not_a;
855 	    num_words++;
856 	} else if (!strncmp (args[0], "#", 1)) {
857 	    /* do nothing for comment */
858 	} else if (!strcmp (args[0], "file")) {
859 	    break;
860 	} else {		/* anything else is an error */
861 	    *a = 0;
862 	    check_a;
863 	}
864 	free_args (args);
865 	syntax_free (l);
866     }
867     free_args (args);
868     syntax_free (l);
869 
870     if (!edit->rules[0])
871 	syntax_free (edit->rules);
872 
873     if (result)
874 	return result;
875 
876     if (num_contexts == -1) {
877 	result = line;
878 	return result;
879     }
880 
881     {
882 	char first_chars[MAX_WORDS_PER_CONTEXT + 2], *p;
883 	for (i = 0; edit->rules[i]; i++) {
884 	    c = edit->rules[i];
885 	    p = first_chars;
886 	    *p++ = (char) 1;
887 	    for (j = 1; c->keyword[j]; j++)
888 		*p++ = c->keyword[j]->first;
889 	    *p = '\0';
890 	    c->keyword_first_chars = syntax_malloc (strlen (first_chars) + 2);
891 	    strcpy (c->keyword_first_chars, first_chars);
892 	}
893     }
894 
895     return result;
896 }
897 
898 #if !defined (GTK) && !defined (MIDNIGHT)
899 
900 /* strdup and append c */
strdupc(char * s,int c)901 static char *strdupc (char *s, int c)
902 {
903     char *t;
904     int l;
905     strcpy (t = syntax_malloc ((l = strlen (s)) + 3), s);
906     t[l] = c;
907     t[l + 1] = '\0';
908     return t;
909 }
910 
edit_syntax_clear_keyword(WEdit * edit,int context,int j)911 static void edit_syntax_clear_keyword (WEdit * edit, int context, int j)
912 {
913     int k;
914     char *q;
915     struct context_rule *c;
916     struct _syntax_marker *s;
917     c = edit->rules[context];
918 /* first we clear any instances of this keyword in our cache chain (we used to just clear the cache chain, but this slows things down) */
919     for (s = edit->syntax_marker; s; s = s->next)
920 	if (s->rule.keyword == j)
921 	    s->rule.keyword = 0;
922 	else if (s->rule.keyword > j)
923 	    s->rule.keyword--;
924     syntax_free (c->keyword[j]->keyword);
925     syntax_free (c->keyword[j]->whole_word_chars_left);
926     syntax_free (c->keyword[j]->whole_word_chars_right);
927     syntax_free (c->keyword[j]);
928 #if 1
929     for (k = j; k < MAX_WORDS_PER_CONTEXT - 1; k++)
930         c->keyword[k] = c->keyword[k + 1];
931     for (q = &c->keyword_first_chars[j]; *q; q++)
932         *q = *(q + 1);
933 #else
934     memcpy (&c->keyword[j], &c->keyword[j + 1], (MAX_WORDS_PER_CONTEXT - j - 1) * sizeof (struct keyword *)); /* valgrind warning 'Source and destination overlap' */
935     strcpy (&c->keyword_first_chars[j], &c->keyword_first_chars[j + 1]);        /* valgrind warning 'Source and destination overlap' */
936 #endif
937 }
938 
939 
940 FILE *spelling_pipe_in = 0;
941 FILE *spelling_pipe_out = 0;
942 pid_t ispell_pid = 0;
943 
944 
945 /* adds a keyword for underlining into the keyword list for this context, returns 1 if too many words */
edit_syntax_add_keyword(WEdit * edit,char * keyword,int context,time_t t)946 static int edit_syntax_add_keyword (WEdit * edit, char *keyword, int context, time_t t)
947 {
948     int j;
949     char *s;
950     struct context_rule *c;
951     c = edit->rules[context];
952     for (j = 1; c->keyword[j]; j++) {
953 /* if a keyword has been around for more than TRANSIENT_WORD_TIME_OUT
954    seconds, then remove it - we don't want to run out of space or makes syntax highlighting to slow */
955 	if (c->keyword[j]->time) {
956 	    if (c->keyword[j]->time + TRANSIENT_WORD_TIME_OUT < t) {
957 		edit->force |= REDRAW_PAGE;
958 		edit_syntax_clear_keyword (edit, context, j);
959 		j--;
960 	    }
961 	}
962     }
963 /* are we out of space? */
964     if (j >= MAX_WORDS_PER_CONTEXT - 2)
965 	return 1;
966 /* add the new keyword and date it */
967     c->keyword[j + 1] = 0;
968     c->keyword[j] = syntax_malloc (sizeof (struct key_word));
969 #ifdef MIDNIGHT
970     c->keyword[j]->fg = SPELLING_ERROR;
971 #else
972     c->keyword[j]->fg = c->keyword[0]->fg;
973     c->keyword[j]->bg = SPELLING_ERROR;
974 #endif
975     c->keyword[j]->keyword = (char *) strdup (keyword);
976     c->keyword[j]->first = *c->keyword[j]->keyword;
977     c->keyword[j]->whole_word_chars_left = (char *) strdup ("--abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ����������������������������������������������������������������������������������������������������");
978     c->keyword[j]->whole_word_chars_right = (char *) strdup ("--abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ����������������������������������������������������������������������������������������������������");
979     c->keyword[j]->whole_word_chars_left[0] = (c->first_left == '\'' ? '-' : '\'');
980     c->keyword[j]->whole_word_chars_right[0] = (c->first_right == '\'' ? '-' : '\'');
981     c->keyword[j]->time = t;
982     s = strdupc (c->keyword_first_chars, c->keyword[j]->first);
983     syntax_free (c->keyword_first_chars);
984     c->keyword_first_chars = s;
985     return 0;
986 }
987 
988 /* checks spelling of the word at offset */
edit_check_spelling_at(WEdit * edit,long byte_index)989 static int edit_check_spelling_at (WEdit * edit, long byte_index)
990 {
991     int context;
992     long p1, p2;
993     unsigned char *p, *q;
994     int r, c1, c2, j;
995     int ch;
996     time_t t;
997     struct context_rule *c;
998 /* sanity check */
999     if (!edit->rules || byte_index > edit->last_byte)
1000 	return 0;
1001 /* in what context are we */
1002     context = edit_get_rule (edit, byte_index).context;
1003     c = edit->rules[context];
1004 /* does this context have `spellcheck' */
1005     if (!edit->rules[context]->spelling)
1006 	return 0;
1007 /* find word start */
1008     for (p1 = byte_index - 1;; p1--) {
1009 	ch = edit_get_byte (edit, p1);
1010 	if (isalpha (ch))
1011 	    continue;
1012         if (ch == c->first_left)
1013 	    break;
1014 	if (ch == '-' || ch == '\'')
1015 	    continue;
1016 	break;
1017     }
1018     p1++;
1019 /* find word end */
1020     for (p2 = byte_index;; p2++) {
1021 	ch = edit_get_byte (edit, p2);
1022 	if (isalpha (ch))
1023 	    continue;
1024         if (ch == c->first_right)
1025 	    break;
1026 	if (ch == '-' || ch == '\'')
1027 	    continue;
1028 	break;
1029     }
1030     if (p2 <= p1)
1031 	return 0;
1032 /* create string */
1033     q = p = syntax_malloc (p2 - p1 + 2);
1034     for (; p1 < p2; p1++)
1035 	*p++ = edit_get_byte (edit, p1);
1036     *p = '\0';
1037     if (q[0] == '-' || strlen ((char *) q) > 40) {	/* if you are using words over 40 characters, you are on your own */
1038 	syntax_free (q);
1039 	return 0;
1040     }
1041     time (&t);
1042     for (j = 1; c->keyword[j]; j++) {
1043 /* if the keyword is present, then update its time only. if it is a fixed keyword from the rules file, then just return */
1044 	if (!strcmp (c->keyword[j]->keyword, (char *) q)) {
1045 	    if (c->keyword[j]->time)
1046 		c->keyword[j]->time = t;
1047 	    syntax_free (q);
1048 	    return 0;
1049 	}
1050     }
1051 /* feed it to ispell */
1052     fprintf (spelling_pipe_out, "%s\n", (char *) q);
1053     fflush (spelling_pipe_out);
1054 /* what does ispell say? */
1055     do {
1056 	r = fgetc (spelling_pipe_in);
1057     } while (r == -1 && errno == EINTR);
1058     if (r == -1) {
1059 	syntax_free (q);
1060 	return 1;
1061     }
1062     if (r == '\n') {		/* ispell sometimes returns just blank line if it is given bad characters */
1063 	syntax_free (q);
1064 	return 0;
1065     }
1066 /* now read ispell output untill we get two blanks lines - we are not intersted in this part */
1067     do {
1068 	c1 = fgetc (spelling_pipe_in);
1069     } while (c1 == -1 && errno == EINTR);
1070     for (;;) {
1071 	if (c1 == -1) {
1072 	    syntax_free (q);
1073 	    return 1;
1074 	}
1075 	do {
1076 	    c2 = fgetc (spelling_pipe_in);
1077 	} while (c2 == -1 && errno == EINTR);
1078 	if (c1 == '\n' && c2 == '\n')
1079 	    break;
1080 	c1 = c2;
1081     }
1082 /* spelled ok */
1083     if (r == '*' || r == '+' || r == '-') {
1084 	syntax_free (q);
1085 	return 0;
1086     }
1087 /* not spelled ok - so add a syntax keyword for this word */
1088     edit_syntax_add_keyword (edit, (char *) q, context, t);
1089     syntax_free (q);
1090     return 0;
1091 }
1092 
1093 char *option_alternate_dictionary = "";
1094 
1095 int PATH_search (const char *file);
1096 
edit_check_spelling(WEdit * edit)1097 int edit_check_spelling (WEdit * edit)
1098 {
1099     if (!option_auto_spellcheck)
1100 	return 0;
1101 /* magic arg to close up shop */
1102     if (!edit) {
1103 	option_auto_spellcheck = 0;
1104 	goto close_spelling;
1105     }
1106 /* do we at least have a syntax rule struct to put new wrongly spelled keyword in for highlighting? */
1107     if (!edit->rules && !edit->explicit_syntax)
1108 	edit_load_syntax (edit, 0, UNKNOWN_FORMAT);
1109     if (!edit->rules) {
1110 	option_auto_spellcheck = 0;
1111 	return 0;
1112     }
1113 /* is ispell running? */
1114     if (!spelling_pipe_in) {
1115 	int in, out, a = 0;
1116 	char *arg[20];
1117 	if (PATH_search ("aspell")) {
1118 	    arg[a++] = "aspell";
1119 	    arg[a++] = "--sug-mode=ultra";
1120 	    if (option_alternate_dictionary && *option_alternate_dictionary) {
1121 		arg[a++] = "-d";
1122 		arg[a++] = option_alternate_dictionary;
1123 	    }
1124 	    arg[a++] = "-a";
1125 	    arg[a++] = 0;
1126 	} else {
1127 	    arg[a++] = "ispell";
1128 	    arg[a++] = "-a";
1129 	    if (option_alternate_dictionary && *option_alternate_dictionary) {
1130 		arg[a++] = "-d";
1131 		arg[a++] = option_alternate_dictionary;
1132 	    }
1133 	    arg[a++] = "-a";
1134 	    arg[a++] = 0;
1135 	}
1136 /* start ispell process */
1137 	ispell_pid = triple_pipe_open (&in, &out, 0, 1, arg[0], arg);
1138 	if (ispell_pid < 1 && errno == ENOENT) {	/* ispell not present in the path */
1139 	    static int tries = 0;
1140 	    option_auto_spellcheck = 0;
1141 	    if (++tries >= 2)
1142 		CErrorDialog (0, 0, 0, _(" Spelling Message "), "%s",
1143 			      _
1144 			      (" The ispell (or aspell) program could not be found in your path. \n Check that it is in your path and works with the -a option. "));
1145 	    return 1;
1146 	}
1147 	if (ispell_pid < 1) {
1148 	    option_auto_spellcheck = 0;
1149 	    CErrorDialog (0, 0, 0, _(" Spelling Message "), "%s",
1150 			  _
1151 			  (" Fail trying to open ispell (or aspell) program. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
1152 	    return 1;
1153 	}
1154 /* prepare pipes */
1155 	spelling_pipe_in = (FILE *) fdopen (out, "r");
1156 	spelling_pipe_out = (FILE *) fdopen (in, "w");
1157 	if (!spelling_pipe_in || !spelling_pipe_out) {
1158 	    option_auto_spellcheck = 0;
1159 	    CErrorDialog (0, 0, 0, _(" Spelling Message "), "%s",
1160 			  _
1161 			  (" Fail trying to open ispell (or aspell) pipes. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
1162 	    return 1;
1163 	}
1164 /* read the banner message */
1165 	for (;;) {
1166 	    int c1;
1167 	    c1 = fgetc (spelling_pipe_in);
1168 	    if (c1 == -1 && errno != EINTR) {
1169 		option_auto_spellcheck = 0;
1170 		CErrorDialog (0, 0, 0, _(" Spelling Message "), "%s",
1171 			      _
1172 			      (" Fail trying to read ispell (or aspell) pipes. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
1173 		return 1;
1174 	    }
1175 	    if (c1 == '\n')
1176 		break;
1177 	}
1178     }
1179 /* spellcheck the word under the cursor */
1180     if (edit_check_spelling_at (edit, edit->curs1)) {
1181 	CMessageDialog (0, 0, 0, 0, _(" Spelling Message "), "%s",
1182 			_(" Error reading from ispell (or aspell). \n Ispell is being restarted. "));
1183       close_spelling:
1184 	fclose (spelling_pipe_in);
1185 	spelling_pipe_in = 0;
1186 	fclose (spelling_pipe_out);
1187 	spelling_pipe_out = 0;
1188 	kill (ispell_pid, SIGKILL);
1189     }
1190     return 0;
1191 }
1192 
1193 #else				/* ! GTK && ! MIDNIGHT*/
1194 
edit_check_spelling(WEdit * edit)1195 int edit_check_spelling (WEdit * edit)
1196 {
1197     return 0;
1198 }
1199 
1200 #endif
1201 
1202 void (*syntax_change_callback) (CWidget *) = 0;
1203 
edit_set_syntax_change_callback(void (* callback)(CWidget *))1204 void edit_set_syntax_change_callback (void (*callback) (CWidget *))
1205 {
1206     syntax_change_callback = callback;
1207 }
1208 
edit_free_syntax_rules(WEdit * edit)1209 void edit_free_syntax_rules (WEdit * edit)
1210 {
1211     int i, j;
1212     if (!edit)
1213 	return;
1214     if (!edit->rules)
1215 	return;
1216     edit_get_rule (edit, -1);
1217     syntax_free (edit->syntax_type);
1218     edit->syntax_type = 0;
1219     if (syntax_change_callback)
1220 #ifdef MIDNIGHT
1221 	(*syntax_change_callback) (&edit->widget);
1222 #else
1223 	(*syntax_change_callback) (edit->widget);
1224 #endif
1225     for (i = 0; edit->rules[i]; i++) {
1226 	if (edit->rules[i]->keyword) {
1227 	    for (j = 0; edit->rules[i]->keyword[j]; j++) {
1228 		syntax_free (edit->rules[i]->keyword[j]->keyword);
1229 		syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_left);
1230 		syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_right);
1231 		syntax_free (edit->rules[i]->keyword[j]);
1232 	    }
1233 	}
1234 	syntax_free (edit->rules[i]->left);
1235 	syntax_free (edit->rules[i]->right);
1236 	syntax_free (edit->rules[i]->whole_word_chars_left);
1237 	syntax_free (edit->rules[i]->whole_word_chars_right);
1238 	syntax_free (edit->rules[i]->keyword);
1239 	syntax_free (edit->rules[i]->keyword_first_chars);
1240 	syntax_free (edit->rules[i]);
1241     }
1242     for (;;) {
1243 	struct _syntax_marker *s;
1244 	if (!edit->syntax_marker)
1245 	    break;
1246 	s = edit->syntax_marker->next;
1247 	syntax_free (edit->syntax_marker);
1248 	edit->syntax_marker = s;
1249     }
1250     syntax_free (edit->rules);
1251 }
1252 
1253 #define CURRENT_SYNTAX_RULES_VERSION "72"
1254 
1255 char *syntax_text[] = {
1256 "# syntax rules version " CURRENT_SYNTAX_RULES_VERSION,
1257 "# (after the slash is a Cooledit color, 0-26 or any of the X colors in rgb.txt)",
1258 "# black",
1259 "# red",
1260 "# green",
1261 "# brown",
1262 "# blue",
1263 "# magenta",
1264 "# cyan",
1265 "# lightgray",
1266 "# gray",
1267 "# brightred",
1268 "# brightgreen",
1269 "# yellow",
1270 "# brightblue",
1271 "# brightmagenta",
1272 "# brightcyan",
1273 "# white",
1274 "",
1275 "file gobledy_gook #\\sHelp\\ssupport\\sother\\sfile\\stypes",
1276 "context default",
1277 "file gobledy_gook #\\sby\\scoding\\srules\\sin\\s~/.cedit/syntax.",
1278 "context default",
1279 "file gobledy_gook #\\sSee\\sman/syntax\\sin\\sthe\\ssource\\sdistribution",
1280 "context default",
1281 "file gobledy_gook #\\sand\\sconsult\\sthe\\sman\\spage.",
1282 "context default",
1283 "",
1284 "",
1285 "file ..\\*\\\\.(diff|rej|patch)$ Diff\\sOutput ^diff",
1286 "include diff.syntax",
1287 "",
1288 "file ..\\*\\\\.lsm$ LSM\\sFile\\sVersion\\s4 ^Begin4",
1289 "include lsm4.syntax",
1290 "",
1291 "file ..\\*\\\\.lsm$ LSM\\sFile\\sVersion\\s3 ^Begin3",
1292 "include lsm.syntax",
1293 "",
1294 "file ..\\*\\\\.sh$ Shell\\sScript ^#!(\\s|)\\*/.\\*/(ksh|bash|sh|pdkzsh)",
1295 "include sh.syntax",
1296 "",
1297 "file ..\\*\\\\.(pl|PL)$ Perl\\sProgram ^#!(\\s|)\\*/.\\*/perl",
1298 "include perl.syntax",
1299 "",
1300 "file ..\\*\\\\.(py|PY)$ Python\\sProgram ^#!(\\s|)\\*/.\\*/python",
1301 "include python.syntax",
1302 "",
1303 "file ..\\*\\\\.(man|[0-9n]|[0-9]x)$ NROFF\\sMan\\sPage ^(.\\\"\\s|.de\\s|.ds\\s|.\"Generated\\sby\\sdb2man.xsl|...\\\"\\s$Header|.so\\sman|.TH\\s)",
1304 "include nroff.syntax",
1305 "",
1306 "file ..\\*\\\\.(htm|html|HTM|HTML)$ HTML\\sFile",
1307 "include html.syntax",
1308 "",
1309 "file ..\\*\\\\.(pp|PP|pas|PAS)$ Pascal\\sProgram",
1310 "include pascal.syntax",
1311 "",
1312 "file ..\\*\\\\.(ada|adb|ADA|ADB)$ Ada\\sProgram",
1313 "include ada95.syntax",
1314 "",
1315 "file ..\\*\\\\.tex$ LaTeX\\s2e\\sDocument",
1316 "include latex.syntax",
1317 "",
1318 "file ..\\*\\.(texi|texinfo|TEXI|TEXINFO)$ Texinfo\\sDocument",
1319 "include texinfo.syntax",
1320 "",
1321 "file ..\\*\\\\.([chC]|CC|cxx|cc|cpp|CPP|CXX)$ C/C\\+\\+\\sProgram",
1322 "include c.syntax",
1323 "",
1324 "file ..\\*\\\\.[fF]$ Fortran\\sProgram",
1325 "include fortran.syntax",
1326 "",
1327 "file ..\\*\\\\.i$ SWIG\\sSource",
1328 "include swig.syntax",
1329 "",
1330 "file ..\\*\\\\.php[0-9]$ PHP\\sProgram",
1331 "include php.syntax",
1332 "",
1333 "file ..\\*\\\\.(java|JAVA|Java|jav)$ Java\\sProgram",
1334 "include java.syntax",
1335 "",
1336 "file ..\\*\\\\.js$ Java\\sScript ^^#!(\\s|)\\*/.\\*/node$",
1337 "include js.syntax",
1338 "",
1339 "file ..\\*\\\\.(st)$ SmallTalk\\sProgram",
1340 "include smalltalk.syntax",
1341 "",
1342 "file ..\\*\\\\.(ml|mli|mly|mll|mlp)$ ML\\sProgram",
1343 "include ml.syntax",
1344 "",
1345 "file ..\\*\\\\.(ly|fly|sly)$ Lilypond\\sSource",
1346 "include mudela.syntax",
1347 "",
1348 "file .\\*ChangeLog$ GNU\\sDistribution\\sChangeLog\\sFile",
1349 "include changelog.syntax",
1350 "",
1351 "file .\\*Makefile[\\\\\\.a-z]\\*$ Makefile",
1352 "include makefile.syntax",
1353 "",
1354 "file ..\\*\\\\.(bap|bp2|bp3|bpp|bpe|lib|l32)$ BAssPasC\\sProgram",
1355 "include bapc.syntax",
1356 "",
1357 "file ..\\*\\\\.(mhtml|mac)$ Macro-HTML\\sSource",
1358 "include mhtml.syntax",
1359 "",
1360 "file ..\\*\\\\.(jasm|JASM)$ Java\\sAssembly",
1361 "include jasm.syntax",
1362 "",
1363 "file ..\\*\\\\.(lua|LUA)$ LUA\\sSource",
1364 "include lua.syntax",
1365 "",
1366 "file ..\\*\\\\.(p|P)$ Prolog\\sProgram",
1367 "include prolog.syntax",
1368 "",
1369 "file ..\\*\\\\.(xml|XML)$ XML\\sFile <?xml",
1370 "include xml.syntax",
1371 "",
1372 "file ..\\*\\\\.(css|CSS)$ CSS\\sFile <?xml",
1373 "include css.syntax",
1374 "",
1375 "file ..\\*\\\\.(sql|SQL)$ SQL\\sFile",
1376 "include sql.syntax",
1377 "",
1378 "file ..\\*\\\\.(scm|SCM)$ Gimp\\sScript-Fu",
1379 "include scm.syntax",
1380 "",
1381 "file Don_t_match_me Mail\\sfolder ^From\\s",
1382 "include mail.syntax",
1383 "",
1384 "file .\\*syntax$ Syntax\\sHighlighting\\sdefinitions",
1385 "",
1386 "context default",
1387 "    keyword whole spellch\\eck yellow/24",
1388 "    keyword whole keyw\\ord yellow/24",
1389 "    keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17",
1390 "    keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17",
1391 "    keyword whole wh\\oleleft\\[\\t\\s\\]l\\inestart brightcyan/17",
1392 "    keyword whole wh\\oleright\\[\\t\\s\\]l\\inestart brightcyan/17",
1393 "    keyword whole l\\inestart\\[\\t\\s\\]wh\\ole",
1394 "    keyword whole l\\inestart\\[\\t\\s\\]wh\\ole",
1395 "    keyword whole l\\inestart\\[\\t\\s\\]wh\\oleleft",
1396 "    keyword whole l\\inestart\\[\\t\\s\\]wh\\oleright",
1397 "    keyword wholeleft whole\\s brightcyan/17",
1398 "    keyword wholeleft whole\\t brightcyan/17",
1399 "    keyword whole wh\\oleleft brightcyan/17",
1400 "    keyword whole wh\\oleright brightcyan/17",
1401 "    keyword whole lin\\[e\\]start brightcyan/17",
1402 "    keyword whole c\\ontext\\[\\t\\s\\]exclusive brightred/18",
1403 "    keyword whole c\\ontext\\[\\t\\s\\]default brightred/18",
1404 "    keyword whole c\\ontext brightred/18",
1405 "    keyword whole wh\\olechars\\[\\t\\s\\]left brightcyan/17",
1406 "    keyword whole wh\\olechars\\[\\t\\s\\]right brightcyan/17",
1407 "    keyword whole wh\\olechars brightcyan/17",
1408 "    keyword whole f\\ile brightgreen/6",
1409 "    keyword whole in\\clude brightred/18",
1410 "",
1411 "    keyword whole 0 lightgray/0	blue/26",
1412 "    keyword whole 1 lightgray/1	blue/26",
1413 "    keyword whole 2 lightgray/2	blue/26",
1414 "    keyword whole 3 lightgray/3	blue/26",
1415 "    keyword whole 4 lightgray/4	blue/26",
1416 "    keyword whole 5 lightgray/5	blue/26",
1417 "    keyword whole 6 lightgray/6",
1418 "    keyword whole 7 lightgray/7",
1419 "    keyword whole 8 lightgray/8",
1420 "    keyword whole 9 lightgray/9",
1421 "    keyword whole 10 lightgray/10",
1422 "    keyword whole 11 lightgray/11",
1423 "    keyword whole 12 lightgray/12",
1424 "    keyword whole 13 lightgray/13",
1425 "    keyword whole 14 lightgray/14",
1426 "    keyword whole 15 lightgray/15",
1427 "    keyword whole 16 lightgray/16",
1428 "    keyword whole 17 lightgray/17",
1429 "    keyword whole 18 lightgray/18",
1430 "    keyword whole 19 lightgray/19",
1431 "    keyword whole 20 lightgray/20",
1432 "    keyword whole 21 lightgray/21",
1433 "    keyword whole 22 lightgray/22",
1434 "    keyword whole 23 lightgray/23",
1435 "    keyword whole 24 lightgray/24",
1436 "    keyword whole 25 lightgray/25",
1437 "    keyword whole 26 lightgray/26",
1438 "",
1439 "    keyword wholeleft black\\/ black/0",
1440 "    keyword wholeleft red\\/ red/DarkRed",
1441 "    keyword wholeleft green\\/ green/green3",
1442 "    keyword wholeleft brown\\/ brown/saddlebrown",
1443 "    keyword wholeleft blue\\/ blue/blue3",
1444 "    keyword wholeleft magenta\\/ magenta/magenta3",
1445 "    keyword wholeleft cyan\\/ cyan/cyan3",
1446 "    keyword wholeleft lightgray\\/ lightgray/lightgray",
1447 "    keyword wholeleft gray\\/ gray/gray",
1448 "    keyword wholeleft brightred\\/ brightred/red",
1449 "    keyword wholeleft brightgreen\\/ brightgreen/green1",
1450 "    keyword wholeleft yellow\\/ yellow/yellow",
1451 "    keyword wholeleft brightblue\\/ brightblue/blue1",
1452 "    keyword wholeleft brightmagenta\\/ brightmagenta/magenta",
1453 "    keyword wholeleft brightcyan\\/ brightcyan/cyan1",
1454 "    keyword wholeleft white\\/ white/26",
1455 "",
1456 "context linestart # \\n brown/22",
1457 "",
1458 "file .\\* " UNKNOWN_FORMAT,
1459 "include unknown.syntax",
1460 "",
1461 0};
1462 
1463 
upgrade_syntax_file(char * syntax_file)1464 FILE *upgrade_syntax_file (char *syntax_file)
1465 {
1466     FILE *f;
1467     char *p;
1468     char line[80];
1469     f = fopen (syntax_file, "r");
1470     if (!f) {
1471 	char **syntax_line;
1472 	f = fopen (syntax_file, "w");
1473 	if (!f)
1474 	    return 0;
1475 	for (syntax_line = syntax_text; *syntax_line; syntax_line++)
1476 	    fprintf (f, "%s\n", *syntax_line);
1477 	fclose (f);
1478 	return fopen (syntax_file, "r");
1479     }
1480     memset (line, 0, 79);
1481     fread (line, 80, 1, f);
1482     if (!strstr (line, "syntax rules version"))
1483 	goto rename_rule_file;
1484     p = strstr (line, "version") + strlen ("version") + 1;
1485     if (atoi (p) < atoi (CURRENT_SYNTAX_RULES_VERSION)) {
1486 	char s[1024];
1487       rename_rule_file:
1488 	strcpy (s, syntax_file);
1489 	strcat (s, ".OLD");
1490 	unlink (s);
1491 	rename (syntax_file, s);
1492 	unlink (syntax_file);	/* might rename() fail ? */
1493 #if defined(MIDNIGHT) || defined(GTK)
1494 	edit_message_dialog (" Load Syntax Rules ", " Your syntax rule file is outdated \n A new rule file is being installed. \n Your old rule file has been saved with a .OLD extension. ");
1495 #else
1496 	CMessageDialog (0, 20, 20, 0, " Load Syntax Rules ", " Your syntax rule file is outdated \n A new rule file is being installed. \n Your old rule file has been saved with a .OLD extension. ");
1497 #endif
1498 	return upgrade_syntax_file (syntax_file);
1499     }
1500     rewind (f);
1501     return f;
1502 }
1503 
apply_syntax_rules(WEdit * edit,FILE * f,int line,char * syntax_type)1504 static int apply_syntax_rules (WEdit * edit, FILE * f, int line, char *syntax_type)
1505 {
1506     int line_error, result = 0;
1507     line_error = edit_read_syntax_rules (edit, f);
1508     if (line_error) {
1509 	if (!error_file_name)	/* an included file */
1510 	    result = line + line_error;
1511 	else
1512 	    result = line_error;
1513     } else {
1514 	syntax_free (edit->syntax_type);
1515 	edit->syntax_type = (char *) strdup (syntax_type);
1516 /* if there are no rules then turn off syntax highlighting for speed */
1517 	if (!edit->rules[1])
1518 	    if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling) {
1519 		edit_free_syntax_rules (edit);
1520 		return result;
1521 	    }
1522 /* notify the callback of a change in rule set */
1523 	if (syntax_change_callback)
1524 #ifdef MIDNIGHT
1525 	    (*syntax_change_callback) (&edit->widget);
1526 #else
1527 	    (*syntax_change_callback) (edit->widget);
1528 #endif
1529     }
1530     return result;
1531 }
1532 
1533 /* returns -1 on file error, line number on error in file syntax */
edit_read_syntax_file(WEdit * edit,char ** names,char * syntax_file,char * editor_file,char * first_line,char * type)1534 static int edit_read_syntax_file (WEdit * edit, char **names, char *syntax_file, char *editor_file,
1535 				  char *first_line, char *type)
1536 {
1537     FILE *f;
1538     regex_t r;
1539     regmatch_t pmatch[1];
1540     char *args[1024], *l = 0;
1541     int line = 0;
1542     int argc;
1543     int result = 0;
1544     int count = 0;
1545     int max_score = 0;
1546     long offset_at_max_score = 0;
1547     char *syntax_type = NULL;
1548     f = upgrade_syntax_file (syntax_file);
1549     if (!f)
1550 	return -1;
1551     args[0] = 0;
1552     for (;;) {
1553 	line++;
1554 	syntax_free (l);
1555 	if (!read_one_line (&l, f))
1556 	    break;
1557 	get_args (l, args, &argc);
1558 	if (!args[0])
1559 	    continue;
1560 /* looking for `file ...' lines only */
1561 	if (strcmp (args[0], "file")) {
1562 	    free_args (args);
1563 	    continue;
1564 	}
1565 /* must have two args or report error */
1566 	if (!args[1] || !args[2]) {
1567 	    result = line;
1568 	    break;
1569 	}
1570 	if (names) {
1571 /* 1: just collecting a list of names of rule sets */
1572 	    names[count++] = (char *) strdup (args[2]);
1573 	    names[count] = 0;
1574 	} else if (type) {
1575 /* 2: rule set was explicitly specified by the caller */
1576 	    if (!strcmp (type, args[2])) {
1577 		result = apply_syntax_rules (edit, f, line, args[2]);
1578 		break;
1579 	    }
1580 	} else if (editor_file && edit) {
1581 /* 3: auto-detect rule set from regular expressions */
1582 	    int q = 0;
1583 	    memset (&r, '\0', sizeof (r));
1584 	    if (regcomp (&r, args[1], REG_EXTENDED)) {
1585 		result = line;
1586 		break;
1587 	    }
1588 /* does filename match arg 1 ? */
1589 	    q = !regexec (&r, editor_file, 1, pmatch, 0);
1590 	    regfree (&r);
1591 	    if (args[3]) {
1592 		memset (&r, '\0', sizeof (r));
1593 		if (regcomp (&r, args[3], REG_EXTENDED)) {
1594 		    result = line;
1595 		    break;
1596 		}
1597 /* does first line match arg 3 ? */
1598 		q += (!regexec (&r, first_line, 1, pmatch, 0));
1599 		regfree (&r);
1600 	    }
1601 	    if (q > max_score) {
1602 		max_score = q;
1603 		offset_at_max_score = ftell (f);
1604 		syntax_type = (char *) strdup ((char *) args[2]);
1605 	    }
1606 	}
1607 	free_args (args);
1608     }
1609     if (editor_file && edit)
1610 	if (!result && max_score) {
1611 	    fseek (f, offset_at_max_score, 0);
1612 	    result = apply_syntax_rules (edit, f, line, syntax_type);
1613 	}
1614     if (syntax_type)
1615 	free (syntax_type);
1616     free_args (args);
1617     syntax_free (l);
1618     fclose (f);
1619     return result;
1620 }
1621 
get_first_editor_line(WEdit * edit)1622 static char *get_first_editor_line (WEdit * edit)
1623 {
1624     int i;
1625     static char s[256];
1626     s[0] = '\0';
1627     if (!edit)
1628 	return s;
1629     for (i = 0; i < 255; i++) {
1630 	s[i] = edit_get_byte (edit, i);
1631 	if (s[i] == '\n') {
1632 	    s[i] = '\0';
1633 	    break;
1634 	}
1635     }
1636     s[255] = '\0';
1637     return s;
1638 }
1639 
1640 /* loads rules into edit struct. one of edit or names must be zero. if
1641    edit is zero, a list of types will be stored into name. type may be zero
1642    in which case the type will be selected according to the filename. */
edit_load_syntax(WEdit * edit,char ** names,char * type)1643 void edit_load_syntax (WEdit * edit, char **names, char *type)
1644 {
1645     int r;
1646     char *f;
1647 
1648     edit_free_syntax_rules (edit);
1649 
1650 #ifdef MIDNIGHT
1651     if (!SLtt_Use_Ansi_Colors || !use_colors)
1652 	return;
1653 #endif
1654 
1655     if (edit) {
1656 	if (!edit->filename)
1657 	    return;
1658 	if (!*edit->filename && !type)
1659 	    return;
1660     }
1661     f = catstrs (home_dir, SYNTAX_FILE, NULL);
1662     CDisableAlarm();
1663     r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0, get_first_editor_line (edit), type);
1664     CEnableAlarm();
1665     if (r == -1) {
1666 	edit_free_syntax_rules (edit);
1667 	edit_error_dialog (_ (" Load syntax file "), _ (" File access error "));
1668 	return;
1669     }
1670     if (r) {
1671 	char s[80];
1672 	edit_free_syntax_rules (edit);
1673 	sprintf (s, _ (" Error in file %s on line %d "), error_file_name ? error_file_name : f, r);
1674 	edit_error_dialog (_ (" Load syntax file "), s);
1675 	syntax_free (error_file_name);
1676 	return;
1677     }
1678 }
1679 
1680 #else
1681 
1682 int option_syntax_highlighting = 0;
1683 
edit_load_syntax(WEdit * edit,char ** names,char * type)1684 void edit_load_syntax (WEdit * edit, char **names, char *type)
1685 {
1686     return;
1687 }
1688 
edit_free_syntax_rules(WEdit * edit)1689 void edit_free_syntax_rules (WEdit * edit)
1690 {
1691     return;
1692 }
1693 
edit_get_syntax_color(WEdit * edit,long byte_index,int * fg,int * bg)1694 void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
1695 {
1696     *fg = NORMAL_COLOR;
1697 }
1698 
1699 #endif		/* !defined(MIDNIGHT) || defined(HAVE_SYNTAXH) */
1700 
1701 
1702 
1703