*** empty log message ***
[midnight-commander.git] / edit / syntax.c
bloba3c7fffbe7e12eaff943f00fcb0b63513ade44b6
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 #include "edit.h"
28 /* bytes */
29 #define SYNTAX_MARKER_DENSITY 512
32 Mispelled words are flushed from the syntax highlighting rules
33 when they have been around longer than
34 TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
35 chars per second and say 3 chars + a space per word, we can
36 accumulate 450 words absolute max with a value of 60. This is
37 below this limit of 1024 words in a context.
39 #define TRANSIENT_WORD_TIME_OUT 60
41 #define UNKNOWN_FORMAT "unknown"
43 #ifdef HAVE_SYNTAXH
45 int option_syntax_highlighting = 1;
46 int option_auto_spellcheck = 1;
48 /* these three functions are called from the outside */
49 void edit_load_syntax (WEdit * edit, char **names, char *type);
50 void edit_free_syntax_rules (WEdit * edit);
51 void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg);
53 #ifdef HAVE_MAD
54 static void *mad_syntax_malloc (size_t x, char *file, int line)
55 #define syntax_malloc(x) mad_syntax_malloc (x, __FILE__, __LINE__)
56 #else
57 static void *syntax_malloc (size_t x)
58 #endif
60 void *p;
61 #ifdef HAVE_MAD
62 p = mad_alloc (x, file, line);
63 #else
64 p = malloc (x);
65 #endif
66 memset (p, 0, x);
67 return p;
70 #define syntax_free(x) {if(x){free(x);(x)=0;}}
72 static long compare_word_to_right (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start)
74 unsigned char *p, *q;
75 int c, d, j;
76 if (!*text)
77 return -1;
78 c = edit_get_byte (edit, i - 1);
79 if (line_start)
80 if (c != '\n')
81 return -1;
82 if (whole_left)
83 if (strchr (whole_left, c))
84 return -1;
85 for (p = (unsigned char *) text, q = p + strlen ((char *) p); (unsigned long) p < (unsigned long) q; p++, i++) {
86 switch (*p) {
87 case '\001':
88 p++;
89 for (;;) {
90 c = edit_get_byte (edit, i);
91 if (!*p)
92 if (whole_right)
93 if (!strchr (whole_right, c))
94 break;
95 if (c == *p)
96 break;
97 if (c == '\n')
98 return -1;
99 i++;
101 break;
102 case '\002':
103 p++;
104 j = 0;
105 for (;;) {
106 c = edit_get_byte (edit, i);
107 if (c == *p) {
108 j = i;
109 if (*p == *text && !p[1]) /* handle eg '+' and @+@ keywords properly */
110 break;
112 if (j && strchr ((char *) p + 1, c)) /* c exists further down, so it will get matched later */
113 break;
114 if (c == '\n' || c == '\t' || c == ' ') {
115 if (!*p) {
116 i--;
117 break;
119 if (!j)
120 return -1;
121 i = j;
122 break;
124 if (whole_right)
125 if (!strchr (whole_right, c)) {
126 if (!*p) {
127 i--;
128 break;
130 if (!j)
131 return -1;
132 i = j;
133 break;
135 i++;
137 break;
138 case '\003':
139 p++;
140 c = -1;
141 for (;; i++) {
142 d = c;
143 c = edit_get_byte (edit, i);
144 for (j = 0; p[j] != '\003'; j++)
145 if (c == p[j])
146 goto found_char2;
147 break;
148 found_char2:
149 j = c; /* dummy command */
151 i--;
152 while (*p != '\003')
153 p++;
154 if (p[1] == d)
155 i--;
156 break;
157 case '\004':
158 p++;
159 c = edit_get_byte (edit, i);
160 for (; *p != '\004'; p++)
161 if (c == *p)
162 goto found_char3;
163 return -1;
164 found_char3:
165 for (; *p != '\004'; p++);
166 break;
167 default:
168 if (*p != edit_get_byte (edit, i))
169 return -1;
172 if (whole_right)
173 if (strchr (whole_right, edit_get_byte (edit, i)))
174 return -1;
175 return i;
178 #define XXX \
179 if (*s < '\005' || *s == (unsigned char) c) \
180 goto done; \
181 s++;
183 static inline char *xx_strchr (const unsigned char *s, int c)
185 repeat:
186 XXX XXX XXX XXX XXX XXX XXX XXX;
187 XXX XXX XXX XXX XXX XXX XXX XXX;
188 goto repeat;
189 done:
190 return (char *) s;
193 static inline struct syntax_rule apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule)
195 struct context_rule *r;
196 int contextchanged = 0, c;
197 int found_right = 0, found_left = 0, keyword_foundleft = 0, keyword_foundright = 0;
198 int is_end;
199 long end = 0;
200 struct syntax_rule _rule = rule;
201 if (!(c = edit_get_byte (edit, i)))
202 return rule;
203 is_end = (rule.end == (unsigned char) i);
204 /* check to turn off a keyword */
205 if (_rule.keyword) {
206 struct key_word *k;
207 k = edit->rules[_rule.context]->keyword[_rule.keyword];
208 if (edit_get_byte (edit, i - 1) == '\n')
209 _rule.keyword = 0;
210 if (is_end) {
211 _rule.keyword = 0;
212 keyword_foundleft = 1;
215 /* check to turn off a context */
216 if (_rule.context && !_rule.keyword) {
217 long e;
218 r = edit->rules[_rule.context];
219 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) {
220 _rule.end = e;
221 found_right = 1;
222 _rule.border = RULE_ON_RIGHT_BORDER;
223 if (r->between_delimiters)
224 _rule.context = 0;
225 } else if (is_end && rule.border & RULE_ON_RIGHT_BORDER) {
226 /* always turn off a context at 4 */
227 found_left = 1;
228 _rule.border = 0;
229 if (!keyword_foundleft)
230 _rule.context = 0;
231 } else if (is_end && rule.border & RULE_ON_LEFT_BORDER) {
232 /* never turn off a context at 2 */
233 found_left = 1;
234 _rule.border = 0;
237 /* check to turn on a keyword */
238 if (!_rule.keyword) {
239 char *p;
240 p = (r = edit->rules[_rule.context])->keyword_first_chars;
241 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
242 struct key_word *k;
243 int count;
244 long e;
245 count = (unsigned long) p - (unsigned long) r->keyword_first_chars;
246 k = r->keyword[count];
247 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
248 if (e > 0) {
249 end = e;
250 _rule.end = e;
251 _rule.keyword = count;
252 keyword_foundright = 1;
253 break;
257 /* check to turn on a context */
258 if (!_rule.context) {
259 if (!found_left && is_end) {
260 if (rule.border & RULE_ON_RIGHT_BORDER) {
261 _rule.border = 0;
262 _rule.context = 0;
263 contextchanged = 1;
264 _rule.keyword = 0;
265 } else if (rule.border & RULE_ON_LEFT_BORDER) {
266 r = edit->rules[_rule._context];
267 _rule.border = 0;
268 if (r->between_delimiters) {
269 long e;
270 _rule.context = _rule._context;
271 contextchanged = 1;
272 _rule.keyword = 0;
273 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) {
274 _rule.end = e;
275 found_right = 1;
276 _rule.border = RULE_ON_RIGHT_BORDER;
277 _rule.context = 0;
282 if (!found_right) {
283 int count;
284 struct context_rule **rules = edit->rules;
285 for (count = 1; rules[count]; count++) {
286 r = rules[count];
287 if (r->first_left == c) {
288 long e;
289 e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left);
290 if (e >= end && (!_rule.keyword || keyword_foundright)) {
291 _rule.end = e;
292 found_right = 1;
293 _rule.border = RULE_ON_LEFT_BORDER;
294 _rule._context = count;
295 if (!r->between_delimiters)
296 if (!_rule.keyword)
297 _rule.context = count;
298 break;
304 /* check again to turn on a keyword if the context switched */
305 if (contextchanged && !_rule.keyword) {
306 char *p;
307 p = (r = edit->rules[_rule.context])->keyword_first_chars;
308 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
309 struct key_word *k;
310 int count;
311 long e;
312 count = (unsigned long) p - (unsigned long) r->keyword_first_chars;
313 k = r->keyword[count];
314 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
315 if (e > 0) {
316 _rule.end = e;
317 _rule.keyword = count;
318 break;
322 return _rule;
325 static struct syntax_rule edit_get_rule (WEdit * edit, long byte_index)
327 long i;
328 if (byte_index > edit->last_get_rule) {
329 for (i = edit->last_get_rule + 1; i <= byte_index; i++) {
330 edit->rule = apply_rules_going_right (edit, i, edit->rule);
331 if (i > (edit->syntax_marker ? edit->syntax_marker->offset + SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY)) {
332 struct _syntax_marker *s;
333 s = edit->syntax_marker;
334 edit->syntax_marker = syntax_malloc (sizeof (struct _syntax_marker));
335 edit->syntax_marker->next = s;
336 edit->syntax_marker->offset = i;
337 edit->syntax_marker->rule = edit->rule;
340 } else if (byte_index < edit->last_get_rule) {
341 struct _syntax_marker *s;
342 for (;;) {
343 if (!edit->syntax_marker) {
344 memset (&edit->rule, 0, sizeof (edit->rule));
345 for (i = -1; i <= byte_index; i++)
346 edit->rule = apply_rules_going_right (edit, i, edit->rule);
347 break;
349 if (byte_index >= edit->syntax_marker->offset) {
350 edit->rule = edit->syntax_marker->rule;
351 for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++)
352 edit->rule = apply_rules_going_right (edit, i, edit->rule);
353 break;
355 s = edit->syntax_marker->next;
356 syntax_free (edit->syntax_marker);
357 edit->syntax_marker = s;
360 edit->last_get_rule = byte_index;
361 return edit->rule;
364 static void translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *fg, int *bg)
366 struct key_word *k;
367 k = edit->rules[rule.context]->keyword[rule.keyword];
368 *bg = k->bg;
369 *fg = k->fg;
372 extern int use_colors;
374 void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
376 if (edit->rules && byte_index < edit->last_byte &&
377 option_syntax_highlighting && use_colors) {
378 translate_rule_to_color (edit, edit_get_rule (edit, byte_index), fg, bg);
379 } else {
380 *fg = EDITOR_NORMAL_COLOR;
386 Returns 0 on error/eof or a count of the number of bytes read
387 including the newline. Result must be free'd.
389 #ifdef HAVE_MAD
390 static int mad_read_one_line (char **line, FILE * f, char *file, int line_)
391 #define read_one_line(a,b) mad_read_one_line(a,b,__FILE__,__LINE__)
392 #else
393 static int read_one_line (char **line, FILE * f)
394 #endif
396 char *p;
397 int len = 256, c, r = 0, i = 0;
398 #ifdef HAVE_MAD
399 p = mad_syntax_malloc (len, file, line_);
400 #else
401 p = syntax_malloc (len);
402 #endif
403 for (;;) {
404 c = fgetc (f);
405 if (c == -1) {
406 if (errno == EINTR)
407 continue;
408 r = 0;
409 break;
410 } else if (c == '\n') {
411 r = i + 1; /* extra 1 for the newline just read */
412 break;
413 } else {
414 if (i >= len - 1) {
415 char *q;
416 q = syntax_malloc (len * 2);
417 memcpy (q, p, len);
418 syntax_free (p);
419 p = q;
420 len *= 2;
422 p[i++] = c;
425 p[i] = 0;
426 *line = p;
427 return r;
430 static char *strdup_convert (char *s)
432 char *r, *p;
433 p = r = (char *) strdup (s);
434 while (*s) {
435 switch (*s) {
436 case '\\':
437 s++;
438 switch (*s) {
439 case ' ':
440 *p = ' ';
441 s--;
442 break;
443 case 'n':
444 *p = '\n';
445 break;
446 case 'r':
447 *p = '\r';
448 break;
449 case 't':
450 *p = '\t';
451 break;
452 case 's':
453 *p = ' ';
454 break;
455 case '*':
456 *p = '*';
457 break;
458 case '\\':
459 *p = '\\';
460 break;
461 case '[':
462 case ']':
463 *p = '\003';
464 break;
465 case '{':
466 case '}':
467 *p = '\004';
468 break;
469 default:
470 *p = *s;
471 break;
473 break;
474 case '*':
475 *p = '\001';
476 break;
477 case '+':
478 *p = '\002';
479 break;
480 default:
481 *p = *s;
482 break;
484 s++;
485 p++;
487 *p = '\0';
488 return r;
491 #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
493 static void get_args (char *l, char **args, int *argc)
495 *argc = 0;
496 l--;
497 for (;;) {
498 char *p;
499 for (p = l + 1; *p && whiteness (*p); p++);
500 if (!*p)
501 break;
502 for (l = p + 1; *l && !whiteness (*l); l++);
503 *l = '\0';
504 *args = strdup_convert (p);
505 (*argc)++;
506 args++;
508 *args = 0;
511 static void free_args (char **args)
513 while (*args) {
514 syntax_free (*args);
515 *args = 0;
516 args++;
520 #define check_a {if(!*a){result=line;break;}}
521 #define check_not_a {if(*a){result=line;break;}}
523 int try_alloc_color_pair (char *fg, char *bg);
525 int this_try_alloc_color_pair (char *fg, char *bg)
527 char f[80], b[80], *p;
528 if (bg)
529 if (!*bg)
530 bg = 0;
531 if (fg)
532 if (!*fg)
533 fg = 0;
534 if (fg) {
535 strcpy (f, fg);
536 p = strchr (f, '/');
537 if (p)
538 *p = '\0';
539 fg = f;
541 if (bg) {
542 strcpy (b, bg);
543 p = strchr (b, '/');
544 if (p)
545 *p = '\0';
546 bg = b;
548 return try_alloc_color_pair (fg, bg);
551 static char *error_file_name = 0;
553 extern char *mc_home;
555 static FILE *open_include_file (char *filename)
557 FILE *f;
558 char p[MAX_PATH_LEN];
559 syntax_free (error_file_name);
560 error_file_name = (char *) strdup (filename);
561 if (*filename == '/')
562 return fopen (filename, "r");
563 strcpy (p, home_dir);
564 strcat (p, EDIT_DIR "/");
565 strcat (p, filename);
566 syntax_free (error_file_name);
567 error_file_name = (char *) strdup (p);
568 f = fopen (p, "r");
569 if (f)
570 return f;
571 strcpy (p, mc_home);
572 strcat (p, "/syntax/");
573 strcat (p, filename);
574 syntax_free (error_file_name);
575 error_file_name = (char *) strdup (p);
576 return fopen (p, "r");
579 /* returns line number on error */
580 static int edit_read_syntax_rules (WEdit * edit, FILE * f)
582 FILE *g = 0;
583 char *fg, *bg;
584 char last_fg[32] = "", last_bg[32] = "";
585 char whole_right[512];
586 char whole_left[512];
587 char *args[1024], *l = 0;
588 int save_line = 0, line = 0;
589 struct context_rule **r, *c = 0;
590 int num_words = -1, num_contexts = -1;
591 int argc, result = 0;
592 int i, j;
594 args[0] = 0;
596 strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
597 strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
599 r = edit->rules = syntax_malloc (MAX_CONTEXTS * sizeof (struct context_rule *));
601 for (;;) {
602 char **a;
603 line++;
604 l = 0;
605 if (!read_one_line (&l, f)) {
606 if (g) {
607 fclose (f);
608 f = g;
609 g = 0;
610 line = save_line + 1;
611 syntax_free (error_file_name);
612 if (l)
613 syntax_free (l);
614 if (!read_one_line (&l, f))
615 break;
616 } else {
617 break;
620 get_args (l, args, &argc);
621 a = args + 1;
622 if (!args[0]) {
623 /* do nothing */
624 } else if (!strcmp (args[0], "include")) {
625 if (g || argc != 2) {
626 result = line;
627 break;
629 g = f;
630 f = open_include_file (args[1]);
631 if (!f) {
632 syntax_free (error_file_name);
633 result = line;
634 break;
636 save_line = line;
637 line = 0;
638 } else if (!strcmp (args[0], "wholechars")) {
639 check_a;
640 if (!strcmp (*a, "left")) {
641 a++;
642 strcpy (whole_left, *a);
643 } else if (!strcmp (*a, "right")) {
644 a++;
645 strcpy (whole_right, *a);
646 } else {
647 strcpy (whole_left, *a);
648 strcpy (whole_right, *a);
650 a++;
651 check_not_a;
652 } else if (!strcmp (args[0], "context")) {
653 check_a;
654 if (num_contexts == -1) {
655 if (strcmp (*a, "default")) { /* first context is the default */
656 *a = 0;
657 check_a;
659 a++;
660 c = r[0] = syntax_malloc (sizeof (struct context_rule));
661 c->left = (char *) strdup (" ");
662 c->right = (char *) strdup (" ");
663 num_contexts = 0;
664 } else {
665 c = r[num_contexts] = syntax_malloc (sizeof (struct context_rule));
666 if (!strcmp (*a, "exclusive")) {
667 a++;
668 c->between_delimiters = 1;
670 check_a;
671 if (!strcmp (*a, "whole")) {
672 a++;
673 c->whole_word_chars_left = (char *) strdup (whole_left);
674 c->whole_word_chars_right = (char *) strdup (whole_right);
675 } else if (!strcmp (*a, "wholeleft")) {
676 a++;
677 c->whole_word_chars_left = (char *) strdup (whole_left);
678 } else if (!strcmp (*a, "wholeright")) {
679 a++;
680 c->whole_word_chars_right = (char *) strdup (whole_right);
682 check_a;
683 if (!strcmp (*a, "linestart")) {
684 a++;
685 c->line_start_left = 1;
687 check_a;
688 c->left = (char *) strdup (*a++);
689 check_a;
690 if (!strcmp (*a, "linestart")) {
691 a++;
692 c->line_start_right = 1;
694 check_a;
695 c->right = (char *) strdup (*a++);
696 c->first_left = *c->left;
697 c->first_right = *c->right;
698 c->single_char = (strlen (c->right) == 1);
700 c->keyword = syntax_malloc (MAX_WORDS_PER_CONTEXT * sizeof (struct key_word *));
701 #if 0
702 c->max_words = MAX_WORDS_PER_CONTEXT;
703 #endif
704 num_words = 1;
705 c->keyword[0] = syntax_malloc (sizeof (struct key_word));
706 fg = *a;
707 if (*a)
708 a++;
709 bg = *a;
710 if (*a)
711 a++;
712 strcpy (last_fg, fg ? fg : "");
713 strcpy (last_bg, bg ? bg : "");
714 c->keyword[0]->fg = this_try_alloc_color_pair (fg, bg);
715 c->keyword[0]->keyword = (char *) strdup (" ");
716 check_not_a;
717 num_contexts++;
718 } else if (!strcmp (args[0], "spellcheck")) {
719 if (!c) {
720 result = line;
721 break;
723 c->spelling = 1;
724 } else if (!strcmp (args[0], "keyword")) {
725 struct key_word *k;
726 if (num_words == -1)
727 *a = 0;
728 check_a;
729 k = r[num_contexts - 1]->keyword[num_words] = syntax_malloc (sizeof (struct key_word));
730 if (!strcmp (*a, "whole")) {
731 a++;
732 k->whole_word_chars_left = (char *) strdup (whole_left);
733 k->whole_word_chars_right = (char *) strdup (whole_right);
734 } else if (!strcmp (*a, "wholeleft")) {
735 a++;
736 k->whole_word_chars_left = (char *) strdup (whole_left);
737 } else if (!strcmp (*a, "wholeright")) {
738 a++;
739 k->whole_word_chars_right = (char *) strdup (whole_right);
741 check_a;
742 if (!strcmp (*a, "linestart")) {
743 a++;
744 k->line_start = 1;
746 check_a;
747 if (!strcmp (*a, "whole")) {
748 *a = 0;
749 check_a;
751 k->keyword = (char *) strdup (*a++);
752 k->first = *k->keyword;
753 fg = *a;
754 if (*a)
755 a++;
756 bg = *a;
757 if (*a)
758 a++;
759 if (!fg)
760 fg = last_fg;
761 if (!bg)
762 bg = last_bg;
763 k->fg = this_try_alloc_color_pair (fg, bg);
764 check_not_a;
765 num_words++;
766 } else if (!strncmp (args[0], "#", 1)) {
767 /* do nothing for comment */
768 } else if (!strcmp (args[0], "file")) {
769 break;
770 } else { /* anything else is an error */
771 *a = 0;
772 check_a;
774 free_args (args);
775 syntax_free (l);
777 free_args (args);
778 syntax_free (l);
780 if (!edit->rules[0])
781 syntax_free (edit->rules);
783 if (result)
784 return result;
786 if (num_contexts == -1) {
787 result = line;
788 return result;
792 char first_chars[MAX_WORDS_PER_CONTEXT + 2], *p;
793 for (i = 0; edit->rules[i]; i++) {
794 c = edit->rules[i];
795 p = first_chars;
796 *p++ = (char) 1;
797 for (j = 1; c->keyword[j]; j++)
798 *p++ = c->keyword[j]->first;
799 *p = '\0';
800 c->keyword_first_chars = syntax_malloc (strlen (first_chars) + 2);
801 strcpy (c->keyword_first_chars, first_chars);
805 return result;
808 int edit_check_spelling (WEdit * edit)
810 return 0;
813 void (*syntax_change_callback) (CWidget *) = 0;
815 void edit_set_syntax_change_callback (void (*callback) (CWidget *))
817 syntax_change_callback = callback;
820 void edit_free_syntax_rules (WEdit * edit)
822 int i, j;
823 if (!edit)
824 return;
825 if (!edit->rules)
826 return;
827 edit_get_rule (edit, -1);
828 syntax_free (edit->syntax_type);
829 edit->syntax_type = 0;
830 if (syntax_change_callback)
831 (*syntax_change_callback) (&edit->widget);
832 for (i = 0; edit->rules[i]; i++) {
833 if (edit->rules[i]->keyword) {
834 for (j = 0; edit->rules[i]->keyword[j]; j++) {
835 syntax_free (edit->rules[i]->keyword[j]->keyword);
836 syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_left);
837 syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_right);
838 syntax_free (edit->rules[i]->keyword[j]);
841 syntax_free (edit->rules[i]->left);
842 syntax_free (edit->rules[i]->right);
843 syntax_free (edit->rules[i]->whole_word_chars_left);
844 syntax_free (edit->rules[i]->whole_word_chars_right);
845 syntax_free (edit->rules[i]->keyword);
846 syntax_free (edit->rules[i]->keyword_first_chars);
847 syntax_free (edit->rules[i]);
849 while (edit->syntax_marker) {
850 struct _syntax_marker *s = edit->syntax_marker->next;
851 syntax_free (edit->syntax_marker);
852 edit->syntax_marker = s;
854 syntax_free (edit->rules);
857 /* returns -1 on file error, line number on error in file syntax */
858 static int edit_read_syntax_file (WEdit * edit, char **names, char *syntax_file, char *editor_file, char *first_line, char *type)
860 FILE *f;
861 regex_t r;
862 regmatch_t pmatch[1];
863 char *args[1024], *l = 0;
864 int line = 0;
865 int argc;
866 int result = 0;
867 int count = 0;
868 char *lib_file;
870 lib_file = concat_dir_and_file (mc_home, "syntax/Syntax");
871 check_for_default (lib_file, syntax_file);
872 g_free (lib_file);
874 f = fopen (syntax_file, "r");
875 if (!f)
876 return -1;
877 args[0] = 0;
878 for (;;) {
879 line++;
880 syntax_free (l);
881 if (!read_one_line (&l, f))
882 break;
883 get_args (l, args, &argc);
884 if (!args[0])
885 continue;
886 /* looking for `file ...' lines only */
887 if (strcmp (args[0], "file")) {
888 free_args (args);
889 continue;
891 /* must have two args or report error */
892 if (!args[1] || !args[2]) {
893 result = line;
894 break;
896 if (names) {
897 /* 1: just collecting a list of names of rule sets */
898 names[count++] = (char *) strdup (args[2]);
899 names[count] = 0;
900 } else if (type) {
901 /* 2: rule set was explicitly specified by the caller */
902 if (!strcmp (type, args[2]))
903 goto found_type;
904 } else if (editor_file && edit) {
905 /* 3: auto-detect rule set from regular expressions */
906 int q;
907 if (regcomp (&r, args[1], REG_EXTENDED)) {
908 result = line;
909 break;
911 /* does filename match arg 1 ? */
912 q = !regexec (&r, editor_file, 1, pmatch, 0);
913 regfree (&r);
914 if (!q && args[3]) {
915 if (regcomp (&r, args[3], REG_EXTENDED)) {
916 result = line;
917 break;
919 /* does first line match arg 3 ? */
920 q = !regexec (&r, first_line, 1, pmatch, 0);
921 regfree (&r);
923 if (q) {
924 int line_error;
925 found_type:
926 line_error = edit_read_syntax_rules (edit, f);
927 if (line_error) {
928 if (!error_file_name) /* an included file */
929 result = line + line_error;
930 else
931 result = line_error;
932 } else {
933 syntax_free (edit->syntax_type);
934 edit->syntax_type = (char *) strdup (args[2]);
935 /* if there are no rules then turn off syntax highlighting for speed */
936 if (!edit->rules[1])
937 if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling) {
938 edit_free_syntax_rules (edit);
939 break;
941 /* notify the callback of a change in rule set */
942 if (syntax_change_callback)
943 (*syntax_change_callback) (&edit->widget);
945 break;
948 free_args (args);
950 free_args (args);
951 syntax_free (l);
952 fclose (f);
953 return result;
956 static char *get_first_editor_line (WEdit * edit)
958 int i;
959 static char s[256];
960 s[0] = '\0';
961 if (!edit)
962 return s;
963 for (i = 0; i < 255; i++) {
964 s[i] = edit_get_byte (edit, i);
965 if (s[i] == '\n') {
966 s[i] = '\0';
967 break;
970 s[255] = '\0';
971 return s;
974 /* loads rules into edit struct. one of edit or names must be zero. if
975 edit is zero, a list of types will be stored into name. type may be zero
976 in which case the type will be selected according to the filename. */
977 void edit_load_syntax (WEdit * edit, char **names, char *type)
979 int r;
980 char *f;
982 edit_free_syntax_rules (edit);
984 if (!option_syntax_highlighting)
985 return;
987 if (edit) {
988 if (!edit->filename)
989 return;
990 if (!*edit->filename && !type)
991 return;
993 f = catstrs (home_dir, SYNTAX_FILE, 0);
994 r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0, get_first_editor_line (edit), type);
995 if (r == -1) {
996 edit_free_syntax_rules (edit);
997 edit_error_dialog (_ (" Load syntax file "), _ (" File access error "));
998 return;
1000 if (r) {
1001 char s[80];
1002 edit_free_syntax_rules (edit);
1003 sprintf (s, _ (" Error in file %s on line %d "), error_file_name ? error_file_name : f, r);
1004 edit_error_dialog (_ (" Load syntax file "), s);
1005 syntax_free (error_file_name);
1006 return;
1010 #else
1012 int option_syntax_highlighting = 0;
1014 void edit_load_syntax (WEdit * edit, char **names, char *type)
1016 return;
1019 void edit_free_syntax_rules (WEdit * edit)
1021 return;
1024 void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
1026 *fg = NORMAL_COLOR;
1029 int edit_check_spelling (WEdit * edit)
1031 return 0;
1034 #endif /* HAVE_SYNTAXH */