Used .TP for coherency all over the key description pages.
[midnight-commander.git] / edit / syntax.c
blobb3babfa18844e860951cffe89559927d39705a98
1 /* editor syntax highlighting.
3 Copyright (C) 1996, 1997, 1998 the Free Software Foundation
5 Authors: 1998 Paul Sheer
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.
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.
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.
23 #include <config.h>
24 #include "edit.h"
26 /* bytes */
27 #define SYNTAX_MARKER_DENSITY 512
30 Mispelled words are flushed from the syntax highlighting rules
31 when they have been around longer than
32 TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
33 chars per second and say 3 chars + a space per word, we can
34 accumulate 450 words absolute max with a value of 60. This is
35 below this limit of 1024 words in a context.
37 #define TRANSIENT_WORD_TIME_OUT 60
39 #define UNKNOWN_FORMAT "unknown"
41 #ifdef HAVE_SYNTAXH
43 int option_syntax_highlighting = 1;
44 int option_auto_spellcheck = 1;
46 static inline void *syntax_malloc (size_t x)
48 void *p;
49 p = malloc (x);
50 memset (p, 0, x);
51 return p;
54 #define syntax_free(x) {if(x){free(x);(x)=0;}}
55 #define syntax_g_free(x) {if(x){g_free(x);(x)=0;}}
57 static long compare_word_to_right (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start)
59 unsigned char *p, *q;
60 int c, d, j;
61 if (!*text)
62 return -1;
63 c = edit_get_byte (edit, i - 1);
64 if (line_start)
65 if (c != '\n')
66 return -1;
67 if (whole_left)
68 if (strchr (whole_left, c))
69 return -1;
70 for (p = (unsigned char *) text, q = p + strlen ((char *) p); p < q; p++, i++) {
71 switch (*p) {
72 case '\001':
73 p++;
74 for (;;) {
75 c = edit_get_byte (edit, i);
76 if (!*p)
77 if (whole_right)
78 if (!strchr (whole_right, c))
79 break;
80 if (c == *p)
81 break;
82 if (c == '\n')
83 return -1;
84 i++;
86 break;
87 case '\002':
88 p++;
89 j = 0;
90 for (;;) {
91 c = edit_get_byte (edit, i);
92 if (c == *p) {
93 j = i;
94 if (*p == *text && !p[1]) /* handle eg '+' and @+@ keywords properly */
95 break;
97 if (j && strchr ((char *) p + 1, c)) /* c exists further down, so it will get matched later */
98 break;
99 if (c == '\n' || c == '\t' || c == ' ') {
100 if (!*p) {
101 i--;
102 break;
104 if (!j)
105 return -1;
106 i = j;
107 break;
109 if (whole_right)
110 if (!strchr (whole_right, c)) {
111 if (!*p) {
112 i--;
113 break;
115 if (!j)
116 return -1;
117 i = j;
118 break;
120 i++;
122 break;
123 case '\003':
124 p++;
125 c = -1;
126 for (;; i++) {
127 d = c;
128 c = edit_get_byte (edit, i);
129 for (j = 0; p[j] != '\003'; j++)
130 if (c == p[j])
131 goto found_char2;
132 break;
133 found_char2:
134 j = c; /* dummy command */
136 i--;
137 while (*p != '\003')
138 p++;
139 if (p[1] == d)
140 i--;
141 break;
142 case '\004':
143 p++;
144 c = edit_get_byte (edit, i);
145 for (; *p != '\004'; p++)
146 if (c == *p)
147 goto found_char3;
148 return -1;
149 found_char3:
150 for (; *p != '\004'; p++);
151 break;
152 default:
153 if (*p != edit_get_byte (edit, i))
154 return -1;
157 if (whole_right)
158 if (strchr (whole_right, edit_get_byte (edit, i)))
159 return -1;
160 return i;
163 #define XXX \
164 if (*s < '\005' || *s == (unsigned char) c) \
165 goto done; \
166 s++;
168 static inline char *xx_strchr (const unsigned char *s, int c)
170 repeat:
171 XXX XXX XXX XXX XXX XXX XXX XXX;
172 XXX XXX XXX XXX XXX XXX XXX XXX;
173 goto repeat;
174 done:
175 return (char *) s;
178 static inline struct syntax_rule apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule)
180 struct context_rule *r;
181 int contextchanged = 0, c;
182 int found_right = 0, found_left = 0, keyword_foundleft = 0, keyword_foundright = 0;
183 int is_end;
184 long end = 0;
185 struct syntax_rule _rule = rule;
186 if (!(c = edit_get_byte (edit, i)))
187 return rule;
188 is_end = (rule.end == (unsigned char) i);
189 /* check to turn off a keyword */
190 if (_rule.keyword) {
191 if (edit_get_byte (edit, i - 1) == '\n')
192 _rule.keyword = 0;
193 if (is_end) {
194 _rule.keyword = 0;
195 keyword_foundleft = 1;
198 /* check to turn off a context */
199 if (_rule.context && !_rule.keyword) {
200 long e;
201 r = edit->rules[_rule.context];
202 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) {
203 _rule.end = e;
204 found_right = 1;
205 _rule.border = RULE_ON_RIGHT_BORDER;
206 if (r->between_delimiters)
207 _rule.context = 0;
208 } else if (is_end && rule.border & RULE_ON_RIGHT_BORDER) {
209 /* always turn off a context at 4 */
210 found_left = 1;
211 _rule.border = 0;
212 if (!keyword_foundleft)
213 _rule.context = 0;
214 } else if (is_end && rule.border & RULE_ON_LEFT_BORDER) {
215 /* never turn off a context at 2 */
216 found_left = 1;
217 _rule.border = 0;
220 /* check to turn on a keyword */
221 if (!_rule.keyword) {
222 char *p;
223 p = (r = edit->rules[_rule.context])->keyword_first_chars;
224 if (p)
225 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
226 struct key_word *k;
227 int count;
228 long e;
229 count = p - r->keyword_first_chars;
230 k = r->keyword[count];
231 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
232 if (e > 0) {
233 end = e;
234 _rule.end = e;
235 _rule.keyword = count;
236 keyword_foundright = 1;
237 break;
241 /* check to turn on a context */
242 if (!_rule.context) {
243 if (!found_left && is_end) {
244 if (rule.border & RULE_ON_RIGHT_BORDER) {
245 _rule.border = 0;
246 _rule.context = 0;
247 contextchanged = 1;
248 _rule.keyword = 0;
249 } else if (rule.border & RULE_ON_LEFT_BORDER) {
250 r = edit->rules[_rule._context];
251 _rule.border = 0;
252 if (r->between_delimiters) {
253 long e;
254 _rule.context = _rule._context;
255 contextchanged = 1;
256 _rule.keyword = 0;
257 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) {
258 _rule.end = e;
259 found_right = 1;
260 _rule.border = RULE_ON_RIGHT_BORDER;
261 _rule.context = 0;
266 if (!found_right) {
267 int count;
268 struct context_rule **rules = edit->rules;
269 for (count = 1; rules[count]; count++) {
270 r = rules[count];
271 if (r->first_left == c) {
272 long e;
273 e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left);
274 if (e >= end && (!_rule.keyword || keyword_foundright)) {
275 _rule.end = e;
276 found_right = 1;
277 _rule.border = RULE_ON_LEFT_BORDER;
278 _rule._context = count;
279 if (!r->between_delimiters)
280 if (!_rule.keyword) {
281 _rule.context = count;
282 contextchanged = 1;
284 break;
290 /* check again to turn on a keyword if the context switched */
291 if (contextchanged && !_rule.keyword) {
292 char *p;
293 p = (r = edit->rules[_rule.context])->keyword_first_chars;
294 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
295 struct key_word *k;
296 int count;
297 long e;
298 count = p - r->keyword_first_chars;
299 k = r->keyword[count];
300 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
301 if (e > 0) {
302 _rule.end = e;
303 _rule.keyword = count;
304 break;
308 return _rule;
311 static struct syntax_rule edit_get_rule (WEdit * edit, long byte_index)
313 long i;
314 if (byte_index > edit->last_get_rule) {
315 for (i = edit->last_get_rule + 1; i <= byte_index; i++) {
316 edit->rule = apply_rules_going_right (edit, i, edit->rule);
317 if (i > (edit->syntax_marker ? edit->syntax_marker->offset + SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY)) {
318 struct _syntax_marker *s;
319 s = edit->syntax_marker;
320 edit->syntax_marker = syntax_malloc (sizeof (struct _syntax_marker));
321 edit->syntax_marker->next = s;
322 edit->syntax_marker->offset = i;
323 edit->syntax_marker->rule = edit->rule;
326 } else if (byte_index < edit->last_get_rule) {
327 struct _syntax_marker *s;
328 for (;;) {
329 if (!edit->syntax_marker) {
330 memset (&edit->rule, 0, sizeof (edit->rule));
331 for (i = -1; i <= byte_index; i++)
332 edit->rule = apply_rules_going_right (edit, i, edit->rule);
333 break;
335 if (byte_index >= edit->syntax_marker->offset) {
336 edit->rule = edit->syntax_marker->rule;
337 for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++)
338 edit->rule = apply_rules_going_right (edit, i, edit->rule);
339 break;
341 s = edit->syntax_marker->next;
342 syntax_free (edit->syntax_marker);
343 edit->syntax_marker = s;
346 edit->last_get_rule = byte_index;
347 return edit->rule;
350 static void translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *color)
352 struct key_word *k;
353 k = edit->rules[rule.context]->keyword[rule.keyword];
354 *color = k->color;
357 void edit_get_syntax_color (WEdit * edit, long byte_index, int *color)
359 if (edit->rules && byte_index < edit->last_byte &&
360 option_syntax_highlighting && use_colors) {
361 translate_rule_to_color (edit, edit_get_rule (edit, byte_index), color);
362 } else {
363 *color = use_colors ? EDITOR_NORMAL_COLOR_INDEX : 0;
369 Returns 0 on error/eof or a count of the number of bytes read
370 including the newline. Result must be free'd.
372 static int read_one_line (char **line, FILE * f)
374 char *p;
375 int len = 256, c, r = 0, i = 0;
376 p = syntax_malloc (len);
378 for (;;) {
379 c = fgetc (f);
380 if (c == EOF) {
381 if (ferror (f)) {
382 if (errno == EINTR)
383 continue;
384 r = 0;
386 break;
387 } else if (c == '\n') {
388 r = i + 1; /* extra 1 for the newline just read */
389 break;
390 } else {
391 if (i >= len - 1) {
392 char *q;
393 q = syntax_malloc (len * 2);
394 memcpy (q, p, len);
395 syntax_free (p);
396 p = q;
397 len *= 2;
399 p[i++] = c;
402 p[i] = 0;
403 *line = p;
404 return r;
407 static char *convert (char *s)
409 char *r, *p;
410 p = r = s;
411 while (*s) {
412 switch (*s) {
413 case '\\':
414 s++;
415 switch (*s) {
416 case ' ':
417 *p = ' ';
418 s--;
419 break;
420 case 'n':
421 *p = '\n';
422 break;
423 case 'r':
424 *p = '\r';
425 break;
426 case 't':
427 *p = '\t';
428 break;
429 case 's':
430 *p = ' ';
431 break;
432 case '*':
433 *p = '*';
434 break;
435 case '\\':
436 *p = '\\';
437 break;
438 case '[':
439 case ']':
440 *p = '\003';
441 break;
442 case '{':
443 case '}':
444 *p = '\004';
445 break;
446 case 0:
447 *p = *s;
448 return r;
449 default:
450 *p = *s;
451 break;
453 break;
454 case '*':
455 *p = '\001';
456 break;
457 case '+':
458 *p = '\002';
459 break;
460 default:
461 *p = *s;
462 break;
464 s++;
465 p++;
467 *p = '\0';
468 return r;
471 #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
473 static void get_args (char *l, char **args, int *argc)
475 *argc = 0;
476 for (;;) {
477 char *p = l;
478 while (*p && whiteness (*p))
479 p++;
480 if (!*p)
481 break;
482 for (l = p + 1; *l && !whiteness (*l); l++);
483 if (*l)
484 *l++ = '\0';
485 *args = convert (p);
486 (*argc)++;
487 args++;
489 *args = 0;
492 #define free_args(x)
493 #define break_a {result=line;break;}
494 #define check_a {if(!*a){result=line;break;}}
495 #define check_not_a {if(*a){result=line;break;}}
497 int try_alloc_color_pair (char *fg, char *bg);
499 int this_try_alloc_color_pair (char *fg, char *bg)
501 char f[80], b[80], *p;
502 if (bg)
503 if (!*bg)
504 bg = 0;
505 if (fg)
506 if (!*fg)
507 fg = 0;
508 if (fg) {
509 strcpy (f, fg);
510 p = strchr (f, '/');
511 if (p)
512 *p = '\0';
513 fg = f;
515 if (bg) {
516 strcpy (b, bg);
517 p = strchr (b, '/');
518 if (p)
519 *p = '\0';
520 bg = b;
522 return try_alloc_color_pair (fg, bg);
525 static char *error_file_name = 0;
527 static FILE *open_include_file (char *filename)
529 FILE *f;
531 syntax_g_free (error_file_name);
532 error_file_name = g_strdup (filename);
533 if (*filename == PATH_SEP)
534 return fopen (filename, "r");
536 g_free (error_file_name);
537 error_file_name = g_strconcat (home_dir, EDIT_DIR PATH_SEP_STR,
538 filename, NULL);
539 f = fopen (error_file_name, "r");
540 if (f)
541 return f;
543 g_free (error_file_name);
544 error_file_name = g_strconcat (mc_home, PATH_SEP_STR "syntax" PATH_SEP_STR,
545 filename, NULL);
546 return fopen (error_file_name, "r");
549 /* returns line number on error */
550 static int edit_read_syntax_rules (WEdit * edit, FILE * f)
552 FILE *g = 0;
553 char *fg, *bg;
554 char last_fg[32] = "", last_bg[32] = "";
555 char whole_right[512];
556 char whole_left[512];
557 char *args[1024], *l = 0;
558 int save_line = 0, line = 0;
559 struct context_rule **r, *c = 0;
560 int num_words = -1, num_contexts = -1;
561 int argc, result = 0;
562 int i, j;
564 args[0] = 0;
566 strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
567 strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
569 r = edit->rules = syntax_malloc (MAX_CONTEXTS * sizeof (struct context_rule *));
571 for (;;) {
572 char **a;
573 line++;
574 l = 0;
575 if (!read_one_line (&l, f)) {
576 if (g) {
577 fclose (f);
578 f = g;
579 g = 0;
580 line = save_line + 1;
581 syntax_g_free (error_file_name);
582 if (l)
583 syntax_free (l);
584 if (!read_one_line (&l, f))
585 break;
586 } else {
587 break;
590 get_args (l, args, &argc);
591 a = args + 1;
592 if (!args[0]) {
593 /* do nothing */
594 } else if (!strcmp (args[0], "include")) {
595 if (g || argc != 2) {
596 result = line;
597 break;
599 g = f;
600 f = open_include_file (args[1]);
601 if (!f) {
602 syntax_g_free (error_file_name);
603 result = line;
604 break;
606 save_line = line;
607 line = 0;
608 } else if (!strcmp (args[0], "wholechars")) {
609 check_a;
610 if (!strcmp (*a, "left")) {
611 a++;
612 strcpy (whole_left, *a);
613 } else if (!strcmp (*a, "right")) {
614 a++;
615 strcpy (whole_right, *a);
616 } else {
617 strcpy (whole_left, *a);
618 strcpy (whole_right, *a);
620 a++;
621 check_not_a;
622 } else if (!strcmp (args[0], "context")) {
623 check_a;
624 if (num_contexts == -1) {
625 if (strcmp (*a, "default")) { /* first context is the default */
626 break_a;
628 a++;
629 c = r[0] = syntax_malloc (sizeof (struct context_rule));
630 c->left = (char *) strdup (" ");
631 c->right = (char *) strdup (" ");
632 num_contexts = 0;
633 } else {
634 c = r[num_contexts] = syntax_malloc (sizeof (struct context_rule));
635 if (!strcmp (*a, "exclusive")) {
636 a++;
637 c->between_delimiters = 1;
639 check_a;
640 if (!strcmp (*a, "whole")) {
641 a++;
642 c->whole_word_chars_left = (char *) strdup (whole_left);
643 c->whole_word_chars_right = (char *) strdup (whole_right);
644 } else if (!strcmp (*a, "wholeleft")) {
645 a++;
646 c->whole_word_chars_left = (char *) strdup (whole_left);
647 } else if (!strcmp (*a, "wholeright")) {
648 a++;
649 c->whole_word_chars_right = (char *) strdup (whole_right);
651 check_a;
652 if (!strcmp (*a, "linestart")) {
653 a++;
654 c->line_start_left = 1;
656 check_a;
657 c->left = (char *) strdup (*a++);
658 check_a;
659 if (!strcmp (*a, "linestart")) {
660 a++;
661 c->line_start_right = 1;
663 check_a;
664 c->right = (char *) strdup (*a++);
665 c->first_left = *c->left;
666 c->first_right = *c->right;
668 c->keyword = syntax_malloc (MAX_WORDS_PER_CONTEXT * sizeof (struct key_word *));
669 #if 0
670 c->max_words = MAX_WORDS_PER_CONTEXT;
671 #endif
672 num_words = 1;
673 c->keyword[0] = syntax_malloc (sizeof (struct key_word));
674 fg = *a;
675 if (*a)
676 a++;
677 bg = *a;
678 if (*a)
679 a++;
680 strcpy (last_fg, fg ? fg : "");
681 strcpy (last_bg, bg ? bg : "");
682 c->keyword[0]->color = this_try_alloc_color_pair (fg, bg);
683 c->keyword[0]->keyword = (char *) strdup (" ");
684 check_not_a;
685 num_contexts++;
686 } else if (!strcmp (args[0], "spellcheck")) {
687 if (!c) {
688 result = line;
689 break;
691 c->spelling = 1;
692 } else if (!strcmp (args[0], "keyword")) {
693 struct key_word *k;
694 if (num_words == -1)
695 break_a;
696 check_a;
697 k = r[num_contexts - 1]->keyword[num_words] = syntax_malloc (sizeof (struct key_word));
698 if (!strcmp (*a, "whole")) {
699 a++;
700 k->whole_word_chars_left = (char *) strdup (whole_left);
701 k->whole_word_chars_right = (char *) strdup (whole_right);
702 } else if (!strcmp (*a, "wholeleft")) {
703 a++;
704 k->whole_word_chars_left = (char *) strdup (whole_left);
705 } else if (!strcmp (*a, "wholeright")) {
706 a++;
707 k->whole_word_chars_right = (char *) strdup (whole_right);
709 check_a;
710 if (!strcmp (*a, "linestart")) {
711 a++;
712 k->line_start = 1;
714 check_a;
715 if (!strcmp (*a, "whole")) {
716 break_a;
718 k->keyword = (char *) strdup (*a++);
719 k->first = *k->keyword;
720 fg = *a;
721 if (*a)
722 a++;
723 bg = *a;
724 if (*a)
725 a++;
726 if (!fg)
727 fg = last_fg;
728 if (!bg)
729 bg = last_bg;
730 k->color = this_try_alloc_color_pair (fg, bg);
731 check_not_a;
732 num_words++;
733 } else if (*(args[0]) == '#') {
734 /* do nothing for comment */
735 } else if (!strcmp (args[0], "file")) {
736 break;
737 } else { /* anything else is an error */
738 break_a;
740 free_args (args);
741 syntax_free (l);
743 free_args (args);
744 syntax_free (l);
746 if (!edit->rules[0])
747 syntax_free (edit->rules);
749 if (result)
750 return result;
752 if (num_contexts == -1) {
753 result = line;
754 return result;
758 char first_chars[MAX_WORDS_PER_CONTEXT + 2], *p;
759 for (i = 0; edit->rules[i]; i++) {
760 c = edit->rules[i];
761 p = first_chars;
762 *p++ = (char) 1;
763 for (j = 1; c->keyword[j]; j++)
764 *p++ = c->keyword[j]->first;
765 *p = '\0';
766 c->keyword_first_chars = syntax_malloc (strlen (first_chars) + 2);
767 strcpy (c->keyword_first_chars, first_chars);
771 return result;
774 int edit_check_spelling (WEdit * edit)
776 return 0;
779 void (*syntax_change_callback) (CWidget *) = 0;
781 void edit_set_syntax_change_callback (void (*callback) (CWidget *))
783 syntax_change_callback = callback;
786 void edit_free_syntax_rules (WEdit * edit)
788 int i, j;
789 if (!edit)
790 return;
791 if (!edit->rules)
792 return;
793 edit_get_rule (edit, -1);
794 syntax_free (edit->syntax_type);
795 edit->syntax_type = 0;
796 if (syntax_change_callback)
797 (*syntax_change_callback) (&edit->widget);
798 for (i = 0; edit->rules[i]; i++) {
799 if (edit->rules[i]->keyword) {
800 for (j = 0; edit->rules[i]->keyword[j]; j++) {
801 syntax_free (edit->rules[i]->keyword[j]->keyword);
802 syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_left);
803 syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_right);
804 syntax_free (edit->rules[i]->keyword[j]);
807 syntax_free (edit->rules[i]->left);
808 syntax_free (edit->rules[i]->right);
809 syntax_free (edit->rules[i]->whole_word_chars_left);
810 syntax_free (edit->rules[i]->whole_word_chars_right);
811 syntax_free (edit->rules[i]->keyword);
812 syntax_free (edit->rules[i]->keyword_first_chars);
813 syntax_free (edit->rules[i]);
815 while (edit->syntax_marker) {
816 struct _syntax_marker *s = edit->syntax_marker->next;
817 syntax_free (edit->syntax_marker);
818 edit->syntax_marker = s;
820 syntax_free (edit->rules);
823 /* returns -1 on file error, line number on error in file syntax */
824 static int edit_read_syntax_file (WEdit * edit, char **names, char *syntax_file, char *editor_file, char *first_line, char *type)
826 FILE *f;
827 regex_t r;
828 regmatch_t pmatch[1];
829 char *args[1024], *l = 0;
830 int line = 0;
831 int argc;
832 int result = 0;
833 int count = 0;
834 char *lib_file;
836 f = fopen (syntax_file, "r");
837 if (!f){
838 lib_file = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
839 f = fopen (lib_file, "r");
840 g_free (lib_file);
841 if (!f)
842 return -1;
844 args[0] = 0;
845 for (;;) {
846 line++;
847 syntax_free (l);
848 if (!read_one_line (&l, f))
849 break;
850 get_args (l, args, &argc);
851 if (!args[0])
852 continue;
853 /* looking for `file ...' lines only */
854 if (strcmp (args[0], "file")) {
855 free_args (args);
856 continue;
858 /* must have two args or report error */
859 if (!args[1] || !args[2]) {
860 result = line;
861 break;
863 if (names) {
864 /* 1: just collecting a list of names of rule sets */
865 names[count++] = (char *) strdup (args[2]);
866 names[count] = 0;
867 } else if (type) {
868 /* 2: rule set was explicitly specified by the caller */
869 if (!strcmp (type, args[2]))
870 goto found_type;
871 } else if (editor_file && edit) {
872 /* 3: auto-detect rule set from regular expressions */
873 int q;
874 if (regcomp (&r, args[1], REG_EXTENDED)) {
875 result = line;
876 break;
878 /* does filename match arg 1 ? */
879 q = !regexec (&r, editor_file, 1, pmatch, 0);
880 regfree (&r);
881 if (!q && args[3]) {
882 if (regcomp (&r, args[3], REG_EXTENDED)) {
883 result = line;
884 break;
886 /* does first line match arg 3 ? */
887 q = !regexec (&r, first_line, 1, pmatch, 0);
888 regfree (&r);
890 if (q) {
891 int line_error;
892 found_type:
893 line_error = edit_read_syntax_rules (edit, f);
894 if (line_error) {
895 if (!error_file_name) /* an included file */
896 result = line + line_error;
897 else
898 result = line_error;
899 } else {
900 syntax_free (edit->syntax_type);
901 edit->syntax_type = (char *) strdup (args[2]);
902 /* if there are no rules then turn off syntax highlighting for speed */
903 if (!edit->rules[1])
904 if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling) {
905 edit_free_syntax_rules (edit);
906 break;
908 /* notify the callback of a change in rule set */
909 if (syntax_change_callback)
910 (*syntax_change_callback) (&edit->widget);
912 break;
915 free_args (args);
917 free_args (args);
918 syntax_free (l);
919 fclose (f);
920 return result;
923 static char *get_first_editor_line (WEdit * edit)
925 int i;
926 static char s[256];
927 s[0] = '\0';
928 if (!edit)
929 return s;
930 for (i = 0; i < 255; i++) {
931 s[i] = edit_get_byte (edit, i);
932 if (s[i] == '\n') {
933 s[i] = '\0';
934 break;
937 s[255] = '\0';
938 return s;
941 /* loads rules into edit struct. one of edit or names must be zero. if
942 edit is zero, a list of types will be stored into name. type may be zero
943 in which case the type will be selected according to the filename. */
944 void edit_load_syntax (WEdit * edit, char **names, char *type)
946 int r;
947 char *f;
949 edit_free_syntax_rules (edit);
951 if (!use_colors)
952 return;
954 if (!option_syntax_highlighting)
955 return;
957 if (edit) {
958 if (!edit->filename)
959 return;
960 if (!*edit->filename && !type)
961 return;
963 f = catstrs (home_dir, SYNTAX_FILE, 0);
964 r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0, get_first_editor_line (edit), type);
965 if (r == -1) {
966 edit_free_syntax_rules (edit);
967 edit_error_dialog (_ (" Load syntax file "), _ (" File access error "));
968 return;
970 if (r) {
971 edit_free_syntax_rules (edit);
972 message (0, _(" Load syntax file "),
973 _(" Error in file %s on line %d "),
974 error_file_name ? error_file_name : f, r);
975 syntax_g_free (error_file_name);
976 return;
980 #else
982 int option_syntax_highlighting = 0;
984 void edit_load_syntax (WEdit * edit, char **names, char *type)
986 return;
989 void edit_free_syntax_rules (WEdit * edit)
991 return;
994 void edit_get_syntax_color (WEdit * edit, long byte_index, int *color)
996 *color = use_colors ? EDITOR_NORMAL_COLOR_INDEX : 0;
999 int edit_check_spelling (WEdit * edit)
1001 return 0;
1004 #endif /* HAVE_SYNTAXH */