Updated italian translatio
[midnight-commander.git] / edit / syntax.c
blobd8db3a24a9e14ec97892a6f1cf0f978f7954ac9c
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"
25 #include "edit-widget.h"
26 #include "../src/color.h" /* use_colors */
27 #include "../src/main.h" /* mc_home */
28 #include "../src/wtools.h" /* message() */
30 /* bytes */
31 #define SYNTAX_MARKER_DENSITY 512
34 Mispelled words are flushed from the syntax highlighting rules
35 when they have been around longer than
36 TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
37 chars per second and say 3 chars + a space per word, we can
38 accumulate 450 words absolute max with a value of 60. This is
39 below this limit of 1024 words in a context.
41 #define TRANSIENT_WORD_TIME_OUT 60
43 #define UNKNOWN_FORMAT "unknown"
45 #define MAX_WORDS_PER_CONTEXT 1024
46 #define MAX_CONTEXTS 128
48 #define RULE_ON_LEFT_BORDER 1
49 #define RULE_ON_RIGHT_BORDER 2
51 #define SYNTAX_TOKEN_STAR '\001'
52 #define SYNTAX_TOKEN_PLUS '\002'
53 #define SYNTAX_TOKEN_BRACKET '\003'
54 #define SYNTAX_TOKEN_BRACE '\004'
56 struct key_word {
57 char *keyword;
58 unsigned char first;
59 char *whole_word_chars_left;
60 char *whole_word_chars_right;
61 int line_start;
62 int color;
65 struct context_rule {
66 char *left;
67 unsigned char first_left;
68 char *right;
69 unsigned char first_right;
70 char line_start_left;
71 char line_start_right;
72 int between_delimiters;
73 char *whole_word_chars_left;
74 char *whole_word_chars_right;
75 char *keyword_first_chars;
76 int spelling;
77 /* first word is word[1] */
78 struct key_word **keyword;
81 struct _syntax_marker {
82 long offset;
83 struct syntax_rule rule;
84 struct _syntax_marker *next;
87 int option_syntax_highlighting = 1;
89 #define syntax_g_free(x) do {if(x) {g_free(x); (x)=0;}} while (0)
91 static gint
92 mc_defines_destroy (gpointer key, gpointer value, gpointer data)
94 char **values = value;
96 g_free (key);
97 while (*values)
98 g_free (*values++);
99 g_free (value);
101 return FALSE;
104 /* Completely destroys the defines tree */
105 static inline void
106 destroy_defines (GTree **defines)
108 g_tree_traverse (*defines, mc_defines_destroy, G_POST_ORDER, NULL);
109 g_tree_destroy (*defines);
110 *defines = 0;
113 static void
114 subst_defines (GTree *defines, char **argv, char **argv_end)
116 char **t, **p;
117 int argc;
118 while (*argv && argv < argv_end) {
119 if ((t = g_tree_lookup (defines, *argv))) {
120 int count = 0;
121 /* Count argv array members */
122 argc = 0;
123 for (p = &argv[1]; *p; p++)
124 argc++;
125 /* Count members of definition array */
126 for (p = t; *p; p++)
127 count++;
128 p = &argv[count + argc];
129 /* Buffer overflow or infinitive loop in define */
130 if (p >= argv_end)
131 break;
132 /* Move rest of argv after definition members */
133 while (argc >= 0)
134 *p-- = argv[argc-- + 1];
135 /* Copy definition members to argv */
136 for (p = argv; *t; *p++ = *t++);
138 argv++;
142 static long
143 compare_word_to_right (WEdit *edit, long i, const char *text,
144 const char *whole_left, const char *whole_right,
145 int line_start)
147 const unsigned char *p, *q;
148 int c, d, j;
149 if (!*text)
150 return -1;
151 c = edit_get_byte (edit, i - 1);
152 if (line_start)
153 if (c != '\n')
154 return -1;
155 if (whole_left)
156 if (strchr (whole_left, c))
157 return -1;
158 for (p = (unsigned char *) text, q = p + strlen ((char *) p); p < q; p++, i++) {
159 switch (*p) {
160 case SYNTAX_TOKEN_STAR:
161 if (++p > q)
162 return -1;
163 for (;;) {
164 c = edit_get_byte (edit, i);
165 if (!*p)
166 if (whole_right)
167 if (!strchr (whole_right, c))
168 break;
169 if (c == *p)
170 break;
171 if (c == '\n')
172 return -1;
173 i++;
175 break;
176 case SYNTAX_TOKEN_PLUS:
177 if (++p > q)
178 return -1;
179 j = 0;
180 for (;;) {
181 c = edit_get_byte (edit, i);
182 if (c == *p) {
183 j = i;
184 if (*p == *text && !p[1]) /* handle eg '+' and @+@ keywords properly */
185 break;
187 if (j && strchr ((char *) p + 1, c)) /* c exists further down, so it will get matched later */
188 break;
189 if (c == '\n' || c == '\t' || c == ' ') {
190 if (!*p) {
191 i--;
192 break;
194 if (!j)
195 return -1;
196 i = j;
197 break;
199 if (whole_right)
200 if (!strchr (whole_right, c)) {
201 if (!*p) {
202 i--;
203 break;
205 if (!j)
206 return -1;
207 i = j;
208 break;
210 i++;
212 break;
213 case SYNTAX_TOKEN_BRACKET:
214 if (++p > q)
215 return -1;
216 c = -1;
217 for (;; i++) {
218 d = c;
219 c = edit_get_byte (edit, i);
220 for (j = 0; p[j] != SYNTAX_TOKEN_BRACKET && p[j]; j++)
221 if (c == p[j])
222 goto found_char2;
223 break;
224 found_char2:
225 ; /* dummy command */
227 i--;
228 while (*p != SYNTAX_TOKEN_BRACKET && p <= q)
229 p++;
230 if (p > q)
231 return -1;
232 if (p[1] == d)
233 i--;
234 break;
235 case SYNTAX_TOKEN_BRACE:
236 if (++p > q)
237 return -1;
238 c = edit_get_byte (edit, i);
239 for (; *p != SYNTAX_TOKEN_BRACE && *p; p++)
240 if (c == *p)
241 goto found_char3;
242 return -1;
243 found_char3:
244 while (*p != SYNTAX_TOKEN_BRACE && p < q)
245 p++;
246 break;
247 default:
248 if (*p != edit_get_byte (edit, i))
249 return -1;
252 if (whole_right)
253 if (strchr (whole_right, edit_get_byte (edit, i)))
254 return -1;
255 return i;
258 #define XXX \
259 if (*s < '\005' || *s == (unsigned char) c) \
260 goto done; \
261 s++;
263 static inline char *xx_strchr (const unsigned char *s, int c)
265 repeat:
266 XXX XXX XXX XXX XXX XXX XXX XXX;
267 XXX XXX XXX XXX XXX XXX XXX XXX;
268 goto repeat;
269 done:
270 return (char *) s;
273 static inline struct syntax_rule apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule)
275 struct context_rule *r;
276 int contextchanged = 0, c;
277 int found_right = 0, found_left = 0, keyword_foundleft = 0, keyword_foundright = 0;
278 int is_end;
279 long end = 0;
280 struct syntax_rule _rule = rule;
281 if (!(c = edit_get_byte (edit, i)))
282 return rule;
283 is_end = (rule.end == (unsigned char) i);
284 /* check to turn off a keyword */
285 if (_rule.keyword) {
286 if (edit_get_byte (edit, i - 1) == '\n')
287 _rule.keyword = 0;
288 if (is_end) {
289 _rule.keyword = 0;
290 keyword_foundleft = 1;
293 /* check to turn off a context */
294 if (_rule.context && !_rule.keyword) {
295 long e;
296 r = edit->rules[_rule.context];
297 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) {
298 _rule.end = e;
299 found_right = 1;
300 _rule.border = RULE_ON_RIGHT_BORDER;
301 if (r->between_delimiters)
302 _rule.context = 0;
303 } else if (is_end && rule.border & RULE_ON_RIGHT_BORDER) {
304 /* always turn off a context at 4 */
305 found_left = 1;
306 _rule.border = 0;
307 if (!keyword_foundleft)
308 _rule.context = 0;
309 } else if (is_end && rule.border & RULE_ON_LEFT_BORDER) {
310 /* never turn off a context at 2 */
311 found_left = 1;
312 _rule.border = 0;
315 /* check to turn on a keyword */
316 if (!_rule.keyword) {
317 char *p;
318 p = (r = edit->rules[_rule.context])->keyword_first_chars;
319 if (p)
320 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
321 struct key_word *k;
322 int count;
323 long e;
324 count = p - r->keyword_first_chars;
325 k = r->keyword[count];
326 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
327 if (e > 0) {
328 end = e;
329 _rule.end = e;
330 _rule.keyword = count;
331 keyword_foundright = 1;
332 break;
336 /* check to turn on a context */
337 if (!_rule.context) {
338 if (!found_left && is_end) {
339 if (rule.border & RULE_ON_RIGHT_BORDER) {
340 _rule.border = 0;
341 _rule.context = 0;
342 contextchanged = 1;
343 _rule.keyword = 0;
344 } else if (rule.border & RULE_ON_LEFT_BORDER) {
345 r = edit->rules[_rule._context];
346 _rule.border = 0;
347 if (r->between_delimiters) {
348 long e;
349 _rule.context = _rule._context;
350 contextchanged = 1;
351 _rule.keyword = 0;
352 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) {
353 _rule.end = e;
354 found_right = 1;
355 _rule.border = RULE_ON_RIGHT_BORDER;
356 _rule.context = 0;
361 if (!found_right) {
362 int count;
363 struct context_rule **rules = edit->rules;
364 for (count = 1; rules[count]; count++) {
365 r = rules[count];
366 if (r->first_left == c) {
367 long e;
368 e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left);
369 if (e >= end && (!_rule.keyword || keyword_foundright)) {
370 _rule.end = e;
371 found_right = 1;
372 _rule.border = RULE_ON_LEFT_BORDER;
373 _rule._context = count;
374 if (!r->between_delimiters)
375 if (!_rule.keyword) {
376 _rule.context = count;
377 contextchanged = 1;
379 break;
385 /* check again to turn on a keyword if the context switched */
386 if (contextchanged && !_rule.keyword) {
387 char *p;
388 p = (r = edit->rules[_rule.context])->keyword_first_chars;
389 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
390 struct key_word *k;
391 int count;
392 long e;
393 count = p - r->keyword_first_chars;
394 k = r->keyword[count];
395 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
396 if (e > 0) {
397 _rule.end = e;
398 _rule.keyword = count;
399 break;
403 return _rule;
406 static struct syntax_rule edit_get_rule (WEdit * edit, long byte_index)
408 long i;
409 if (byte_index > edit->last_get_rule) {
410 for (i = edit->last_get_rule + 1; i <= byte_index; i++) {
411 edit->rule = apply_rules_going_right (edit, i, edit->rule);
412 if (i > (edit->syntax_marker ? edit->syntax_marker->offset + SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY)) {
413 struct _syntax_marker *s;
414 s = edit->syntax_marker;
415 edit->syntax_marker = g_malloc0 (sizeof (struct _syntax_marker));
416 edit->syntax_marker->next = s;
417 edit->syntax_marker->offset = i;
418 edit->syntax_marker->rule = edit->rule;
421 } else if (byte_index < edit->last_get_rule) {
422 struct _syntax_marker *s;
423 for (;;) {
424 if (!edit->syntax_marker) {
425 memset (&edit->rule, 0, sizeof (edit->rule));
426 for (i = -1; i <= byte_index; i++)
427 edit->rule = apply_rules_going_right (edit, i, edit->rule);
428 break;
430 if (byte_index >= edit->syntax_marker->offset) {
431 edit->rule = edit->syntax_marker->rule;
432 for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++)
433 edit->rule = apply_rules_going_right (edit, i, edit->rule);
434 break;
436 s = edit->syntax_marker->next;
437 syntax_g_free (edit->syntax_marker);
438 edit->syntax_marker = s;
441 edit->last_get_rule = byte_index;
442 return edit->rule;
445 static void translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *color)
447 struct key_word *k;
448 k = edit->rules[rule.context]->keyword[rule.keyword];
449 *color = k->color;
452 void edit_get_syntax_color (WEdit * edit, long byte_index, int *color)
454 if (edit->rules && byte_index < edit->last_byte &&
455 option_syntax_highlighting && use_colors) {
456 translate_rule_to_color (edit, edit_get_rule (edit, byte_index), color);
457 } else {
458 *color = use_colors ? EDITOR_NORMAL_COLOR_INDEX : 0;
464 Returns 0 on error/eof or a count of the number of bytes read
465 including the newline. Result must be free'd.
467 static int read_one_line (char **line, FILE * f)
469 char *p;
470 int len = 256, c, r = 0, i = 0;
471 p = g_malloc0 (len);
473 for (;;) {
474 c = fgetc (f);
475 if (c == EOF) {
476 if (ferror (f)) {
477 if (errno == EINTR)
478 continue;
479 r = 0;
481 break;
482 } else if (c == '\n') {
483 r = i + 1; /* extra 1 for the newline just read */
484 break;
485 } else {
486 if (i >= len - 1) {
487 char *q;
488 q = g_malloc0 (len * 2);
489 memcpy (q, p, len);
490 syntax_g_free (p);
491 p = q;
492 len *= 2;
494 p[i++] = c;
497 p[i] = 0;
498 *line = p;
499 return r;
502 static char *convert (char *s)
504 char *r, *p;
505 p = r = s;
506 while (*s) {
507 switch (*s) {
508 case '\\':
509 s++;
510 switch (*s) {
511 case ' ':
512 *p = ' ';
513 s--;
514 break;
515 case 'n':
516 *p = '\n';
517 break;
518 case 'r':
519 *p = '\r';
520 break;
521 case 't':
522 *p = '\t';
523 break;
524 case 's':
525 *p = ' ';
526 break;
527 case '*':
528 *p = '*';
529 break;
530 case '\\':
531 *p = '\\';
532 break;
533 case '[':
534 case ']':
535 *p = SYNTAX_TOKEN_BRACKET;
536 break;
537 case '{':
538 case '}':
539 *p = SYNTAX_TOKEN_BRACE;
540 break;
541 case 0:
542 *p = *s;
543 return r;
544 default:
545 *p = *s;
546 break;
548 break;
549 case '*':
550 *p = SYNTAX_TOKEN_STAR;
551 break;
552 case '+':
553 *p = SYNTAX_TOKEN_PLUS;
554 break;
555 default:
556 *p = *s;
557 break;
559 s++;
560 p++;
562 *p = '\0';
563 return r;
566 #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
568 static void get_args (char *l, char **args, int *argc)
570 *argc = 0;
571 for (;;) {
572 char *p = l;
573 while (*p && whiteness (*p))
574 p++;
575 if (!*p)
576 break;
577 for (l = p + 1; *l && !whiteness (*l); l++);
578 if (*l)
579 *l++ = '\0';
580 *args = convert (p);
581 (*argc)++;
582 args++;
584 *args = 0;
587 #define free_args(x)
588 #define break_a {result=line;break;}
589 #define check_a {if(!*a){result=line;break;}}
590 #define check_not_a {if(*a){result=line;break;}}
592 static int
593 this_try_alloc_color_pair (char *fg, char *bg)
595 char f[80], b[80], *p;
596 if (bg)
597 if (!*bg)
598 bg = 0;
599 if (fg)
600 if (!*fg)
601 fg = 0;
602 if (fg) {
603 strncpy (f, fg, sizeof (f) - 1);
604 f[sizeof (f) - 1] = 0;
605 p = strchr (f, '/');
606 if (p)
607 *p = '\0';
608 fg = f;
610 if (bg) {
611 strncpy (b, bg, sizeof (b) - 1);
612 b[sizeof (b) - 1] = 0;
613 p = strchr (b, '/');
614 if (p)
615 *p = '\0';
616 bg = b;
618 return try_alloc_color_pair (fg, bg);
621 static char *error_file_name = 0;
623 static FILE *open_include_file (const char *filename)
625 FILE *f;
627 syntax_g_free (error_file_name);
628 error_file_name = g_strdup (filename);
629 if (*filename == PATH_SEP)
630 return fopen (filename, "r");
632 g_free (error_file_name);
633 error_file_name = g_strconcat (home_dir, EDIT_DIR PATH_SEP_STR,
634 filename, NULL);
635 f = fopen (error_file_name, "r");
636 if (f)
637 return f;
639 g_free (error_file_name);
640 error_file_name = g_strconcat (mc_home, PATH_SEP_STR "syntax" PATH_SEP_STR,
641 filename, NULL);
642 return fopen (error_file_name, "r");
645 /* returns line number on error */
646 static int
647 edit_read_syntax_rules (WEdit *edit, FILE *f, char **args)
649 FILE *g = 0;
650 char *fg, *bg;
651 char last_fg[32] = "", last_bg[32] = "";
652 char whole_right[512];
653 char whole_left[512];
654 char *l = 0;
655 int save_line = 0, line = 0;
656 struct context_rule **r, *c = 0;
657 int num_words = -1, num_contexts = -1;
658 int argc, result = 0;
659 int i, j;
661 args[0] = 0;
663 strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
664 strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
666 r = edit->rules = g_malloc0 (MAX_CONTEXTS * sizeof (struct context_rule *));
668 if (!edit->defines)
669 edit->defines = g_tree_new ((GCompareFunc) strcmp);
671 for (;;) {
672 char **a;
673 line++;
674 l = 0;
675 if (!read_one_line (&l, f)) {
676 if (g) {
677 fclose (f);
678 f = g;
679 g = 0;
680 line = save_line + 1;
681 syntax_g_free (error_file_name);
682 if (l)
683 syntax_g_free (l);
684 if (!read_one_line (&l, f))
685 break;
686 } else {
687 break;
690 get_args (l, args, &argc);
691 a = args + 1;
692 if (!args[0]) {
693 /* do nothing */
694 } else if (!strcmp (args[0], "include")) {
695 if (g || argc != 2) {
696 result = line;
697 break;
699 g = f;
700 f = open_include_file (args[1]);
701 if (!f) {
702 syntax_g_free (error_file_name);
703 result = line;
704 break;
706 save_line = line;
707 line = 0;
708 } else if (!strcmp (args[0], "wholechars")) {
709 check_a;
710 if (!strcmp (*a, "left")) {
711 a++;
712 strncpy (whole_left, *a, sizeof (whole_left) - 1);
713 whole_left[sizeof (whole_left) - 1] = 0;
714 } else if (!strcmp (*a, "right")) {
715 a++;
716 strncpy (whole_right, *a, sizeof (whole_right) - 1);
717 whole_right[sizeof (whole_right) - 1] = 0;
718 } else {
719 strncpy (whole_left, *a, sizeof (whole_left) - 1);
720 whole_left[sizeof (whole_left) - 1] = 0;
721 strncpy (whole_right, *a, sizeof (whole_right) - 1);
722 whole_right[sizeof (whole_right) - 1] = 0;
724 a++;
725 check_not_a;
726 } else if (!strcmp (args[0], "context")) {
727 check_a;
728 if (num_contexts == -1) {
729 if (strcmp (*a, "default")) { /* first context is the default */
730 break_a;
732 a++;
733 c = r[0] = g_malloc0 (sizeof (struct context_rule));
734 c->left = g_strdup (" ");
735 c->right = g_strdup (" ");
736 num_contexts = 0;
737 } else {
738 c = r[num_contexts] = g_malloc0 (sizeof (struct context_rule));
739 if (!strcmp (*a, "exclusive")) {
740 a++;
741 c->between_delimiters = 1;
743 check_a;
744 if (!strcmp (*a, "whole")) {
745 a++;
746 c->whole_word_chars_left = g_strdup (whole_left);
747 c->whole_word_chars_right = g_strdup (whole_right);
748 } else if (!strcmp (*a, "wholeleft")) {
749 a++;
750 c->whole_word_chars_left = g_strdup (whole_left);
751 } else if (!strcmp (*a, "wholeright")) {
752 a++;
753 c->whole_word_chars_right = g_strdup (whole_right);
755 check_a;
756 if (!strcmp (*a, "linestart")) {
757 a++;
758 c->line_start_left = 1;
760 check_a;
761 c->left = g_strdup (*a++);
762 check_a;
763 if (!strcmp (*a, "linestart")) {
764 a++;
765 c->line_start_right = 1;
767 check_a;
768 c->right = g_strdup (*a++);
769 c->first_left = *c->left;
770 c->first_right = *c->right;
772 c->keyword = g_malloc0 (MAX_WORDS_PER_CONTEXT * sizeof (struct key_word *));
773 #if 0
774 c->max_words = MAX_WORDS_PER_CONTEXT;
775 #endif
776 num_words = 1;
777 c->keyword[0] = g_malloc0 (sizeof (struct key_word));
778 subst_defines (edit->defines, a, &args[1024]);
779 fg = *a;
780 if (*a)
781 a++;
782 bg = *a;
783 if (*a)
784 a++;
785 strncpy (last_fg, fg ? fg : "", sizeof (last_fg) - 1);
786 last_fg[sizeof (last_fg) - 1] = 0;
787 strncpy (last_bg, bg ? bg : "", sizeof (last_bg) - 1);
788 last_bg[sizeof (last_bg) - 1] = 0;
789 c->keyword[0]->color = this_try_alloc_color_pair (fg, bg);
790 c->keyword[0]->keyword = g_strdup (" ");
791 check_not_a;
792 num_contexts++;
793 } else if (!strcmp (args[0], "spellcheck")) {
794 if (!c) {
795 result = line;
796 break;
798 c->spelling = 1;
799 } else if (!strcmp (args[0], "keyword")) {
800 struct key_word *k;
801 if (num_words == -1)
802 break_a;
803 check_a;
804 k = r[num_contexts - 1]->keyword[num_words] = g_malloc0 (sizeof (struct key_word));
805 if (!strcmp (*a, "whole")) {
806 a++;
807 k->whole_word_chars_left = g_strdup (whole_left);
808 k->whole_word_chars_right = g_strdup (whole_right);
809 } else if (!strcmp (*a, "wholeleft")) {
810 a++;
811 k->whole_word_chars_left = g_strdup (whole_left);
812 } else if (!strcmp (*a, "wholeright")) {
813 a++;
814 k->whole_word_chars_right = g_strdup (whole_right);
816 check_a;
817 if (!strcmp (*a, "linestart")) {
818 a++;
819 k->line_start = 1;
821 check_a;
822 if (!strcmp (*a, "whole")) {
823 break_a;
825 k->keyword = g_strdup (*a++);
826 k->first = *k->keyword;
827 subst_defines (edit->defines, a, &args[1024]);
828 fg = *a;
829 if (*a)
830 a++;
831 bg = *a;
832 if (*a)
833 a++;
834 if (!fg)
835 fg = last_fg;
836 if (!bg)
837 bg = last_bg;
838 k->color = this_try_alloc_color_pair (fg, bg);
839 check_not_a;
840 num_words++;
841 } else if (*(args[0]) == '#') {
842 /* do nothing for comment */
843 } else if (!strcmp (args[0], "file")) {
844 break;
845 } else if (!strcmp (args[0], "define")) {
846 char *key = *a++;
847 char **argv;
849 if (argc < 3)
850 break_a;
851 if ((argv = g_tree_lookup (edit->defines, key))) {
852 mc_defines_destroy (NULL, argv, NULL);
853 } else {
854 key = g_strdup (key);
856 argv = g_new (char *, argc - 1);
857 g_tree_insert (edit->defines, key, argv);
858 while (*a) {
859 *argv++ = g_strdup (*a++);
861 *argv = NULL;
862 } else { /* anything else is an error */
863 break_a;
865 free_args (args);
866 syntax_g_free (l);
868 free_args (args);
869 syntax_g_free (l);
871 if (!edit->rules[0])
872 syntax_g_free (edit->rules);
874 if (result)
875 return result;
877 if (num_contexts == -1) {
878 return line;
882 char first_chars[MAX_WORDS_PER_CONTEXT + 2], *p;
883 for (i = 0; edit->rules[i]; i++) {
884 c = edit->rules[i];
885 p = first_chars;
886 *p++ = (char) 1;
887 for (j = 1; c->keyword[j]; j++)
888 *p++ = c->keyword[j]->first;
889 *p = '\0';
890 c->keyword_first_chars = g_strdup (first_chars);
894 return result;
897 void edit_free_syntax_rules (WEdit * edit)
899 int i, j;
900 if (!edit)
901 return;
902 if (edit->defines)
903 destroy_defines (&edit->defines);
904 if (!edit->rules)
905 return;
906 edit_get_rule (edit, -1);
907 syntax_g_free (edit->syntax_type);
908 edit->syntax_type = 0;
909 for (i = 0; edit->rules[i]; i++) {
910 if (edit->rules[i]->keyword) {
911 for (j = 0; edit->rules[i]->keyword[j]; j++) {
912 syntax_g_free (edit->rules[i]->keyword[j]->keyword);
913 syntax_g_free (edit->rules[i]->keyword[j]->whole_word_chars_left);
914 syntax_g_free (edit->rules[i]->keyword[j]->whole_word_chars_right);
915 syntax_g_free (edit->rules[i]->keyword[j]);
918 syntax_g_free (edit->rules[i]->left);
919 syntax_g_free (edit->rules[i]->right);
920 syntax_g_free (edit->rules[i]->whole_word_chars_left);
921 syntax_g_free (edit->rules[i]->whole_word_chars_right);
922 syntax_g_free (edit->rules[i]->keyword);
923 syntax_g_free (edit->rules[i]->keyword_first_chars);
924 syntax_g_free (edit->rules[i]);
926 while (edit->syntax_marker) {
927 struct _syntax_marker *s = edit->syntax_marker->next;
928 syntax_g_free (edit->syntax_marker);
929 edit->syntax_marker = s;
931 syntax_g_free (edit->rules);
934 /* returns -1 on file error, line number on error in file syntax */
935 static int
936 edit_read_syntax_file (WEdit * edit, char **names, const char *syntax_file,
937 const char *editor_file, const char *first_line,
938 const char *type)
940 FILE *f, *g = NULL;
941 regex_t r;
942 regmatch_t pmatch[1];
943 char *args[1024], *l = 0;
944 int line = 0;
945 int argc;
946 int result = 0;
947 int count = 0;
948 char *lib_file;
949 int found = 0;
951 f = fopen (syntax_file, "r");
952 if (!f){
953 lib_file = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
954 f = fopen (lib_file, "r");
955 g_free (lib_file);
956 if (!f)
957 return -1;
959 args[0] = 0;
960 for (;;) {
961 line++;
962 syntax_g_free (l);
963 if (!read_one_line (&l, f))
964 break;
965 get_args (l, args, &argc);
966 if (!args[0])
967 continue;
968 /* Looking for `include ...` lines before first `file ...` ones */
969 if (!found && !strcmp (args[0], "include")) {
970 if (g)
971 continue;
972 if (!args[1] || !(g = open_include_file (args[1]))) {
973 result = line;
974 break;
976 goto found_type;
978 /* looking for `file ...' lines only */
979 if (strcmp (args[0], "file")) {
980 continue;
982 found = 1;
983 /* must have two args or report error */
984 if (!args[1] || !args[2]) {
985 result = line;
986 break;
988 if (names) {
989 /* 1: just collecting a list of names of rule sets */
990 names[count++] = g_strdup (args[2]);
991 names[count] = 0;
992 } else if (type) {
993 /* 2: rule set was explicitly specified by the caller */
994 if (!strcmp (type, args[2]))
995 goto found_type;
996 } else if (editor_file && edit) {
997 /* 3: auto-detect rule set from regular expressions */
998 int q;
999 if (regcomp (&r, args[1], REG_EXTENDED)) {
1000 result = line;
1001 break;
1003 /* does filename match arg 1 ? */
1004 q = !regexec (&r, editor_file, 1, pmatch, 0);
1005 regfree (&r);
1006 if (!q && args[3]) {
1007 if (regcomp (&r, args[3], REG_EXTENDED)) {
1008 result = line;
1009 break;
1011 /* does first line match arg 3 ? */
1012 q = !regexec (&r, first_line, 1, pmatch, 0);
1013 regfree (&r);
1015 if (q) {
1016 int line_error;
1017 char *syntax_type;
1018 found_type:
1019 syntax_type = args[2];
1020 line_error = edit_read_syntax_rules (edit, g ? g : f, args);
1021 if (line_error) {
1022 if (!error_file_name) /* an included file */
1023 result = line + line_error;
1024 else
1025 result = line_error;
1026 } else {
1027 syntax_g_free (edit->syntax_type);
1028 edit->syntax_type = g_strdup (syntax_type);
1029 /* if there are no rules then turn off syntax highlighting for speed */
1030 if (!g && !edit->rules[1])
1031 if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling) {
1032 edit_free_syntax_rules (edit);
1033 break;
1036 if (g) {
1037 fclose (g);
1038 g = NULL;
1039 } else {
1040 break;
1045 syntax_g_free (l);
1046 fclose (f);
1047 return result;
1050 static char *get_first_editor_line (WEdit * edit)
1052 int i;
1053 static char s[256];
1054 s[0] = '\0';
1055 if (!edit)
1056 return s;
1057 for (i = 0; i < 255; i++) {
1058 s[i] = edit_get_byte (edit, i);
1059 if (s[i] == '\n') {
1060 s[i] = '\0';
1061 break;
1064 s[255] = '\0';
1065 return s;
1069 * Load rules into edit struct. Either edit or names must be NULL. If
1070 * edit is NULL, a list of types will be stored into names. If type is
1071 * NULL, then the type will be selected according to the filename.
1073 void
1074 edit_load_syntax (WEdit *edit, char **names, char *type)
1076 int r;
1077 char *f;
1079 edit_free_syntax_rules (edit);
1081 if (!use_colors)
1082 return;
1084 if (!option_syntax_highlighting)
1085 return;
1087 if (edit) {
1088 if (!edit->filename)
1089 return;
1090 if (!*edit->filename && !type)
1091 return;
1093 f = catstrs (home_dir, SYNTAX_FILE, 0);
1094 r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0,
1095 get_first_editor_line (edit), type);
1096 if (r == -1) {
1097 edit_free_syntax_rules (edit);
1098 message (D_ERROR, _(" Load syntax file "),
1099 _(" Cannot open file %s \n %s "), f,
1100 unix_error_string (errno));
1101 return;
1103 if (r) {
1104 edit_free_syntax_rules (edit);
1105 message (D_ERROR, _(" Load syntax file "),
1106 _(" Error in file %s on line %d "),
1107 error_file_name ? error_file_name : f, r);
1108 syntax_g_free (error_file_name);
1109 return;