1 /* editor syntax highlighting.
3 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007, 2010 Free Software Foundation, Inc.
8 Egmont Koblinger <egmont@gmail.com>, 2010
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 * \brief Source: editor syntax highlighting
30 * \author Mikhail Pobolovets
33 * Mispelled words are flushed from the syntax highlighting rules
34 * when they have been around longer than
35 * TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
36 * chars per second and say 3 chars + a space per word, we can
37 * accumulate 450 words absolute max with a value of 60. This is
38 * below this limit of 1024 words in a context.
45 #include <sys/types.h>
53 #include "lib/global.h"
54 #include "lib/search.h" /* search engine */
56 #include "lib/strutil.h" /* utf string functions */
58 #include "lib/widget.h" /* message() */
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 ****************************************************************/
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) == ' ')
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 ****************************************************************/
101 char *whole_word_chars_left
;
102 char *whole_word_chars_right
;
110 unsigned char first_left
;
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
;
120 /* first word is word[1] */
121 struct key_word
**keyword
;
124 struct _syntax_marker
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 /* --------------------------------------------------------------------------------------------- */
139 mc_defines_destroy (gpointer key
, gpointer value
, gpointer data
)
141 char **values
= value
;
153 /* --------------------------------------------------------------------------------------------- */
154 /** Completely destroys the defines tree */
157 destroy_defines (GTree
** defines
)
159 g_tree_foreach (*defines
, mc_defines_destroy
, NULL
);
160 g_tree_destroy (*defines
);
164 /* --------------------------------------------------------------------------------------------- */
166 /** Wrapper for case insensitive mode */
168 xx_tolower (WEdit
* edit
, int c
)
170 return edit
->is_case_insensitive
? tolower (c
) : c
;
173 /* --------------------------------------------------------------------------------------------- */
176 subst_defines (GTree
* defines
, char **argv
, char **argv_end
)
181 while (*argv
!= NULL
&& argv
< argv_end
)
183 t
= g_tree_lookup (defines
, *argv
);
188 /* Count argv array members */
190 for (p
= &argv
[1]; *p
!= NULL
; p
++)
193 /* Count members of definition array */
194 for (p
= t
; *p
!= NULL
; p
++)
196 p
= &argv
[count
+ argc
];
198 /* Buffer overflow or infinitive loop in define */
202 /* Move rest of argv after definition members */
204 *p
-- = argv
[argc
-- + 1];
206 /* Copy definition members to argv */
207 for (p
= argv
; *t
!= NULL
; *p
++ = *t
++)
214 /* --------------------------------------------------------------------------------------------- */
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
;
226 c
= xx_tolower (edit
, edit_get_byte (edit
, i
- 1));
227 if (line_start
!= 0 && c
!= '\n')
229 if (whole_left
!= NULL
&& strchr (whole_left
, c
) != NULL
)
232 for (p
= (unsigned char *) text
, q
= p
+ str_term_width1 ((char *) p
); p
< q
; p
++, i
++)
236 case SYNTAX_TOKEN_STAR
:
241 c
= xx_tolower (edit
, edit_get_byte (edit
, i
));
242 if (*p
== '\0' && whole_right
!= NULL
&& strchr (whole_right
, c
) == NULL
)
251 case SYNTAX_TOKEN_PLUS
:
257 c
= xx_tolower (edit
, edit_get_byte (edit
, i
));
261 if (*p
== *text
&& p
[1] == '\0') /* handle eg '+' and @+@ keywords properly */
264 if (j
&& strchr ((char *) p
+ 1, c
)) /* c exists further down, so it will get matched later */
266 if (c
== '\n' || c
== '\t' || c
== ' ')
278 if (whole_right
!= NULL
&& (strchr (whole_right
, c
) == NULL
))
293 case SYNTAX_TOKEN_BRACKET
:
300 c
= xx_tolower (edit
, edit_get_byte (edit
, i
));
301 for (j
= 0; p
[j
] != SYNTAX_TOKEN_BRACKET
&& p
[j
]; j
++)
306 ; /* dummy command */
309 while (*p
!= SYNTAX_TOKEN_BRACKET
&& p
<= q
)
316 case SYNTAX_TOKEN_BRACE
:
319 c
= xx_tolower (edit
, edit_get_byte (edit
, i
));
320 for (; *p
!= SYNTAX_TOKEN_BRACE
&& *p
; p
++)
325 while (*p
!= SYNTAX_TOKEN_BRACE
&& p
< q
)
329 if (*p
!= xx_tolower (edit
, edit_get_byte (edit
, i
)))
333 if (whole_right
!= NULL
334 && strchr (whole_right
, xx_tolower (edit
, edit_get_byte (edit
, i
))) != NULL
)
339 /* --------------------------------------------------------------------------------------------- */
342 xx_strchr (WEdit
* edit
, const unsigned char *s
, int char_byte
)
344 while (*s
>= '\005' && xx_tolower (edit
, *s
) != char_byte
)
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
;
357 gboolean contextchanged
= FALSE
;
358 gboolean found_left
= FALSE
, found_right
= FALSE
;
359 gboolean keyword_foundleft
= FALSE
, keyword_foundright
= FALSE
;
362 struct syntax_rule _rule
= rule
;
364 c
= xx_tolower (edit
, edit_get_byte (edit
, i
));
367 is_end
= (rule
.end
== (unsigned char) i
);
369 /* check to turn off a keyword */
372 if (edit_get_byte (edit
, i
- 1) == '\n')
377 keyword_foundleft
= TRUE
;
381 /* check to turn off a context */
382 if (_rule
.context
&& !_rule
.keyword
)
386 r
= edit
->rules
[_rule
.context
];
387 if (r
->first_right
== c
&& !(rule
.border
& RULE_ON_RIGHT_BORDER
)
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)
394 _rule
.border
= RULE_ON_RIGHT_BORDER
;
395 if (r
->between_delimiters
)
398 else if (is_end
&& rule
.border
& RULE_ON_RIGHT_BORDER
)
400 /* always turn off a context at 4 */
403 if (!keyword_foundleft
)
406 else if (is_end
&& rule
.border
& RULE_ON_LEFT_BORDER
)
408 /* never turn off a context at 2 */
414 /* check to turn on a keyword */
419 r
= edit
->rules
[_rule
.context
];
420 p
= r
->keyword_first_chars
;
423 while (*(p
= xx_strchr (edit
, (unsigned char *) p
+ 1, c
)) != '\0')
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
);
437 _rule
.keyword
= count
;
438 keyword_foundright
= TRUE
;
444 /* check to turn on a context */
447 if (!found_left
&& is_end
)
449 if (rule
.border
& RULE_ON_RIGHT_BORDER
)
453 contextchanged
= TRUE
;
457 else if (rule
.border
& RULE_ON_LEFT_BORDER
)
459 r
= edit
->rules
[_rule
._context
];
461 if (r
->between_delimiters
)
463 _rule
.context
= _rule
._context
;
464 contextchanged
= TRUE
;
467 if (r
->first_right
== c
)
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
);
477 _rule
.border
= RULE_ON_RIGHT_BORDER
;
488 struct context_rule
**rules
= edit
->rules
;
490 for (count
= 1; rules
[count
]; count
++)
493 if (r
->first_left
== c
)
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
))
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
;
517 /* check again to turn on a keyword if the context switched */
518 if (contextchanged
&& !_rule
.keyword
)
522 r
= edit
->rules
[_rule
.context
];
523 p
= r
->keyword_first_chars
;
525 while (*(p
= xx_strchr (edit
, (unsigned char *) p
+ 1, c
)) != '\0')
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
);
538 _rule
.keyword
= count
;
547 /* --------------------------------------------------------------------------------------------- */
549 static struct syntax_rule
550 edit_get_rule (WEdit
* edit
, long byte_index
)
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
);
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
;
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
);
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
);
593 s
= edit
->syntax_marker
->next
;
594 g_free (edit
->syntax_marker
);
595 edit
->syntax_marker
= s
;
598 edit
->last_get_rule
= byte_index
;
602 /* --------------------------------------------------------------------------------------------- */
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.
619 read_one_line (char **line
, FILE * f
)
624 /* not reallocate string too often */
625 p
= g_string_sized_new (64);
644 /* handle all of \r\n, \r, \n correctly. */
657 g_string_append_c (p
, c
);
660 *line
= g_string_free (p
, FALSE
);
662 g_string_free (p
, TRUE
);
667 /* --------------------------------------------------------------------------------------------- */
707 *p
= SYNTAX_TOKEN_BRACKET
;
711 *p
= SYNTAX_TOKEN_BRACE
;
722 *p
= SYNTAX_TOKEN_STAR
;
725 *p
= SYNTAX_TOKEN_PLUS
;
738 /* --------------------------------------------------------------------------------------------- */
741 get_args (char *l
, char **args
, int args_size
)
745 while (argc
< args_size
)
748 while (*p
!= '\0' && whiteness (*p
))
752 for (l
= p
+ 1; *l
!= '\0' && !whiteness (*l
); l
++)
756 args
[argc
++] = convert (p
);
758 args
[argc
] = (char *) NULL
;
762 /* --------------------------------------------------------------------------------------------- */
765 this_try_alloc_color_pair (const char *fg
, const char *bg
, const char *attrs
)
767 char f
[80], b
[80], a
[80], *p
;
769 if (bg
!= NULL
&& *bg
== '\0')
771 if (fg
!= NULL
&& *fg
== '\0')
773 if (attrs
!= NULL
&& *attrs
== '\0')
776 if ((fg
== NULL
) && (bg
== NULL
))
777 return EDITOR_NORMAL_COLOR
;
781 g_strlcpy (f
, fg
, sizeof (f
));
789 g_strlcpy (b
, bg
, sizeof (b
));
795 if ((fg
== NULL
) || (bg
== NULL
))
797 /* get colors from skin */
800 editnormal
= mc_skin_get ("editor", "_default_", "default;default");
804 g_strlcpy (f
, editnormal
, sizeof (f
));
809 g_strlcpy (f
, "default", sizeof (f
));
814 p
= strchr (editnormal
, ';');
815 if ((p
!= NULL
) && (*(++p
) != '\0'))
816 g_strlcpy (b
, p
, sizeof (b
));
818 g_strlcpy (b
, "default", sizeof (b
));
827 g_strlcpy (a
, attrs
, sizeof (a
));
831 /* get_args() mangles the + signs, unmangle 'em */
833 while ((p
= strchr (p
, SYNTAX_TOKEN_PLUS
)) != NULL
)
837 return tty_try_alloc_color_pair (fg
, bg
, attrs
);
840 /* --------------------------------------------------------------------------------------------- */
843 open_include_file (const char *filename
)
847 MC_PTR_FREE (error_file_name
);
848 error_file_name
= g_strdup (filename
);
849 if (g_path_is_absolute (filename
))
850 return fopen (filename
, "r");
852 g_free (error_file_name
);
854 g_build_filename (mc_config_get_data_path (), EDIT_DIR
, filename
, (char *) NULL
);
855 f
= fopen (error_file_name
, "r");
859 g_free (error_file_name
);
860 error_file_name
= g_build_filename (mc_global
.sysconfig_dir
, "syntax", filename
, (char *) NULL
);
861 f
= fopen (error_file_name
, "r");
865 g_free (error_file_name
);
866 error_file_name
= g_build_filename (mc_global
.share_data_dir
, "syntax", filename
, (char *) NULL
);
868 return fopen (error_file_name
, "r");
871 /* --------------------------------------------------------------------------------------------- */
874 xx_lowerize_line (WEdit
* edit
, char *line
, size_t len
)
876 if (edit
->is_case_insensitive
)
879 for (i
= 0; i
< len
; ++i
)
880 line
[i
] = tolower (line
[i
]);
884 /* --------------------------------------------------------------------------------------------- */
885 /** returns line number on error */
888 edit_read_syntax_rules (WEdit
* edit
, FILE * f
, char **args
, int args_size
)
891 char *fg
, *bg
, *attrs
;
892 char last_fg
[32] = "", last_bg
[32] = "", last_attrs
[64] = "";
893 char whole_right
[512];
894 char whole_left
[512];
896 int save_line
= 0, line
= 0;
897 struct context_rule
**r
, *c
= NULL
;
898 int num_words
= -1, num_contexts
= -1;
902 int alloc_contexts
= MAX_CONTEXTS
,
903 alloc_words_per_context
= MAX_WORDS_PER_CONTEXT
,
904 max_alloc_words_per_context
= MAX_WORDS_PER_CONTEXT
;
907 edit
->is_case_insensitive
= FALSE
;
909 strcpy (whole_left
, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
910 strcpy (whole_right
, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
912 r
= edit
->rules
= g_malloc0 (alloc_contexts
* sizeof (struct context_rule
*));
915 edit
->defines
= g_tree_new ((GCompareFunc
) strcmp
);
925 len
= read_one_line (&l
, f
);
933 line
= save_line
+ 1;
934 MC_PTR_FREE (error_file_name
);
936 len
= read_one_line (&l
, f
);
940 xx_lowerize_line (edit
, l
, len
);
949 xx_lowerize_line (edit
, l
, len
);
951 argc
= get_args (l
, args
, args_size
);
957 else if (!strcmp (args
[0], "include"))
965 f
= open_include_file (args
[1]);
968 MC_PTR_FREE (error_file_name
);
975 else if (!strcmp (args
[0], "caseinsensitive"))
977 edit
->is_case_insensitive
= TRUE
;
979 else if (!strcmp (args
[0], "wholechars"))
982 if (!strcmp (*a
, "left"))
985 g_strlcpy (whole_left
, *a
, sizeof (whole_left
));
987 else if (!strcmp (*a
, "right"))
990 g_strlcpy (whole_right
, *a
, sizeof (whole_right
));
994 g_strlcpy (whole_left
, *a
, sizeof (whole_left
));
995 g_strlcpy (whole_right
, *a
, sizeof (whole_right
));
1000 else if (!strcmp (args
[0], "context"))
1003 if (num_contexts
== -1)
1005 if (strcmp (*a
, "default"))
1006 { /* first context is the default */
1010 c
= r
[0] = g_malloc0 (sizeof (struct context_rule
));
1011 c
->left
= g_strdup (" ");
1012 c
->right
= g_strdup (" ");
1017 /* Terminate previous context. */
1018 r
[num_contexts
- 1]->keyword
[num_words
] = NULL
;
1019 c
= r
[num_contexts
] = g_malloc0 (sizeof (struct context_rule
));
1020 if (!strcmp (*a
, "exclusive"))
1023 c
->between_delimiters
= 1;
1026 if (!strcmp (*a
, "whole"))
1029 c
->whole_word_chars_left
= g_strdup (whole_left
);
1030 c
->whole_word_chars_right
= g_strdup (whole_right
);
1032 else if (!strcmp (*a
, "wholeleft"))
1035 c
->whole_word_chars_left
= g_strdup (whole_left
);
1037 else if (!strcmp (*a
, "wholeright"))
1040 c
->whole_word_chars_right
= g_strdup (whole_right
);
1043 if (!strcmp (*a
, "linestart"))
1046 c
->line_start_left
= 1;
1049 c
->left
= g_strdup (*a
++);
1051 if (!strcmp (*a
, "linestart"))
1054 c
->line_start_right
= 1;
1057 c
->right
= g_strdup (*a
++);
1058 c
->first_left
= *c
->left
;
1059 c
->first_right
= *c
->right
;
1061 c
->keyword
= g_malloc (alloc_words_per_context
* sizeof (struct key_word
*));
1063 c
->keyword
[0] = g_malloc0 (sizeof (struct key_word
));
1064 subst_defines (edit
->defines
, a
, &args
[1024]);
1074 g_strlcpy (last_fg
, fg
? fg
: "", sizeof (last_fg
));
1075 g_strlcpy (last_bg
, bg
? bg
: "", sizeof (last_bg
));
1076 g_strlcpy (last_attrs
, attrs
? attrs
: "", sizeof (last_attrs
));
1077 c
->keyword
[0]->color
= this_try_alloc_color_pair (fg
, bg
, attrs
);
1078 c
->keyword
[0]->keyword
= g_strdup (" ");
1081 alloc_words_per_context
= MAX_WORDS_PER_CONTEXT
;
1082 if (++num_contexts
>= alloc_contexts
)
1084 struct context_rule
**tmp
;
1086 alloc_contexts
+= 128;
1087 tmp
= g_realloc (r
, alloc_contexts
* sizeof (struct context_rule
*));
1091 else if (!strcmp (args
[0], "spellcheck"))
1100 else if (!strcmp (args
[0], "keyword"))
1104 if (num_words
== -1)
1107 k
= r
[num_contexts
- 1]->keyword
[num_words
] = g_malloc0 (sizeof (struct key_word
));
1108 if (!strcmp (*a
, "whole"))
1111 k
->whole_word_chars_left
= g_strdup (whole_left
);
1112 k
->whole_word_chars_right
= g_strdup (whole_right
);
1114 else if (!strcmp (*a
, "wholeleft"))
1117 k
->whole_word_chars_left
= g_strdup (whole_left
);
1119 else if (!strcmp (*a
, "wholeright"))
1122 k
->whole_word_chars_right
= g_strdup (whole_right
);
1125 if (!strcmp (*a
, "linestart"))
1131 if (!strcmp (*a
, "whole"))
1135 k
->keyword
= g_strdup (*a
++);
1136 k
->first
= *k
->keyword
;
1137 subst_defines (edit
->defines
, a
, &args
[1024]);
1153 k
->color
= this_try_alloc_color_pair (fg
, bg
, attrs
);
1156 if (++num_words
>= alloc_words_per_context
)
1158 struct key_word
**tmp
;
1160 alloc_words_per_context
+= 1024;
1162 if (alloc_words_per_context
> max_alloc_words_per_context
)
1163 max_alloc_words_per_context
= alloc_words_per_context
;
1165 tmp
= g_realloc (c
->keyword
, alloc_words_per_context
* sizeof (struct key_word
*));
1169 else if (*(args
[0]) == '#')
1171 /* do nothing for comment */
1173 else if (!strcmp (args
[0], "file"))
1177 else if (!strcmp (args
[0], "define"))
1184 argv
= g_tree_lookup (edit
->defines
, key
);
1186 mc_defines_destroy (NULL
, argv
, NULL
);
1188 key
= g_strdup (key
);
1190 argv
= g_new (char *, argc
- 1);
1191 g_tree_insert (edit
->defines
, key
, argv
);
1194 *argv
++ = g_strdup (*a
++);
1199 { /* anything else is an error */
1208 /* Terminate context array. */
1209 if (num_contexts
> 0)
1211 r
[num_contexts
- 1]->keyword
[num_words
] = NULL
;
1212 r
[num_contexts
] = NULL
;
1215 if (!edit
->rules
[0])
1216 MC_PTR_FREE (edit
->rules
);
1221 if (num_contexts
== -1)
1227 char *first_chars
, *p
;
1229 first_chars
= g_malloc0 (max_alloc_words_per_context
+ 2);
1231 for (i
= 0; edit
->rules
[i
]; i
++)
1236 for (j
= 1; c
->keyword
[j
]; j
++)
1237 *p
++ = c
->keyword
[j
]->first
;
1239 c
->keyword_first_chars
= g_strdup (first_chars
);
1242 g_free (first_chars
);
1248 /* --------------------------------------------------------------------------------------------- */
1250 /* returns -1 on file error, line number on error in file syntax */
1252 edit_read_syntax_file (WEdit
* edit
, char ***pnames
, const char *syntax_file
,
1253 const char *editor_file
, const char *first_line
, const char *type
)
1257 char *args
[1024], *l
= NULL
;
1262 gboolean found
= FALSE
;
1263 char **tmpnames
= NULL
;
1265 f
= fopen (syntax_file
, "r");
1268 lib_file
= g_build_filename (mc_global
.share_data_dir
, "syntax", "Syntax", (char *) NULL
);
1269 f
= fopen (lib_file
, "r");
1280 if (read_one_line (&l
, f
) == 0)
1282 (void) get_args (l
, args
, 1023); /* Final NULL */
1283 if (args
[0] == NULL
)
1286 /* Looking for `include ...` lines before first `file ...` ones */
1287 if (!found
&& strcmp (args
[0], "include") == 0)
1292 if (!args
[1] || !(g
= open_include_file (args
[1])))
1300 /* looking for `file ...' lines only */
1301 if (strcmp (args
[0], "file") != 0)
1306 /* must have two args or report error */
1307 if (!args
[1] || !args
[2])
1312 if (pnames
&& *pnames
)
1314 /* 1: just collecting a list of names of rule sets */
1315 /* Reallocate the list if required */
1316 if (count
% NENTRIES
== 0)
1319 (char **) g_try_realloc (*pnames
, (count
+ NENTRIES
+ 1) * sizeof (char *));
1320 if (tmpnames
== NULL
)
1324 (*pnames
)[count
++] = g_strdup (args
[2]);
1325 (*pnames
)[count
] = NULL
;
1329 /* 2: rule set was explicitly specified by the caller */
1330 if (strcmp (type
, args
[2]) == 0)
1333 else if (editor_file
&& edit
)
1335 /* 3: auto-detect rule set from regular expressions */
1338 q
= mc_search (args
[1], editor_file
, MC_SEARCH_T_REGEX
);
1339 /* does filename match arg 1 ? */
1342 /* does first line match arg 3 ? */
1343 q
= mc_search (args
[3], first_line
, MC_SEARCH_T_REGEX
);
1350 syntax_type
= args
[2];
1351 line_error
= edit_read_syntax_rules (edit
, g
? g
: f
, args
, 1023);
1354 if (!error_file_name
) /* an included file */
1355 result
= line
+ line_error
;
1357 result
= line_error
;
1361 g_free (edit
->syntax_type
);
1362 edit
->syntax_type
= g_strdup (syntax_type
);
1363 /* if there are no rules then turn off syntax highlighting for speed */
1364 if (!g
&& !edit
->rules
[1])
1365 if (!edit
->rules
[0]->keyword
[1] && !edit
->rules
[0]->spelling
)
1367 edit_free_syntax_rules (edit
);
1385 /* --------------------------------------------------------------------------------------------- */
1388 get_first_editor_line (WEdit
* edit
)
1397 for (i
= 0; i
< sizeof (s
) - 1; i
++)
1399 s
[i
] = edit_get_byte (edit
, i
);
1406 s
[sizeof (s
) - 1] = '\0';
1410 /* --------------------------------------------------------------------------------------------- */
1411 /*** public functions ****************************************************************************/
1412 /* --------------------------------------------------------------------------------------------- */
1415 edit_get_syntax_color (WEdit
* edit
, long byte_index
, int *color
)
1417 if (!tty_use_colors ())
1419 else if (edit
->rules
&& byte_index
< edit
->last_byte
&& option_syntax_highlighting
)
1420 translate_rule_to_color (edit
, edit_get_rule (edit
, byte_index
), color
);
1422 *color
= EDITOR_NORMAL_COLOR
;
1425 /* --------------------------------------------------------------------------------------------- */
1428 edit_free_syntax_rules (WEdit
* edit
)
1435 destroy_defines (&edit
->defines
);
1439 edit_get_rule (edit
, -1);
1440 MC_PTR_FREE (edit
->syntax_type
);
1442 for (i
= 0; edit
->rules
[i
]; i
++)
1444 if (edit
->rules
[i
]->keyword
)
1446 for (j
= 0; edit
->rules
[i
]->keyword
[j
]; j
++)
1448 MC_PTR_FREE (edit
->rules
[i
]->keyword
[j
]->keyword
);
1449 MC_PTR_FREE (edit
->rules
[i
]->keyword
[j
]->whole_word_chars_left
);
1450 MC_PTR_FREE (edit
->rules
[i
]->keyword
[j
]->whole_word_chars_right
);
1451 MC_PTR_FREE (edit
->rules
[i
]->keyword
[j
]);
1454 MC_PTR_FREE (edit
->rules
[i
]->left
);
1455 MC_PTR_FREE (edit
->rules
[i
]->right
);
1456 MC_PTR_FREE (edit
->rules
[i
]->whole_word_chars_left
);
1457 MC_PTR_FREE (edit
->rules
[i
]->whole_word_chars_right
);
1458 MC_PTR_FREE (edit
->rules
[i
]->keyword
);
1459 MC_PTR_FREE (edit
->rules
[i
]->keyword_first_chars
);
1460 MC_PTR_FREE (edit
->rules
[i
]);
1463 while (edit
->syntax_marker
)
1465 struct _syntax_marker
*s
= edit
->syntax_marker
->next
;
1466 g_free (edit
->syntax_marker
);
1467 edit
->syntax_marker
= s
;
1470 MC_PTR_FREE (edit
->rules
);
1471 tty_color_free_all_tmp ();
1474 /* --------------------------------------------------------------------------------------------- */
1476 * Load rules into edit struct. Either edit or *pnames must be NULL. If
1477 * edit is NULL, a list of types will be stored into names. If type is
1478 * NULL, then the type will be selected according to the filename.
1479 * type must be edit->syntax_type or NULL
1482 edit_load_syntax (WEdit
* edit
, char ***pnames
, const char *type
)
1487 if (option_auto_syntax
)
1494 saved_type
= g_strdup (type
); /* save edit->syntax_type */
1495 edit_free_syntax_rules (edit
);
1496 edit
->syntax_type
= saved_type
; /* restore edit->syntax_type */
1499 if (!tty_use_colors ())
1502 if (!option_syntax_highlighting
&& (!pnames
|| !*pnames
))
1507 if (!edit
->filename
)
1509 if (!*edit
->filename
&& !type
)
1512 f
= g_build_filename (mc_config_get_data_path (), EDIT_SYNTAX_FILE
, (char *) NULL
);
1514 r
= edit_read_syntax_file (edit
, pnames
, f
, edit
->filename
,
1515 get_first_editor_line (edit
),
1516 option_auto_syntax
? NULL
: edit
->syntax_type
);
1518 r
= edit_read_syntax_file (NULL
, pnames
, f
, NULL
, "", NULL
);
1521 edit_free_syntax_rules (edit
);
1522 message (D_ERROR
, _("Load syntax file"),
1523 _("Cannot open file %s\n%s"), f
, unix_error_string (errno
));
1527 edit_free_syntax_rules (edit
);
1528 message (D_ERROR
, _("Load syntax file"),
1529 _("Error in file %s on line %d"), error_file_name
? error_file_name
: f
, r
);
1530 MC_PTR_FREE (error_file_name
);
1536 /* --------------------------------------------------------------------------------------------- */
1539 edit_get_syntax_type (const WEdit
* edit
)
1541 return edit
->syntax_type
;
1544 /* --------------------------------------------------------------------------------------------- */