Ticket #2434: fixed source file name of file operation.
[midnight-commander.git] / src / editor / syntax.c
blobb7678547292e69d3b499e9f58e277de3d7effb68
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 */
55 #include "lib/util.h"
56 #include "lib/widget.h" /* message() */
58 #include "src/main.h" /* mc_home */
60 #include "edit-impl.h"
61 #include "edit-widget.h"
63 /*** global variables ****************************************************************************/
65 int option_syntax_highlighting = 1;
66 int option_auto_syntax = 1;
68 /*** file scope macro definitions ****************************************************************/
70 /* bytes */
71 #define SYNTAX_MARKER_DENSITY 512
73 #define TRANSIENT_WORD_TIME_OUT 60
75 #define UNKNOWN_FORMAT "unknown"
77 #define MAX_WORDS_PER_CONTEXT 1024
78 #define MAX_CONTEXTS 128
80 #define RULE_ON_LEFT_BORDER 1
81 #define RULE_ON_RIGHT_BORDER 2
83 #define SYNTAX_TOKEN_STAR '\001'
84 #define SYNTAX_TOKEN_PLUS '\002'
85 #define SYNTAX_TOKEN_BRACKET '\003'
86 #define SYNTAX_TOKEN_BRACE '\004'
88 #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
90 #define free_args(x)
91 #define break_a {result=line;break;}
92 #define check_a {if(!*a){result=line;break;}}
93 #define check_not_a {if(*a){result=line;break;}}
95 /*** file scope type declarations ****************************************************************/
97 struct key_word
99 char *keyword;
100 unsigned char first;
101 char *whole_word_chars_left;
102 char *whole_word_chars_right;
103 int line_start;
104 int color;
107 struct context_rule
109 char *left;
110 unsigned char first_left;
111 char *right;
112 unsigned char first_right;
113 char line_start_left;
114 char line_start_right;
115 int between_delimiters;
116 char *whole_word_chars_left;
117 char *whole_word_chars_right;
118 char *keyword_first_chars;
119 int spelling;
120 /* first word is word[1] */
121 struct key_word **keyword;
124 struct _syntax_marker
126 long offset;
127 struct syntax_rule rule;
128 struct _syntax_marker *next;
131 /*** file scope variables ************************************************************************/
133 static char *error_file_name = NULL;
135 /*** file scope functions ************************************************************************/
136 /* --------------------------------------------------------------------------------------------- */
138 static gint
139 mc_defines_destroy (gpointer key, gpointer value, gpointer data)
141 char **values = value;
143 (void) data;
145 g_free (key);
146 while (*values)
147 g_free (*values++);
148 g_free (value);
150 return FALSE;
153 /* --------------------------------------------------------------------------------------------- */
154 /** Completely destroys the defines tree */
156 static void
157 destroy_defines (GTree ** defines)
159 g_tree_foreach (*defines, mc_defines_destroy, NULL);
160 g_tree_destroy (*defines);
161 *defines = NULL;
164 /* --------------------------------------------------------------------------------------------- */
166 /** Wrapper for case insensitive mode */
167 inline static int
168 xx_tolower (WEdit * edit, int c)
170 return edit->is_case_insensitive ? tolower (c) : c;
173 /* --------------------------------------------------------------------------------------------- */
175 static void
176 subst_defines (GTree * defines, char **argv, char **argv_end)
178 char **t, **p;
179 int argc;
181 while (*argv != NULL && argv < argv_end)
183 t = g_tree_lookup (defines, *argv);
184 if (t != NULL)
186 int count = 0;
188 /* Count argv array members */
189 argc = 0;
190 for (p = &argv[1]; *p != NULL; p++)
191 argc++;
193 /* Count members of definition array */
194 for (p = t; *p != NULL; p++)
195 count++;
196 p = &argv[count + argc];
198 /* Buffer overflow or infinitive loop in define */
199 if (p >= argv_end)
200 break;
202 /* Move rest of argv after definition members */
203 while (argc >= 0)
204 *p-- = argv[argc-- + 1];
206 /* Copy definition members to argv */
207 for (p = argv; *t != NULL; *p++ = *t++)
210 argv++;
214 /* --------------------------------------------------------------------------------------------- */
216 static long
217 compare_word_to_right (WEdit * edit, long i, const char *text,
218 const char *whole_left, const char *whole_right, int line_start)
220 const unsigned char *p, *q;
221 int c, d, j;
223 if (*text == '\0')
224 return -1;
226 c = xx_tolower (edit, edit_get_byte (edit, i - 1));
227 if (line_start != 0 && c != '\n')
228 return -1;
229 if (whole_left != NULL && strchr (whole_left, c) != NULL)
230 return -1;
232 for (p = (unsigned char *) text, q = p + str_term_width1 ((char *) p); p < q; p++, i++)
234 switch (*p)
236 case SYNTAX_TOKEN_STAR:
237 if (++p > q)
238 return -1;
239 for (;;)
241 c = xx_tolower (edit, edit_get_byte (edit, i));
242 if (*p == '\0' && whole_right != NULL && strchr (whole_right, c) == NULL)
243 break;
244 if (c == *p)
245 break;
246 if (c == '\n')
247 return -1;
248 i++;
250 break;
251 case SYNTAX_TOKEN_PLUS:
252 if (++p > q)
253 return -1;
254 j = 0;
255 for (;;)
257 c = xx_tolower (edit, edit_get_byte (edit, i));
258 if (c == *p)
260 j = i;
261 if (*p == *text && p[1] == '\0') /* handle eg '+' and @+@ keywords properly */
262 break;
264 if (j && strchr ((char *) p + 1, c)) /* c exists further down, so it will get matched later */
265 break;
266 if (c == '\n' || c == '\t' || c == ' ')
268 if (!*p)
270 i--;
271 break;
273 if (j == 0)
274 return -1;
275 i = j;
276 break;
278 if (whole_right != NULL && (strchr (whole_right, c) == NULL))
280 if (*p == '\0')
282 i--;
283 break;
285 if (j == 0)
286 return -1;
287 i = j;
288 break;
290 i++;
292 break;
293 case SYNTAX_TOKEN_BRACKET:
294 if (++p > q)
295 return -1;
296 c = -1;
297 for (;; i++)
299 d = c;
300 c = xx_tolower (edit, edit_get_byte (edit, i));
301 for (j = 0; p[j] != SYNTAX_TOKEN_BRACKET && p[j]; j++)
302 if (c == p[j])
303 goto found_char2;
304 break;
305 found_char2:
306 ; /* dummy command */
308 i--;
309 while (*p != SYNTAX_TOKEN_BRACKET && p <= q)
310 p++;
311 if (p > q)
312 return -1;
313 if (p[1] == d)
314 i--;
315 break;
316 case SYNTAX_TOKEN_BRACE:
317 if (++p > q)
318 return -1;
319 c = xx_tolower (edit, edit_get_byte (edit, i));
320 for (; *p != SYNTAX_TOKEN_BRACE && *p; p++)
321 if (c == *p)
322 goto found_char3;
323 return -1;
324 found_char3:
325 while (*p != SYNTAX_TOKEN_BRACE && p < q)
326 p++;
327 break;
328 default:
329 if (*p != xx_tolower (edit, edit_get_byte (edit, i)))
330 return -1;
333 if (whole_right != NULL
334 && strchr (whole_right, xx_tolower (edit, edit_get_byte (edit, i))) != NULL)
335 return -1;
336 return i;
339 /* --------------------------------------------------------------------------------------------- */
341 static const char *
342 xx_strchr (WEdit * edit, const unsigned char *s, int char_byte)
344 while (*s >= '\005' && xx_tolower (edit, *s) != char_byte)
345 s++;
347 return (const char *) s;
350 /* --------------------------------------------------------------------------------------------- */
352 static struct syntax_rule
353 apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule)
355 struct context_rule *r;
356 int c;
357 gboolean contextchanged = FALSE;
358 gboolean found_left = FALSE, found_right = FALSE;
359 gboolean keyword_foundleft = FALSE, keyword_foundright = FALSE;
360 gboolean is_end;
361 long end = 0;
362 struct syntax_rule _rule = rule;
364 c = xx_tolower (edit, edit_get_byte (edit, i));
365 if (c == 0)
366 return rule;
367 is_end = (rule.end == (unsigned char) i);
369 /* check to turn off a keyword */
370 if (_rule.keyword)
372 if (edit_get_byte (edit, i - 1) == '\n')
373 _rule.keyword = 0;
374 if (is_end)
376 _rule.keyword = 0;
377 keyword_foundleft = TRUE;
381 /* check to turn off a context */
382 if (_rule.context && !_rule.keyword)
384 long e;
386 r = edit->rules[_rule.context];
387 if (r->first_right == c && !(rule.border & RULE_ON_RIGHT_BORDER)
388 && (e =
389 compare_word_to_right (edit, i, r->right, r->whole_word_chars_left,
390 r->whole_word_chars_right, r->line_start_right)) > 0)
392 _rule.end = e;
393 found_right = TRUE;
394 _rule.border = RULE_ON_RIGHT_BORDER;
395 if (r->between_delimiters)
396 _rule.context = 0;
398 else if (is_end && rule.border & RULE_ON_RIGHT_BORDER)
400 /* always turn off a context at 4 */
401 found_left = TRUE;
402 _rule.border = 0;
403 if (!keyword_foundleft)
404 _rule.context = 0;
406 else if (is_end && rule.border & RULE_ON_LEFT_BORDER)
408 /* never turn off a context at 2 */
409 found_left = TRUE;
410 _rule.border = 0;
414 /* check to turn on a keyword */
415 if (!_rule.keyword)
417 const char *p;
419 r = edit->rules[_rule.context];
420 p = r->keyword_first_chars;
422 if (p != NULL)
423 while (*(p = xx_strchr (edit, (unsigned char *) p + 1, c)) != '\0')
425 struct key_word *k;
426 int count;
427 long e;
429 count = p - r->keyword_first_chars;
430 k = r->keyword[count];
431 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left,
432 k->whole_word_chars_right, k->line_start);
433 if (e > 0)
435 end = e;
436 _rule.end = e;
437 _rule.keyword = count;
438 keyword_foundright = TRUE;
439 break;
444 /* check to turn on a context */
445 if (!_rule.context)
447 if (!found_left && is_end)
449 if (rule.border & RULE_ON_RIGHT_BORDER)
451 _rule.border = 0;
452 _rule.context = 0;
453 contextchanged = TRUE;
454 _rule.keyword = 0;
457 else if (rule.border & RULE_ON_LEFT_BORDER)
459 r = edit->rules[_rule._context];
460 _rule.border = 0;
461 if (r->between_delimiters)
463 _rule.context = _rule._context;
464 contextchanged = TRUE;
465 _rule.keyword = 0;
467 if (r->first_right == c)
469 long e;
471 e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left,
472 r->whole_word_chars_right, r->line_start_right);
473 if (e >= end)
475 _rule.end = e;
476 found_right = TRUE;
477 _rule.border = RULE_ON_RIGHT_BORDER;
478 _rule.context = 0;
485 if (!found_right)
487 int count;
488 struct context_rule **rules = edit->rules;
490 for (count = 1; rules[count]; count++)
492 r = rules[count];
493 if (r->first_left == c)
495 long e;
497 e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left,
498 r->whole_word_chars_right, r->line_start_left);
499 if (e >= end && (!_rule.keyword || keyword_foundright))
501 _rule.end = e;
502 found_right = TRUE;
503 _rule.border = RULE_ON_LEFT_BORDER;
504 _rule._context = count;
505 if (!r->between_delimiters && !_rule.keyword)
507 _rule.context = count;
508 contextchanged = TRUE;
510 break;
517 /* check again to turn on a keyword if the context switched */
518 if (contextchanged && !_rule.keyword)
520 const char *p;
522 r = edit->rules[_rule.context];
523 p = r->keyword_first_chars;
525 while (*(p = xx_strchr (edit, (unsigned char *) p + 1, c)) != '\0')
527 struct key_word *k;
528 int count;
529 long e;
531 count = p - r->keyword_first_chars;
532 k = r->keyword[count];
533 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left,
534 k->whole_word_chars_right, k->line_start);
535 if (e > 0)
537 _rule.end = e;
538 _rule.keyword = count;
539 break;
544 return _rule;
547 /* --------------------------------------------------------------------------------------------- */
549 static struct syntax_rule
550 edit_get_rule (WEdit * edit, long byte_index)
552 long i;
554 if (byte_index > edit->last_get_rule)
556 for (i = edit->last_get_rule + 1; i <= byte_index; i++)
558 edit->rule = apply_rules_going_right (edit, i, edit->rule);
559 if (i >
560 (edit->syntax_marker ? edit->syntax_marker->offset +
561 SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY))
563 struct _syntax_marker *s;
565 s = edit->syntax_marker;
566 edit->syntax_marker = g_malloc (sizeof (struct _syntax_marker));
567 edit->syntax_marker->next = s;
568 edit->syntax_marker->offset = i;
569 edit->syntax_marker->rule = edit->rule;
573 else if (byte_index < edit->last_get_rule)
575 struct _syntax_marker *s;
577 for (;;)
579 if (!edit->syntax_marker)
581 memset (&edit->rule, 0, sizeof (edit->rule));
582 for (i = -1; i <= byte_index; i++)
583 edit->rule = apply_rules_going_right (edit, i, edit->rule);
584 break;
586 if (byte_index >= edit->syntax_marker->offset)
588 edit->rule = edit->syntax_marker->rule;
589 for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++)
590 edit->rule = apply_rules_going_right (edit, i, edit->rule);
591 break;
593 s = edit->syntax_marker->next;
594 g_free (edit->syntax_marker);
595 edit->syntax_marker = s;
598 edit->last_get_rule = byte_index;
599 return edit->rule;
602 /* --------------------------------------------------------------------------------------------- */
604 static inline void
605 translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *color)
607 *color = edit->rules[rule.context]->keyword[rule.keyword]->color;
611 /* --------------------------------------------------------------------------------------------- */
613 Returns 0 on error/eof or a count of the number of bytes read
614 including the newline. Result must be free'd.
615 In case of an error, *line will not be modified.
618 static size_t
619 read_one_line (char **line, FILE * f)
621 GString *p;
622 size_t r = 0;
624 /* not reallocate string too often */
625 p = g_string_sized_new (64);
627 for (;;)
629 int c;
631 c = fgetc (f);
632 if (c == EOF)
634 if (ferror (f))
636 if (errno == EINTR)
637 continue;
638 r = 0;
640 break;
642 r++;
644 /* handle all of \r\n, \r, \n correctly. */
645 if (c == '\n')
646 break;
647 if (c == '\r')
649 c = fgetc (f);
650 if (c == '\n')
651 r++;
652 else
653 ungetc (c, f);
654 break;
657 g_string_append_c (p, c);
659 if (r != 0)
660 *line = g_string_free (p, FALSE);
661 else
662 g_string_free (p, TRUE);
664 return r;
667 /* --------------------------------------------------------------------------------------------- */
669 static char *
670 convert (char *s)
672 char *r, *p;
674 p = r = s;
675 while (*s)
677 switch (*s)
679 case '\\':
680 s++;
681 switch (*s)
683 case ' ':
684 *p = ' ';
685 s--;
686 break;
687 case 'n':
688 *p = '\n';
689 break;
690 case 'r':
691 *p = '\r';
692 break;
693 case 't':
694 *p = '\t';
695 break;
696 case 's':
697 *p = ' ';
698 break;
699 case '*':
700 *p = '*';
701 break;
702 case '\\':
703 *p = '\\';
704 break;
705 case '[':
706 case ']':
707 *p = SYNTAX_TOKEN_BRACKET;
708 break;
709 case '{':
710 case '}':
711 *p = SYNTAX_TOKEN_BRACE;
712 break;
713 case 0:
714 *p = *s;
715 return r;
716 default:
717 *p = *s;
718 break;
720 break;
721 case '*':
722 *p = SYNTAX_TOKEN_STAR;
723 break;
724 case '+':
725 *p = SYNTAX_TOKEN_PLUS;
726 break;
727 default:
728 *p = *s;
729 break;
731 s++;
732 p++;
734 *p = '\0';
735 return r;
738 /* --------------------------------------------------------------------------------------------- */
740 static int
741 get_args (char *l, char **args, int args_size)
743 int argc = 0;
745 while (argc < args_size)
747 char *p = l;
748 while (*p != '\0' && whiteness (*p))
749 p++;
750 if (*p == '\0')
751 break;
752 for (l = p + 1; *l != '\0' && !whiteness (*l); l++)
754 if (*l != '\0')
755 *l++ = '\0';
756 args[argc++] = convert (p);
758 args[argc] = (char *) NULL;
759 return argc;
762 /* --------------------------------------------------------------------------------------------- */
764 static int
765 this_try_alloc_color_pair (const char *fg, const char *bg)
767 char f[80], b[80], *p;
769 if (bg != NULL && *bg == '\0')
770 bg = NULL;
771 if (fg != NULL && *fg == '\0')
772 fg = NULL;
774 if ((fg == NULL) && (bg == NULL))
775 return EDITOR_NORMAL_COLOR;
777 if (fg != NULL)
779 g_strlcpy (f, fg, sizeof (f));
780 p = strchr (f, '/');
781 if (p != NULL)
782 *p = '\0';
783 fg = f;
785 if (bg != NULL)
787 g_strlcpy (b, bg, sizeof (b));
788 p = strchr (b, '/');
789 if (p != NULL)
790 *p = '\0';
791 bg = b;
793 if ((fg == NULL) || (bg == NULL))
795 /* get colors from skin */
796 char *editnormal;
798 editnormal = mc_skin_get ("editor", "_default_", "default;default");
800 if (fg == NULL)
802 g_strlcpy (f, editnormal, sizeof (f));
803 p = strchr (f, ';');
804 if (p != NULL)
805 *p = '\0';
806 if (f[0] == '\0')
807 g_strlcpy (f, "default", sizeof (f));
808 fg = f;
810 if (bg == NULL)
812 p = strchr (editnormal, ';');
813 if ((p != NULL) && (*(++p) != '\0'))
814 g_strlcpy (b, p, sizeof (b));
815 else
816 g_strlcpy (b, "default", sizeof (b));
817 bg = b;
820 g_free (editnormal);
823 return tty_try_alloc_color_pair (fg, bg);
826 /* --------------------------------------------------------------------------------------------- */
828 static FILE *
829 open_include_file (const char *filename)
831 FILE *f;
833 MC_PTR_FREE (error_file_name);
834 error_file_name = g_strdup (filename);
835 if (g_path_is_absolute (filename))
836 return fopen (filename, "r");
838 g_free (error_file_name);
839 error_file_name = g_build_filename (home_dir, EDIT_DIR, filename, (char *) NULL);
840 f = fopen (error_file_name, "r");
841 if (f != NULL)
842 return f;
844 g_free (error_file_name);
845 error_file_name = g_build_filename (mc_home, "syntax", filename, (char *) NULL);
846 f = fopen (error_file_name, "r");
847 if (f != NULL)
848 return f;
850 g_free (error_file_name);
851 error_file_name = g_build_filename (mc_home_alt, "syntax", filename, (char *) NULL);
853 return fopen (error_file_name, "r");
856 /* --------------------------------------------------------------------------------------------- */
858 inline static void
859 xx_lowerize_line (WEdit * edit, char *line, size_t len)
861 if (edit->is_case_insensitive)
863 size_t i;
864 for (i = 0; i < len; ++i)
865 line[i] = tolower (line[i]);
869 /* --------------------------------------------------------------------------------------------- */
870 /** returns line number on error */
872 static int
873 edit_read_syntax_rules (WEdit * edit, FILE * f, char **args, int args_size)
875 FILE *g = NULL;
876 char *fg, *bg;
877 char last_fg[32] = "", last_bg[32] = "";
878 char whole_right[512];
879 char whole_left[512];
880 char *l = 0;
881 int save_line = 0, line = 0;
882 struct context_rule **r, *c = NULL;
883 int num_words = -1, num_contexts = -1;
884 int result = 0;
885 int argc;
886 int i, j;
887 int alloc_contexts = MAX_CONTEXTS,
888 alloc_words_per_context = MAX_WORDS_PER_CONTEXT,
889 max_alloc_words_per_context = MAX_WORDS_PER_CONTEXT;
891 args[0] = NULL;
892 edit->is_case_insensitive = FALSE;
894 strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
895 strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
897 r = edit->rules = g_malloc0 (alloc_contexts * sizeof (struct context_rule *));
899 if (!edit->defines)
900 edit->defines = g_tree_new ((GCompareFunc) strcmp);
902 for (;;)
904 char **a;
905 size_t len;
907 line++;
908 l = 0;
910 len = read_one_line (&l, f);
911 if (len == 0)
913 if (g)
915 fclose (f);
916 f = g;
917 g = 0;
918 line = save_line + 1;
919 MC_PTR_FREE (error_file_name);
920 MC_PTR_FREE (l);
921 len = read_one_line (&l, f);
922 if (len == 0)
923 break;
924 else
925 xx_lowerize_line (edit, l, len);
927 else
929 break;
932 else
934 xx_lowerize_line (edit, l, len);
936 argc = get_args (l, args, args_size);
937 a = args + 1;
938 if (!args[0])
940 /* do nothing */
942 else if (!strcmp (args[0], "include"))
944 if (g || argc != 2)
946 result = line;
947 break;
949 g = f;
950 f = open_include_file (args[1]);
951 if (!f)
953 MC_PTR_FREE (error_file_name);
954 result = line;
955 break;
957 save_line = line;
958 line = 0;
960 else if (!strcmp (args[0], "caseinsensitive"))
962 edit->is_case_insensitive = TRUE;
964 else if (!strcmp (args[0], "wholechars"))
966 check_a;
967 if (!strcmp (*a, "left"))
969 a++;
970 g_strlcpy (whole_left, *a, sizeof (whole_left));
972 else if (!strcmp (*a, "right"))
974 a++;
975 g_strlcpy (whole_right, *a, sizeof (whole_right));
977 else
979 g_strlcpy (whole_left, *a, sizeof (whole_left));
980 g_strlcpy (whole_right, *a, sizeof (whole_right));
982 a++;
983 check_not_a;
985 else if (!strcmp (args[0], "context"))
987 check_a;
988 if (num_contexts == -1)
990 if (strcmp (*a, "default"))
991 { /* first context is the default */
992 break_a;
994 a++;
995 c = r[0] = g_malloc0 (sizeof (struct context_rule));
996 c->left = g_strdup (" ");
997 c->right = g_strdup (" ");
998 num_contexts = 0;
1000 else
1002 /* Terminate previous context. */
1003 r[num_contexts - 1]->keyword[num_words] = NULL;
1004 c = r[num_contexts] = g_malloc0 (sizeof (struct context_rule));
1005 if (!strcmp (*a, "exclusive"))
1007 a++;
1008 c->between_delimiters = 1;
1010 check_a;
1011 if (!strcmp (*a, "whole"))
1013 a++;
1014 c->whole_word_chars_left = g_strdup (whole_left);
1015 c->whole_word_chars_right = g_strdup (whole_right);
1017 else if (!strcmp (*a, "wholeleft"))
1019 a++;
1020 c->whole_word_chars_left = g_strdup (whole_left);
1022 else if (!strcmp (*a, "wholeright"))
1024 a++;
1025 c->whole_word_chars_right = g_strdup (whole_right);
1027 check_a;
1028 if (!strcmp (*a, "linestart"))
1030 a++;
1031 c->line_start_left = 1;
1033 check_a;
1034 c->left = g_strdup (*a++);
1035 check_a;
1036 if (!strcmp (*a, "linestart"))
1038 a++;
1039 c->line_start_right = 1;
1041 check_a;
1042 c->right = g_strdup (*a++);
1043 c->first_left = *c->left;
1044 c->first_right = *c->right;
1046 c->keyword = g_malloc (alloc_words_per_context * sizeof (struct key_word *));
1047 num_words = 1;
1048 c->keyword[0] = g_malloc0 (sizeof (struct key_word));
1049 subst_defines (edit->defines, a, &args[1024]);
1050 fg = *a;
1051 if (*a)
1052 a++;
1053 bg = *a;
1054 if (*a)
1055 a++;
1056 g_strlcpy (last_fg, fg ? fg : "", sizeof (last_fg));
1057 g_strlcpy (last_bg, bg ? bg : "", sizeof (last_bg));
1058 c->keyword[0]->color = this_try_alloc_color_pair (fg, bg);
1059 c->keyword[0]->keyword = g_strdup (" ");
1060 check_not_a;
1062 alloc_words_per_context = MAX_WORDS_PER_CONTEXT;
1063 if (++num_contexts >= alloc_contexts)
1065 struct context_rule **tmp;
1067 alloc_contexts += 128;
1068 tmp = g_realloc (r, alloc_contexts * sizeof (struct context_rule *));
1069 r = tmp;
1072 else if (!strcmp (args[0], "spellcheck"))
1074 if (!c)
1076 result = line;
1077 break;
1079 c->spelling = 1;
1081 else if (!strcmp (args[0], "keyword"))
1083 struct key_word *k;
1085 if (num_words == -1)
1086 break_a;
1087 check_a;
1088 k = r[num_contexts - 1]->keyword[num_words] = g_malloc0 (sizeof (struct key_word));
1089 if (!strcmp (*a, "whole"))
1091 a++;
1092 k->whole_word_chars_left = g_strdup (whole_left);
1093 k->whole_word_chars_right = g_strdup (whole_right);
1095 else if (!strcmp (*a, "wholeleft"))
1097 a++;
1098 k->whole_word_chars_left = g_strdup (whole_left);
1100 else if (!strcmp (*a, "wholeright"))
1102 a++;
1103 k->whole_word_chars_right = g_strdup (whole_right);
1105 check_a;
1106 if (!strcmp (*a, "linestart"))
1108 a++;
1109 k->line_start = 1;
1111 check_a;
1112 if (!strcmp (*a, "whole"))
1114 break_a;
1116 k->keyword = g_strdup (*a++);
1117 k->first = *k->keyword;
1118 subst_defines (edit->defines, a, &args[1024]);
1119 fg = *a;
1120 if (*a)
1121 a++;
1122 bg = *a;
1123 if (*a)
1124 a++;
1125 if (!fg)
1126 fg = last_fg;
1127 if (!bg)
1128 bg = last_bg;
1129 k->color = this_try_alloc_color_pair (fg, bg);
1130 check_not_a;
1132 if (++num_words >= alloc_words_per_context)
1134 struct key_word **tmp;
1136 alloc_words_per_context += 1024;
1138 if (alloc_words_per_context > max_alloc_words_per_context)
1139 max_alloc_words_per_context = alloc_words_per_context;
1141 tmp = g_realloc (c->keyword, alloc_words_per_context * sizeof (struct key_word *));
1142 c->keyword = tmp;
1145 else if (*(args[0]) == '#')
1147 /* do nothing for comment */
1149 else if (!strcmp (args[0], "file"))
1151 break;
1153 else if (!strcmp (args[0], "define"))
1155 char *key = *a++;
1156 char **argv;
1158 if (argc < 3)
1159 break_a;
1160 argv = g_tree_lookup (edit->defines, key);
1161 if (argv != NULL)
1162 mc_defines_destroy (NULL, argv, NULL);
1163 else
1164 key = g_strdup (key);
1166 argv = g_new (char *, argc - 1);
1167 g_tree_insert (edit->defines, key, argv);
1168 while (*a != NULL)
1170 *argv++ = g_strdup (*a++);
1172 *argv = NULL;
1174 else
1175 { /* anything else is an error */
1176 break_a;
1178 free_args (args);
1179 MC_PTR_FREE (l);
1181 free_args (args);
1182 MC_PTR_FREE (l);
1184 /* Terminate context array. */
1185 if (num_contexts > 0)
1187 r[num_contexts - 1]->keyword[num_words] = NULL;
1188 r[num_contexts] = NULL;
1191 if (!edit->rules[0])
1192 MC_PTR_FREE (edit->rules);
1194 if (result)
1195 return result;
1197 if (num_contexts == -1)
1199 return line;
1203 char *first_chars, *p;
1205 first_chars = g_malloc0 (max_alloc_words_per_context + 2);
1207 for (i = 0; edit->rules[i]; i++)
1209 c = edit->rules[i];
1210 p = first_chars;
1211 *p++ = (char) 1;
1212 for (j = 1; c->keyword[j]; j++)
1213 *p++ = c->keyword[j]->first;
1214 *p = '\0';
1215 c->keyword_first_chars = g_strdup (first_chars);
1218 g_free (first_chars);
1221 return result;
1224 /* --------------------------------------------------------------------------------------------- */
1226 /* returns -1 on file error, line number on error in file syntax */
1227 static int
1228 edit_read_syntax_file (WEdit * edit, char ***pnames, const char *syntax_file,
1229 const char *editor_file, const char *first_line, const char *type)
1231 #define NENTRIES 30
1232 FILE *f, *g = NULL;
1233 char *args[1024], *l = NULL;
1234 int line = 0;
1235 int result = 0;
1236 int count = 0;
1237 char *lib_file;
1238 gboolean found = FALSE;
1239 char **tmpnames = NULL;
1241 f = fopen (syntax_file, "r");
1242 if (f == NULL)
1244 lib_file = g_build_filename (mc_home_alt, "syntax", "Syntax", (char *) NULL);
1245 f = fopen (lib_file, "r");
1246 g_free (lib_file);
1247 if (f == NULL)
1248 return -1;
1251 args[0] = NULL;
1252 for (;;)
1254 line++;
1255 MC_PTR_FREE (l);
1256 if (read_one_line (&l, f) == 0)
1257 break;
1258 (void) get_args (l, args, 1023); /* Final NULL */
1259 if (args[0] == NULL)
1260 continue;
1262 /* Looking for `include ...` lines before first `file ...` ones */
1263 if (!found && strcmp (args[0], "include") == 0)
1265 if (g != NULL)
1266 continue;
1268 if (!args[1] || !(g = open_include_file (args[1])))
1270 result = line;
1271 break;
1273 goto found_type;
1276 /* looking for `file ...' lines only */
1277 if (strcmp (args[0], "file") != 0)
1278 continue;
1280 found = TRUE;
1282 /* must have two args or report error */
1283 if (!args[1] || !args[2])
1285 result = line;
1286 break;
1288 if (pnames && *pnames)
1290 /* 1: just collecting a list of names of rule sets */
1291 /* Reallocate the list if required */
1292 if (count % NENTRIES == 0)
1294 tmpnames =
1295 (char **) g_try_realloc (*pnames, (count + NENTRIES + 1) * sizeof (char *));
1296 if (tmpnames == NULL)
1297 break;
1298 *pnames = tmpnames;
1300 (*pnames)[count++] = g_strdup (args[2]);
1301 (*pnames)[count] = NULL;
1303 else if (type)
1305 /* 2: rule set was explicitly specified by the caller */
1306 if (strcmp (type, args[2]) == 0)
1307 goto found_type;
1309 else if (editor_file && edit)
1311 /* 3: auto-detect rule set from regular expressions */
1312 int q;
1314 q = mc_search (args[1], editor_file, MC_SEARCH_T_REGEX);
1315 /* does filename match arg 1 ? */
1316 if (!q && args[3])
1318 /* does first line match arg 3 ? */
1319 q = mc_search (args[3], first_line, MC_SEARCH_T_REGEX);
1321 if (q)
1323 int line_error;
1324 char *syntax_type;
1325 found_type:
1326 syntax_type = args[2];
1327 line_error = edit_read_syntax_rules (edit, g ? g : f, args, 1023);
1328 if (line_error)
1330 if (!error_file_name) /* an included file */
1331 result = line + line_error;
1332 else
1333 result = line_error;
1335 else
1337 g_free (edit->syntax_type);
1338 edit->syntax_type = g_strdup (syntax_type);
1339 /* if there are no rules then turn off syntax highlighting for speed */
1340 if (!g && !edit->rules[1])
1341 if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling)
1343 edit_free_syntax_rules (edit);
1344 break;
1348 if (g == NULL)
1349 break;
1351 fclose (g);
1352 g = NULL;
1356 g_free (l);
1357 fclose (f);
1358 return result;
1361 /* --------------------------------------------------------------------------------------------- */
1363 static char *
1364 get_first_editor_line (WEdit * edit)
1366 size_t i;
1367 static char s[256];
1369 s[0] = '\0';
1370 if (edit == NULL)
1371 return s;
1373 for (i = 0; i < sizeof (s) - 1; i++)
1375 s[i] = edit_get_byte (edit, i);
1376 if (s[i] == '\n')
1378 s[i] = '\0';
1379 break;
1382 s[sizeof (s) - 1] = '\0';
1383 return s;
1386 /* --------------------------------------------------------------------------------------------- */
1387 /*** public functions ****************************************************************************/
1388 /* --------------------------------------------------------------------------------------------- */
1390 void
1391 edit_get_syntax_color (WEdit * edit, long byte_index, int *color)
1393 if (!tty_use_colors ())
1394 *color = 0;
1395 else if (edit->rules && byte_index < edit->last_byte && option_syntax_highlighting)
1396 translate_rule_to_color (edit, edit_get_rule (edit, byte_index), color);
1397 else
1398 *color = EDITOR_NORMAL_COLOR;
1401 /* --------------------------------------------------------------------------------------------- */
1403 void
1404 edit_free_syntax_rules (WEdit * edit)
1406 size_t i, j;
1408 if (!edit)
1409 return;
1410 if (edit->defines)
1411 destroy_defines (&edit->defines);
1412 if (!edit->rules)
1413 return;
1415 edit_get_rule (edit, -1);
1416 MC_PTR_FREE (edit->syntax_type);
1418 for (i = 0; edit->rules[i]; i++)
1420 if (edit->rules[i]->keyword)
1422 for (j = 0; edit->rules[i]->keyword[j]; j++)
1424 MC_PTR_FREE (edit->rules[i]->keyword[j]->keyword);
1425 MC_PTR_FREE (edit->rules[i]->keyword[j]->whole_word_chars_left);
1426 MC_PTR_FREE (edit->rules[i]->keyword[j]->whole_word_chars_right);
1427 MC_PTR_FREE (edit->rules[i]->keyword[j]);
1430 MC_PTR_FREE (edit->rules[i]->left);
1431 MC_PTR_FREE (edit->rules[i]->right);
1432 MC_PTR_FREE (edit->rules[i]->whole_word_chars_left);
1433 MC_PTR_FREE (edit->rules[i]->whole_word_chars_right);
1434 MC_PTR_FREE (edit->rules[i]->keyword);
1435 MC_PTR_FREE (edit->rules[i]->keyword_first_chars);
1436 MC_PTR_FREE (edit->rules[i]);
1439 while (edit->syntax_marker)
1441 struct _syntax_marker *s = edit->syntax_marker->next;
1442 g_free (edit->syntax_marker);
1443 edit->syntax_marker = s;
1446 MC_PTR_FREE (edit->rules);
1447 tty_color_free_all_tmp ();
1450 /* --------------------------------------------------------------------------------------------- */
1452 * Load rules into edit struct. Either edit or *pnames must be NULL. If
1453 * edit is NULL, a list of types will be stored into names. If type is
1454 * NULL, then the type will be selected according to the filename.
1455 * type must be edit->syntax_type or NULL
1457 void
1458 edit_load_syntax (WEdit * edit, char ***pnames, const char *type)
1460 int r;
1461 char *f = NULL;
1463 if (option_auto_syntax)
1464 type = NULL;
1466 if (edit != NULL)
1468 char *saved_type;
1470 saved_type = g_strdup (type); /* save edit->syntax_type */
1471 edit_free_syntax_rules (edit);
1472 edit->syntax_type = saved_type; /* restore edit->syntax_type */
1475 if (!tty_use_colors ())
1476 return;
1478 if (!option_syntax_highlighting && (!pnames || !*pnames))
1479 return;
1481 if (edit != NULL)
1483 if (!edit->filename)
1484 return;
1485 if (!*edit->filename && !type)
1486 return;
1488 f = g_build_filename (home_dir, EDIT_SYNTAX_FILE, (char *) NULL);
1489 if (edit != NULL)
1490 r = edit_read_syntax_file (edit, pnames, f, edit->filename,
1491 get_first_editor_line (edit),
1492 option_auto_syntax ? NULL : edit->syntax_type);
1493 else
1494 r = edit_read_syntax_file (NULL, pnames, f, NULL, "", NULL);
1495 if (r == -1)
1497 edit_free_syntax_rules (edit);
1498 message (D_ERROR, _("Load syntax file"),
1499 _("Cannot open file %s\n%s"), f, unix_error_string (errno));
1501 else if (r != 0)
1503 edit_free_syntax_rules (edit);
1504 message (D_ERROR, _("Load syntax file"),
1505 _("Error in file %s on line %d"), error_file_name ? error_file_name : f, r);
1506 MC_PTR_FREE (error_file_name);
1509 g_free (f);
1512 /* --------------------------------------------------------------------------------------------- */
1514 const char *
1515 edit_get_syntax_type (const WEdit * edit)
1517 return edit->syntax_type;
1520 /* --------------------------------------------------------------------------------------------- */