small typo
[midnight-commander.git] / edit / syntax.c
blob9118e035e5becb4fcb8243f6d4431f85b973ecba
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 static inline void *syntax_malloc (size_t x)
50 void *p;
51 p = malloc (x);
52 memset (p, 0, x);
53 return p;
56 #define syntax_free(x) {if(x){free(x);(x)=0;}}
57 #define syntax_g_free(x) {if(x){g_free(x);(x)=0;}}
59 static long compare_word_to_right (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start)
61 unsigned char *p, *q;
62 int c, d, j;
63 if (!*text)
64 return -1;
65 c = edit_get_byte (edit, i - 1);
66 if (line_start)
67 if (c != '\n')
68 return -1;
69 if (whole_left)
70 if (strchr (whole_left, c))
71 return -1;
72 for (p = (unsigned char *) text, q = p + strlen ((char *) p); p < q; p++, i++) {
73 switch (*p) {
74 case '\001':
75 p++;
76 for (;;) {
77 c = edit_get_byte (edit, i);
78 if (!*p)
79 if (whole_right)
80 if (!strchr (whole_right, c))
81 break;
82 if (c == *p)
83 break;
84 if (c == '\n')
85 return -1;
86 i++;
88 break;
89 case '\002':
90 p++;
91 j = 0;
92 for (;;) {
93 c = edit_get_byte (edit, i);
94 if (c == *p) {
95 j = i;
96 if (*p == *text && !p[1]) /* handle eg '+' and @+@ keywords properly */
97 break;
99 if (j && strchr ((char *) p + 1, c)) /* c exists further down, so it will get matched later */
100 break;
101 if (c == '\n' || c == '\t' || c == ' ') {
102 if (!*p) {
103 i--;
104 break;
106 if (!j)
107 return -1;
108 i = j;
109 break;
111 if (whole_right)
112 if (!strchr (whole_right, c)) {
113 if (!*p) {
114 i--;
115 break;
117 if (!j)
118 return -1;
119 i = j;
120 break;
122 i++;
124 break;
125 case '\003':
126 p++;
127 c = -1;
128 for (;; i++) {
129 d = c;
130 c = edit_get_byte (edit, i);
131 for (j = 0; p[j] != '\003'; j++)
132 if (c == p[j])
133 goto found_char2;
134 break;
135 found_char2:
136 j = c; /* dummy command */
138 i--;
139 while (*p != '\003')
140 p++;
141 if (p[1] == d)
142 i--;
143 break;
144 case '\004':
145 p++;
146 c = edit_get_byte (edit, i);
147 for (; *p != '\004'; p++)
148 if (c == *p)
149 goto found_char3;
150 return -1;
151 found_char3:
152 for (; *p != '\004'; p++);
153 break;
154 default:
155 if (*p != edit_get_byte (edit, i))
156 return -1;
159 if (whole_right)
160 if (strchr (whole_right, edit_get_byte (edit, i)))
161 return -1;
162 return i;
165 #define XXX \
166 if (*s < '\005' || *s == (unsigned char) c) \
167 goto done; \
168 s++;
170 static inline char *xx_strchr (const unsigned char *s, int c)
172 repeat:
173 XXX XXX XXX XXX XXX XXX XXX XXX;
174 XXX XXX XXX XXX XXX XXX XXX XXX;
175 goto repeat;
176 done:
177 return (char *) s;
180 static inline struct syntax_rule apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule)
182 struct context_rule *r;
183 int contextchanged = 0, c;
184 int found_right = 0, found_left = 0, keyword_foundleft = 0, keyword_foundright = 0;
185 int is_end;
186 long end = 0;
187 struct syntax_rule _rule = rule;
188 if (!(c = edit_get_byte (edit, i)))
189 return rule;
190 is_end = (rule.end == (unsigned char) i);
191 /* check to turn off a keyword */
192 if (_rule.keyword) {
193 struct key_word *k;
194 k = edit->rules[_rule.context]->keyword[_rule.keyword];
195 if (edit_get_byte (edit, i - 1) == '\n')
196 _rule.keyword = 0;
197 if (is_end) {
198 _rule.keyword = 0;
199 keyword_foundleft = 1;
202 /* check to turn off a context */
203 if (_rule.context && !_rule.keyword) {
204 long e;
205 r = edit->rules[_rule.context];
206 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) {
207 _rule.end = e;
208 found_right = 1;
209 _rule.border = RULE_ON_RIGHT_BORDER;
210 if (r->between_delimiters)
211 _rule.context = 0;
212 } else if (is_end && rule.border & RULE_ON_RIGHT_BORDER) {
213 /* always turn off a context at 4 */
214 found_left = 1;
215 _rule.border = 0;
216 if (!keyword_foundleft)
217 _rule.context = 0;
218 } else if (is_end && rule.border & RULE_ON_LEFT_BORDER) {
219 /* never turn off a context at 2 */
220 found_left = 1;
221 _rule.border = 0;
224 /* check to turn on a keyword */
225 if (!_rule.keyword) {
226 char *p;
227 p = (r = edit->rules[_rule.context])->keyword_first_chars;
228 if (p)
229 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
230 struct key_word *k;
231 int count;
232 long e;
233 count = p - r->keyword_first_chars;
234 k = r->keyword[count];
235 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
236 if (e > 0) {
237 end = e;
238 _rule.end = e;
239 _rule.keyword = count;
240 keyword_foundright = 1;
241 break;
245 /* check to turn on a context */
246 if (!_rule.context) {
247 if (!found_left && is_end) {
248 if (rule.border & RULE_ON_RIGHT_BORDER) {
249 _rule.border = 0;
250 _rule.context = 0;
251 contextchanged = 1;
252 _rule.keyword = 0;
253 } else if (rule.border & RULE_ON_LEFT_BORDER) {
254 r = edit->rules[_rule._context];
255 _rule.border = 0;
256 if (r->between_delimiters) {
257 long e;
258 _rule.context = _rule._context;
259 contextchanged = 1;
260 _rule.keyword = 0;
261 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) {
262 _rule.end = e;
263 found_right = 1;
264 _rule.border = RULE_ON_RIGHT_BORDER;
265 _rule.context = 0;
270 if (!found_right) {
271 int count;
272 struct context_rule **rules = edit->rules;
273 for (count = 1; rules[count]; count++) {
274 r = rules[count];
275 if (r->first_left == c) {
276 long e;
277 e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left);
278 if (e >= end && (!_rule.keyword || keyword_foundright)) {
279 _rule.end = e;
280 found_right = 1;
281 _rule.border = RULE_ON_LEFT_BORDER;
282 _rule._context = count;
283 if (!r->between_delimiters)
284 if (!_rule.keyword) {
285 _rule.context = count;
286 contextchanged = 1;
288 break;
294 /* check again to turn on a keyword if the context switched */
295 if (contextchanged && !_rule.keyword) {
296 char *p;
297 p = (r = edit->rules[_rule.context])->keyword_first_chars;
298 while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
299 struct key_word *k;
300 int count;
301 long e;
302 count = p - r->keyword_first_chars;
303 k = r->keyword[count];
304 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
305 if (e > 0) {
306 _rule.end = e;
307 _rule.keyword = count;
308 break;
312 return _rule;
315 static struct syntax_rule edit_get_rule (WEdit * edit, long byte_index)
317 long i;
318 if (byte_index > edit->last_get_rule) {
319 for (i = edit->last_get_rule + 1; i <= byte_index; i++) {
320 edit->rule = apply_rules_going_right (edit, i, edit->rule);
321 if (i > (edit->syntax_marker ? edit->syntax_marker->offset + SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY)) {
322 struct _syntax_marker *s;
323 s = edit->syntax_marker;
324 edit->syntax_marker = syntax_malloc (sizeof (struct _syntax_marker));
325 edit->syntax_marker->next = s;
326 edit->syntax_marker->offset = i;
327 edit->syntax_marker->rule = edit->rule;
330 } else if (byte_index < edit->last_get_rule) {
331 struct _syntax_marker *s;
332 for (;;) {
333 if (!edit->syntax_marker) {
334 memset (&edit->rule, 0, sizeof (edit->rule));
335 for (i = -1; i <= byte_index; i++)
336 edit->rule = apply_rules_going_right (edit, i, edit->rule);
337 break;
339 if (byte_index >= edit->syntax_marker->offset) {
340 edit->rule = edit->syntax_marker->rule;
341 for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++)
342 edit->rule = apply_rules_going_right (edit, i, edit->rule);
343 break;
345 s = edit->syntax_marker->next;
346 syntax_free (edit->syntax_marker);
347 edit->syntax_marker = s;
350 edit->last_get_rule = byte_index;
351 return edit->rule;
354 static void translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *color)
356 struct key_word *k;
357 k = edit->rules[rule.context]->keyword[rule.keyword];
358 *color = k->color;
361 void edit_get_syntax_color (WEdit * edit, long byte_index, int *color)
363 if (edit->rules && byte_index < edit->last_byte &&
364 option_syntax_highlighting && use_colors) {
365 translate_rule_to_color (edit, edit_get_rule (edit, byte_index), color);
366 } else {
367 *color = use_colors ? EDITOR_NORMAL_COLOR_INDEX : 0;
373 Returns 0 on error/eof or a count of the number of bytes read
374 including the newline. Result must be free'd.
376 #ifdef HAVE_MAD
377 static int mad_read_one_line (char **line, FILE * f, char *file, int line_)
378 #define read_one_line(a,b) mad_read_one_line(a,b,__FILE__,__LINE__)
379 #else
380 static int read_one_line (char **line, FILE * f)
381 #endif
383 char *p;
384 int len = 256, c, r = 0, i = 0;
385 p = syntax_malloc (len);
387 for (;;) {
388 c = fgetc (f);
389 if (c == EOF) {
390 if (ferror (f)) {
391 if (errno == EINTR)
392 continue;
393 r = 0;
395 break;
396 } else if (c == '\n') {
397 r = i + 1; /* extra 1 for the newline just read */
398 break;
399 } else {
400 if (i >= len - 1) {
401 char *q;
402 q = syntax_malloc (len * 2);
403 memcpy (q, p, len);
404 syntax_free (p);
405 p = q;
406 len *= 2;
408 p[i++] = c;
411 p[i] = 0;
412 *line = p;
413 return r;
416 static char *convert (char *s)
418 char *r, *p;
419 p = r = s;
420 while (*s) {
421 switch (*s) {
422 case '\\':
423 s++;
424 switch (*s) {
425 case ' ':
426 *p = ' ';
427 s--;
428 break;
429 case 'n':
430 *p = '\n';
431 break;
432 case 'r':
433 *p = '\r';
434 break;
435 case 't':
436 *p = '\t';
437 break;
438 case 's':
439 *p = ' ';
440 break;
441 case '*':
442 *p = '*';
443 break;
444 case '\\':
445 *p = '\\';
446 break;
447 case '[':
448 case ']':
449 *p = '\003';
450 break;
451 case '{':
452 case '}':
453 *p = '\004';
454 break;
455 case 0:
456 *p = *s;
457 return r;
458 default:
459 *p = *s;
460 break;
462 break;
463 case '*':
464 *p = '\001';
465 break;
466 case '+':
467 *p = '\002';
468 break;
469 default:
470 *p = *s;
471 break;
473 s++;
474 p++;
476 *p = '\0';
477 return r;
480 #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
482 static void get_args (char *l, char **args, int *argc)
484 *argc = 0;
485 for (;;) {
486 char *p = l;
487 while (*p && whiteness (*p))
488 p++;
489 if (!*p)
490 break;
491 for (l = p + 1; *l && !whiteness (*l); l++);
492 if (*l)
493 *l++ = '\0';
494 *args = convert (p);
495 (*argc)++;
496 args++;
498 *args = 0;
501 #define free_args(x)
502 #define break_a {result=line;break;}
503 #define check_a {if(!*a){result=line;break;}}
504 #define check_not_a {if(*a){result=line;break;}}
506 int try_alloc_color_pair (char *fg, char *bg);
508 int this_try_alloc_color_pair (char *fg, char *bg)
510 char f[80], b[80], *p;
511 if (bg)
512 if (!*bg)
513 bg = 0;
514 if (fg)
515 if (!*fg)
516 fg = 0;
517 if (fg) {
518 strcpy (f, fg);
519 p = strchr (f, '/');
520 if (p)
521 *p = '\0';
522 fg = f;
524 if (bg) {
525 strcpy (b, bg);
526 p = strchr (b, '/');
527 if (p)
528 *p = '\0';
529 bg = b;
531 return try_alloc_color_pair (fg, bg);
534 static char *error_file_name = 0;
536 static FILE *open_include_file (char *filename)
538 FILE *f;
540 syntax_g_free (error_file_name);
541 error_file_name = g_strdup (filename);
542 if (*filename == PATH_SEP)
543 return fopen (filename, "r");
545 g_free (error_file_name);
546 error_file_name = g_strconcat (home_dir, EDIT_DIR PATH_SEP_STR,
547 filename, NULL);
548 f = fopen (error_file_name, "r");
549 if (f)
550 return f;
552 g_free (error_file_name);
553 error_file_name = g_strconcat (mc_home, PATH_SEP_STR "syntax" PATH_SEP_STR,
554 filename, NULL);
555 return fopen (error_file_name, "r");
558 /* returns line number on error */
559 static int edit_read_syntax_rules (WEdit * edit, FILE * f)
561 FILE *g = 0;
562 char *fg, *bg;
563 char last_fg[32] = "", last_bg[32] = "";
564 char whole_right[512];
565 char whole_left[512];
566 char *args[1024], *l = 0;
567 int save_line = 0, line = 0;
568 struct context_rule **r, *c = 0;
569 int num_words = -1, num_contexts = -1;
570 int argc, result = 0;
571 int i, j;
573 args[0] = 0;
575 strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
576 strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
578 r = edit->rules = syntax_malloc (MAX_CONTEXTS * sizeof (struct context_rule *));
580 for (;;) {
581 char **a;
582 line++;
583 l = 0;
584 if (!read_one_line (&l, f)) {
585 if (g) {
586 fclose (f);
587 f = g;
588 g = 0;
589 line = save_line + 1;
590 syntax_g_free (error_file_name);
591 if (l)
592 syntax_free (l);
593 if (!read_one_line (&l, f))
594 break;
595 } else {
596 break;
599 get_args (l, args, &argc);
600 a = args + 1;
601 if (!args[0]) {
602 /* do nothing */
603 } else if (!strcmp (args[0], "include")) {
604 if (g || argc != 2) {
605 result = line;
606 break;
608 g = f;
609 f = open_include_file (args[1]);
610 if (!f) {
611 syntax_g_free (error_file_name);
612 result = line;
613 break;
615 save_line = line;
616 line = 0;
617 } else if (!strcmp (args[0], "wholechars")) {
618 check_a;
619 if (!strcmp (*a, "left")) {
620 a++;
621 strcpy (whole_left, *a);
622 } else if (!strcmp (*a, "right")) {
623 a++;
624 strcpy (whole_right, *a);
625 } else {
626 strcpy (whole_left, *a);
627 strcpy (whole_right, *a);
629 a++;
630 check_not_a;
631 } else if (!strcmp (args[0], "context")) {
632 check_a;
633 if (num_contexts == -1) {
634 if (strcmp (*a, "default")) { /* first context is the default */
635 break_a;
637 a++;
638 c = r[0] = syntax_malloc (sizeof (struct context_rule));
639 c->left = (char *) strdup (" ");
640 c->right = (char *) strdup (" ");
641 num_contexts = 0;
642 } else {
643 c = r[num_contexts] = syntax_malloc (sizeof (struct context_rule));
644 if (!strcmp (*a, "exclusive")) {
645 a++;
646 c->between_delimiters = 1;
648 check_a;
649 if (!strcmp (*a, "whole")) {
650 a++;
651 c->whole_word_chars_left = (char *) strdup (whole_left);
652 c->whole_word_chars_right = (char *) strdup (whole_right);
653 } else if (!strcmp (*a, "wholeleft")) {
654 a++;
655 c->whole_word_chars_left = (char *) strdup (whole_left);
656 } else if (!strcmp (*a, "wholeright")) {
657 a++;
658 c->whole_word_chars_right = (char *) strdup (whole_right);
660 check_a;
661 if (!strcmp (*a, "linestart")) {
662 a++;
663 c->line_start_left = 1;
665 check_a;
666 c->left = (char *) strdup (*a++);
667 check_a;
668 if (!strcmp (*a, "linestart")) {
669 a++;
670 c->line_start_right = 1;
672 check_a;
673 c->right = (char *) strdup (*a++);
674 c->first_left = *c->left;
675 c->first_right = *c->right;
676 #if 0
677 c->single_char = (strlen (c->right) == 1);
678 #endif
680 c->keyword = syntax_malloc (MAX_WORDS_PER_CONTEXT * sizeof (struct key_word *));
681 #if 0
682 c->max_words = MAX_WORDS_PER_CONTEXT;
683 #endif
684 num_words = 1;
685 c->keyword[0] = syntax_malloc (sizeof (struct key_word));
686 fg = *a;
687 if (*a)
688 a++;
689 bg = *a;
690 if (*a)
691 a++;
692 strcpy (last_fg, fg ? fg : "");
693 strcpy (last_bg, bg ? bg : "");
694 c->keyword[0]->color = this_try_alloc_color_pair (fg, bg);
695 c->keyword[0]->keyword = (char *) strdup (" ");
696 check_not_a;
697 num_contexts++;
698 } else if (!strcmp (args[0], "spellcheck")) {
699 if (!c) {
700 result = line;
701 break;
703 c->spelling = 1;
704 } else if (!strcmp (args[0], "keyword")) {
705 struct key_word *k;
706 if (num_words == -1)
707 break_a;
708 check_a;
709 k = r[num_contexts - 1]->keyword[num_words] = syntax_malloc (sizeof (struct key_word));
710 if (!strcmp (*a, "whole")) {
711 a++;
712 k->whole_word_chars_left = (char *) strdup (whole_left);
713 k->whole_word_chars_right = (char *) strdup (whole_right);
714 } else if (!strcmp (*a, "wholeleft")) {
715 a++;
716 k->whole_word_chars_left = (char *) strdup (whole_left);
717 } else if (!strcmp (*a, "wholeright")) {
718 a++;
719 k->whole_word_chars_right = (char *) strdup (whole_right);
721 check_a;
722 if (!strcmp (*a, "linestart")) {
723 a++;
724 k->line_start = 1;
726 check_a;
727 if (!strcmp (*a, "whole")) {
728 break_a;
730 k->keyword = (char *) strdup (*a++);
731 k->first = *k->keyword;
732 fg = *a;
733 if (*a)
734 a++;
735 bg = *a;
736 if (*a)
737 a++;
738 if (!fg)
739 fg = last_fg;
740 if (!bg)
741 bg = last_bg;
742 k->color = this_try_alloc_color_pair (fg, bg);
743 check_not_a;
744 num_words++;
745 } else if (!strncmp (args[0], "#", 1)) {
746 /* do nothing for comment */
747 } else if (!strcmp (args[0], "file")) {
748 break;
749 } else { /* anything else is an error */
750 break_a;
752 free_args (args);
753 syntax_free (l);
755 free_args (args);
756 syntax_free (l);
758 if (!edit->rules[0])
759 syntax_free (edit->rules);
761 if (result)
762 return result;
764 if (num_contexts == -1) {
765 result = line;
766 return result;
770 char first_chars[MAX_WORDS_PER_CONTEXT + 2], *p;
771 for (i = 0; edit->rules[i]; i++) {
772 c = edit->rules[i];
773 p = first_chars;
774 *p++ = (char) 1;
775 for (j = 1; c->keyword[j]; j++)
776 *p++ = c->keyword[j]->first;
777 *p = '\0';
778 c->keyword_first_chars = syntax_malloc (strlen (first_chars) + 2);
779 strcpy (c->keyword_first_chars, first_chars);
783 return result;
786 int edit_check_spelling (WEdit * edit)
788 return 0;
791 void (*syntax_change_callback) (CWidget *) = 0;
793 void edit_set_syntax_change_callback (void (*callback) (CWidget *))
795 syntax_change_callback = callback;
798 void edit_free_syntax_rules (WEdit * edit)
800 int i, j;
801 if (!edit)
802 return;
803 if (!edit->rules)
804 return;
805 edit_get_rule (edit, -1);
806 syntax_free (edit->syntax_type);
807 edit->syntax_type = 0;
808 if (syntax_change_callback)
809 (*syntax_change_callback) (&edit->widget);
810 for (i = 0; edit->rules[i]; i++) {
811 if (edit->rules[i]->keyword) {
812 for (j = 0; edit->rules[i]->keyword[j]; j++) {
813 syntax_free (edit->rules[i]->keyword[j]->keyword);
814 syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_left);
815 syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_right);
816 syntax_free (edit->rules[i]->keyword[j]);
819 syntax_free (edit->rules[i]->left);
820 syntax_free (edit->rules[i]->right);
821 syntax_free (edit->rules[i]->whole_word_chars_left);
822 syntax_free (edit->rules[i]->whole_word_chars_right);
823 syntax_free (edit->rules[i]->keyword);
824 syntax_free (edit->rules[i]->keyword_first_chars);
825 syntax_free (edit->rules[i]);
827 while (edit->syntax_marker) {
828 struct _syntax_marker *s = edit->syntax_marker->next;
829 syntax_free (edit->syntax_marker);
830 edit->syntax_marker = s;
832 syntax_free (edit->rules);
835 /* returns -1 on file error, line number on error in file syntax */
836 static int edit_read_syntax_file (WEdit * edit, char **names, char *syntax_file, char *editor_file, char *first_line, char *type)
838 FILE *f;
839 regex_t r;
840 regmatch_t pmatch[1];
841 char *args[1024], *l = 0;
842 int line = 0;
843 int argc;
844 int result = 0;
845 int count = 0;
846 char *lib_file;
848 f = fopen (syntax_file, "r");
849 if (!f){
850 lib_file = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
851 f = fopen (lib_file, "r");
852 g_free (lib_file);
853 if (!f)
854 return -1;
856 args[0] = 0;
857 for (;;) {
858 line++;
859 syntax_free (l);
860 if (!read_one_line (&l, f))
861 break;
862 get_args (l, args, &argc);
863 if (!args[0])
864 continue;
865 /* looking for `file ...' lines only */
866 if (strcmp (args[0], "file")) {
867 free_args (args);
868 continue;
870 /* must have two args or report error */
871 if (!args[1] || !args[2]) {
872 result = line;
873 break;
875 if (names) {
876 /* 1: just collecting a list of names of rule sets */
877 names[count++] = (char *) strdup (args[2]);
878 names[count] = 0;
879 } else if (type) {
880 /* 2: rule set was explicitly specified by the caller */
881 if (!strcmp (type, args[2]))
882 goto found_type;
883 } else if (editor_file && edit) {
884 /* 3: auto-detect rule set from regular expressions */
885 int q;
886 if (regcomp (&r, args[1], REG_EXTENDED)) {
887 result = line;
888 break;
890 /* does filename match arg 1 ? */
891 q = !regexec (&r, editor_file, 1, pmatch, 0);
892 regfree (&r);
893 if (!q && args[3]) {
894 if (regcomp (&r, args[3], REG_EXTENDED)) {
895 result = line;
896 break;
898 /* does first line match arg 3 ? */
899 q = !regexec (&r, first_line, 1, pmatch, 0);
900 regfree (&r);
902 if (q) {
903 int line_error;
904 found_type:
905 line_error = edit_read_syntax_rules (edit, f);
906 if (line_error) {
907 if (!error_file_name) /* an included file */
908 result = line + line_error;
909 else
910 result = line_error;
911 } else {
912 syntax_free (edit->syntax_type);
913 edit->syntax_type = (char *) strdup (args[2]);
914 /* if there are no rules then turn off syntax highlighting for speed */
915 if (!edit->rules[1])
916 if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling) {
917 edit_free_syntax_rules (edit);
918 break;
920 /* notify the callback of a change in rule set */
921 if (syntax_change_callback)
922 (*syntax_change_callback) (&edit->widget);
924 break;
927 free_args (args);
929 free_args (args);
930 syntax_free (l);
931 fclose (f);
932 return result;
935 static char *get_first_editor_line (WEdit * edit)
937 int i;
938 static char s[256];
939 s[0] = '\0';
940 if (!edit)
941 return s;
942 for (i = 0; i < 255; i++) {
943 s[i] = edit_get_byte (edit, i);
944 if (s[i] == '\n') {
945 s[i] = '\0';
946 break;
949 s[255] = '\0';
950 return s;
953 /* loads rules into edit struct. one of edit or names must be zero. if
954 edit is zero, a list of types will be stored into name. type may be zero
955 in which case the type will be selected according to the filename. */
956 void edit_load_syntax (WEdit * edit, char **names, char *type)
958 int r;
959 char *f;
961 edit_free_syntax_rules (edit);
963 if (!use_colors)
964 return;
966 if (!option_syntax_highlighting)
967 return;
969 if (edit) {
970 if (!edit->filename)
971 return;
972 if (!*edit->filename && !type)
973 return;
975 f = catstrs (home_dir, SYNTAX_FILE, 0);
976 r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0, get_first_editor_line (edit), type);
977 if (r == -1) {
978 edit_free_syntax_rules (edit);
979 edit_error_dialog (_ (" Load syntax file "), _ (" File access error "));
980 return;
982 if (r) {
983 edit_free_syntax_rules (edit);
984 message (0, _(" Load syntax file "),
985 _(" Error in file %s on line %d "),
986 error_file_name ? error_file_name : f, r);
987 syntax_g_free (error_file_name);
988 return;
992 #else
994 int option_syntax_highlighting = 0;
996 void edit_load_syntax (WEdit * edit, char **names, char *type)
998 return;
1001 void edit_free_syntax_rules (WEdit * edit)
1003 return;
1006 void edit_get_syntax_color (WEdit * edit, long byte_index, int *color)
1008 *color = use_colors ? EDITOR_NORMAL_COLOR_INDEX : 0;
1011 int edit_check_spelling (WEdit * edit)
1013 return 0;
1016 #endif /* HAVE_SYNTAXH */