This source file includes following definitions.
- syntax_keyword_free
- context_rule_free
- mc_defines_destroy
- destroy_defines
- xx_tolower
- subst_defines
- compare_word_to_right
- xx_strchr
- apply_rules_going_right
- edit_get_rule
- translate_rule_to_color
- read_one_line
- convert
- get_args
- this_try_alloc_color_pair
- open_include_file
- xx_lowerize_line
- edit_read_syntax_rules
- edit_read_syntax_file
- get_first_editor_line
- pstrcmp
- exec_edit_syntax_dialog
- edit_get_syntax_color
- edit_free_syntax_rules
- edit_load_syntax
- edit_get_syntax_type
- edit_syntax_dialog
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 #include <config.h>
46
47 #include <stdio.h>
48 #include <stdarg.h>
49 #include <sys/types.h>
50 #include <unistd.h>
51 #include <string.h>
52 #include <ctype.h>
53 #include <errno.h>
54 #include <sys/stat.h>
55 #include <stdlib.h>
56
57 #include "lib/global.h"
58 #include "lib/search.h"
59 #include "lib/skin.h"
60 #include "lib/fileloc.h"
61 #include "lib/strutil.h"
62 #include "lib/util.h"
63 #include "lib/widget.h"
64
65 #include "src/util.h"
66
67 #include "edit-impl.h"
68 #include "editwidget.h"
69
70
71
72 gboolean auto_syntax = TRUE;
73
74
75
76
77 #define SYNTAX_MARKER_DENSITY 512
78
79 #define RULE_ON_LEFT_BORDER 1
80 #define RULE_ON_RIGHT_BORDER 2
81
82 #define SYNTAX_TOKEN_STAR '\001'
83 #define SYNTAX_TOKEN_PLUS '\002'
84 #define SYNTAX_TOKEN_BRACKET '\003'
85 #define SYNTAX_TOKEN_BRACE '\004'
86
87 #define break_a \
88 { \
89 result = line; \
90 break; \
91 }
92 #define check_a \
93 { \
94 if (*a == NULL) \
95 { \
96 result = line; \
97 break; \
98 } \
99 }
100 #define check_not_a \
101 { \
102 if (*a != NULL) \
103 { \
104 result = line; \
105 break; \
106 } \
107 }
108
109 #define SYNTAX_KEYWORD(x) ((syntax_keyword_t *) (x))
110 #define CONTEXT_RULE(x) ((context_rule_t *) (x))
111
112 #define ARGS_LEN 1024
113
114 #define MAX_ENTRY_LEN 40
115 #define LIST_LINES 14
116 #define N_DFLT_ENTRIES 2
117
118
119
120 typedef struct
121 {
122 GString *keyword;
123 char *whole_word_chars_left;
124 char *whole_word_chars_right;
125 gboolean line_start;
126 int color;
127 } syntax_keyword_t;
128
129 typedef struct
130 {
131 GString *left;
132 unsigned char first_left;
133 GString *right;
134 unsigned char first_right;
135 gboolean line_start_left;
136 gboolean line_start_right;
137 gboolean between_delimiters;
138 char *whole_word_chars_left;
139 char *whole_word_chars_right;
140 char *keyword_first_chars;
141 gboolean spelling;
142
143 GPtrArray *keyword;
144 } context_rule_t;
145
146 typedef struct
147 {
148 off_t offset;
149 edit_syntax_rule_t rule;
150 } syntax_marker_t;
151
152
153
154
155
156 static char *error_file_name = NULL;
157
158
159
160
161
162 static void
163 syntax_keyword_free (gpointer keyword)
164 {
165 syntax_keyword_t *k = SYNTAX_KEYWORD (keyword);
166
167 g_string_free (k->keyword, TRUE);
168 g_free (k->whole_word_chars_left);
169 g_free (k->whole_word_chars_right);
170 g_free (k);
171 }
172
173
174
175 static void
176 context_rule_free (gpointer rule)
177 {
178 context_rule_t *r = CONTEXT_RULE (rule);
179
180 g_string_free (r->left, TRUE);
181 g_string_free (r->right, TRUE);
182 g_free (r->whole_word_chars_left);
183 g_free (r->whole_word_chars_right);
184 g_free (r->keyword_first_chars);
185
186 if (r->keyword != NULL)
187 g_ptr_array_free (r->keyword, TRUE);
188
189 g_free (r);
190 }
191
192
193
194 static gint
195 mc_defines_destroy (gpointer key, gpointer value, gpointer data)
196 {
197 (void) data;
198
199 g_free (key);
200 g_strfreev ((char **) value);
201
202 return FALSE;
203 }
204
205
206
207
208 static void
209 destroy_defines (GTree **defines)
210 {
211 g_tree_foreach (*defines, mc_defines_destroy, NULL);
212 g_tree_destroy (*defines);
213 *defines = NULL;
214 }
215
216
217
218
219 inline static int
220 xx_tolower (const WEdit *edit, int c)
221 {
222 return edit->is_case_insensitive ? tolower (c) : c;
223 }
224
225
226
227 static void
228 subst_defines (GTree *defines, char **argv, char **argv_end)
229 {
230 for (; *argv != NULL && argv < argv_end; argv++)
231 {
232 char **t;
233
234 t = g_tree_lookup (defines, *argv);
235 if (t != NULL)
236 {
237 int argc, count;
238 char **p;
239
240
241 argc = g_strv_length (argv + 1);
242
243
244 count = g_strv_length (t);
245
246 p = argv + count + argc;
247
248 if (p >= argv_end)
249 break;
250
251
252 while (argc >= 0)
253 *p-- = argv[argc-- + 1];
254
255
256 for (p = argv; *t != NULL; *p++ = *t++)
257 ;
258 }
259 }
260 }
261
262
263
264 static off_t
265 compare_word_to_right (const WEdit *edit, off_t i, const GString *text, const char *whole_left,
266 const char *whole_right, gboolean line_start)
267 {
268 const unsigned char *p, *q;
269 int c, d, j;
270
271 c = edit_buffer_get_byte (&edit->buffer, i - 1);
272 c = xx_tolower (edit, c);
273 if ((line_start && c != '\n') || (whole_left != NULL && strchr (whole_left, c) != NULL))
274 return -1;
275
276 for (p = (const unsigned char *) text->str, q = p + text->len; p < q; p++, i++)
277 {
278 switch (*p)
279 {
280 case SYNTAX_TOKEN_STAR:
281 if (++p > q)
282 return -1;
283 while (TRUE)
284 {
285 c = edit_buffer_get_byte (&edit->buffer, i);
286 c = xx_tolower (edit, c);
287 if (*p == '\0' && whole_right != NULL && strchr (whole_right, c) == NULL)
288 break;
289 if (c == *p)
290 break;
291 if (c == '\n')
292 return -1;
293 i++;
294 }
295 break;
296 case SYNTAX_TOKEN_PLUS:
297 if (++p > q)
298 return -1;
299 j = 0;
300 while (TRUE)
301 {
302 c = edit_buffer_get_byte (&edit->buffer, i);
303 c = xx_tolower (edit, c);
304 if (c == *p)
305 {
306 j = i;
307 if (p[0] == text->str[0]
308 && p[1] == '\0')
309 break;
310 }
311 if (j != 0
312 && strchr ((const char *) p + 1, c)
313 != NULL)
314 break;
315 if (whiteness (c) || (whole_right != NULL && strchr (whole_right, c) == NULL))
316 {
317 if (*p == '\0')
318 {
319 i--;
320 break;
321 }
322 if (j == 0)
323 return -1;
324 i = j;
325 break;
326 }
327 i++;
328 }
329 break;
330 case SYNTAX_TOKEN_BRACKET:
331 if (++p > q)
332 return -1;
333 c = -1;
334 while (TRUE)
335 {
336 d = c;
337 c = edit_buffer_get_byte (&edit->buffer, i);
338 c = xx_tolower (edit, c);
339 for (j = 0; p[j] != SYNTAX_TOKEN_BRACKET && p[j] != '\0'; j++)
340 if (c == p[j])
341 goto found_char2;
342 break;
343 found_char2:
344 i++;
345 }
346 i--;
347 while (*p != SYNTAX_TOKEN_BRACKET && p <= q)
348 p++;
349 if (p > q)
350 return -1;
351 if (p[1] == d)
352 i--;
353 break;
354 case SYNTAX_TOKEN_BRACE:
355 if (++p > q)
356 return -1;
357 c = edit_buffer_get_byte (&edit->buffer, i);
358 c = xx_tolower (edit, c);
359 for (; *p != SYNTAX_TOKEN_BRACE && *p != '\0'; p++)
360 if (c == *p)
361 goto found_char3;
362 return -1;
363 found_char3:
364 while (*p != SYNTAX_TOKEN_BRACE && p < q)
365 p++;
366 break;
367 default:
368 c = edit_buffer_get_byte (&edit->buffer, i);
369 if (*p != xx_tolower (edit, c))
370 return -1;
371 }
372 }
373
374 if (whole_right == NULL)
375 return i;
376
377 c = edit_buffer_get_byte (&edit->buffer, i);
378 c = xx_tolower (edit, c);
379 return strchr (whole_right, c) != NULL ? -1 : i;
380 }
381
382
383
384 static const char *
385 xx_strchr (const WEdit *edit, const unsigned char *s, int char_byte)
386 {
387 while (*s >= '\005' && xx_tolower (edit, *s) != char_byte)
388 s++;
389
390 return (const char *) s;
391 }
392
393
394
395 static void
396 apply_rules_going_right (WEdit *edit, off_t i)
397 {
398 context_rule_t *r;
399 int c;
400 gboolean contextchanged = FALSE;
401 gboolean found_left = FALSE, found_right = FALSE;
402 gboolean keyword_foundleft = FALSE, keyword_foundright = FALSE;
403 gboolean is_end;
404 off_t end = 0;
405 edit_syntax_rule_t _rule = edit->rule;
406
407 c = edit_buffer_get_byte (&edit->buffer, i);
408 c = xx_tolower (edit, c);
409 if (c == 0)
410 return;
411
412 is_end = (edit->rule.end == i);
413
414
415 if (_rule.keyword != 0)
416 {
417 if (edit_buffer_get_byte (&edit->buffer, i - 1) == '\n')
418 _rule.keyword = 0;
419 if (is_end)
420 {
421 _rule.keyword = 0;
422 keyword_foundleft = TRUE;
423 }
424 }
425
426
427 if (_rule.context != 0 && _rule.keyword == 0)
428 {
429 off_t e;
430
431 r = CONTEXT_RULE (g_ptr_array_index (edit->rules, _rule.context));
432 if (r->first_right == c && (edit->rule.border & RULE_ON_RIGHT_BORDER) == 0
433 && r->right->len != 0
434 && (e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left,
435 r->whole_word_chars_right, r->line_start_right))
436 > 0)
437 {
438 _rule.end = e;
439 found_right = TRUE;
440 _rule.border = RULE_ON_RIGHT_BORDER;
441 if (r->between_delimiters)
442 _rule.context = 0;
443 }
444 else if (is_end && (edit->rule.border & RULE_ON_RIGHT_BORDER) != 0)
445 {
446
447 found_left = TRUE;
448 _rule.border = 0;
449 if (!keyword_foundleft)
450 _rule.context = 0;
451 }
452 else if (is_end && (edit->rule.border & RULE_ON_LEFT_BORDER) != 0)
453 {
454
455 found_left = TRUE;
456 _rule.border = 0;
457 }
458 }
459
460
461 if (_rule.keyword == 0)
462 {
463 const char *p;
464
465 r = CONTEXT_RULE (g_ptr_array_index (edit->rules, _rule.context));
466 p = r->keyword_first_chars;
467
468 if (p != NULL)
469 while (*(p = xx_strchr (edit, (const unsigned char *) p + 1, c)) != '\0')
470 {
471 syntax_keyword_t *k;
472 int count;
473 off_t e = -1;
474
475 count = p - r->keyword_first_chars;
476 k = SYNTAX_KEYWORD (g_ptr_array_index (r->keyword, count));
477 if (k->keyword != 0)
478 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left,
479 k->whole_word_chars_right, k->line_start);
480 if (e > 0)
481 {
482
483
484 if (e > i + 1 && _rule._context != 0
485 && k->keyword->str[k->keyword->len - 1] == '\n')
486 {
487 r = CONTEXT_RULE (g_ptr_array_index (edit->rules, _rule._context));
488 if (r->right != NULL && r->right->len != 0
489 && r->right->str[r->right->len - 1] == '\n')
490 e--;
491 }
492
493 end = e;
494 _rule.end = e;
495 _rule.keyword = count;
496 keyword_foundright = TRUE;
497 break;
498 }
499 }
500 }
501
502
503 if (_rule.context == 0)
504 {
505 if (!found_left && is_end)
506 {
507 if ((edit->rule.border & RULE_ON_RIGHT_BORDER) != 0)
508 {
509 _rule.border = 0;
510 _rule.context = 0;
511 contextchanged = TRUE;
512 _rule.keyword = 0;
513 }
514 else if ((edit->rule.border & RULE_ON_LEFT_BORDER) != 0)
515 {
516 r = CONTEXT_RULE (g_ptr_array_index (edit->rules, _rule._context));
517 _rule.border = 0;
518 if (r->between_delimiters)
519 {
520 _rule.context = _rule._context;
521 contextchanged = TRUE;
522 _rule.keyword = 0;
523
524 if (r->first_right == c)
525 {
526 off_t e = -1;
527
528 if (r->right->len != 0)
529 e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left,
530 r->whole_word_chars_right,
531 r->line_start_right);
532 if (e >= end)
533 {
534 _rule.end = e;
535 found_right = TRUE;
536 _rule.border = RULE_ON_RIGHT_BORDER;
537 _rule.context = 0;
538 }
539 }
540 }
541 }
542 }
543
544 if (!found_right)
545 {
546 size_t count;
547
548 for (count = 1; count < edit->rules->len; count++)
549 {
550 r = CONTEXT_RULE (g_ptr_array_index (edit->rules, count));
551 if (r->first_left == c)
552 {
553 off_t e = -1;
554
555 if (r->left->len != 0)
556 e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left,
557 r->whole_word_chars_right, r->line_start_left);
558 if (e >= end && (_rule.keyword == 0 || keyword_foundright))
559 {
560 _rule.end = e;
561 _rule.border = RULE_ON_LEFT_BORDER;
562 _rule._context = count;
563 if (!r->between_delimiters && _rule.keyword == 0)
564 {
565 _rule.context = count;
566 contextchanged = TRUE;
567 }
568 break;
569 }
570 }
571 }
572 }
573 }
574
575
576 if (contextchanged && _rule.keyword == 0)
577 {
578 const char *p;
579
580 r = CONTEXT_RULE (g_ptr_array_index (edit->rules, _rule.context));
581 p = r->keyword_first_chars;
582
583 while (*(p = xx_strchr (edit, (const unsigned char *) p + 1, c)) != '\0')
584 {
585 syntax_keyword_t *k;
586 int count;
587 off_t e = -1;
588
589 count = p - r->keyword_first_chars;
590 k = SYNTAX_KEYWORD (g_ptr_array_index (r->keyword, count));
591
592 if (k->keyword->len != 0)
593 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left,
594 k->whole_word_chars_right, k->line_start);
595 if (e > 0)
596 {
597 _rule.end = e;
598 _rule.keyword = count;
599 break;
600 }
601 }
602 }
603
604 edit->rule = _rule;
605 }
606
607
608
609 static void
610 edit_get_rule (WEdit *edit, off_t byte_index)
611 {
612 off_t i;
613
614 if (byte_index > edit->last_get_rule)
615 {
616 for (i = edit->last_get_rule + 1; i <= byte_index; i++)
617 {
618 off_t d = SYNTAX_MARKER_DENSITY;
619
620 apply_rules_going_right (edit, i);
621
622 if (edit->syntax_marker != NULL)
623 d += ((syntax_marker_t *) edit->syntax_marker->data)->offset;
624
625 if (i > d)
626 {
627 syntax_marker_t *s;
628
629 s = g_new (syntax_marker_t, 1);
630 s->offset = i;
631 s->rule = edit->rule;
632 edit->syntax_marker = g_slist_prepend (edit->syntax_marker, s);
633 }
634 }
635 }
636 else if (byte_index < edit->last_get_rule)
637 {
638 while (TRUE)
639 {
640 syntax_marker_t *s;
641
642 if (edit->syntax_marker == NULL)
643 {
644 memset (&edit->rule, 0, sizeof (edit->rule));
645 for (i = -1; i <= byte_index; i++)
646 apply_rules_going_right (edit, i);
647 break;
648 }
649
650 s = (syntax_marker_t *) edit->syntax_marker->data;
651
652 if (byte_index >= s->offset)
653 {
654 edit->rule = s->rule;
655 for (i = s->offset + 1; i <= byte_index; i++)
656 apply_rules_going_right (edit, i);
657 break;
658 }
659
660 g_free (s);
661 edit->syntax_marker = g_slist_delete_link (edit->syntax_marker, edit->syntax_marker);
662 }
663 }
664 edit->last_get_rule = byte_index;
665 }
666
667
668
669 static int
670 translate_rule_to_color (const WEdit *edit, const edit_syntax_rule_t *rule)
671 {
672 syntax_keyword_t *k;
673 context_rule_t *r;
674
675 r = CONTEXT_RULE (g_ptr_array_index (edit->rules, rule->context));
676 k = SYNTAX_KEYWORD (g_ptr_array_index (r->keyword, rule->keyword));
677
678 return k->color;
679 }
680
681
682
683
684
685
686
687
688 static size_t
689 read_one_line (char **line, FILE *f)
690 {
691 GString *p;
692 size_t r = 0;
693
694
695 p = g_string_sized_new (64);
696
697 while (TRUE)
698 {
699 int c;
700
701 c = fgetc (f);
702 if (c == EOF)
703 {
704 if (ferror (f))
705 {
706 if (errno == EINTR)
707 continue;
708 r = 0;
709 }
710 break;
711 }
712 r++;
713
714
715 if (c == '\n')
716 break;
717 if (c == '\r')
718 {
719 c = fgetc (f);
720 if (c == '\n')
721 r++;
722 else
723 ungetc (c, f);
724 break;
725 }
726
727 g_string_append_c (p, c);
728 }
729 if (r != 0)
730 *line = g_string_free (p, FALSE);
731 else
732 g_string_free (p, TRUE);
733
734 return r;
735 }
736
737
738
739 static char *
740 convert (char *s)
741 {
742 char *r, *p;
743
744 p = r = s;
745 while (*s)
746 {
747 switch (*s)
748 {
749 case '\\':
750 s++;
751 switch (*s)
752 {
753 case ' ':
754 *p = ' ';
755 s--;
756 break;
757 case 'n':
758 *p = '\n';
759 break;
760 case 'r':
761 *p = '\r';
762 break;
763 case 't':
764 *p = '\t';
765 break;
766 case 's':
767 *p = ' ';
768 break;
769 case '*':
770 *p = '*';
771 break;
772 case '\\':
773 *p = '\\';
774 break;
775 case '[':
776 case ']':
777 *p = SYNTAX_TOKEN_BRACKET;
778 break;
779 case '{':
780 case '}':
781 *p = SYNTAX_TOKEN_BRACE;
782 break;
783 case 0:
784 *p = *s;
785 return r;
786 default:
787 *p = *s;
788 break;
789 }
790 break;
791 case '*':
792 *p = SYNTAX_TOKEN_STAR;
793 break;
794 case '+':
795 *p = SYNTAX_TOKEN_PLUS;
796 break;
797 default:
798 *p = *s;
799 break;
800 }
801 s++;
802 p++;
803 }
804 *p = '\0';
805 return r;
806 }
807
808
809
810 static int
811 get_args (char *l, char **args, int args_size)
812 {
813 int argc = 0;
814
815 while (argc < args_size)
816 {
817 char *p = l;
818
819 while (*p != '\0' && whiteness (*p))
820 p++;
821 if (*p == '\0')
822 break;
823 for (l = p + 1; *l != '\0' && !whiteness (*l); l++)
824 ;
825 if (*l != '\0')
826 *l++ = '\0';
827 args[argc++] = convert (p);
828 }
829 args[argc] = (char *) NULL;
830 return argc;
831 }
832
833
834
835 static int
836 this_try_alloc_color_pair (tty_color_pair_t *color)
837 {
838 char f[80], b[80], a[80], *p;
839
840 if (color->bg != NULL && *color->bg == '\0')
841 color->bg = NULL;
842 if (color->fg != NULL && *color->fg == '\0')
843 color->fg = NULL;
844 if (color->attrs != NULL && *color->attrs == '\0')
845 color->attrs = NULL;
846
847 if (color->fg == NULL && color->bg == NULL)
848 return EDITOR_NORMAL_COLOR;
849
850 if (color->fg != NULL)
851 {
852 g_strlcpy (f, color->fg, sizeof (f));
853 p = strchr (f, '/');
854 if (p != NULL)
855 *p = '\0';
856 color->fg = f;
857 }
858 if (color->bg != NULL)
859 {
860 g_strlcpy (b, color->bg, sizeof (b));
861 p = strchr (b, '/');
862 if (p != NULL)
863 *p = '\0';
864 color->bg = b;
865 }
866 if (color->fg == NULL || color->bg == NULL)
867 {
868
869 char *editnormal;
870
871 editnormal = mc_skin_get ("editor", "_default_", "default;default");
872
873 if (color->fg == NULL)
874 {
875 g_strlcpy (f, editnormal, sizeof (f));
876 p = strchr (f, ';');
877 if (p != NULL)
878 *p = '\0';
879 if (f[0] == '\0')
880 g_strlcpy (f, "default", sizeof (f));
881 color->fg = f;
882 }
883 if (color->bg == NULL)
884 {
885 p = strchr (editnormal, ';');
886 if ((p != NULL) && (*(++p) != '\0'))
887 g_strlcpy (b, p, sizeof (b));
888 else
889 g_strlcpy (b, "default", sizeof (b));
890 color->bg = b;
891 }
892
893 g_free (editnormal);
894 }
895
896 if (color->attrs != NULL)
897 {
898 g_strlcpy (a, color->attrs, sizeof (a));
899 p = strchr (a, '/');
900 if (p != NULL)
901 *p = '\0';
902
903 p = a;
904 while ((p = strchr (p, SYNTAX_TOKEN_PLUS)) != NULL)
905 *p++ = '+';
906 color->attrs = a;
907 }
908
909 return tty_try_alloc_color_pair (color, TRUE);
910 }
911
912
913
914 static FILE *
915 open_include_file (const char *filename)
916 {
917 FILE *f;
918
919 g_free (error_file_name);
920 error_file_name = g_strdup (filename);
921 if (g_path_is_absolute (filename))
922 return fopen (filename, "r");
923
924 g_free (error_file_name);
925 error_file_name =
926 g_build_filename (mc_config_get_data_path (), EDIT_SYNTAX_DIR, filename, (char *) NULL);
927 f = fopen (error_file_name, "r");
928 if (f != NULL)
929 return f;
930
931 g_free (error_file_name);
932 error_file_name =
933 g_build_filename (mc_global.share_data_dir, EDIT_SYNTAX_DIR, filename, (char *) NULL);
934
935 return fopen (error_file_name, "r");
936 }
937
938
939
940 inline static void
941 xx_lowerize_line (WEdit *edit, char *line, size_t len)
942 {
943 if (edit->is_case_insensitive)
944 {
945 size_t i;
946
947 for (i = 0; i < len; ++i)
948 line[i] = tolower (line[i]);
949 }
950 }
951
952
953
954
955 static int
956 edit_read_syntax_rules (WEdit *edit, FILE *f, char **args, int args_size)
957 {
958 FILE *g = NULL;
959 tty_color_pair_t color;
960 char last_fg[BUF_TINY / 2] = "";
961 char last_bg[BUF_TINY / 2] = "";
962 char last_attrs[BUF_TINY] = "";
963 char whole_right[BUF_MEDIUM];
964 char whole_left[BUF_MEDIUM];
965 char *l = NULL;
966 int save_line = 0, line = 0;
967 context_rule_t *c = NULL;
968 gboolean no_words = TRUE;
969 int result = 0;
970
971 args[0] = NULL;
972 edit->is_case_insensitive = FALSE;
973
974 strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
975 strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
976
977 edit->rules = g_ptr_array_new_with_free_func (context_rule_free);
978
979 if (edit->defines == NULL)
980 edit->defines = g_tree_new ((GCompareFunc) strcmp);
981
982 while (TRUE)
983 {
984 char **a;
985 size_t len;
986 int argc;
987
988 line++;
989 l = NULL;
990
991 len = read_one_line (&l, f);
992 if (len == 0)
993 {
994 if (g == NULL)
995 break;
996
997 fclose (f);
998 f = g;
999 g = NULL;
1000 line = save_line + 1;
1001 MC_PTR_FREE (error_file_name);
1002 MC_PTR_FREE (l);
1003 len = read_one_line (&l, f);
1004 if (len == 0)
1005 break;
1006 }
1007
1008 xx_lowerize_line (edit, l, len);
1009
1010 argc = get_args (l, args, args_size);
1011 a = args + 1;
1012 if (args[0] == NULL)
1013 {
1014
1015 }
1016 else if (strcmp (args[0], "include") == 0)
1017 {
1018 if (g != NULL || argc != 2)
1019 {
1020 result = line;
1021 break;
1022 }
1023 g = f;
1024 f = open_include_file (args[1]);
1025 if (f == NULL)
1026 {
1027 MC_PTR_FREE (error_file_name);
1028 result = line;
1029 break;
1030 }
1031 save_line = line;
1032 line = 0;
1033 }
1034 else if (strcmp (args[0], "caseinsensitive") == 0)
1035 {
1036 edit->is_case_insensitive = TRUE;
1037 }
1038 else if (strcmp (args[0], "wholechars") == 0)
1039 {
1040 check_a;
1041 if (strcmp (*a, "left") == 0)
1042 {
1043 a++;
1044 g_strlcpy (whole_left, *a, sizeof (whole_left));
1045 }
1046 else if (strcmp (*a, "right") == 0)
1047 {
1048 a++;
1049 g_strlcpy (whole_right, *a, sizeof (whole_right));
1050 }
1051 else
1052 {
1053 g_strlcpy (whole_left, *a, sizeof (whole_left));
1054 g_strlcpy (whole_right, *a, sizeof (whole_right));
1055 }
1056 a++;
1057 check_not_a;
1058 }
1059 else if (strcmp (args[0], "context") == 0)
1060 {
1061 syntax_keyword_t *k;
1062
1063 check_a;
1064 if (edit->rules->len == 0)
1065 {
1066
1067 if (strcmp (*a, "default") != 0)
1068 break_a;
1069
1070 a++;
1071 c = g_new0 (context_rule_t, 1);
1072 g_ptr_array_add (edit->rules, c);
1073 c->left = g_string_new (" ");
1074 c->right = g_string_new (" ");
1075 }
1076 else
1077 {
1078
1079 c = g_new0 (context_rule_t, 1);
1080 g_ptr_array_add (edit->rules, c);
1081 if (strcmp (*a, "exclusive") == 0)
1082 {
1083 a++;
1084 c->between_delimiters = TRUE;
1085 }
1086 check_a;
1087 if (strcmp (*a, "whole") == 0)
1088 {
1089 a++;
1090 c->whole_word_chars_left = g_strdup (whole_left);
1091 c->whole_word_chars_right = g_strdup (whole_right);
1092 }
1093 else if (strcmp (*a, "wholeleft") == 0)
1094 {
1095 a++;
1096 c->whole_word_chars_left = g_strdup (whole_left);
1097 }
1098 else if (strcmp (*a, "wholeright") == 0)
1099 {
1100 a++;
1101 c->whole_word_chars_right = g_strdup (whole_right);
1102 }
1103 check_a;
1104 if (strcmp (*a, "linestart") == 0)
1105 {
1106 a++;
1107 c->line_start_left = TRUE;
1108 }
1109 check_a;
1110 c->left = g_string_new (*a++);
1111 check_a;
1112 if (strcmp (*a, "linestart") == 0)
1113 {
1114 a++;
1115 c->line_start_right = TRUE;
1116 }
1117 check_a;
1118 c->right = g_string_new (*a++);
1119 c->first_left = c->left->str[0];
1120 c->first_right = c->right->str[0];
1121 }
1122 c->keyword = g_ptr_array_new_with_free_func (syntax_keyword_free);
1123 k = g_new0 (syntax_keyword_t, 1);
1124 g_ptr_array_add (c->keyword, k);
1125 no_words = FALSE;
1126 subst_defines (edit->defines, a, &args[ARGS_LEN]);
1127 color.fg = *a;
1128 if (*a != NULL)
1129 a++;
1130 color.bg = *a;
1131 if (*a != NULL)
1132 a++;
1133 color.attrs = *a;
1134 if (*a != NULL)
1135 a++;
1136 g_strlcpy (last_fg, color.fg != NULL ? color.fg : "", sizeof (last_fg));
1137 g_strlcpy (last_bg, color.bg != NULL ? color.bg : "", sizeof (last_bg));
1138 g_strlcpy (last_attrs, color.attrs != NULL ? color.attrs : "", sizeof (last_attrs));
1139 k->color = this_try_alloc_color_pair (&color);
1140 k->keyword = g_string_new (" ");
1141 check_not_a;
1142 }
1143 else if (strcmp (args[0], "spellcheck") == 0)
1144 {
1145 if (c == NULL)
1146 {
1147 result = line;
1148 break;
1149 }
1150 c->spelling = TRUE;
1151 }
1152 else if (strcmp (args[0], "keyword") == 0)
1153 {
1154 context_rule_t *last_rule;
1155 syntax_keyword_t *k;
1156
1157 if (no_words)
1158 break_a;
1159 check_a;
1160 last_rule = CONTEXT_RULE (g_ptr_array_index (edit->rules, edit->rules->len - 1));
1161 k = g_new0 (syntax_keyword_t, 1);
1162 g_ptr_array_add (last_rule->keyword, k);
1163 if (strcmp (*a, "whole") == 0)
1164 {
1165 a++;
1166 k->whole_word_chars_left = g_strdup (whole_left);
1167 k->whole_word_chars_right = g_strdup (whole_right);
1168 }
1169 else if (strcmp (*a, "wholeleft") == 0)
1170 {
1171 a++;
1172 k->whole_word_chars_left = g_strdup (whole_left);
1173 }
1174 else if (strcmp (*a, "wholeright") == 0)
1175 {
1176 a++;
1177 k->whole_word_chars_right = g_strdup (whole_right);
1178 }
1179 check_a;
1180 if (strcmp (*a, "linestart") == 0)
1181 {
1182 a++;
1183 k->line_start = TRUE;
1184 }
1185 check_a;
1186 if (strcmp (*a, "whole") == 0)
1187 break_a;
1188
1189 k->keyword = g_string_new (*a++);
1190 subst_defines (edit->defines, a, &args[ARGS_LEN]);
1191 color.fg = *a;
1192 if (*a != NULL)
1193 a++;
1194 color.bg = *a;
1195 if (*a != NULL)
1196 a++;
1197 color.attrs = *a;
1198 if (*a != NULL)
1199 a++;
1200 if (color.fg == NULL)
1201 color.fg = last_fg;
1202 if (color.bg == NULL)
1203 color.bg = last_bg;
1204 if (color.attrs == NULL)
1205 color.attrs = last_attrs;
1206 k->color = this_try_alloc_color_pair (&color);
1207 check_not_a;
1208 }
1209 else if (*(args[0]) == '#')
1210 {
1211
1212 }
1213 else if (strcmp (args[0], "file") == 0)
1214 {
1215 break;
1216 }
1217 else if (strcmp (args[0], "define") == 0)
1218 {
1219 char *key = *a++;
1220 char **argv;
1221
1222 if (argc < 3)
1223 break_a;
1224 argv = g_tree_lookup (edit->defines, key);
1225 if (argv != NULL)
1226 mc_defines_destroy (NULL, argv, NULL);
1227 else
1228 key = g_strdup (key);
1229
1230 argv = g_new (char *, argc - 1);
1231 g_tree_insert (edit->defines, key, argv);
1232 while (*a != NULL)
1233 *argv++ = g_strdup (*a++);
1234 *argv = NULL;
1235 }
1236 else
1237 {
1238
1239 break_a;
1240 }
1241 MC_PTR_FREE (l);
1242 }
1243 MC_PTR_FREE (l);
1244
1245 if (edit->rules->len == 0)
1246 {
1247 g_ptr_array_free (edit->rules, TRUE);
1248 edit->rules = NULL;
1249 }
1250
1251 if (result == 0)
1252 {
1253 size_t i;
1254 GString *first_chars;
1255
1256 if (edit->rules == NULL)
1257 return line;
1258
1259 first_chars = g_string_sized_new (32);
1260
1261
1262 for (i = 0; i < edit->rules->len; i++)
1263 {
1264 size_t j;
1265
1266 g_string_set_size (first_chars, 0);
1267 c = CONTEXT_RULE (g_ptr_array_index (edit->rules, i));
1268
1269 g_string_append_c (first_chars, (char) 1);
1270 for (j = 1; j < c->keyword->len; j++)
1271 {
1272 syntax_keyword_t *k;
1273
1274 k = SYNTAX_KEYWORD (g_ptr_array_index (c->keyword, j));
1275 g_string_append_c (first_chars, k->keyword->str[0]);
1276 }
1277
1278 c->keyword_first_chars = g_strndup (first_chars->str, first_chars->len);
1279 }
1280
1281 g_string_free (first_chars, TRUE);
1282 }
1283
1284 return result;
1285 }
1286
1287
1288
1289
1290 static int
1291 edit_read_syntax_file (WEdit *edit, GPtrArray *pnames, const char *syntax_file,
1292 const char *editor_file, const char *first_line, const char *type)
1293 {
1294 FILE *f, *g = NULL;
1295 char *args[ARGS_LEN], *l = NULL;
1296 long line = 0;
1297 int result = 0;
1298 gboolean found = FALSE;
1299
1300 f = fopen (syntax_file, "r");
1301 if (f == NULL)
1302 {
1303 char *global_syntax_file;
1304
1305 global_syntax_file =
1306 g_build_filename (mc_global.share_data_dir, EDIT_SYNTAX_FILE, (char *) NULL);
1307 f = fopen (global_syntax_file, "r");
1308 g_free (global_syntax_file);
1309 if (f == NULL)
1310 return -1;
1311 }
1312
1313 args[0] = NULL;
1314 while (TRUE)
1315 {
1316 line++;
1317 MC_PTR_FREE (l);
1318 if (read_one_line (&l, f) == 0)
1319 break;
1320 (void) get_args (l, args, ARGS_LEN - 1);
1321 if (args[0] == NULL)
1322 continue;
1323
1324
1325 if (!found && strcmp (args[0], "include") == 0)
1326 {
1327 if (args[1] == NULL || (g = open_include_file (args[1])) == NULL)
1328 {
1329 result = line;
1330 break;
1331 }
1332 goto found_type;
1333 }
1334
1335
1336 if (strcmp (args[0], "file") != 0)
1337 continue;
1338
1339 found = TRUE;
1340
1341
1342 if (args[1] == NULL || args[2] == NULL)
1343 {
1344 result = line;
1345 break;
1346 }
1347
1348 if (pnames != NULL)
1349 {
1350
1351 g_ptr_array_add (pnames, g_strdup (args[2]));
1352 }
1353 else if (type != NULL)
1354 {
1355
1356 if (strcmp (type, args[2]) == 0)
1357 goto found_type;
1358 }
1359 else if (editor_file != NULL && edit != NULL)
1360 {
1361
1362 gboolean q;
1363
1364 q = mc_search (args[1], NULL, editor_file, MC_SEARCH_T_REGEX);
1365
1366 if (!q && args[3] != NULL)
1367 {
1368
1369 q = mc_search (args[3], NULL, first_line, MC_SEARCH_T_REGEX);
1370 }
1371 if (q)
1372 {
1373 int line_error;
1374 char *syntax_type;
1375
1376 found_type:
1377 syntax_type = args[2];
1378 line_error = edit_read_syntax_rules (edit, g ? g : f, args, ARGS_LEN - 1);
1379 if (line_error != 0)
1380 {
1381 if (error_file_name == NULL)
1382 result = line + line_error;
1383 else
1384 result = line_error;
1385 }
1386 else
1387 {
1388 g_free (edit->syntax_type);
1389 edit->syntax_type = g_strdup (syntax_type);
1390
1391 if (g == NULL && edit->rules->len == 1)
1392 {
1393 context_rule_t *r0;
1394
1395 r0 = CONTEXT_RULE (g_ptr_array_index (edit->rules, 0));
1396 if (r0->keyword->len == 1 && !r0->spelling)
1397 {
1398 edit_free_syntax_rules (edit);
1399 break;
1400 }
1401 }
1402 }
1403
1404 if (g == NULL)
1405 break;
1406
1407 fclose (g);
1408 g = NULL;
1409 }
1410 }
1411 }
1412 g_free (l);
1413 fclose (f);
1414 return result;
1415 }
1416
1417
1418
1419 static const char *
1420 get_first_editor_line (WEdit *edit)
1421 {
1422 static char s[256];
1423
1424 s[0] = '\0';
1425
1426 if (edit != NULL)
1427 {
1428 size_t i;
1429
1430 for (i = 0; i < sizeof (s) - 1; i++)
1431 {
1432 s[i] = edit_buffer_get_byte (&edit->buffer, i);
1433 if (s[i] == '\n')
1434 {
1435 s[i] = '\0';
1436 break;
1437 }
1438 }
1439
1440 s[sizeof (s) - 1] = '\0';
1441 }
1442
1443 return s;
1444 }
1445
1446
1447
1448 static int
1449 pstrcmp (const void *p1, const void *p2)
1450 {
1451 return strcmp (*(char *const *) p1, *(char *const *) p2);
1452 }
1453
1454
1455
1456 static int
1457 exec_edit_syntax_dialog (const GPtrArray *names, const char *current_syntax)
1458 {
1459 size_t i;
1460 Listbox *syntaxlist;
1461
1462 syntaxlist =
1463 listbox_window_new (LIST_LINES, MAX_ENTRY_LEN, _ ("Choose syntax highlighting"), NULL);
1464 LISTBOX_APPEND_TEXT (syntaxlist, 'A', _ ("< Auto >"), NULL, FALSE);
1465 LISTBOX_APPEND_TEXT (syntaxlist, 'R', _ ("< Reload Current Syntax >"), NULL, FALSE);
1466
1467 for (i = 0; i < names->len; i++)
1468 {
1469 const char *name;
1470
1471 name = g_ptr_array_index (names, i);
1472 LISTBOX_APPEND_TEXT (syntaxlist, 0, name, NULL, FALSE);
1473 if (current_syntax != NULL && strcmp (name, current_syntax) == 0)
1474 listbox_set_current (syntaxlist->list, i + N_DFLT_ENTRIES);
1475 }
1476
1477 return listbox_run (syntaxlist);
1478 }
1479
1480
1481
1482
1483
1484 int
1485 edit_get_syntax_color (WEdit *edit, off_t byte_index)
1486 {
1487 if (!tty_use_colors ())
1488 return 0;
1489
1490 if (edit_options.syntax_highlighting && edit->rules != NULL && byte_index < edit->buffer.size)
1491 {
1492 edit_get_rule (edit, byte_index);
1493 return translate_rule_to_color (edit, &edit->rule);
1494 }
1495
1496 return EDITOR_NORMAL_COLOR;
1497 }
1498
1499
1500
1501 void
1502 edit_free_syntax_rules (WEdit *edit)
1503 {
1504 if (edit == NULL)
1505 return;
1506
1507 if (edit->defines != NULL)
1508 destroy_defines (&edit->defines);
1509
1510 if (edit->rules == NULL)
1511 return;
1512
1513 edit_get_rule (edit, -1);
1514 MC_PTR_FREE (edit->syntax_type);
1515
1516 g_ptr_array_free (edit->rules, TRUE);
1517 edit->rules = NULL;
1518 g_clear_slist (&edit->syntax_marker, g_free);
1519 tty_color_free_temp ();
1520 }
1521
1522
1523
1524
1525
1526
1527
1528
1529 void
1530 edit_load_syntax (WEdit *edit, GPtrArray *pnames, const char *type)
1531 {
1532 int r;
1533 char *f = NULL;
1534
1535 if (auto_syntax)
1536 type = NULL;
1537
1538 if (edit != NULL)
1539 {
1540 char *saved_type;
1541
1542 saved_type = g_strdup (type);
1543 edit_free_syntax_rules (edit);
1544 edit->syntax_type = saved_type;
1545 }
1546
1547 if (!tty_use_colors ())
1548 return;
1549
1550 if (!edit_options.syntax_highlighting && (pnames == NULL || pnames->len == 0))
1551 return;
1552
1553 if (edit != NULL && edit->filename_vpath == NULL)
1554 return;
1555
1556 f = mc_config_get_full_path (EDIT_SYNTAX_FILE);
1557 if (edit != NULL)
1558 r = edit_read_syntax_file (edit, pnames, f, vfs_path_as_str (edit->filename_vpath),
1559 get_first_editor_line (edit),
1560 auto_syntax ? NULL : edit->syntax_type);
1561 else
1562 r = edit_read_syntax_file (NULL, pnames, f, NULL, "", NULL);
1563 if (r == -1)
1564 {
1565 edit_free_syntax_rules (edit);
1566 file_error_message (_ ("Cannot open file\n%s"), f);
1567 }
1568 else if (r != 0)
1569 {
1570 edit_free_syntax_rules (edit);
1571 message (D_ERROR, _ ("Load syntax file"), _ ("Error in file %s on line %d"),
1572 error_file_name != NULL ? error_file_name : f, r);
1573 MC_PTR_FREE (error_file_name);
1574 }
1575
1576 g_free (f);
1577 }
1578
1579
1580
1581 const char *
1582 edit_get_syntax_type (const WEdit *edit)
1583 {
1584 return edit->syntax_type;
1585 }
1586
1587
1588
1589 void
1590 edit_syntax_dialog (WEdit *edit)
1591 {
1592 GPtrArray *names;
1593 int syntax;
1594
1595 names = g_ptr_array_new_with_free_func (g_free);
1596
1597
1598
1599
1600 edit_load_syntax (NULL, names, NULL);
1601 g_ptr_array_sort (names, pstrcmp);
1602
1603 syntax = exec_edit_syntax_dialog (names, edit->syntax_type);
1604 if (syntax >= 0)
1605 {
1606 gboolean force_reload = FALSE;
1607 char *current_syntax;
1608 gboolean old_auto_syntax;
1609
1610 current_syntax = g_strdup (edit->syntax_type);
1611 old_auto_syntax = auto_syntax;
1612
1613 switch (syntax)
1614 {
1615 case 0:
1616 auto_syntax = TRUE;
1617 break;
1618 case 1:
1619 force_reload = TRUE;
1620 break;
1621 default:
1622 auto_syntax = FALSE;
1623 g_free (edit->syntax_type);
1624 edit->syntax_type = g_strdup (g_ptr_array_index (names, syntax - N_DFLT_ENTRIES));
1625 }
1626
1627
1628 if (force_reload || (auto_syntax && !old_auto_syntax) || old_auto_syntax
1629 || (current_syntax != NULL && edit->syntax_type != NULL
1630 && strcmp (current_syntax, edit->syntax_type) != 0))
1631 edit_load_syntax (edit, NULL, edit->syntax_type);
1632
1633 g_free (current_syntax);
1634 }
1635
1636 g_ptr_array_free (names, TRUE);
1637 }
1638
1639