Merge branch '2134_am_silent_rules'
[kaloumi3.git] / src / editor / syntax.c
blob179f2677bddbb2a7e308249007dccf5772e41e71
1 /* editor syntax highlighting.
3 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007 Free Software Foundation, Inc.
6 Authors: 1998 Paul Sheer
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
24 /** \file
25 * \brief Source: editor syntax highlighting
26 * \author Paul Sheer
27 * \date 1996, 1997
28 * \author Mikhail Pobolovets
29 * \date 2010
31 * Mispelled words are flushed from the syntax highlighting rules
32 * when they have been around longer than
33 * TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
34 * chars per second and say 3 chars + a space per word, we can
35 * accumulate 450 words absolute max with a value of 60. This is
36 * below this limit of 1024 words in a context.
39 #include <config.h>
41 #include <stdio.h>
42 #include <stdarg.h>
43 #include <sys/types.h>
44 #include <unistd.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include <errno.h>
48 #include <sys/stat.h>
49 #include <stdlib.h>
51 #include "lib/global.h"
52 #include "lib/search.h" /* search engine */
53 #include "lib/skin.h"
54 #include "lib/strutil.h" /* utf string functions */
56 #include "src/main.h" /* mc_home */
57 #include "src/wtools.h" /* message() */
59 #include "edit-impl.h"
60 #include "edit-widget.h"
63 /* bytes */
64 #define SYNTAX_MARKER_DENSITY 512
66 #define TRANSIENT_WORD_TIME_OUT 60
68 #define UNKNOWN_FORMAT "unknown"
70 #define MAX_WORDS_PER_CONTEXT 1024
71 #define MAX_CONTEXTS 128
73 #define RULE_ON_LEFT_BORDER 1
74 #define RULE_ON_RIGHT_BORDER 2
76 #define SYNTAX_TOKEN_STAR '\001'
77 #define SYNTAX_TOKEN_PLUS '\002'
78 #define SYNTAX_TOKEN_BRACKET '\003'
79 #define SYNTAX_TOKEN_BRACE '\004'
81 struct key_word
83 char *keyword;
84 unsigned char first;
85 char *whole_word_chars_left;
86 char *whole_word_chars_right;
87 int line_start;
88 int color;
91 struct context_rule
93 char *left;
94 unsigned char first_left;
95 char *right;
96 unsigned char first_right;
97 char line_start_left;
98 char line_start_right;
99 int between_delimiters;
100 char *whole_word_chars_left;
101 char *whole_word_chars_right;
102 char *keyword_first_chars;
103 int spelling;
104 /* first word is word[1] */
105 struct key_word **keyword;
108 struct _syntax_marker
110 long offset;
111 struct syntax_rule rule;
112 struct _syntax_marker *next;
115 int option_syntax_highlighting = 1;
116 int option_auto_syntax = 1;
117 char *option_syntax_type = NULL;
119 static gint
120 mc_defines_destroy (gpointer key, gpointer value, gpointer data)
122 char **values = value;
124 (void) data;
126 g_free (key);
127 while (*values)
128 g_free (*values++);
129 g_free (value);
131 return FALSE;
134 /* Completely destroys the defines tree */
135 static void
136 destroy_defines (GTree ** defines)
138 g_tree_traverse (*defines, mc_defines_destroy, G_POST_ORDER, NULL);
139 g_tree_destroy (*defines);
140 *defines = NULL;
143 /* Wrapper for case insensitive mode */
144 inline static int
145 xx_tolower (WEdit * edit, int c)
147 if (edit->is_case_insensitive)
149 return tolower (c);
151 return c;
154 static void
155 subst_defines (GTree * defines, char **argv, char **argv_end)
157 char **t, **p;
158 int argc;
160 while (*argv && argv < argv_end)
162 if ((t = g_tree_lookup (defines, *argv)))
164 int count = 0;
166 /* Count argv array members */
167 argc = 0;
168 for (p = &argv[1]; *p; p++)
169 argc++;
171 /* Count members of definition array */
172 for (p = t; *p; p++)
173 count++;
174 p = &argv[count + argc];
176 /* Buffer overflow or infinitive loop in define */
177 if (p >= argv_end)
178 break;
180 /* Move rest of argv after definition members */
181 while (argc >= 0)
182 *p-- = argv[argc-- + 1];
184 /* Copy definition members to argv */
185 for (p = argv; *t; *p++ = *t++);
187 argv++;
191 static long
192 compare_word_to_right (WEdit * edit, long i, const char *text,
193 const char *whole_left, const char *whole_right, int line_start)
195 const unsigned char *p, *q;
196 int c, d, j;
198 if (!*text)
199 return -1;
200 c = xx_tolower (edit, edit_get_byte (edit, i - 1));
201 if (line_start)
202 if (c != '\n')
203 return -1;
204 if (whole_left)
205 if (strchr (whole_left, c))
206 return -1;
208 for (p = (unsigned char *) text, q = p + str_term_width1 ((char *) p); p < q; p++, i++)
210 switch (*p)
212 case SYNTAX_TOKEN_STAR:
213 if (++p > q)
214 return -1;
215 for (;;)
217 c = xx_tolower (edit, edit_get_byte (edit, i));
218 if (!*p)
219 if (whole_right)
220 if (!strchr (whole_right, c))
221 break;
222 if (c == *p)
223 break;
224 if (c == '\n')
225 return -1;
226 i++;
228 break;
229 case SYNTAX_TOKEN_PLUS:
230 if (++p > q)
231 return -1;
232 j = 0;
233 for (;;)
235 c = xx_tolower (edit, edit_get_byte (edit, i));
236 if (c == *p)
238 j = i;
239 if (*p == *text && !p[1]) /* handle eg '+' and @+@ keywords properly */
240 break;
242 if (j && strchr ((char *) p + 1, c)) /* c exists further down, so it will get matched later */
243 break;
244 if (c == '\n' || c == '\t' || c == ' ')
246 if (!*p)
248 i--;
249 break;
251 if (!j)
252 return -1;
253 i = j;
254 break;
256 if (whole_right)
257 if (!strchr (whole_right, c))
259 if (!*p)
261 i--;
262 break;
264 if (!j)
265 return -1;
266 i = j;
267 break;
269 i++;
271 break;
272 case SYNTAX_TOKEN_BRACKET:
273 if (++p > q)
274 return -1;
275 c = -1;
276 for (;; i++)
278 d = c;
279 c = xx_tolower (edit, edit_get_byte (edit, i));
280 for (j = 0; p[j] != SYNTAX_TOKEN_BRACKET && p[j]; j++)
281 if (c == p[j])
282 goto found_char2;
283 break;
284 found_char2:
285 ; /* dummy command */
287 i--;
288 while (*p != SYNTAX_TOKEN_BRACKET && p <= q)
289 p++;
290 if (p > q)
291 return -1;
292 if (p[1] == d)
293 i--;
294 break;
295 case SYNTAX_TOKEN_BRACE:
296 if (++p > q)
297 return -1;
298 c = xx_tolower (edit, edit_get_byte (edit, i));
299 for (; *p != SYNTAX_TOKEN_BRACE && *p; p++)
300 if (c == *p)
301 goto found_char3;
302 return -1;
303 found_char3:
304 while (*p != SYNTAX_TOKEN_BRACE && p < q)
305 p++;
306 break;
307 default:
308 if (*p != xx_tolower (edit, edit_get_byte (edit, i)))
309 return -1;
312 if (whole_right)
313 if (strchr (whole_right, xx_tolower (edit, edit_get_byte (edit, i))))
314 return -1;
315 return i;
318 static const char *
319 xx_strchr (WEdit * edit, const unsigned char *s, int char_byte)
321 while (*s >= '\005' && xx_tolower (edit, *s) != char_byte)
323 s++;
326 return (const char *) s;
329 static struct syntax_rule
330 apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule)
332 struct context_rule *r;
333 int contextchanged = 0, c;
334 int found_right = 0, found_left = 0, keyword_foundleft = 0, keyword_foundright = 0;
335 int is_end;
336 long end = 0;
337 struct syntax_rule _rule = rule;
339 if (!(c = xx_tolower (edit, edit_get_byte (edit, i))))
340 return rule;
341 is_end = (rule.end == (unsigned char) i);
343 /* check to turn off a keyword */
344 if (_rule.keyword)
346 if (edit_get_byte (edit, i - 1) == '\n')
347 _rule.keyword = 0;
348 if (is_end)
350 _rule.keyword = 0;
351 keyword_foundleft = 1;
355 /* check to turn off a context */
356 if (_rule.context && !_rule.keyword)
358 long e;
359 r = edit->rules[_rule.context];
360 if (r->first_right == c && !(rule.border & RULE_ON_RIGHT_BORDER)
361 && (e =
362 compare_word_to_right (edit, i, r->right, r->whole_word_chars_left,
363 r->whole_word_chars_right, r->line_start_right)) > 0)
365 _rule.end = e;
366 found_right = 1;
367 _rule.border = RULE_ON_RIGHT_BORDER;
368 if (r->between_delimiters)
369 _rule.context = 0;
371 else if (is_end && rule.border & RULE_ON_RIGHT_BORDER)
374 /* always turn off a context at 4 */
375 found_left = 1;
376 _rule.border = 0;
377 if (!keyword_foundleft)
378 _rule.context = 0;
380 else if (is_end && rule.border & RULE_ON_LEFT_BORDER)
383 /* never turn off a context at 2 */
384 found_left = 1;
385 _rule.border = 0;
389 /* check to turn on a keyword */
390 if (!_rule.keyword)
392 const char *p;
394 p = (r = edit->rules[_rule.context])->keyword_first_chars;
395 if (p)
396 while (*(p = xx_strchr (edit, (unsigned char *) p + 1, c)))
398 struct key_word *k;
399 int count;
400 long e;
402 count = p - r->keyword_first_chars;
403 k = r->keyword[count];
404 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left,
405 k->whole_word_chars_right, k->line_start);
406 if (e > 0)
408 end = e;
409 _rule.end = e;
410 _rule.keyword = count;
411 keyword_foundright = 1;
412 break;
416 /* check to turn on a context */
417 if (!_rule.context)
419 if (!found_left && is_end)
421 if (rule.border & RULE_ON_RIGHT_BORDER)
423 _rule.border = 0;
424 _rule.context = 0;
425 contextchanged = 1;
426 _rule.keyword = 0;
429 else if (rule.border & RULE_ON_LEFT_BORDER)
431 r = edit->rules[_rule._context];
432 _rule.border = 0;
433 if (r->between_delimiters)
435 long e;
436 _rule.context = _rule._context;
437 contextchanged = 1;
438 _rule.keyword = 0;
439 if (r->first_right == c
440 && (e =
441 compare_word_to_right (edit, i, r->right, r->whole_word_chars_left,
442 r->whole_word_chars_right,
443 r->line_start_right)) >= end)
445 _rule.end = e;
446 found_right = 1;
447 _rule.border = RULE_ON_RIGHT_BORDER;
448 _rule.context = 0;
454 if (!found_right)
456 int count;
457 struct context_rule **rules = edit->rules;
459 for (count = 1; rules[count]; count++)
461 r = rules[count];
462 if (r->first_left == c)
464 long e;
466 e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left,
467 r->whole_word_chars_right, r->line_start_left);
468 if (e >= end && (!_rule.keyword || keyword_foundright))
470 _rule.end = e;
471 found_right = 1;
472 _rule.border = RULE_ON_LEFT_BORDER;
473 _rule._context = count;
474 if (!r->between_delimiters)
475 if (!_rule.keyword)
477 _rule.context = count;
478 contextchanged = 1;
480 break;
487 /* check again to turn on a keyword if the context switched */
488 if (contextchanged && !_rule.keyword)
490 const char *p;
492 p = (r = edit->rules[_rule.context])->keyword_first_chars;
493 while (*(p = xx_strchr (edit, (unsigned char *) p + 1, c)))
495 struct key_word *k;
496 int count;
497 long e;
499 count = p - r->keyword_first_chars;
500 k = r->keyword[count];
501 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left,
502 k->whole_word_chars_right, k->line_start);
503 if (e > 0)
505 _rule.end = e;
506 _rule.keyword = count;
507 break;
511 return _rule;
514 static struct syntax_rule
515 edit_get_rule (WEdit * edit, long byte_index)
517 long i;
519 if (byte_index > edit->last_get_rule)
521 for (i = edit->last_get_rule + 1; i <= byte_index; i++)
523 edit->rule = apply_rules_going_right (edit, i, edit->rule);
524 if (i >
525 (edit->syntax_marker ? edit->syntax_marker->offset +
526 SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY))
528 struct _syntax_marker *s;
530 s = edit->syntax_marker;
531 edit->syntax_marker = g_malloc (sizeof (struct _syntax_marker));
532 edit->syntax_marker->next = s;
533 edit->syntax_marker->offset = i;
534 edit->syntax_marker->rule = edit->rule;
538 else if (byte_index < edit->last_get_rule)
540 struct _syntax_marker *s;
542 for (;;)
544 if (!edit->syntax_marker)
546 memset (&edit->rule, 0, sizeof (edit->rule));
547 for (i = -1; i <= byte_index; i++)
548 edit->rule = apply_rules_going_right (edit, i, edit->rule);
549 break;
551 if (byte_index >= edit->syntax_marker->offset)
553 edit->rule = edit->syntax_marker->rule;
554 for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++)
555 edit->rule = apply_rules_going_right (edit, i, edit->rule);
556 break;
558 s = edit->syntax_marker->next;
559 g_free (edit->syntax_marker);
560 edit->syntax_marker = s;
563 edit->last_get_rule = byte_index;
564 return edit->rule;
567 static inline void
568 translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *color)
570 *color = edit->rules[rule.context]->keyword[rule.keyword]->color;
573 void
574 edit_get_syntax_color (WEdit * edit, long byte_index, int *color)
576 if (!tty_use_colors ())
577 *color = 0;
578 else if (edit->rules && byte_index < edit->last_byte && option_syntax_highlighting)
579 translate_rule_to_color (edit, edit_get_rule (edit, byte_index), color);
580 else
581 *color = EDITOR_NORMAL_COLOR;
586 Returns 0 on error/eof or a count of the number of bytes read
587 including the newline. Result must be free'd.
588 In case of an error, *line will not be modified.
590 static size_t
591 read_one_line (char **line, FILE * f)
593 GString *p;
594 size_t r = 0;
596 /* not reallocate string too often */
597 p = g_string_sized_new (64);
599 for (;;)
601 int c;
603 c = fgetc (f);
604 if (c == EOF)
606 if (ferror (f))
608 if (errno == EINTR)
609 continue;
610 r = 0;
612 break;
614 r++;
616 /* handle all of \r\n, \r, \n correctly. */
617 if (c == '\n')
618 break;
619 if (c == '\r')
621 c = fgetc (f);
622 if (c == '\n')
623 r++;
624 else
625 ungetc (c, f);
626 break;
629 g_string_append_c (p, c);
631 if (r != 0)
632 *line = g_string_free (p, FALSE);
633 else
634 g_string_free (p, TRUE);
636 return r;
639 static char *
640 convert (char *s)
642 char *r, *p;
644 p = r = s;
645 while (*s)
647 switch (*s)
649 case '\\':
650 s++;
651 switch (*s)
653 case ' ':
654 *p = ' ';
655 s--;
656 break;
657 case 'n':
658 *p = '\n';
659 break;
660 case 'r':
661 *p = '\r';
662 break;
663 case 't':
664 *p = '\t';
665 break;
666 case 's':
667 *p = ' ';
668 break;
669 case '*':
670 *p = '*';
671 break;
672 case '\\':
673 *p = '\\';
674 break;
675 case '[':
676 case ']':
677 *p = SYNTAX_TOKEN_BRACKET;
678 break;
679 case '{':
680 case '}':
681 *p = SYNTAX_TOKEN_BRACE;
682 break;
683 case 0:
684 *p = *s;
685 return r;
686 default:
687 *p = *s;
688 break;
690 break;
691 case '*':
692 *p = SYNTAX_TOKEN_STAR;
693 break;
694 case '+':
695 *p = SYNTAX_TOKEN_PLUS;
696 break;
697 default:
698 *p = *s;
699 break;
701 s++;
702 p++;
704 *p = '\0';
705 return r;
708 #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
710 static int
711 get_args (char *l, char **args, int args_size)
713 int argc = 0;
715 while (argc < args_size)
717 char *p = l;
718 while (*p && whiteness (*p))
719 p++;
720 if (!*p)
721 break;
722 for (l = p + 1; *l && !whiteness (*l); l++);
723 if (*l)
724 *l++ = '\0';
725 args[argc++] = convert (p);
727 args[argc] = (char *) NULL;
728 return argc;
731 #define free_args(x)
732 #define break_a {result=line;break;}
733 #define check_a {if(!*a){result=line;break;}}
734 #define check_not_a {if(*a){result=line;break;}}
736 static int
737 this_try_alloc_color_pair (const char *fg, const char *bg)
739 char f[80], b[80], *p;
741 if (bg)
742 if (!*bg)
743 bg = 0;
744 if (fg)
745 if (!*fg)
746 fg = 0;
747 if (fg)
749 g_strlcpy (f, fg, sizeof (f));
750 p = strchr (f, '/');
751 if (p)
752 *p = '\0';
753 fg = f;
755 if (bg)
757 g_strlcpy (b, bg, sizeof (b));
758 p = strchr (b, '/');
759 if (p)
760 *p = '\0';
761 bg = b;
763 return tty_try_alloc_color_pair (fg, bg);
766 static char *error_file_name = 0;
768 static FILE *
769 open_include_file (const char *filename)
771 FILE *f;
773 MC_PTR_FREE (error_file_name);
774 error_file_name = g_strdup (filename);
775 if (*filename == PATH_SEP)
776 return fopen (filename, "r");
778 g_free (error_file_name);
779 error_file_name = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR PATH_SEP_STR,
780 filename, (char *) NULL);
781 f = fopen (error_file_name, "r");
782 if (f)
783 return f;
785 g_free (error_file_name);
786 error_file_name = g_strconcat (mc_home, PATH_SEP_STR, "syntax", PATH_SEP_STR,
787 filename, (char *) NULL);
788 f = fopen (error_file_name, "r");
789 if (f)
790 return f;
792 g_free (error_file_name);
793 error_file_name = g_strconcat (mc_home_alt, PATH_SEP_STR "syntax" PATH_SEP_STR,
794 filename, (char *) NULL);
796 return fopen (error_file_name, "r");
799 inline static void
800 xx_lowerize_line (WEdit * edit, char *line, size_t len)
802 if (edit->is_case_insensitive)
804 size_t i;
805 for (i = 0; i < len; ++i)
806 line[i] = tolower (line[i]);
810 /* returns line number on error */
811 static int
812 edit_read_syntax_rules (WEdit * edit, FILE * f, char **args, int args_size)
814 FILE *g = NULL;
815 char *fg, *bg;
816 char last_fg[32] = "", last_bg[32] = "";
817 char whole_right[512];
818 char whole_left[512];
819 char *l = 0;
820 int save_line = 0, line = 0;
821 struct context_rule **r, *c = NULL;
822 int num_words = -1, num_contexts = -1;
823 int result = 0;
824 int argc;
825 int i, j;
826 int alloc_contexts = MAX_CONTEXTS,
827 alloc_words_per_context = MAX_WORDS_PER_CONTEXT,
828 max_alloc_words_per_context = MAX_WORDS_PER_CONTEXT;
830 args[0] = 0;
831 edit->is_case_insensitive = FALSE;
833 strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
834 strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
836 r = edit->rules = g_malloc0 (alloc_contexts * sizeof (struct context_rule *));
838 if (!edit->defines)
839 edit->defines = g_tree_new ((GCompareFunc) strcmp);
841 for (;;)
843 char **a;
844 size_t len;
846 line++;
847 l = 0;
849 len = read_one_line (&l, f);
850 if (len == 0)
852 if (g)
854 fclose (f);
855 f = g;
856 g = 0;
857 line = save_line + 1;
858 MC_PTR_FREE (error_file_name);
859 MC_PTR_FREE (l);
860 len = read_one_line (&l, f);
861 if (len == 0)
862 break;
863 else
864 xx_lowerize_line (edit, l, len);
866 else
868 break;
871 else
873 xx_lowerize_line (edit, l, len);
875 argc = get_args (l, args, args_size);
876 a = args + 1;
877 if (!args[0])
879 /* do nothing */
881 else if (!strcmp (args[0], "include"))
883 if (g || argc != 2)
885 result = line;
886 break;
888 g = f;
889 f = open_include_file (args[1]);
890 if (!f)
892 MC_PTR_FREE (error_file_name);
893 result = line;
894 break;
896 save_line = line;
897 line = 0;
899 else if (!strcmp (args[0], "caseinsensitive"))
901 edit->is_case_insensitive = TRUE;
903 else if (!strcmp (args[0], "wholechars"))
905 check_a;
906 if (!strcmp (*a, "left"))
908 a++;
909 g_strlcpy (whole_left, *a, sizeof (whole_left));
911 else if (!strcmp (*a, "right"))
913 a++;
914 g_strlcpy (whole_right, *a, sizeof (whole_right));
916 else
918 g_strlcpy (whole_left, *a, sizeof (whole_left));
919 g_strlcpy (whole_right, *a, sizeof (whole_right));
921 a++;
922 check_not_a;
924 else if (!strcmp (args[0], "context"))
926 check_a;
927 if (num_contexts == -1)
929 if (strcmp (*a, "default"))
930 { /* first context is the default */
931 break_a;
933 a++;
934 c = r[0] = g_malloc0 (sizeof (struct context_rule));
935 c->left = g_strdup (" ");
936 c->right = g_strdup (" ");
937 num_contexts = 0;
939 else
941 /* Terminate previous context. */
942 r[num_contexts - 1]->keyword[num_words] = NULL;
943 c = r[num_contexts] = g_malloc0 (sizeof (struct context_rule));
944 if (!strcmp (*a, "exclusive"))
946 a++;
947 c->between_delimiters = 1;
949 check_a;
950 if (!strcmp (*a, "whole"))
952 a++;
953 c->whole_word_chars_left = g_strdup (whole_left);
954 c->whole_word_chars_right = g_strdup (whole_right);
956 else if (!strcmp (*a, "wholeleft"))
958 a++;
959 c->whole_word_chars_left = g_strdup (whole_left);
961 else if (!strcmp (*a, "wholeright"))
963 a++;
964 c->whole_word_chars_right = g_strdup (whole_right);
966 check_a;
967 if (!strcmp (*a, "linestart"))
969 a++;
970 c->line_start_left = 1;
972 check_a;
973 c->left = g_strdup (*a++);
974 check_a;
975 if (!strcmp (*a, "linestart"))
977 a++;
978 c->line_start_right = 1;
980 check_a;
981 c->right = g_strdup (*a++);
982 c->first_left = *c->left;
983 c->first_right = *c->right;
985 c->keyword = g_malloc (alloc_words_per_context * sizeof (struct key_word *));
986 num_words = 1;
987 c->keyword[0] = g_malloc0 (sizeof (struct key_word));
988 subst_defines (edit->defines, a, &args[1024]);
989 fg = *a;
990 if (*a)
991 a++;
992 bg = *a;
993 if (*a)
994 a++;
995 g_strlcpy (last_fg, fg ? fg : "", sizeof (last_fg));
996 g_strlcpy (last_bg, bg ? bg : "", sizeof (last_bg));
997 c->keyword[0]->color = this_try_alloc_color_pair (fg, bg);
998 c->keyword[0]->keyword = g_strdup (" ");
999 check_not_a;
1001 alloc_words_per_context = MAX_WORDS_PER_CONTEXT;
1002 if (++num_contexts >= alloc_contexts)
1004 struct context_rule **tmp;
1006 alloc_contexts += 128;
1007 tmp = g_realloc (r, alloc_contexts * sizeof (struct context_rule *));
1008 r = tmp;
1011 else if (!strcmp (args[0], "spellcheck"))
1013 if (!c)
1015 result = line;
1016 break;
1018 c->spelling = 1;
1020 else if (!strcmp (args[0], "keyword"))
1022 struct key_word *k;
1024 if (num_words == -1)
1025 break_a;
1026 check_a;
1027 k = r[num_contexts - 1]->keyword[num_words] = g_malloc0 (sizeof (struct key_word));
1028 if (!strcmp (*a, "whole"))
1030 a++;
1031 k->whole_word_chars_left = g_strdup (whole_left);
1032 k->whole_word_chars_right = g_strdup (whole_right);
1034 else if (!strcmp (*a, "wholeleft"))
1036 a++;
1037 k->whole_word_chars_left = g_strdup (whole_left);
1039 else if (!strcmp (*a, "wholeright"))
1041 a++;
1042 k->whole_word_chars_right = g_strdup (whole_right);
1044 check_a;
1045 if (!strcmp (*a, "linestart"))
1047 a++;
1048 k->line_start = 1;
1050 check_a;
1051 if (!strcmp (*a, "whole"))
1053 break_a;
1055 k->keyword = g_strdup (*a++);
1056 k->first = *k->keyword;
1057 subst_defines (edit->defines, a, &args[1024]);
1058 fg = *a;
1059 if (*a)
1060 a++;
1061 bg = *a;
1062 if (*a)
1063 a++;
1064 if (!fg)
1065 fg = last_fg;
1066 if (!bg)
1067 bg = last_bg;
1068 k->color = this_try_alloc_color_pair (fg, bg);
1069 check_not_a;
1071 if (++num_words >= alloc_words_per_context)
1073 struct key_word **tmp;
1075 alloc_words_per_context += 1024;
1077 if (alloc_words_per_context > max_alloc_words_per_context)
1078 max_alloc_words_per_context = alloc_words_per_context;
1080 tmp = g_realloc (c->keyword, alloc_words_per_context * sizeof (struct key_word *));
1081 c->keyword = tmp;
1084 else if (*(args[0]) == '#')
1086 /* do nothing for comment */
1088 else if (!strcmp (args[0], "file"))
1090 break;
1092 else if (!strcmp (args[0], "define"))
1094 char *key = *a++;
1095 char **argv;
1097 if (argc < 3)
1098 break_a;
1099 if ((argv = g_tree_lookup (edit->defines, key)))
1101 mc_defines_destroy (NULL, argv, NULL);
1103 else
1105 key = g_strdup (key);
1107 argv = g_new (char *, argc - 1);
1108 g_tree_insert (edit->defines, key, argv);
1109 while (*a)
1111 *argv++ = g_strdup (*a++);
1113 *argv = NULL;
1115 else
1116 { /* anything else is an error */
1117 break_a;
1119 free_args (args);
1120 MC_PTR_FREE (l);
1122 free_args (args);
1123 MC_PTR_FREE (l);
1125 /* Terminate context array. */
1126 if (num_contexts > 0)
1128 r[num_contexts - 1]->keyword[num_words] = NULL;
1129 r[num_contexts] = NULL;
1132 if (!edit->rules[0])
1133 MC_PTR_FREE (edit->rules);
1135 if (result)
1136 return result;
1138 if (num_contexts == -1)
1140 return line;
1144 char *first_chars, *p;
1146 first_chars = g_malloc0 (max_alloc_words_per_context + 2);
1148 for (i = 0; edit->rules[i]; i++)
1150 c = edit->rules[i];
1151 p = first_chars;
1152 *p++ = (char) 1;
1153 for (j = 1; c->keyword[j]; j++)
1154 *p++ = c->keyword[j]->first;
1155 *p = '\0';
1156 c->keyword_first_chars = g_strdup (first_chars);
1159 g_free (first_chars);
1162 return result;
1165 void
1166 edit_free_syntax_rules (WEdit * edit)
1168 size_t i, j;
1170 if (!edit)
1171 return;
1172 if (edit->defines)
1173 destroy_defines (&edit->defines);
1174 if (!edit->rules)
1175 return;
1177 edit_get_rule (edit, -1);
1178 MC_PTR_FREE (edit->syntax_type);
1180 for (i = 0; edit->rules[i]; i++)
1182 if (edit->rules[i]->keyword)
1184 for (j = 0; edit->rules[i]->keyword[j]; j++)
1186 MC_PTR_FREE (edit->rules[i]->keyword[j]->keyword);
1187 MC_PTR_FREE (edit->rules[i]->keyword[j]->whole_word_chars_left);
1188 MC_PTR_FREE (edit->rules[i]->keyword[j]->whole_word_chars_right);
1189 MC_PTR_FREE (edit->rules[i]->keyword[j]);
1192 MC_PTR_FREE (edit->rules[i]->left);
1193 MC_PTR_FREE (edit->rules[i]->right);
1194 MC_PTR_FREE (edit->rules[i]->whole_word_chars_left);
1195 MC_PTR_FREE (edit->rules[i]->whole_word_chars_right);
1196 MC_PTR_FREE (edit->rules[i]->keyword);
1197 MC_PTR_FREE (edit->rules[i]->keyword_first_chars);
1198 MC_PTR_FREE (edit->rules[i]);
1201 while (edit->syntax_marker)
1203 struct _syntax_marker *s = edit->syntax_marker->next;
1204 g_free (edit->syntax_marker);
1205 edit->syntax_marker = s;
1208 MC_PTR_FREE (edit->rules);
1209 tty_color_free_all_tmp ();
1212 /* returns -1 on file error, line number on error in file syntax */
1213 static int
1214 edit_read_syntax_file (WEdit * edit, char ***pnames, const char *syntax_file,
1215 const char *editor_file, const char *first_line, const char *type)
1217 #define NENTRIES 30
1218 FILE *f, *g = NULL;
1219 char *args[1024], *l = NULL;
1220 int line = 0;
1221 int result = 0;
1222 int count = 0;
1223 char *lib_file;
1224 int found = 0;
1225 char **tmpnames = NULL;
1227 f = fopen (syntax_file, "r");
1228 if (!f)
1230 lib_file = concat_dir_and_file (mc_home, "Syntax");
1231 f = fopen (lib_file, "r");
1232 g_free (lib_file);
1233 if (!f)
1234 return -1;
1237 args[0] = 0;
1238 for (;;)
1240 line++;
1241 MC_PTR_FREE (l);
1242 if (read_one_line (&l, f) == 0)
1243 break;
1244 (void) get_args (l, args, 1023); /* Final NULL */
1245 if (!args[0])
1246 continue;
1248 /* Looking for `include ...` lines before first `file ...` ones */
1249 if (!found && !strcmp (args[0], "include"))
1251 if (g)
1252 continue;
1253 if (!args[1] || !(g = open_include_file (args[1])))
1255 result = line;
1256 break;
1258 goto found_type;
1261 /* looking for `file ...' lines only */
1262 if (strcmp (args[0], "file"))
1264 continue;
1266 found = 1;
1268 /* must have two args or report error */
1269 if (!args[1] || !args[2])
1271 result = line;
1272 break;
1274 if (pnames && *pnames)
1277 /* 1: just collecting a list of names of rule sets */
1278 /* Reallocate the list if required */
1279 if (count % NENTRIES == 0)
1281 tmpnames =
1282 (char **) g_try_realloc (*pnames, (count + NENTRIES + 1) * sizeof (char *));
1283 if (tmpnames == NULL)
1284 break;
1285 *pnames = tmpnames;
1287 (*pnames)[count++] = g_strdup (args[2]);
1288 (*pnames)[count] = NULL;
1290 else if (type)
1293 /* 2: rule set was explicitly specified by the caller */
1294 if (!strcmp (type, args[2]))
1295 goto found_type;
1297 else if (editor_file && edit)
1300 /* 3: auto-detect rule set from regular expressions */
1301 int q;
1302 q = mc_search (args[1], editor_file, MC_SEARCH_T_REGEX);
1303 /* does filename match arg 1 ? */
1304 if (!q && args[3])
1306 /* does first line match arg 3 ? */
1307 q = mc_search (args[3], first_line, MC_SEARCH_T_REGEX);
1309 if (q)
1311 int line_error;
1312 char *syntax_type;
1313 found_type:
1314 syntax_type = args[2];
1315 line_error = edit_read_syntax_rules (edit, g ? g : f, args, 1023);
1316 if (line_error)
1318 if (!error_file_name) /* an included file */
1319 result = line + line_error;
1320 else
1321 result = line_error;
1323 else
1325 MC_PTR_FREE (edit->syntax_type);
1326 edit->syntax_type = g_strdup (syntax_type);
1327 /* if there are no rules then turn off syntax highlighting for speed */
1328 if (!g && !edit->rules[1])
1329 if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling)
1331 edit_free_syntax_rules (edit);
1332 break;
1335 if (g)
1337 fclose (g);
1338 g = NULL;
1340 else
1342 break;
1347 MC_PTR_FREE (l);
1348 fclose (f);
1349 return result;
1352 static char *
1353 get_first_editor_line (WEdit * edit)
1355 size_t i;
1356 static char s[256];
1358 s[0] = '\0';
1359 if (edit == NULL)
1360 return s;
1362 for (i = 0; i < sizeof (s) - 1; i++)
1364 s[i] = edit_get_byte (edit, i);
1365 if (s[i] == '\n')
1367 s[i] = '\0';
1368 break;
1371 s[sizeof (s) - 1] = '\0';
1372 return s;
1376 * Load rules into edit struct. Either edit or *pnames must be NULL. If
1377 * edit is NULL, a list of types will be stored into names. If type is
1378 * NULL, then the type will be selected according to the filename.
1380 void
1381 edit_load_syntax (WEdit * edit, char ***pnames, const char *type)
1383 int r;
1384 char *f = NULL;
1386 if (option_auto_syntax)
1387 type = NULL;
1389 edit_free_syntax_rules (edit);
1391 if (!tty_use_colors ())
1392 return;
1394 if (!option_syntax_highlighting && (!pnames || !*pnames))
1395 return;
1397 if (edit)
1399 if (!edit->filename)
1400 return;
1401 if (!*edit->filename && !type)
1402 return;
1404 f = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
1405 r = edit_read_syntax_file (edit, pnames, f, edit ? edit->filename : 0,
1406 get_first_editor_line (edit), type);
1407 if (r == -1)
1409 edit_free_syntax_rules (edit);
1410 message (D_ERROR, _(" Load syntax file "),
1411 _(" Cannot open file %s \n %s "), f, unix_error_string (errno));
1413 else if (r)
1415 edit_free_syntax_rules (edit);
1416 message (D_ERROR, _(" Load syntax file "),
1417 _(" Error in file %s on line %d "), error_file_name ? error_file_name : f, r);
1418 MC_PTR_FREE (error_file_name);
1420 else
1422 /* succeeded */
1424 g_free (f);
1427 const char *
1428 edit_get_syntax_type (const WEdit * edit)
1430 return edit->syntax_type;