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