Codepage messages related translated & other stuff...
[midnight-commander.git] / gtkedit / syntax.c
blob3ae71d933ec82bd00c1ef6e4ee334d463d1ceadd
1 /* editor syntax highlighting.
3 Copyright (C) 1996, 1997, 1998 the Free Software Foundation
5 Authors: 1998 Paul Sheer
7 $Id$
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 02111-1307, USA.
25 #include <config.h>
26 #if defined(MIDNIGHT) || defined(GTK)
27 #include "edit.h"
28 #else
29 #include "coolwidget.h"
30 #endif
31 #if defined (HAVE_MAD) && ! defined (MIDNIGHT) && ! defined (GTK)
32 #include "mad.h"
33 #endif
35 /* bytes */
36 #define SYNTAX_MARKER_DENSITY 512
39 Mispelled words are flushed from the syntax highlighting rules
40 when they have been around longer than
41 TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
42 chars per second and say 3 chars + a space per word, we can
43 accumulate 450 words absolute max with a value of 60. This is
44 below this limit of 1024 words in a context.
46 #define TRANSIENT_WORD_TIME_OUT 60
48 #define UNKNOWN_FORMAT "unknown"
50 #if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH)
52 int option_syntax_highlighting = 1;
53 int option_auto_spellcheck = 1;
55 /* these three functions are called from the outside */
56 void edit_load_syntax (WEdit * edit, char **names, char *type);
57 void edit_free_syntax_rules (WEdit * edit);
58 void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg);
60 #ifdef HAVE_MAD
61 static void *mad_syntax_malloc (size_t x, char *file, int line)
62 #define syntax_malloc(x) mad_syntax_malloc (x, __FILE__, __LINE__)
63 #else
64 static void *syntax_malloc (size_t x)
65 #endif
67 void *p;
68 #ifdef HAVE_MAD
69 p = mad_alloc (x, file, line);
70 #else
71 p = malloc (x);
72 #endif
73 memset (p, 0, x);
74 return p;
77 #define syntax_free(x) {if(x){free(x);(x)=0;}}
79 static long compare_word_to_right (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start)
81 unsigned char *p, *q;
82 int c, d, j;
83 if (!*text)
84 return -1;
85 c = edit_get_byte (edit, i - 1);
86 if (line_start)
87 if (c != '\n')
88 return -1;
89 if (whole_left)
90 if (strchr (whole_left, c))
91 return -1;
92 for (p = (unsigned char *) text, q = p + strlen ((char *) p); (unsigned long) p < (unsigned long) q; p++, i++) {
93 switch (*p) {
94 case '\001':
95 p++;
96 for (;;) {
97 c = edit_get_byte (edit, i);
98 if (!*p)
99 if (whole_right)
100 if (!strchr (whole_right, c))
101 break;
102 if (c == *p)
103 break;
104 if (c == '\n')
105 return -1;
106 i++;
108 break;
109 case '\002':
110 p++;
111 j = 0;
112 for (;;) {
113 c = edit_get_byte (edit, i);
114 if (c == *p) {
115 j = i;
116 if (*p == *text && !p[1]) /* handle eg '+' and @+@ keywords properly */
117 break;
119 if (j && strchr ((char *) p + 1, c)) /* c exists further down, so it will get matched later */
120 break;
121 if (c == '\n' || c == '\t' || c == ' ') {
122 if (!*p) {
123 i--;
124 break;
126 if (!j)
127 return -1;
128 i = j;
129 break;
131 if (whole_right)
132 if (!strchr (whole_right, c)) {
133 if (!*p) {
134 i--;
135 break;
137 if (!j)
138 return -1;
139 i = j;
140 break;
142 i++;
144 break;
145 case '\003':
146 p++;
147 c = -1;
148 for (;; i++) {
149 d = c;
150 c = edit_get_byte (edit, i);
151 for (j = 0; p[j] != '\003'; j++)
152 if (c == p[j])
153 goto found_char2;
154 break;
155 found_char2:
156 j = c; /* dummy command */
158 i--;
159 while (*p != '\003')
160 p++;
161 if (p[1] == d)
162 i--;
163 break;
164 case '\004':
165 p++;
166 c = edit_get_byte (edit, i);
167 for (; *p != '\004'; p++)
168 if (c == *p)
169 goto found_char3;
170 return -1;
171 found_char3:
172 for (; *p != '\004'; p++);
173 break;
174 default:
175 if (*p != edit_get_byte (edit, i))
176 return -1;
179 if (whole_right)
180 if (strchr (whole_right, edit_get_byte (edit, i)))
181 return -1;
182 return i;
185 #define XXX \
186 if (*s < '\005' || *s == (unsigned char) c) \
187 goto done; \
188 s++;
190 static inline char *xx_strchr (const unsigned char *s, int c)
192 repeat:
193 XXX XXX XXX XXX XXX XXX XXX XXX;
194 XXX XXX XXX XXX XXX XXX XXX XXX;
195 goto repeat;
196 done:
197 return (char *) s;
200 static inline struct syntax_rule apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule)
202 struct context_rule *r;
203 int contextchanged = 0, c;
204 int found_right = 0, found_left = 0, keyword_foundleft = 0, keyword_foundright = 0;
205 int is_end;
206 long end = 0;
207 struct syntax_rule _rule = rule;
208 if (!(c = edit_get_byte (edit, i)))
209 return rule;
210 is_end = (rule.end == (unsigned char) i);
211 /* check to turn off a keyword */
212 if (_rule.keyword) {
213 struct key_word *k;
214 k = edit->rules[_rule.context]->keyword[_rule.keyword];
215 if (edit_get_byte (edit, i - 1) == '\n')
216 _rule.keyword = 0;
217 if (is_end) {
218 _rule.keyword = 0;
219 keyword_foundleft = 1;
222 /* check to turn off a context */
223 if (_rule.context && !_rule.keyword) {
224 long e;
225 r = edit->rules[_rule.context];
226 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) {
227 _rule.end = e;
228 found_right = 1;
229 _rule.border = RULE_ON_RIGHT_BORDER;
230 if (r->between_delimiters)
231 _rule.context = 0;
232 } else if (is_end && rule.border & RULE_ON_RIGHT_BORDER) {
233 /* always turn off a context at 4 */
234 found_left = 1;
235 _rule.border = 0;
236 if (!keyword_foundleft)
237 _rule.context = 0;
238 } else if (is_end && rule.border & RULE_ON_LEFT_BORDER) {
239 /* never turn off a context at 2 */
240 found_left = 1;
241 _rule.border = 0;
244 /* check to turn on a keyword */
245 if (!_rule.keyword) {
246 char *p;
247 p = (r = edit->rules[_rule.context])->keyword_first_chars;
248 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
249 struct key_word *k;
250 int count;
251 long e;
252 count = (unsigned long) p - (unsigned long) r->keyword_first_chars;
253 k = r->keyword[count];
254 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
255 if (e > 0) {
256 end = e;
257 _rule.end = e;
258 _rule.keyword = count;
259 keyword_foundright = 1;
260 break;
264 /* check to turn on a context */
265 if (!_rule.context) {
266 if (!found_left && is_end) {
267 if (rule.border & RULE_ON_RIGHT_BORDER) {
268 _rule.border = 0;
269 _rule.context = 0;
270 contextchanged = 1;
271 _rule.keyword = 0;
272 } else if (rule.border & RULE_ON_LEFT_BORDER) {
273 r = edit->rules[_rule._context];
274 _rule.border = 0;
275 if (r->between_delimiters) {
276 long e;
277 _rule.context = _rule._context;
278 contextchanged = 1;
279 _rule.keyword = 0;
280 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) {
281 _rule.end = e;
282 found_right = 1;
283 _rule.border = RULE_ON_RIGHT_BORDER;
284 _rule.context = 0;
289 if (!found_right) {
290 int count;
291 struct context_rule **rules = edit->rules;
292 for (count = 1; rules[count]; count++) {
293 r = rules[count];
294 if (r->first_left == c) {
295 long e;
296 e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left);
297 if (e >= end && (!_rule.keyword || keyword_foundright)) {
298 _rule.end = e;
299 found_right = 1;
300 _rule.border = RULE_ON_LEFT_BORDER;
301 _rule._context = count;
302 if (!r->between_delimiters)
303 if (!_rule.keyword)
304 _rule.context = count;
305 break;
311 /* check again to turn on a keyword if the context switched */
312 if (contextchanged && !_rule.keyword) {
313 char *p;
314 p = (r = edit->rules[_rule.context])->keyword_first_chars;
315 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
316 struct key_word *k;
317 int count;
318 long e;
319 count = (unsigned long) p - (unsigned long) r->keyword_first_chars;
320 k = r->keyword[count];
321 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
322 if (e > 0) {
323 _rule.end = e;
324 _rule.keyword = count;
325 break;
329 return _rule;
332 static struct syntax_rule edit_get_rule (WEdit * edit, long byte_index)
334 long i;
335 if (byte_index > edit->last_get_rule) {
336 for (i = edit->last_get_rule + 1; i <= byte_index; i++) {
337 edit->rule = apply_rules_going_right (edit, i, edit->rule);
338 if (i > (edit->syntax_marker ? edit->syntax_marker->offset + SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY)) {
339 struct _syntax_marker *s;
340 s = edit->syntax_marker;
341 edit->syntax_marker = syntax_malloc (sizeof (struct _syntax_marker));
342 edit->syntax_marker->next = s;
343 edit->syntax_marker->offset = i;
344 edit->syntax_marker->rule = edit->rule;
347 } else if (byte_index < edit->last_get_rule) {
348 struct _syntax_marker *s;
349 for (;;) {
350 if (!edit->syntax_marker) {
351 memset (&edit->rule, 0, sizeof (edit->rule));
352 for (i = -1; i <= byte_index; i++)
353 edit->rule = apply_rules_going_right (edit, i, edit->rule);
354 break;
356 if (byte_index >= edit->syntax_marker->offset) {
357 edit->rule = edit->syntax_marker->rule;
358 for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++)
359 edit->rule = apply_rules_going_right (edit, i, edit->rule);
360 break;
362 s = edit->syntax_marker->next;
363 syntax_free (edit->syntax_marker);
364 edit->syntax_marker = s;
367 edit->last_get_rule = byte_index;
368 return edit->rule;
371 static void translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *fg, int *bg)
373 struct key_word *k;
374 k = edit->rules[rule.context]->keyword[rule.keyword];
375 *bg = k->bg;
376 *fg = k->fg;
379 extern int use_colors;
381 void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
383 if (edit->rules && byte_index < edit->last_byte &&
384 option_syntax_highlighting && use_colors) {
385 translate_rule_to_color (edit, edit_get_rule (edit, byte_index), fg, bg);
386 } else {
387 #ifdef MIDNIGHT
388 *fg = EDITOR_NORMAL_COLOR;
389 #else
390 *fg = NO_COLOR;
391 *bg = NO_COLOR;
392 #endif
398 Returns 0 on error/eof or a count of the number of bytes read
399 including the newline. Result must be free'd.
401 #ifdef HAVE_MAD
402 static int mad_read_one_line (char **line, FILE * f, char *file, int line_)
403 #define read_one_line(a,b) mad_read_one_line(a,b,__FILE__,__LINE__)
404 #else
405 static int read_one_line (char **line, FILE * f)
406 #endif
408 char *p;
409 int len = 256, c, r = 0, i = 0;
410 #ifdef HAVE_MAD
411 p = mad_syntax_malloc (len, file, line_);
412 #else
413 p = syntax_malloc (len);
414 #endif
415 for (;;) {
416 c = fgetc (f);
417 if (c == -1) {
418 if (errno == EINTR)
419 continue;
420 r = 0;
421 break;
422 } else if (c == '\n') {
423 r = i + 1; /* extra 1 for the newline just read */
424 break;
425 } else {
426 if (i >= len - 1) {
427 char *q;
428 q = syntax_malloc (len * 2);
429 memcpy (q, p, len);
430 syntax_free (p);
431 p = q;
432 len *= 2;
434 p[i++] = c;
437 p[i] = 0;
438 *line = p;
439 return r;
442 static char *strdup_convert (char *s)
444 char *r, *p;
445 p = r = (char *) strdup (s);
446 while (*s) {
447 switch (*s) {
448 case '\\':
449 s++;
450 switch (*s) {
451 case ' ':
452 *p = ' ';
453 s--;
454 break;
455 case 'n':
456 *p = '\n';
457 break;
458 case 'r':
459 *p = '\r';
460 break;
461 case 't':
462 *p = '\t';
463 break;
464 case 's':
465 *p = ' ';
466 break;
467 case '*':
468 *p = '*';
469 break;
470 case '\\':
471 *p = '\\';
472 break;
473 case '[':
474 case ']':
475 *p = '\003';
476 break;
477 case '{':
478 case '}':
479 *p = '\004';
480 break;
481 default:
482 *p = *s;
483 break;
485 break;
486 case '*':
487 *p = '\001';
488 break;
489 case '+':
490 *p = '\002';
491 break;
492 default:
493 *p = *s;
494 break;
496 s++;
497 p++;
499 *p = '\0';
500 return r;
503 #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
505 static void get_args (char *l, char **args, int *argc)
507 *argc = 0;
508 l--;
509 for (;;) {
510 char *p;
511 for (p = l + 1; *p && whiteness (*p); p++);
512 if (!*p)
513 break;
514 for (l = p + 1; *l && !whiteness (*l); l++);
515 *l = '\0';
516 *args = strdup_convert (p);
517 (*argc)++;
518 args++;
520 *args = 0;
523 static void free_args (char **args)
525 while (*args) {
526 syntax_free (*args);
527 *args = 0;
528 args++;
532 #define check_a {if(!*a){result=line;break;}}
533 #define check_not_a {if(*a){result=line;break;}}
535 #ifdef MIDNIGHT
537 int try_alloc_color_pair (char *fg, char *bg);
539 int this_try_alloc_color_pair (char *fg, char *bg)
541 char f[80], b[80], *p;
542 if (bg)
543 if (!*bg)
544 bg = 0;
545 if (fg)
546 if (!*fg)
547 fg = 0;
548 if (fg) {
549 strcpy (f, fg);
550 p = strchr (f, '/');
551 if (p)
552 *p = '\0';
553 fg = f;
555 if (bg) {
556 strcpy (b, bg);
557 p = strchr (b, '/');
558 if (p)
559 *p = '\0';
560 bg = b;
562 return try_alloc_color_pair (fg, bg);
564 #else
565 #ifdef GTK
566 int allocate_color (WEdit *edit, gchar *color);
568 int this_allocate_color (WEdit *edit, char *fg)
570 char *p;
571 if (fg)
572 if (!*fg)
573 fg = 0;
574 if (!fg)
575 return allocate_color (edit, 0);
576 p = strchr (fg, '/');
577 if (!p)
578 return allocate_color (edit, fg);
579 return allocate_color (edit, p + 1);
581 #else
582 int this_allocate_color (WEdit *edit, char *fg)
584 char *p;
585 if (fg)
586 if (!*fg)
587 fg = 0;
588 if (!fg)
589 return allocate_color (0);
590 p = strchr (fg, '/');
591 if (!p)
592 return allocate_color (fg);
593 return allocate_color (p + 1);
595 #endif /* GTK */
596 #endif /* MIDNIGHT */
598 static char *error_file_name = 0;
600 static FILE *open_include_file (char *filename)
602 FILE *f;
603 char p[MAX_PATH_LEN];
604 syntax_free (error_file_name);
605 error_file_name = (char *) strdup (filename);
606 if (*filename == '/')
607 return fopen (filename, "r");
608 strcpy (p, home_dir);
609 strcat (p, EDIT_DIR "/");
610 strcat (p, filename);
611 syntax_free (error_file_name);
612 error_file_name = (char *) strdup (p);
613 f = fopen (p, "r");
614 if (f)
615 return f;
616 #ifndef MIDNIGHT
617 strcpy (p, LIBDIR "/syntax/");
618 #else
619 strcpy (p, mc_home);
620 strcat (p, "/syntax/");
621 #endif
622 strcat (p, filename);
623 syntax_free (error_file_name);
624 error_file_name = (char *) strdup (p);
625 return fopen (p, "r");
628 /* returns line number on error */
629 static int edit_read_syntax_rules (WEdit * edit, FILE * f)
631 FILE *g = 0;
632 char *fg, *bg;
633 char last_fg[32] = "", last_bg[32] = "";
634 char whole_right[512];
635 char whole_left[512];
636 char *args[1024], *l = 0;
637 int save_line = 0, line = 0;
638 struct context_rule **r, *c = 0;
639 int num_words = -1, num_contexts = -1;
640 int argc, result = 0;
641 int i, j;
643 args[0] = 0;
645 strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
646 strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
648 r = edit->rules = syntax_malloc (MAX_CONTEXTS * sizeof (struct context_rule *));
650 for (;;) {
651 char **a;
652 line++;
653 l = 0;
654 if (!read_one_line (&l, f)) {
655 if (g) {
656 fclose (f);
657 f = g;
658 g = 0;
659 line = save_line + 1;
660 syntax_free (error_file_name);
661 if (l)
662 syntax_free (l);
663 if (!read_one_line (&l, f))
664 break;
665 } else {
666 break;
669 get_args (l, args, &argc);
670 a = args + 1;
671 if (!args[0]) {
672 /* do nothing */
673 } else if (!strcmp (args[0], "include")) {
674 if (g || argc != 2) {
675 result = line;
676 break;
678 g = f;
679 f = open_include_file (args[1]);
680 if (!f) {
681 syntax_free (error_file_name);
682 result = line;
683 break;
685 save_line = line;
686 line = 0;
687 } else if (!strcmp (args[0], "wholechars")) {
688 check_a;
689 if (!strcmp (*a, "left")) {
690 a++;
691 strcpy (whole_left, *a);
692 } else if (!strcmp (*a, "right")) {
693 a++;
694 strcpy (whole_right, *a);
695 } else {
696 strcpy (whole_left, *a);
697 strcpy (whole_right, *a);
699 a++;
700 check_not_a;
701 } else if (!strcmp (args[0], "context")) {
702 check_a;
703 if (num_contexts == -1) {
704 if (strcmp (*a, "default")) { /* first context is the default */
705 *a = 0;
706 check_a;
708 a++;
709 c = r[0] = syntax_malloc (sizeof (struct context_rule));
710 c->left = (char *) strdup (" ");
711 c->right = (char *) strdup (" ");
712 num_contexts = 0;
713 } else {
714 c = r[num_contexts] = syntax_malloc (sizeof (struct context_rule));
715 if (!strcmp (*a, "exclusive")) {
716 a++;
717 c->between_delimiters = 1;
719 check_a;
720 if (!strcmp (*a, "whole")) {
721 a++;
722 c->whole_word_chars_left = (char *) strdup (whole_left);
723 c->whole_word_chars_right = (char *) strdup (whole_right);
724 } else if (!strcmp (*a, "wholeleft")) {
725 a++;
726 c->whole_word_chars_left = (char *) strdup (whole_left);
727 } else if (!strcmp (*a, "wholeright")) {
728 a++;
729 c->whole_word_chars_right = (char *) strdup (whole_right);
731 check_a;
732 if (!strcmp (*a, "linestart")) {
733 a++;
734 c->line_start_left = 1;
736 check_a;
737 c->left = (char *) strdup (*a++);
738 check_a;
739 if (!strcmp (*a, "linestart")) {
740 a++;
741 c->line_start_right = 1;
743 check_a;
744 c->right = (char *) strdup (*a++);
745 c->first_left = *c->left;
746 c->first_right = *c->right;
747 c->single_char = (strlen (c->right) == 1);
749 c->keyword = syntax_malloc (MAX_WORDS_PER_CONTEXT * sizeof (struct key_word *));
750 #if 0
751 c->max_words = MAX_WORDS_PER_CONTEXT;
752 #endif
753 num_words = 1;
754 c->keyword[0] = syntax_malloc (sizeof (struct key_word));
755 fg = *a;
756 if (*a)
757 a++;
758 bg = *a;
759 if (*a)
760 a++;
761 strcpy (last_fg, fg ? fg : "");
762 strcpy (last_bg, bg ? bg : "");
763 #ifdef MIDNIGHT
764 c->keyword[0]->fg = this_try_alloc_color_pair (fg, bg);
765 #else
766 c->keyword[0]->fg = this_allocate_color (edit, fg);
767 c->keyword[0]->bg = this_allocate_color (edit, bg);
768 #endif
769 c->keyword[0]->keyword = (char *) strdup (" ");
770 check_not_a;
771 num_contexts++;
772 } else if (!strcmp (args[0], "spellcheck")) {
773 if (!c) {
774 result = line;
775 break;
777 c->spelling = 1;
778 } else if (!strcmp (args[0], "keyword")) {
779 struct key_word *k;
780 if (num_words == -1)
781 *a = 0;
782 check_a;
783 k = r[num_contexts - 1]->keyword[num_words] = syntax_malloc (sizeof (struct key_word));
784 if (!strcmp (*a, "whole")) {
785 a++;
786 k->whole_word_chars_left = (char *) strdup (whole_left);
787 k->whole_word_chars_right = (char *) strdup (whole_right);
788 } else if (!strcmp (*a, "wholeleft")) {
789 a++;
790 k->whole_word_chars_left = (char *) strdup (whole_left);
791 } else if (!strcmp (*a, "wholeright")) {
792 a++;
793 k->whole_word_chars_right = (char *) strdup (whole_right);
795 check_a;
796 if (!strcmp (*a, "linestart")) {
797 a++;
798 k->line_start = 1;
800 check_a;
801 if (!strcmp (*a, "whole")) {
802 *a = 0;
803 check_a;
805 k->keyword = (char *) strdup (*a++);
806 k->first = *k->keyword;
807 fg = *a;
808 if (*a)
809 a++;
810 bg = *a;
811 if (*a)
812 a++;
813 if (!fg)
814 fg = last_fg;
815 if (!bg)
816 bg = last_bg;
817 #ifdef MIDNIGHT
818 k->fg = this_try_alloc_color_pair (fg, bg);
819 #else
820 k->fg = this_allocate_color (edit, fg);
821 k->bg = this_allocate_color (edit, bg);
822 #endif
823 check_not_a;
824 num_words++;
825 } else if (!strncmp (args[0], "#", 1)) {
826 /* do nothing for comment */
827 } else if (!strcmp (args[0], "file")) {
828 break;
829 } else { /* anything else is an error */
830 *a = 0;
831 check_a;
833 free_args (args);
834 syntax_free (l);
836 free_args (args);
837 syntax_free (l);
839 if (!edit->rules[0])
840 syntax_free (edit->rules);
842 if (result)
843 return result;
845 if (num_contexts == -1) {
846 result = line;
847 return result;
851 char first_chars[MAX_WORDS_PER_CONTEXT + 2], *p;
852 for (i = 0; edit->rules[i]; i++) {
853 c = edit->rules[i];
854 p = first_chars;
855 *p++ = (char) 1;
856 for (j = 1; c->keyword[j]; j++)
857 *p++ = c->keyword[j]->first;
858 *p = '\0';
859 c->keyword_first_chars = syntax_malloc (strlen (first_chars) + 2);
860 strcpy (c->keyword_first_chars, first_chars);
864 return result;
867 #if !defined (GTK) && !defined (MIDNIGHT)
869 /* strdup and append c */
870 static char *strdupc (char *s, int c)
872 char *t;
873 int l;
874 strcpy (t = syntax_malloc ((l = strlen (s)) + 3), s);
875 t[l] = c;
876 t[l + 1] = '\0';
877 return t;
880 static void edit_syntax_clear_keyword (WEdit * edit, int context, int j)
882 struct context_rule *c;
883 struct _syntax_marker *s;
884 c = edit->rules[context];
885 /* 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) */
886 for (s = edit->syntax_marker; s; s = s->next)
887 if (s->rule.keyword == j)
888 s->rule.keyword = 0;
889 else if (s->rule.keyword > j)
890 s->rule.keyword--;
891 syntax_free (c->keyword[j]->keyword);
892 syntax_free (c->keyword[j]->whole_word_chars_left);
893 syntax_free (c->keyword[j]->whole_word_chars_right);
894 syntax_free (c->keyword[j]);
895 memcpy (&c->keyword[j], &c->keyword[j + 1], (MAX_WORDS_PER_CONTEXT - j - 1) * sizeof (struct keyword *));
896 strcpy (&c->keyword_first_chars[j], &c->keyword_first_chars[j + 1]);
900 FILE *spelling_pipe_in = 0;
901 FILE *spelling_pipe_out = 0;
902 pid_t ispell_pid = 0;
905 /* adds a keyword for underlining into the keyword list for this context, returns 1 if too many words */
906 static int edit_syntax_add_keyword (WEdit * edit, char *keyword, int context, time_t t)
908 int j;
909 char *s;
910 struct context_rule *c;
911 c = edit->rules[context];
912 for (j = 1; c->keyword[j]; j++) {
913 /* if a keyword has been around for more than TRANSIENT_WORD_TIME_OUT
914 seconds, then remove it - we don't want to run out of space or makes syntax highlighting to slow */
915 if (c->keyword[j]->time) {
916 if (c->keyword[j]->time + TRANSIENT_WORD_TIME_OUT < t) {
917 edit->force |= REDRAW_PAGE;
918 edit_syntax_clear_keyword (edit, context, j);
919 j--;
923 /* are we out of space? */
924 if (j >= MAX_WORDS_PER_CONTEXT - 2)
925 return 1;
926 /* add the new keyword and date it */
927 c->keyword[j + 1] = 0;
928 c->keyword[j] = syntax_malloc (sizeof (struct key_word));
929 #ifdef MIDNIGHT
930 c->keyword[j]->fg = SPELLING_ERROR;
931 #else
932 c->keyword[j]->fg = c->keyword[0]->fg;
933 c->keyword[j]->bg = SPELLING_ERROR;
934 #endif
935 c->keyword[j]->keyword = (char *) strdup (keyword);
936 c->keyword[j]->first = *c->keyword[j]->keyword;
937 c->keyword[j]->whole_word_chars_left = (char *) strdup ("-'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ¡¢£¤¥¦§§¨©©ª«¬­®®¯°±²³´µ¶¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ");
938 c->keyword[j]->whole_word_chars_right = (char *) strdup ("-'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ¡¢£¤¥¦§§¨©©ª«¬­®®¯°±²³´µ¶¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ");
939 c->keyword[j]->time = t;
940 s = strdupc (c->keyword_first_chars, c->keyword[j]->first);
941 syntax_free (c->keyword_first_chars);
942 c->keyword_first_chars = s;
943 return 0;
946 /* checks spelling of the word at offset */
947 static int edit_check_spelling_at (WEdit * edit, long byte_index)
949 int context;
950 long p1, p2;
951 unsigned char *p, *q;
952 int r, c1, c2, j;
953 int ch;
954 time_t t;
955 struct context_rule *c;
956 /* sanity check */
957 if (!edit->rules || byte_index > edit->last_byte)
958 return 0;
959 /* in what context are we */
960 context = edit_get_rule (edit, byte_index).context;
961 c = edit->rules[context];
962 /* does this context have `spellcheck' */
963 if (!edit->rules[context]->spelling)
964 return 0;
965 /* find word start */
966 for (p1 = byte_index - 1;; p1--) {
967 ch = edit_get_byte (edit, p1);
968 if (isalpha (ch) || ch == '-' || ch == '\'')
969 continue;
970 break;
972 p1++;
973 /* find word end */
974 for (p2 = byte_index;; p2++) {
975 ch = edit_get_byte (edit, p2);
976 if (isalpha (ch) || ch == '-' || ch == '\'')
977 continue;
978 break;
980 if (p2 <= p1)
981 return 0;
982 /* create string */
983 q = p = syntax_malloc (p2 - p1 + 2);
984 for (; p1 < p2; p1++)
985 *p++ = edit_get_byte (edit, p1);
986 *p = '\0';
987 if (q[0] == '-' || strlen ((char *) q) > 40) { /* if you are using words over 40 characters, you are on your own */
988 syntax_free (q);
989 return 0;
991 time (&t);
992 for (j = 1; c->keyword[j]; j++) {
993 /* if the keyword is present, then update its time only. if it is a fixed keyword from the rules file, then just return */
994 if (!strcmp (c->keyword[j]->keyword, (char *) q)) {
995 if (c->keyword[j]->time)
996 c->keyword[j]->time = t;
997 syntax_free (q);
998 return 0;
1001 /* feed it to ispell */
1002 fprintf (spelling_pipe_out, "%s\n", (char *) q);
1003 fflush (spelling_pipe_out);
1004 /* what does ispell say? */
1005 do {
1006 r = fgetc (spelling_pipe_in);
1007 } while (r == -1 && errno == EINTR);
1008 if (r == -1) {
1009 syntax_free (q);
1010 return 1;
1012 if (r == '\n') { /* ispell sometimes returns just blank line if it is given bad characters */
1013 syntax_free (q);
1014 return 0;
1016 /* now read ispell output untill we get two blanks lines - we are not intersted in this part */
1017 do {
1018 c1 = fgetc (spelling_pipe_in);
1019 } while (c1 == -1 && errno == EINTR);
1020 for (;;) {
1021 if (c1 == -1) {
1022 syntax_free (q);
1023 return 1;
1025 do {
1026 c2 = fgetc (spelling_pipe_in);
1027 } while (c2 == -1 && errno == EINTR);
1028 if (c1 == '\n' && c2 == '\n')
1029 break;
1030 c1 = c2;
1032 /* spelled ok */
1033 if (r == '*' || r == '+' || r == '-') {
1034 syntax_free (q);
1035 return 0;
1037 /* not spelled ok - so add a syntax keyword for this word */
1038 edit_syntax_add_keyword (edit, (char *) q, context, t);
1039 syntax_free (q);
1040 return 0;
1043 char *option_alternate_dictionary = "";
1045 int edit_check_spelling (WEdit * edit)
1047 if (!option_auto_spellcheck)
1048 return 0;
1049 /* magic arg to close up shop */
1050 if (!edit) {
1051 option_auto_spellcheck = 0;
1052 goto close_spelling;
1054 /* do we at least have a syntax rule struct to put new wrongly spelled keyword in for highlighting? */
1055 if (!edit->rules && !edit->explicit_syntax)
1056 edit_load_syntax (edit, 0, UNKNOWN_FORMAT);
1057 if (!edit->rules) {
1058 option_auto_spellcheck = 0;
1059 return 0;
1061 /* is ispell running? */
1062 if (!spelling_pipe_in) {
1063 int in, out, a = 0;
1064 char *arg[10];
1065 arg[a++] = "ispell";
1066 arg[a++] = "-a";
1067 if (option_alternate_dictionary)
1068 if (*option_alternate_dictionary) {
1069 arg[a++] = "-d";
1070 arg[a++] = option_alternate_dictionary;
1072 arg[a++] = "-a";
1073 arg[a++] = 0;
1074 /* start ispell process */
1075 ispell_pid = triple_pipe_open (&in, &out, 0, 1, arg[0], arg);
1076 if (ispell_pid < 1) {
1077 option_auto_spellcheck = 0;
1078 #if 0
1079 CErrorDialog (0, 0, 0, _ (" Spelling Message "), "%s", _ (" Fail trying to open ispell program. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
1080 #endif
1081 return 1;
1083 /* prepare pipes */
1084 spelling_pipe_in = (FILE *) fdopen (out, "r");
1085 spelling_pipe_out = (FILE *) fdopen (in, "w");
1086 if (!spelling_pipe_in || !spelling_pipe_out) {
1087 option_auto_spellcheck = 0;
1088 CErrorDialog (0, 0, 0, _ (" Spelling Message "), "%s", _ (" Fail trying to open ispell pipes. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
1089 return 1;
1091 /* read the banner message */
1092 for (;;) {
1093 int c1;
1094 c1 = fgetc (spelling_pipe_in);
1095 if (c1 == -1 && errno != EINTR) {
1096 option_auto_spellcheck = 0;
1097 CErrorDialog (0, 0, 0, _ (" Spelling Message "), "%s", _ (" Fail trying to read ispell pipes. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
1098 return 1;
1100 if (c1 == '\n')
1101 break;
1104 /* spellcheck the word under the cursor */
1105 if (edit_check_spelling_at (edit, edit->curs1)) {
1106 CMessageDialog (0, 0, 0, 0, _ (" Spelling Message "), "%s", _ (" Error reading from ispell. \n Ispell is being restarted. "));
1107 close_spelling:
1108 fclose (spelling_pipe_in);
1109 spelling_pipe_in = 0;
1110 fclose (spelling_pipe_out);
1111 spelling_pipe_out = 0;
1112 kill (ispell_pid, SIGKILL);
1114 return 0;
1117 #else /* ! GTK && ! MIDNIGHT*/
1119 int edit_check_spelling (WEdit * edit)
1121 return 0;
1124 #endif
1126 void (*syntax_change_callback) (CWidget *) = 0;
1128 void edit_set_syntax_change_callback (void (*callback) (CWidget *))
1130 syntax_change_callback = callback;
1133 void edit_free_syntax_rules (WEdit * edit)
1135 int i, j;
1136 if (!edit)
1137 return;
1138 if (!edit->rules)
1139 return;
1140 edit_get_rule (edit, -1);
1141 syntax_free (edit->syntax_type);
1142 edit->syntax_type = 0;
1143 if (syntax_change_callback)
1144 #ifdef MIDNIGHT
1145 (*syntax_change_callback) (&edit->widget);
1146 #else
1147 (*syntax_change_callback) (edit->widget);
1148 #endif
1149 for (i = 0; edit->rules[i]; i++) {
1150 if (edit->rules[i]->keyword) {
1151 for (j = 0; edit->rules[i]->keyword[j]; j++) {
1152 syntax_free (edit->rules[i]->keyword[j]->keyword);
1153 syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_left);
1154 syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_right);
1155 syntax_free (edit->rules[i]->keyword[j]);
1158 syntax_free (edit->rules[i]->left);
1159 syntax_free (edit->rules[i]->right);
1160 syntax_free (edit->rules[i]->whole_word_chars_left);
1161 syntax_free (edit->rules[i]->whole_word_chars_right);
1162 syntax_free (edit->rules[i]->keyword);
1163 syntax_free (edit->rules[i]->keyword_first_chars);
1164 syntax_free (edit->rules[i]);
1166 while (edit->syntax_marker) {
1167 struct _syntax_marker *s = edit->syntax_marker->next;
1168 syntax_free (edit->syntax_marker);
1169 edit->syntax_marker = s;
1171 syntax_free (edit->rules);
1174 #define CURRENT_SYNTAX_RULES_VERSION "62"
1176 static const char * const syntax_text[] = {
1177 "# syntax rules version " CURRENT_SYNTAX_RULES_VERSION,
1178 "# (after the slash is a Cooledit color, 0-26 or any of the X colors in rgb.txt)",
1179 "# black",
1180 "# red",
1181 "# green",
1182 "# brown",
1183 "# blue",
1184 "# magenta",
1185 "# cyan",
1186 "# lightgray",
1187 "# gray",
1188 "# brightred",
1189 "# brightgreen",
1190 "# yellow",
1191 "# brightblue",
1192 "# brightmagenta",
1193 "# brightcyan",
1194 "# white",
1196 "file gobledy_gook #\\sHelp\\ssupport\\sother\\sfile\\stypes",
1197 "context default",
1198 "file gobledy_gook #\\sby\\scoding\\srules\\sin\\s~/.cedit/syntax.",
1199 "context default",
1200 "file gobledy_gook #\\sSee\\sman/syntax\\sin\\sthe\\ssource\\sdistribution",
1201 "context default",
1202 "file gobledy_gook #\\sand\\sconsult\\sthe\\sman\\spage.",
1203 "context default",
1206 "file ..\\*\\\\.(diff|rej|patch)$ Diff\\sOutput ^diff",
1207 "include diff.syntax",
1209 "file ..\\*\\\\.lsm$ LSM\\sFile",
1210 "include lsm.syntax",
1212 "file ..\\*\\\\.sh$ Shell\\sScript ^#!\\s\\*/.\\*/(ksh|bash|sh|pdkzsh)",
1213 "include sh.syntax",
1215 "file ..\\*\\\\.(pl|PL|pm|PM])$ Perl\\sProgram ^#!\\s\\*/.\\*/perl",
1216 "include perl.syntax",
1218 "file ..\\*\\\\.(py|PY])$ Python\\sProgram ^#!\\s\\*/.\\*/python",
1219 "include python.syntax",
1221 "file ..\\*\\\\.(man|[0-9n]|[0-9]x)$ NROFF\\sSource",
1222 "include nroff.syntax",
1224 "file ..\\*\\\\.(htm|html|HTM|HTML)$ HTML\\sFile",
1225 "include html.syntax",
1227 "file ..\\*\\\\.(pp|PP|pas|PAS)$ Pascal\\sProgram",
1228 "include pascal.syntax",
1230 "file ..\\*\\\\.(ada|adb|ads|ADA|ADB|ADS)$ Ada\\sProgram",
1231 "include ada95.syntax",
1233 "file ..\\*\\\\.tex$ LaTeX\\s2.09\\sDocument",
1234 "include latex.syntax",
1236 "file ..\\*\\.(texi|texinfo|TEXI|TEXINFO)$ Texinfo\\sDocument",
1237 "include texinfo.syntax",
1239 "file ..\\*\\\\.([chC]|CC|cxx|cc|cpp|CPP|CXX)$ C/C\\+\\+\\sProgram",
1240 "include c.syntax",
1242 "file ..\\*\\\\.[fF]$ Fortran\\sProgram",
1243 "include fortran.syntax",
1245 "file ..\\*\\\\.i$ SWIG\\sSource",
1246 "include swig.syntax",
1248 "file ..\\*\\\\.(java|JAVA|Java|jav)$ Java\\sProgram",
1249 "include java.syntax",
1251 "file ..\\*\\\\.(st)$ SmallTalk\\sProgram",
1252 "include smalltalk.syntax",
1254 "file ..\\*\\\\.(ml|mli|mly|mll|mlp)$ ML\\sProgram",
1255 "include ml.syntax",
1257 "file ..\\*\\\\.m$ Matlab\\sor\\sOctave\\sFile",
1258 "include octave.syntax",
1260 "file .\\*ChangeLog$ GNU\\sDistribution\\sChangeLog\\sFile",
1261 "include changelog.syntax",
1263 "file .\\*[Mm]akefile[\\\\\\.a-z]\\*$ Makefile",
1264 "include makefile.syntax",
1266 "file Don_t_match_me Mail\\sfolder ^From\\s",
1267 "include mail.syntax",
1269 "file .\\*syntax$ Syntax\\sHighlighting\\sdefinitions",
1271 "context default",
1272 " keyword whole spellch\\eck yellow/24",
1273 " keyword whole keyw\\ord yellow/24",
1274 " keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17",
1275 " keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17",
1276 " keyword whole wh\\oleleft\\[\\t\\s\\]l\\inestart brightcyan/17",
1277 " keyword whole wh\\oleright\\[\\t\\s\\]l\\inestart brightcyan/17",
1278 " keyword whole l\\inestart\\[\\t\\s\\]wh\\ole",
1279 " keyword whole l\\inestart\\[\\t\\s\\]wh\\ole",
1280 " keyword whole l\\inestart\\[\\t\\s\\]wh\\oleleft",
1281 " keyword whole l\\inestart\\[\\t\\s\\]wh\\oleright",
1282 " keyword wholeleft whole\\s brightcyan/17",
1283 " keyword wholeleft whole\\t brightcyan/17",
1284 " keyword whole wh\\oleleft brightcyan/17",
1285 " keyword whole wh\\oleright brightcyan/17",
1286 " keyword whole lin\\[e\\]start brightcyan/17",
1287 " keyword whole c\\ontext\\[\\t\\s\\]exclusive brightred/18",
1288 " keyword whole c\\ontext\\[\\t\\s\\]default brightred/18",
1289 " keyword whole c\\ontext brightred/18",
1290 " keyword whole wh\\olechars\\[\\t\\s\\]left brightcyan/17",
1291 " keyword whole wh\\olechars\\[\\t\\s\\]right brightcyan/17",
1292 " keyword whole wh\\olechars brightcyan/17",
1293 " keyword whole f\\ile brightgreen/6",
1294 " keyword whole in\\clude brightred/18",
1296 " keyword whole 0 lightgray/0 blue/26",
1297 " keyword whole 1 lightgray/1 blue/26",
1298 " keyword whole 2 lightgray/2 blue/26",
1299 " keyword whole 3 lightgray/3 blue/26",
1300 " keyword whole 4 lightgray/4 blue/26",
1301 " keyword whole 5 lightgray/5 blue/26",
1302 " keyword whole 6 lightgray/6",
1303 " keyword whole 7 lightgray/7",
1304 " keyword whole 8 lightgray/8",
1305 " keyword whole 9 lightgray/9",
1306 " keyword whole 10 lightgray/10",
1307 " keyword whole 11 lightgray/11",
1308 " keyword whole 12 lightgray/12",
1309 " keyword whole 13 lightgray/13",
1310 " keyword whole 14 lightgray/14",
1311 " keyword whole 15 lightgray/15",
1312 " keyword whole 16 lightgray/16",
1313 " keyword whole 17 lightgray/17",
1314 " keyword whole 18 lightgray/18",
1315 " keyword whole 19 lightgray/19",
1316 " keyword whole 20 lightgray/20",
1317 " keyword whole 21 lightgray/21",
1318 " keyword whole 22 lightgray/22",
1319 " keyword whole 23 lightgray/23",
1320 " keyword whole 24 lightgray/24",
1321 " keyword whole 25 lightgray/25",
1322 " keyword whole 26 lightgray/26",
1324 " keyword wholeleft black\\/ black/0",
1325 " keyword wholeleft red\\/ red/DarkRed",
1326 " keyword wholeleft green\\/ green/green3",
1327 " keyword wholeleft brown\\/ brown/saddlebrown",
1328 " keyword wholeleft blue\\/ blue/blue3",
1329 " keyword wholeleft magenta\\/ magenta/magenta3",
1330 " keyword wholeleft cyan\\/ cyan/cyan3",
1331 " keyword wholeleft lightgray\\/ lightgray/lightgray",
1332 " keyword wholeleft gray\\/ gray/gray",
1333 " keyword wholeleft brightred\\/ brightred/red",
1334 " keyword wholeleft brightgreen\\/ brightgreen/green1",
1335 " keyword wholeleft yellow\\/ yellow/yellow",
1336 " keyword wholeleft brightblue\\/ brightblue/blue1",
1337 " keyword wholeleft brightmagenta\\/ brightmagenta/magenta",
1338 " keyword wholeleft brightcyan\\/ brightcyan/cyan1",
1339 " keyword wholeleft white\\/ white/26",
1341 "context linestart # \\n brown/22",
1343 "file .\\* " UNKNOWN_FORMAT,
1344 "include unknown.syntax",
1349 FILE *upgrade_syntax_file (char *syntax_file)
1351 FILE *f;
1352 char *p;
1353 char line[80];
1354 f = fopen (syntax_file, "r");
1355 if (!f) {
1356 const char * const *syntax_line;
1357 rewrite_rule_file:
1358 f = fopen (syntax_file, "w");
1359 if (!f)
1360 return 0;
1361 for (syntax_line = syntax_text; *syntax_line; syntax_line++)
1362 fprintf (f, "%s\n", *syntax_line);
1363 fclose (f);
1364 return fopen (syntax_file, "r");
1366 memset (line, 0, sizeof (line));
1367 fread (line, sizeof (line) - 1, 1, f);
1368 if (!strstr (line, "syntax rules version"))
1369 goto rename_rule_file;
1370 p = strstr (line, "version") + strlen ("version") + 1;
1371 if (atoi (p) < atoi (CURRENT_SYNTAX_RULES_VERSION)) {
1372 char s[1024];
1373 rename_rule_file:
1374 fclose (f);
1375 strcpy (s, syntax_file);
1376 strcat (s, ".OLD");
1377 unlink (s);
1378 rename (syntax_file, s);
1379 unlink (syntax_file); /* might rename() fail ? */
1380 #if defined(MIDNIGHT) || defined(GTK)
1381 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. "));
1382 #else
1383 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. "));
1384 #endif
1385 goto rewrite_rule_file;
1387 rewind (f);
1388 return f;
1391 /* returns -1 on file error, line number on error in file syntax */
1392 static int edit_read_syntax_file (WEdit * edit, char **names, char *syntax_file, char *editor_file, char *first_line, char *type)
1394 FILE *f;
1395 regex_t r;
1396 regmatch_t pmatch[1];
1397 char *args[1024], *l = 0;
1398 int line = 0;
1399 int argc;
1400 int result = 0;
1401 int count = 0;
1402 f = upgrade_syntax_file (syntax_file);
1403 if (!f)
1404 return -1;
1405 args[0] = 0;
1406 for (;;) {
1407 line++;
1408 syntax_free (l);
1409 if (!read_one_line (&l, f))
1410 break;
1411 get_args (l, args, &argc);
1412 if (!args[0])
1413 continue;
1414 /* looking for `file ...' lines only */
1415 if (strcmp (args[0], "file")) {
1416 free_args (args);
1417 continue;
1419 /* must have two args or report error */
1420 if (!args[1] || !args[2]) {
1421 result = line;
1422 break;
1424 if (names) {
1425 /* 1: just collecting a list of names of rule sets */
1426 names[count++] = (char *) strdup (args[2]);
1427 names[count] = 0;
1428 } else if (type) {
1429 /* 2: rule set was explicitly specified by the caller */
1430 if (!strcmp (type, args[2]))
1431 goto found_type;
1432 } else if (editor_file && edit) {
1433 /* 3: auto-detect rule set from regular expressions */
1434 int q;
1435 if (regcomp (&r, args[1], REG_EXTENDED)) {
1436 result = line;
1437 break;
1439 /* does filename match arg 1 ? */
1440 q = !regexec (&r, editor_file, 1, pmatch, 0);
1441 regfree (&r);
1442 if (!q && args[3]) {
1443 if (regcomp (&r, args[3], REG_EXTENDED)) {
1444 result = line;
1445 break;
1447 /* does first line match arg 3 ? */
1448 q = !regexec (&r, first_line, 1, pmatch, 0);
1449 regfree (&r);
1451 if (q) {
1452 int line_error;
1453 found_type:
1454 line_error = edit_read_syntax_rules (edit, f);
1455 if (line_error) {
1456 if (!error_file_name) /* an included file */
1457 result = line + line_error;
1458 else
1459 result = line_error;
1460 } else {
1461 syntax_free (edit->syntax_type);
1462 edit->syntax_type = (char *) strdup (args[2]);
1463 /* if there are no rules then turn off syntax highlighting for speed */
1464 if (!edit->rules[1])
1465 if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling) {
1466 edit_free_syntax_rules (edit);
1467 break;
1469 /* notify the callback of a change in rule set */
1470 if (syntax_change_callback)
1471 #ifdef MIDNIGHT
1472 (*syntax_change_callback) (&edit->widget);
1473 #else
1474 (*syntax_change_callback) (edit->widget);
1475 #endif
1477 break;
1480 free_args (args);
1482 free_args (args);
1483 syntax_free (l);
1484 fclose (f);
1485 return result;
1488 static char *get_first_editor_line (WEdit * edit)
1490 int i;
1491 static char s[256];
1492 s[0] = '\0';
1493 if (!edit)
1494 return s;
1495 for (i = 0; i < 255; i++) {
1496 s[i] = edit_get_byte (edit, i);
1497 if (s[i] == '\n') {
1498 s[i] = '\0';
1499 break;
1502 s[255] = '\0';
1503 return s;
1506 /* loads rules into edit struct. one of edit or names must be zero. if
1507 edit is zero, a list of types will be stored into name. type may be zero
1508 in which case the type will be selected according to the filename. */
1509 void edit_load_syntax (WEdit * edit, char **names, char *type)
1511 int r;
1512 char *f;
1514 edit_free_syntax_rules (edit);
1516 if (edit) {
1517 if (!edit->filename)
1518 return;
1519 if (!*edit->filename && !type)
1520 return;
1522 f = catstrs (home_dir, SYNTAX_FILE, 0);
1523 r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0, get_first_editor_line (edit), type);
1524 if (r == -1) {
1525 edit_free_syntax_rules (edit);
1526 edit_error_dialog (_ (" Load syntax file "), _ (" File access error "));
1527 return;
1529 if (r) {
1530 char s[80];
1531 edit_free_syntax_rules (edit);
1532 sprintf (s, _ (" Error in file %s on line %d "), error_file_name ? error_file_name : f, r);
1533 edit_error_dialog (_ (" Load syntax file "), s);
1534 syntax_free (error_file_name);
1535 return;
1539 #else
1541 int option_syntax_highlighting = 0;
1543 void edit_load_syntax (WEdit * edit, char **names, char *type)
1545 return;
1548 void edit_free_syntax_rules (WEdit * edit)
1550 return;
1553 void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
1555 *fg = NORMAL_COLOR;
1558 int edit_check_spelling (WEdit * edit)
1560 return 0;
1563 #endif /* !defined(MIDNIGHT) || defined(HAVE_SYNTAXH) */