* syntax.c (syntax_g_free): New macro to release and NULLify
[midnight-commander.git] / edit / syntax.c
blob410d7e894075dbd8f9fb5314303507ba2347b017
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;}}
71 #define syntax_g_free(x) {if(x){g_free(x);(x)=0;}}
73 static long compare_word_to_right (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start)
75 unsigned char *p, *q;
76 int c, d, j;
77 if (!*text)
78 return -1;
79 c = edit_get_byte (edit, i - 1);
80 if (line_start)
81 if (c != '\n')
82 return -1;
83 if (whole_left)
84 if (strchr (whole_left, c))
85 return -1;
86 for (p = (unsigned char *) text, q = p + strlen ((char *) p); p < q; p++, i++) {
87 switch (*p) {
88 case '\001':
89 p++;
90 for (;;) {
91 c = edit_get_byte (edit, i);
92 if (!*p)
93 if (whole_right)
94 if (!strchr (whole_right, c))
95 break;
96 if (c == *p)
97 break;
98 if (c == '\n')
99 return -1;
100 i++;
102 break;
103 case '\002':
104 p++;
105 j = 0;
106 for (;;) {
107 c = edit_get_byte (edit, i);
108 if (c == *p) {
109 j = i;
110 if (*p == *text && !p[1]) /* handle eg '+' and @+@ keywords properly */
111 break;
113 if (j && strchr ((char *) p + 1, c)) /* c exists further down, so it will get matched later */
114 break;
115 if (c == '\n' || c == '\t' || c == ' ') {
116 if (!*p) {
117 i--;
118 break;
120 if (!j)
121 return -1;
122 i = j;
123 break;
125 if (whole_right)
126 if (!strchr (whole_right, c)) {
127 if (!*p) {
128 i--;
129 break;
131 if (!j)
132 return -1;
133 i = j;
134 break;
136 i++;
138 break;
139 case '\003':
140 p++;
141 c = -1;
142 for (;; i++) {
143 d = c;
144 c = edit_get_byte (edit, i);
145 for (j = 0; p[j] != '\003'; j++)
146 if (c == p[j])
147 goto found_char2;
148 break;
149 found_char2:
150 j = c; /* dummy command */
152 i--;
153 while (*p != '\003')
154 p++;
155 if (p[1] == d)
156 i--;
157 break;
158 case '\004':
159 p++;
160 c = edit_get_byte (edit, i);
161 for (; *p != '\004'; p++)
162 if (c == *p)
163 goto found_char3;
164 return -1;
165 found_char3:
166 for (; *p != '\004'; p++);
167 break;
168 default:
169 if (*p != edit_get_byte (edit, i))
170 return -1;
173 if (whole_right)
174 if (strchr (whole_right, edit_get_byte (edit, i)))
175 return -1;
176 return i;
179 #define XXX \
180 if (*s < '\005' || *s == (unsigned char) c) \
181 goto done; \
182 s++;
184 static inline char *xx_strchr (const unsigned char *s, int c)
186 repeat:
187 XXX XXX XXX XXX XXX XXX XXX XXX;
188 XXX XXX XXX XXX XXX XXX XXX XXX;
189 goto repeat;
190 done:
191 return (char *) s;
194 static inline struct syntax_rule apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule)
196 struct context_rule *r;
197 int contextchanged = 0, c;
198 int found_right = 0, found_left = 0, keyword_foundleft = 0, keyword_foundright = 0;
199 int is_end;
200 long end = 0;
201 struct syntax_rule _rule = rule;
202 if (!(c = edit_get_byte (edit, i)))
203 return rule;
204 is_end = (rule.end == (unsigned char) i);
205 /* check to turn off a keyword */
206 if (_rule.keyword) {
207 struct key_word *k;
208 k = edit->rules[_rule.context]->keyword[_rule.keyword];
209 if (edit_get_byte (edit, i - 1) == '\n')
210 _rule.keyword = 0;
211 if (is_end) {
212 _rule.keyword = 0;
213 keyword_foundleft = 1;
216 /* check to turn off a context */
217 if (_rule.context && !_rule.keyword) {
218 long e;
219 r = edit->rules[_rule.context];
220 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) {
221 _rule.end = e;
222 found_right = 1;
223 _rule.border = RULE_ON_RIGHT_BORDER;
224 if (r->between_delimiters)
225 _rule.context = 0;
226 } else if (is_end && rule.border & RULE_ON_RIGHT_BORDER) {
227 /* always turn off a context at 4 */
228 found_left = 1;
229 _rule.border = 0;
230 if (!keyword_foundleft)
231 _rule.context = 0;
232 } else if (is_end && rule.border & RULE_ON_LEFT_BORDER) {
233 /* never turn off a context at 2 */
234 found_left = 1;
235 _rule.border = 0;
238 /* check to turn on a keyword */
239 if (!_rule.keyword) {
240 char *p;
241 p = (r = edit->rules[_rule.context])->keyword_first_chars;
242 if (p)
243 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
244 struct key_word *k;
245 int count;
246 long e;
247 count = p - r->keyword_first_chars;
248 k = r->keyword[count];
249 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
250 if (e > 0) {
251 end = e;
252 _rule.end = e;
253 _rule.keyword = count;
254 keyword_foundright = 1;
255 break;
259 /* check to turn on a context */
260 if (!_rule.context) {
261 if (!found_left && is_end) {
262 if (rule.border & RULE_ON_RIGHT_BORDER) {
263 _rule.border = 0;
264 _rule.context = 0;
265 contextchanged = 1;
266 _rule.keyword = 0;
267 } else if (rule.border & RULE_ON_LEFT_BORDER) {
268 r = edit->rules[_rule._context];
269 _rule.border = 0;
270 if (r->between_delimiters) {
271 long e;
272 _rule.context = _rule._context;
273 contextchanged = 1;
274 _rule.keyword = 0;
275 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) {
276 _rule.end = e;
277 found_right = 1;
278 _rule.border = RULE_ON_RIGHT_BORDER;
279 _rule.context = 0;
284 if (!found_right) {
285 int count;
286 struct context_rule **rules = edit->rules;
287 for (count = 1; rules[count]; count++) {
288 r = rules[count];
289 if (r->first_left == c) {
290 long e;
291 e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left);
292 if (e >= end && (!_rule.keyword || keyword_foundright)) {
293 _rule.end = e;
294 found_right = 1;
295 _rule.border = RULE_ON_LEFT_BORDER;
296 _rule._context = count;
297 if (!r->between_delimiters)
298 if (!_rule.keyword)
299 _rule.context = count;
300 break;
306 /* check again to turn on a keyword if the context switched */
307 if (contextchanged && !_rule.keyword) {
308 char *p;
309 p = (r = edit->rules[_rule.context])->keyword_first_chars;
310 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
311 struct key_word *k;
312 int count;
313 long e;
314 count = p - r->keyword_first_chars;
315 k = r->keyword[count];
316 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
317 if (e > 0) {
318 _rule.end = e;
319 _rule.keyword = count;
320 break;
324 return _rule;
327 static struct syntax_rule edit_get_rule (WEdit * edit, long byte_index)
329 long i;
330 if (byte_index > edit->last_get_rule) {
331 for (i = edit->last_get_rule + 1; i <= byte_index; i++) {
332 edit->rule = apply_rules_going_right (edit, i, edit->rule);
333 if (i > (edit->syntax_marker ? edit->syntax_marker->offset + SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY)) {
334 struct _syntax_marker *s;
335 s = edit->syntax_marker;
336 edit->syntax_marker = syntax_malloc (sizeof (struct _syntax_marker));
337 edit->syntax_marker->next = s;
338 edit->syntax_marker->offset = i;
339 edit->syntax_marker->rule = edit->rule;
342 } else if (byte_index < edit->last_get_rule) {
343 struct _syntax_marker *s;
344 for (;;) {
345 if (!edit->syntax_marker) {
346 memset (&edit->rule, 0, sizeof (edit->rule));
347 for (i = -1; i <= byte_index; i++)
348 edit->rule = apply_rules_going_right (edit, i, edit->rule);
349 break;
351 if (byte_index >= edit->syntax_marker->offset) {
352 edit->rule = edit->syntax_marker->rule;
353 for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++)
354 edit->rule = apply_rules_going_right (edit, i, edit->rule);
355 break;
357 s = edit->syntax_marker->next;
358 syntax_free (edit->syntax_marker);
359 edit->syntax_marker = s;
362 edit->last_get_rule = byte_index;
363 return edit->rule;
366 static void translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *fg, int *bg)
368 struct key_word *k;
369 k = edit->rules[rule.context]->keyword[rule.keyword];
370 *bg = k->bg;
371 *fg = k->fg;
374 extern int use_colors;
376 void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
378 if (edit->rules && byte_index < edit->last_byte &&
379 option_syntax_highlighting && use_colors) {
380 translate_rule_to_color (edit, edit_get_rule (edit, byte_index), fg, bg);
381 } else {
382 *fg = EDITOR_NORMAL_COLOR;
388 Returns 0 on error/eof or a count of the number of bytes read
389 including the newline. Result must be free'd.
391 #ifdef HAVE_MAD
392 static int mad_read_one_line (char **line, FILE * f, char *file, int line_)
393 #define read_one_line(a,b) mad_read_one_line(a,b,__FILE__,__LINE__)
394 #else
395 static int read_one_line (char **line, FILE * f)
396 #endif
398 char *p;
399 int len = 256, c, r = 0, i = 0;
400 #ifdef HAVE_MAD
401 p = mad_syntax_malloc (len, file, line_);
402 #else
403 p = syntax_malloc (len);
404 #endif
406 for (;;) {
407 c = fgetc (f);
408 if (c == EOF) {
409 if (ferror (f)) {
410 if (errno == EINTR)
411 continue;
412 r = 0;
414 break;
415 } else if (c == '\n') {
416 r = i + 1; /* extra 1 for the newline just read */
417 break;
418 } else {
419 if (i >= len - 1) {
420 char *q;
421 q = syntax_malloc (len * 2);
422 memcpy (q, p, len);
423 syntax_free (p);
424 p = q;
425 len *= 2;
427 p[i++] = c;
430 p[i] = 0;
431 *line = p;
432 return r;
435 static char *convert (char *s)
437 char *r, *p;
438 p = r = s;
439 while (*s) {
440 switch (*s) {
441 case '\\':
442 s++;
443 switch (*s) {
444 case ' ':
445 *p = ' ';
446 s--;
447 break;
448 case 'n':
449 *p = '\n';
450 break;
451 case 'r':
452 *p = '\r';
453 break;
454 case 't':
455 *p = '\t';
456 break;
457 case 's':
458 *p = ' ';
459 break;
460 case '*':
461 *p = '*';
462 break;
463 case '\\':
464 *p = '\\';
465 break;
466 case '[':
467 case ']':
468 *p = '\003';
469 break;
470 case '{':
471 case '}':
472 *p = '\004';
473 break;
474 default:
475 *p = *s;
476 break;
478 break;
479 case '*':
480 *p = '\001';
481 break;
482 case '+':
483 *p = '\002';
484 break;
485 default:
486 *p = *s;
487 break;
489 s++;
490 p++;
492 *p = '\0';
493 return r;
496 #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
498 static void get_args (char *l, char **args, int *argc)
500 *argc = 0;
501 for (;;) {
502 char *p = l;
503 while (*p && whiteness (*p))
504 p++;
505 if (!*p)
506 break;
507 for (l = p + 1; *l && !whiteness (*l); l++);
508 if (*l)
509 *l++ = '\0';
510 *args = convert (p);
511 (*argc)++;
512 args++;
514 *args = 0;
517 #define free_args(x)
518 #define break_a {result=line;break;}
519 #define check_a {if(!*a){result=line;break;}}
520 #define check_not_a {if(*a){result=line;break;}}
522 int try_alloc_color_pair (char *fg, char *bg);
524 int this_try_alloc_color_pair (char *fg, char *bg)
526 char f[80], b[80], *p;
527 if (bg)
528 if (!*bg)
529 bg = 0;
530 if (fg)
531 if (!*fg)
532 fg = 0;
533 if (fg) {
534 strcpy (f, fg);
535 p = strchr (f, '/');
536 if (p)
537 *p = '\0';
538 fg = f;
540 if (bg) {
541 strcpy (b, bg);
542 p = strchr (b, '/');
543 if (p)
544 *p = '\0';
545 bg = b;
547 return try_alloc_color_pair (fg, bg);
550 static char *error_file_name = 0;
552 extern char *mc_home;
554 static FILE *open_include_file (char *filename)
556 FILE *f;
558 syntax_g_free (error_file_name);
559 error_file_name = g_strdup (filename);
560 if (*filename == PATH_SEP)
561 return fopen (filename, "r");
563 g_free (error_file_name);
564 error_file_name = g_strconcat (home_dir, EDIT_DIR PATH_SEP_STR,
565 filename, NULL);
566 f = fopen (error_file_name, "r");
567 if (f)
568 return f;
570 g_free (error_file_name);
571 error_file_name = g_strconcat (mc_home, PATH_SEP_STR "syntax" PATH_SEP_STR,
572 filename, NULL);
573 return fopen (error_file_name, "r");
576 /* returns line number on error */
577 static int edit_read_syntax_rules (WEdit * edit, FILE * f)
579 FILE *g = 0;
580 char *fg, *bg;
581 char last_fg[32] = "", last_bg[32] = "";
582 char whole_right[512];
583 char whole_left[512];
584 char *args[1024], *l = 0;
585 int save_line = 0, line = 0;
586 struct context_rule **r, *c = 0;
587 int num_words = -1, num_contexts = -1;
588 int argc, result = 0;
589 int i, j;
591 args[0] = 0;
593 strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
594 strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
596 r = edit->rules = syntax_malloc (MAX_CONTEXTS * sizeof (struct context_rule *));
598 for (;;) {
599 char **a;
600 line++;
601 l = 0;
602 if (!read_one_line (&l, f)) {
603 if (g) {
604 fclose (f);
605 f = g;
606 g = 0;
607 line = save_line + 1;
608 syntax_g_free (error_file_name);
609 if (l)
610 syntax_free (l);
611 if (!read_one_line (&l, f))
612 break;
613 } else {
614 break;
617 get_args (l, args, &argc);
618 a = args + 1;
619 if (!args[0]) {
620 /* do nothing */
621 } else if (!strcmp (args[0], "include")) {
622 if (g || argc != 2) {
623 result = line;
624 break;
626 g = f;
627 f = open_include_file (args[1]);
628 if (!f) {
629 syntax_g_free (error_file_name);
630 result = line;
631 break;
633 save_line = line;
634 line = 0;
635 } else if (!strcmp (args[0], "wholechars")) {
636 check_a;
637 if (!strcmp (*a, "left")) {
638 a++;
639 strcpy (whole_left, *a);
640 } else if (!strcmp (*a, "right")) {
641 a++;
642 strcpy (whole_right, *a);
643 } else {
644 strcpy (whole_left, *a);
645 strcpy (whole_right, *a);
647 a++;
648 check_not_a;
649 } else if (!strcmp (args[0], "context")) {
650 check_a;
651 if (num_contexts == -1) {
652 if (strcmp (*a, "default")) { /* first context is the default */
653 break_a;
655 a++;
656 c = r[0] = syntax_malloc (sizeof (struct context_rule));
657 c->left = (char *) strdup (" ");
658 c->right = (char *) strdup (" ");
659 num_contexts = 0;
660 } else {
661 c = r[num_contexts] = syntax_malloc (sizeof (struct context_rule));
662 if (!strcmp (*a, "exclusive")) {
663 a++;
664 c->between_delimiters = 1;
666 check_a;
667 if (!strcmp (*a, "whole")) {
668 a++;
669 c->whole_word_chars_left = (char *) strdup (whole_left);
670 c->whole_word_chars_right = (char *) strdup (whole_right);
671 } else if (!strcmp (*a, "wholeleft")) {
672 a++;
673 c->whole_word_chars_left = (char *) strdup (whole_left);
674 } else if (!strcmp (*a, "wholeright")) {
675 a++;
676 c->whole_word_chars_right = (char *) strdup (whole_right);
678 check_a;
679 if (!strcmp (*a, "linestart")) {
680 a++;
681 c->line_start_left = 1;
683 check_a;
684 c->left = (char *) strdup (*a++);
685 check_a;
686 if (!strcmp (*a, "linestart")) {
687 a++;
688 c->line_start_right = 1;
690 check_a;
691 c->right = (char *) strdup (*a++);
692 c->first_left = *c->left;
693 c->first_right = *c->right;
694 c->single_char = (strlen (c->right) == 1);
696 c->keyword = syntax_malloc (MAX_WORDS_PER_CONTEXT * sizeof (struct key_word *));
697 #if 0
698 c->max_words = MAX_WORDS_PER_CONTEXT;
699 #endif
700 num_words = 1;
701 c->keyword[0] = syntax_malloc (sizeof (struct key_word));
702 fg = *a;
703 if (*a)
704 a++;
705 bg = *a;
706 if (*a)
707 a++;
708 strcpy (last_fg, fg ? fg : "");
709 strcpy (last_bg, bg ? bg : "");
710 c->keyword[0]->fg = this_try_alloc_color_pair (fg, bg);
711 c->keyword[0]->keyword = (char *) strdup (" ");
712 check_not_a;
713 num_contexts++;
714 } else if (!strcmp (args[0], "spellcheck")) {
715 if (!c) {
716 result = line;
717 break;
719 c->spelling = 1;
720 } else if (!strcmp (args[0], "keyword")) {
721 struct key_word *k;
722 if (num_words == -1)
723 break_a;
724 check_a;
725 k = r[num_contexts - 1]->keyword[num_words] = syntax_malloc (sizeof (struct key_word));
726 if (!strcmp (*a, "whole")) {
727 a++;
728 k->whole_word_chars_left = (char *) strdup (whole_left);
729 k->whole_word_chars_right = (char *) strdup (whole_right);
730 } else if (!strcmp (*a, "wholeleft")) {
731 a++;
732 k->whole_word_chars_left = (char *) strdup (whole_left);
733 } else if (!strcmp (*a, "wholeright")) {
734 a++;
735 k->whole_word_chars_right = (char *) strdup (whole_right);
737 check_a;
738 if (!strcmp (*a, "linestart")) {
739 a++;
740 k->line_start = 1;
742 check_a;
743 if (!strcmp (*a, "whole")) {
744 break_a;
746 k->keyword = (char *) strdup (*a++);
747 k->first = *k->keyword;
748 fg = *a;
749 if (*a)
750 a++;
751 bg = *a;
752 if (*a)
753 a++;
754 if (!fg)
755 fg = last_fg;
756 if (!bg)
757 bg = last_bg;
758 k->fg = this_try_alloc_color_pair (fg, bg);
759 check_not_a;
760 num_words++;
761 } else if (!strncmp (args[0], "#", 1)) {
762 /* do nothing for comment */
763 } else if (!strcmp (args[0], "file")) {
764 break;
765 } else { /* anything else is an error */
766 break_a;
768 free_args (args);
769 syntax_free (l);
771 free_args (args);
772 syntax_free (l);
774 if (!edit->rules[0])
775 syntax_free (edit->rules);
777 if (result)
778 return result;
780 if (num_contexts == -1) {
781 result = line;
782 return result;
786 char first_chars[MAX_WORDS_PER_CONTEXT + 2], *p;
787 for (i = 0; edit->rules[i]; i++) {
788 c = edit->rules[i];
789 p = first_chars;
790 *p++ = (char) 1;
791 for (j = 1; c->keyword[j]; j++)
792 *p++ = c->keyword[j]->first;
793 *p = '\0';
794 c->keyword_first_chars = syntax_malloc (strlen (first_chars) + 2);
795 strcpy (c->keyword_first_chars, first_chars);
799 return result;
802 int edit_check_spelling (WEdit * edit)
804 return 0;
807 void (*syntax_change_callback) (CWidget *) = 0;
809 void edit_set_syntax_change_callback (void (*callback) (CWidget *))
811 syntax_change_callback = callback;
814 void edit_free_syntax_rules (WEdit * edit)
816 int i, j;
817 if (!edit)
818 return;
819 if (!edit->rules)
820 return;
821 edit_get_rule (edit, -1);
822 syntax_free (edit->syntax_type);
823 edit->syntax_type = 0;
824 if (syntax_change_callback)
825 (*syntax_change_callback) (&edit->widget);
826 for (i = 0; edit->rules[i]; i++) {
827 if (edit->rules[i]->keyword) {
828 for (j = 0; edit->rules[i]->keyword[j]; j++) {
829 syntax_free (edit->rules[i]->keyword[j]->keyword);
830 syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_left);
831 syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_right);
832 syntax_free (edit->rules[i]->keyword[j]);
835 syntax_free (edit->rules[i]->left);
836 syntax_free (edit->rules[i]->right);
837 syntax_free (edit->rules[i]->whole_word_chars_left);
838 syntax_free (edit->rules[i]->whole_word_chars_right);
839 syntax_free (edit->rules[i]->keyword);
840 syntax_free (edit->rules[i]->keyword_first_chars);
841 syntax_free (edit->rules[i]);
843 while (edit->syntax_marker) {
844 struct _syntax_marker *s = edit->syntax_marker->next;
845 syntax_free (edit->syntax_marker);
846 edit->syntax_marker = s;
848 syntax_free (edit->rules);
851 /* returns -1 on file error, line number on error in file syntax */
852 static int edit_read_syntax_file (WEdit * edit, char **names, char *syntax_file, char *editor_file, char *first_line, char *type)
854 FILE *f;
855 regex_t r;
856 regmatch_t pmatch[1];
857 char *args[1024], *l = 0;
858 int line = 0;
859 int argc;
860 int result = 0;
861 int count = 0;
862 char *lib_file;
864 lib_file = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
865 check_for_default (lib_file, syntax_file);
866 g_free (lib_file);
868 f = fopen (syntax_file, "r");
869 if (!f)
870 return -1;
871 args[0] = 0;
872 for (;;) {
873 line++;
874 syntax_free (l);
875 if (!read_one_line (&l, f))
876 break;
877 get_args (l, args, &argc);
878 if (!args[0])
879 continue;
880 /* looking for `file ...' lines only */
881 if (strcmp (args[0], "file")) {
882 free_args (args);
883 continue;
885 /* must have two args or report error */
886 if (!args[1] || !args[2]) {
887 result = line;
888 break;
890 if (names) {
891 /* 1: just collecting a list of names of rule sets */
892 names[count++] = (char *) strdup (args[2]);
893 names[count] = 0;
894 } else if (type) {
895 /* 2: rule set was explicitly specified by the caller */
896 if (!strcmp (type, args[2]))
897 goto found_type;
898 } else if (editor_file && edit) {
899 /* 3: auto-detect rule set from regular expressions */
900 int q;
901 if (regcomp (&r, args[1], REG_EXTENDED)) {
902 result = line;
903 break;
905 /* does filename match arg 1 ? */
906 q = !regexec (&r, editor_file, 1, pmatch, 0);
907 regfree (&r);
908 if (!q && args[3]) {
909 if (regcomp (&r, args[3], REG_EXTENDED)) {
910 result = line;
911 break;
913 /* does first line match arg 3 ? */
914 q = !regexec (&r, first_line, 1, pmatch, 0);
915 regfree (&r);
917 if (q) {
918 int line_error;
919 found_type:
920 line_error = edit_read_syntax_rules (edit, f);
921 if (line_error) {
922 if (!error_file_name) /* an included file */
923 result = line + line_error;
924 else
925 result = line_error;
926 } else {
927 syntax_free (edit->syntax_type);
928 edit->syntax_type = (char *) strdup (args[2]);
929 /* if there are no rules then turn off syntax highlighting for speed */
930 if (!edit->rules[1])
931 if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling) {
932 edit_free_syntax_rules (edit);
933 break;
935 /* notify the callback of a change in rule set */
936 if (syntax_change_callback)
937 (*syntax_change_callback) (&edit->widget);
939 break;
942 free_args (args);
944 free_args (args);
945 syntax_free (l);
946 fclose (f);
947 return result;
950 static char *get_first_editor_line (WEdit * edit)
952 int i;
953 static char s[256];
954 s[0] = '\0';
955 if (!edit)
956 return s;
957 for (i = 0; i < 255; i++) {
958 s[i] = edit_get_byte (edit, i);
959 if (s[i] == '\n') {
960 s[i] = '\0';
961 break;
964 s[255] = '\0';
965 return s;
968 /* loads rules into edit struct. one of edit or names must be zero. if
969 edit is zero, a list of types will be stored into name. type may be zero
970 in which case the type will be selected according to the filename. */
971 void edit_load_syntax (WEdit * edit, char **names, char *type)
973 int r;
974 char *f;
976 edit_free_syntax_rules (edit);
978 if (!option_syntax_highlighting)
979 return;
981 if (edit) {
982 if (!edit->filename)
983 return;
984 if (!*edit->filename && !type)
985 return;
987 f = catstrs (home_dir, SYNTAX_FILE, 0);
988 r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0, get_first_editor_line (edit), type);
989 if (r == -1) {
990 edit_free_syntax_rules (edit);
991 edit_error_dialog (_ (" Load syntax file "), _ (" File access error "));
992 return;
994 if (r) {
995 edit_free_syntax_rules (edit);
996 message (0, _(" Load syntax file "),
997 _(" Error in file %s on line %d "),
998 error_file_name ? error_file_name : f, r);
999 syntax_g_free (error_file_name);
1000 return;
1004 #else
1006 int option_syntax_highlighting = 0;
1008 void edit_load_syntax (WEdit * edit, char **names, char *type)
1010 return;
1013 void edit_free_syntax_rules (WEdit * edit)
1015 return;
1018 void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
1020 *fg = NORMAL_COLOR;
1023 int edit_check_spelling (WEdit * edit)
1025 return 0;
1028 #endif /* HAVE_SYNTAXH */