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
841 if (color->bg != NULL && (*color->bg == '\0' || strcmp (color->bg, "default") == 0))
842 color->bg = NULL;
843 if (color->fg != NULL && (*color->fg == '\0' || strcmp (color->fg, "default") == 0))
844 color->fg = NULL;
845 if (color->attrs != NULL && *color->attrs == '\0')
846 color->attrs = NULL;
847
848 if (color->fg == NULL && color->bg == NULL)
849 return EDITOR_NORMAL_COLOR;
850
851 if (color->fg != NULL)
852 {
853 g_strlcpy (f, color->fg, sizeof (f));
854 p = strchr (f, '/');
855 if (p != NULL)
856 *p = '\0';
857 color->fg = f;
858 }
859 if (color->bg != NULL)
860 {
861 g_strlcpy (b, color->bg, sizeof (b));
862 p = strchr (b, '/');
863 if (p != NULL)
864 *p = '\0';
865 color->bg = b;
866 }
867 if (color->fg == NULL || color->bg == NULL)
868 {
869
870 char *editnormal;
871
872 editnormal = mc_skin_get ("editor", "_default_", "default;default");
873
874 if (color->fg == NULL)
875 {
876 g_strlcpy (f, editnormal, sizeof (f));
877 p = strchr (f, ';');
878 if (p != NULL)
879 *p = '\0';
880 if (f[0] == '\0')
881 g_strlcpy (f, "default", sizeof (f));
882 color->fg = f;
883 }
884 if (color->bg == NULL)
885 {
886 p = strchr (editnormal, ';');
887 if ((p != NULL) && (*(++p) != '\0'))
888 g_strlcpy (b, p, sizeof (b));
889 else
890 g_strlcpy (b, "default", sizeof (b));
891 color->bg = b;
892 }
893
894 g_free (editnormal);
895 }
896
897 if (color->attrs != NULL)
898 {
899 g_strlcpy (a, color->attrs, sizeof (a));
900 p = strchr (a, '/');
901 if (p != NULL)
902 *p = '\0';
903
904 p = a;
905 while ((p = strchr (p, SYNTAX_TOKEN_PLUS)) != NULL)
906 *p++ = '+';
907 color->attrs = a;
908 }
909
910 return tty_try_alloc_color_pair (color, TRUE);
911 }
912
913
914
915 static FILE *
916 open_include_file (const char *filename)
917 {
918 FILE *f;
919
920 g_free (error_file_name);
921 error_file_name = g_strdup (filename);
922 if (g_path_is_absolute (filename))
923 return fopen (filename, "r");
924
925 g_free (error_file_name);
926 error_file_name =
927 g_build_filename (mc_config_get_data_path (), EDIT_SYNTAX_DIR, filename, (char *) NULL);
928 f = fopen (error_file_name, "r");
929 if (f != NULL)
930 return f;
931
932 g_free (error_file_name);
933 error_file_name =
934 g_build_filename (mc_global.share_data_dir, EDIT_SYNTAX_DIR, filename, (char *) NULL);
935
936 return fopen (error_file_name, "r");
937 }
938
939
940
941 inline static void
942 xx_lowerize_line (WEdit *edit, char *line, size_t len)
943 {
944 if (edit->is_case_insensitive)
945 {
946 size_t i;
947
948 for (i = 0; i < len; ++i)
949 line[i] = tolower (line[i]);
950 }
951 }
952
953
954
955
956 static int
957 edit_read_syntax_rules (WEdit *edit, FILE *f, char **args, int args_size)
958 {
959 FILE *g = NULL;
960 tty_color_pair_t color;
961 char last_fg[BUF_TINY / 2] = "";
962 char last_bg[BUF_TINY / 2] = "";
963 char last_attrs[BUF_TINY] = "";
964 char whole_right[BUF_MEDIUM];
965 char whole_left[BUF_MEDIUM];
966 char *l = NULL;
967 int save_line = 0, line = 0;
968 context_rule_t *c = NULL;
969 gboolean no_words = TRUE;
970 int result = 0;
971
972 args[0] = NULL;
973 edit->is_case_insensitive = FALSE;
974
975 strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
976 strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
977
978 edit->rules = g_ptr_array_new_with_free_func (context_rule_free);
979
980 if (edit->defines == NULL)
981 edit->defines = g_tree_new ((GCompareFunc) strcmp);
982
983 while (TRUE)
984 {
985 char **a;
986 size_t len;
987 int argc;
988
989 line++;
990 l = NULL;
991
992 len = read_one_line (&l, f);
993 if (len == 0)
994 {
995 if (g == NULL)
996 break;
997
998 fclose (f);
999 f = g;
1000 g = NULL;
1001 line = save_line + 1;
1002 MC_PTR_FREE (error_file_name);
1003 MC_PTR_FREE (l);
1004 len = read_one_line (&l, f);
1005 if (len == 0)
1006 break;
1007 }
1008
1009 xx_lowerize_line (edit, l, len);
1010
1011 argc = get_args (l, args, args_size);
1012 a = args + 1;
1013 if (args[0] == NULL)
1014 {
1015
1016 }
1017 else if (strcmp (args[0], "include") == 0)
1018 {
1019 if (g != NULL || argc != 2)
1020 {
1021 result = line;
1022 break;
1023 }
1024 g = f;
1025 f = open_include_file (args[1]);
1026 if (f == NULL)
1027 {
1028 MC_PTR_FREE (error_file_name);
1029 result = line;
1030 break;
1031 }
1032 save_line = line;
1033 line = 0;
1034 }
1035 else if (strcmp (args[0], "caseinsensitive") == 0)
1036 {
1037 edit->is_case_insensitive = TRUE;
1038 }
1039 else if (strcmp (args[0], "wholechars") == 0)
1040 {
1041 check_a;
1042 if (strcmp (*a, "left") == 0)
1043 {
1044 a++;
1045 g_strlcpy (whole_left, *a, sizeof (whole_left));
1046 }
1047 else if (strcmp (*a, "right") == 0)
1048 {
1049 a++;
1050 g_strlcpy (whole_right, *a, sizeof (whole_right));
1051 }
1052 else
1053 {
1054 g_strlcpy (whole_left, *a, sizeof (whole_left));
1055 g_strlcpy (whole_right, *a, sizeof (whole_right));
1056 }
1057 a++;
1058 check_not_a;
1059 }
1060 else if (strcmp (args[0], "context") == 0)
1061 {
1062 syntax_keyword_t *k;
1063
1064 check_a;
1065 if (edit->rules->len == 0)
1066 {
1067
1068 if (strcmp (*a, "default") != 0)
1069 break_a;
1070
1071 a++;
1072 c = g_new0 (context_rule_t, 1);
1073 g_ptr_array_add (edit->rules, c);
1074 c->left = g_string_new (" ");
1075 c->right = g_string_new (" ");
1076 }
1077 else
1078 {
1079
1080 c = g_new0 (context_rule_t, 1);
1081 g_ptr_array_add (edit->rules, c);
1082 if (strcmp (*a, "exclusive") == 0)
1083 {
1084 a++;
1085 c->between_delimiters = TRUE;
1086 }
1087 check_a;
1088 if (strcmp (*a, "whole") == 0)
1089 {
1090 a++;
1091 c->whole_word_chars_left = g_strdup (whole_left);
1092 c->whole_word_chars_right = g_strdup (whole_right);
1093 }
1094 else if (strcmp (*a, "wholeleft") == 0)
1095 {
1096 a++;
1097 c->whole_word_chars_left = g_strdup (whole_left);
1098 }
1099 else if (strcmp (*a, "wholeright") == 0)
1100 {
1101 a++;
1102 c->whole_word_chars_right = g_strdup (whole_right);
1103 }
1104 check_a;
1105 if (strcmp (*a, "linestart") == 0)
1106 {
1107 a++;
1108 c->line_start_left = TRUE;
1109 }
1110 check_a;
1111 c->left = g_string_new (*a++);
1112 check_a;
1113 if (strcmp (*a, "linestart") == 0)
1114 {
1115 a++;
1116 c->line_start_right = TRUE;
1117 }
1118 check_a;
1119 c->right = g_string_new (*a++);
1120 c->first_left = c->left->str[0];
1121 c->first_right = c->right->str[0];
1122 }
1123 c->keyword = g_ptr_array_new_with_free_func (syntax_keyword_free);
1124 k = g_new0 (syntax_keyword_t, 1);
1125 g_ptr_array_add (c->keyword, k);
1126 no_words = FALSE;
1127 subst_defines (edit->defines, a, &args[ARGS_LEN]);
1128 color.fg = *a;
1129 if (*a != NULL)
1130 a++;
1131 color.bg = *a;
1132 if (*a != NULL)
1133 a++;
1134 color.attrs = *a;
1135 if (*a != NULL)
1136 a++;
1137 g_strlcpy (last_fg, color.fg != NULL ? color.fg : "", sizeof (last_fg));
1138 g_strlcpy (last_bg, color.bg != NULL ? color.bg : "", sizeof (last_bg));
1139 g_strlcpy (last_attrs, color.attrs != NULL ? color.attrs : "", sizeof (last_attrs));
1140 k->color = this_try_alloc_color_pair (&color);
1141 k->keyword = g_string_new (" ");
1142 check_not_a;
1143 }
1144 else if (strcmp (args[0], "spellcheck") == 0)
1145 {
1146 if (c == NULL)
1147 {
1148 result = line;
1149 break;
1150 }
1151 c->spelling = TRUE;
1152 }
1153 else if (strcmp (args[0], "keyword") == 0)
1154 {
1155 context_rule_t *last_rule;
1156 syntax_keyword_t *k;
1157
1158 if (no_words)
1159 break_a;
1160 check_a;
1161 last_rule = CONTEXT_RULE (g_ptr_array_index (edit->rules, edit->rules->len - 1));
1162 k = g_new0 (syntax_keyword_t, 1);
1163 g_ptr_array_add (last_rule->keyword, k);
1164 if (strcmp (*a, "whole") == 0)
1165 {
1166 a++;
1167 k->whole_word_chars_left = g_strdup (whole_left);
1168 k->whole_word_chars_right = g_strdup (whole_right);
1169 }
1170 else if (strcmp (*a, "wholeleft") == 0)
1171 {
1172 a++;
1173 k->whole_word_chars_left = g_strdup (whole_left);
1174 }
1175 else if (strcmp (*a, "wholeright") == 0)
1176 {
1177 a++;
1178 k->whole_word_chars_right = g_strdup (whole_right);
1179 }
1180 check_a;
1181 if (strcmp (*a, "linestart") == 0)
1182 {
1183 a++;
1184 k->line_start = TRUE;
1185 }
1186 check_a;
1187 if (strcmp (*a, "whole") == 0)
1188 break_a;
1189
1190 k->keyword = g_string_new (*a++);
1191 subst_defines (edit->defines, a, &args[ARGS_LEN]);
1192 color.fg = *a;
1193 if (*a != NULL)
1194 a++;
1195 color.bg = *a;
1196 if (*a != NULL)
1197 a++;
1198 color.attrs = *a;
1199 if (*a != NULL)
1200 a++;
1201 if (color.fg == NULL)
1202 color.fg = last_fg;
1203 if (color.bg == NULL)
1204 color.bg = last_bg;
1205 if (color.attrs == NULL)
1206 color.attrs = last_attrs;
1207 k->color = this_try_alloc_color_pair (&color);
1208 check_not_a;
1209 }
1210 else if (*(args[0]) == '#')
1211 {
1212
1213 }
1214 else if (strcmp (args[0], "file") == 0)
1215 {
1216 break;
1217 }
1218 else if (strcmp (args[0], "define") == 0)
1219 {
1220 char *key = *a++;
1221 char **argv;
1222
1223 if (argc < 3)
1224 break_a;
1225 argv = g_tree_lookup (edit->defines, key);
1226 if (argv != NULL)
1227 mc_defines_destroy (NULL, argv, NULL);
1228 else
1229 key = g_strdup (key);
1230
1231 argv = g_new (char *, argc - 1);
1232 g_tree_insert (edit->defines, key, argv);
1233 while (*a != NULL)
1234 *argv++ = g_strdup (*a++);
1235 *argv = NULL;
1236 }
1237 else
1238 {
1239
1240 break_a;
1241 }
1242 MC_PTR_FREE (l);
1243 }
1244 MC_PTR_FREE (l);
1245
1246 if (edit->rules->len == 0)
1247 {
1248 g_ptr_array_free (edit->rules, TRUE);
1249 edit->rules = NULL;
1250 }
1251
1252 if (result == 0)
1253 {
1254 size_t i;
1255 GString *first_chars;
1256
1257 if (edit->rules == NULL)
1258 return line;
1259
1260 first_chars = g_string_sized_new (32);
1261
1262
1263 for (i = 0; i < edit->rules->len; i++)
1264 {
1265 size_t j;
1266
1267 g_string_set_size (first_chars, 0);
1268 c = CONTEXT_RULE (g_ptr_array_index (edit->rules, i));
1269
1270 g_string_append_c (first_chars, (char) 1);
1271 for (j = 1; j < c->keyword->len; j++)
1272 {
1273 syntax_keyword_t *k;
1274
1275 k = SYNTAX_KEYWORD (g_ptr_array_index (c->keyword, j));
1276 g_string_append_c (first_chars, k->keyword->str[0]);
1277 }
1278
1279 c->keyword_first_chars = g_strndup (first_chars->str, first_chars->len);
1280 }
1281
1282 g_string_free (first_chars, TRUE);
1283 }
1284
1285 return result;
1286 }
1287
1288
1289
1290
1291 static int
1292 edit_read_syntax_file (WEdit *edit, GPtrArray *pnames, const char *syntax_file,
1293 const char *editor_file, const char *first_line, const char *type)
1294 {
1295 FILE *f, *g = NULL;
1296 char *args[ARGS_LEN], *l = NULL;
1297 long line = 0;
1298 int result = 0;
1299 gboolean found = FALSE;
1300
1301 f = fopen (syntax_file, "r");
1302 if (f == NULL)
1303 {
1304 char *global_syntax_file;
1305
1306 global_syntax_file =
1307 g_build_filename (mc_global.share_data_dir, EDIT_SYNTAX_FILE, (char *) NULL);
1308 f = fopen (global_syntax_file, "r");
1309 g_free (global_syntax_file);
1310 if (f == NULL)
1311 return -1;
1312 }
1313
1314 args[0] = NULL;
1315 while (TRUE)
1316 {
1317 line++;
1318 MC_PTR_FREE (l);
1319 if (read_one_line (&l, f) == 0)
1320 break;
1321 (void) get_args (l, args, ARGS_LEN - 1);
1322 if (args[0] == NULL)
1323 continue;
1324
1325
1326 if (!found && strcmp (args[0], "include") == 0)
1327 {
1328 if (args[1] == NULL || (g = open_include_file (args[1])) == NULL)
1329 {
1330 result = line;
1331 break;
1332 }
1333 goto found_type;
1334 }
1335
1336
1337 if (strcmp (args[0], "file") != 0)
1338 continue;
1339
1340 found = TRUE;
1341
1342
1343 if (args[1] == NULL || args[2] == NULL)
1344 {
1345 result = line;
1346 break;
1347 }
1348
1349 if (pnames != NULL)
1350 {
1351
1352 g_ptr_array_add (pnames, g_strdup (args[2]));
1353 }
1354 else if (type != NULL)
1355 {
1356
1357 if (strcmp (type, args[2]) == 0)
1358 goto found_type;
1359 }
1360 else if (editor_file != NULL && edit != NULL)
1361 {
1362
1363 gboolean q;
1364
1365 q = mc_search (args[1], NULL, editor_file, MC_SEARCH_T_REGEX);
1366
1367 if (!q && args[3] != NULL)
1368 {
1369
1370 q = mc_search (args[3], NULL, first_line, MC_SEARCH_T_REGEX);
1371 }
1372 if (q)
1373 {
1374 int line_error;
1375 char *syntax_type;
1376
1377 found_type:
1378 syntax_type = args[2];
1379 line_error = edit_read_syntax_rules (edit, g ? g : f, args, ARGS_LEN - 1);
1380 if (line_error != 0)
1381 {
1382 if (error_file_name == NULL)
1383 result = line + line_error;
1384 else
1385 result = line_error;
1386 }
1387 else
1388 {
1389 g_free (edit->syntax_type);
1390 edit->syntax_type = g_strdup (syntax_type);
1391
1392 if (g == NULL && edit->rules->len == 1)
1393 {
1394 context_rule_t *r0;
1395
1396 r0 = CONTEXT_RULE (g_ptr_array_index (edit->rules, 0));
1397 if (r0->keyword->len == 1 && !r0->spelling)
1398 {
1399 edit_free_syntax_rules (edit);
1400 break;
1401 }
1402 }
1403 }
1404
1405 if (g == NULL)
1406 break;
1407
1408 fclose (g);
1409 g = NULL;
1410 }
1411 }
1412 }
1413 g_free (l);
1414 fclose (f);
1415 return result;
1416 }
1417
1418
1419
1420 static const char *
1421 get_first_editor_line (WEdit *edit)
1422 {
1423 static char s[256];
1424
1425 s[0] = '\0';
1426
1427 if (edit != NULL)
1428 {
1429 size_t i;
1430
1431 for (i = 0; i < sizeof (s) - 1; i++)
1432 {
1433 s[i] = edit_buffer_get_byte (&edit->buffer, i);
1434 if (s[i] == '\n')
1435 {
1436 s[i] = '\0';
1437 break;
1438 }
1439 }
1440
1441 s[sizeof (s) - 1] = '\0';
1442 }
1443
1444 return s;
1445 }
1446
1447
1448
1449 static int
1450 pstrcmp (const void *p1, const void *p2)
1451 {
1452 return strcmp (*(char *const *) p1, *(char *const *) p2);
1453 }
1454
1455
1456
1457 static int
1458 exec_edit_syntax_dialog (const GPtrArray *names, const char *current_syntax)
1459 {
1460 size_t i;
1461 Listbox *syntaxlist;
1462
1463 syntaxlist =
1464 listbox_window_new (LIST_LINES, MAX_ENTRY_LEN, _ ("Choose syntax highlighting"), NULL);
1465 LISTBOX_APPEND_TEXT (syntaxlist, 'A', _ ("< Auto >"), NULL, FALSE);
1466 LISTBOX_APPEND_TEXT (syntaxlist, 'R', _ ("< Reload Current Syntax >"), NULL, FALSE);
1467
1468 for (i = 0; i < names->len; i++)
1469 {
1470 const char *name;
1471
1472 name = g_ptr_array_index (names, i);
1473 LISTBOX_APPEND_TEXT (syntaxlist, 0, name, NULL, FALSE);
1474 if (current_syntax != NULL && strcmp (name, current_syntax) == 0)
1475 listbox_set_current (syntaxlist->list, i + N_DFLT_ENTRIES);
1476 }
1477
1478 return listbox_run (syntaxlist);
1479 }
1480
1481
1482
1483
1484
1485 int
1486 edit_get_syntax_color (WEdit *edit, off_t byte_index)
1487 {
1488 if (!tty_use_colors ())
1489 return 0;
1490
1491 if (edit_options.syntax_highlighting && edit->rules != NULL && byte_index < edit->buffer.size)
1492 {
1493 edit_get_rule (edit, byte_index);
1494 return translate_rule_to_color (edit, &edit->rule);
1495 }
1496
1497 return EDITOR_NORMAL_COLOR;
1498 }
1499
1500
1501
1502 void
1503 edit_free_syntax_rules (WEdit *edit)
1504 {
1505 if (edit == NULL)
1506 return;
1507
1508 if (edit->defines != NULL)
1509 destroy_defines (&edit->defines);
1510
1511 if (edit->rules == NULL)
1512 return;
1513
1514 edit_get_rule (edit, -1);
1515 MC_PTR_FREE (edit->syntax_type);
1516
1517 g_ptr_array_free (edit->rules, TRUE);
1518 edit->rules = NULL;
1519 g_clear_slist (&edit->syntax_marker, g_free);
1520 tty_color_free_temp ();
1521 }
1522
1523
1524
1525
1526
1527
1528
1529
1530 void
1531 edit_load_syntax (WEdit *edit, GPtrArray *pnames, const char *type)
1532 {
1533 int r;
1534 char *f = NULL;
1535
1536 if (auto_syntax)
1537 type = NULL;
1538
1539 if (edit != NULL)
1540 {
1541 char *saved_type;
1542
1543 saved_type = g_strdup (type);
1544 edit_free_syntax_rules (edit);
1545 edit->syntax_type = saved_type;
1546 }
1547
1548 if (!tty_use_colors ())
1549 return;
1550
1551 if (!edit_options.syntax_highlighting && (pnames == NULL || pnames->len == 0))
1552 return;
1553
1554 if (edit != NULL && edit->filename_vpath == NULL)
1555 return;
1556
1557 f = mc_config_get_full_path (EDIT_SYNTAX_FILE);
1558 if (edit != NULL)
1559 r = edit_read_syntax_file (edit, pnames, f, vfs_path_as_str (edit->filename_vpath),
1560 get_first_editor_line (edit),
1561 auto_syntax ? NULL : edit->syntax_type);
1562 else
1563 r = edit_read_syntax_file (NULL, pnames, f, NULL, "", NULL);
1564 if (r == -1)
1565 {
1566 edit_free_syntax_rules (edit);
1567 file_error_message (_ ("Cannot open file\n%s"), f);
1568 }
1569 else if (r != 0)
1570 {
1571 edit_free_syntax_rules (edit);
1572 message (D_ERROR, _ ("Load syntax file"), _ ("Error in file %s on line %d"),
1573 error_file_name != NULL ? error_file_name : f, r);
1574 MC_PTR_FREE (error_file_name);
1575 }
1576
1577 g_free (f);
1578 }
1579
1580
1581
1582 const char *
1583 edit_get_syntax_type (const WEdit *edit)
1584 {
1585 return edit->syntax_type;
1586 }
1587
1588
1589
1590 void
1591 edit_syntax_dialog (WEdit *edit)
1592 {
1593 GPtrArray *names;
1594 int syntax;
1595
1596 names = g_ptr_array_new_with_free_func (g_free);
1597
1598
1599
1600
1601 edit_load_syntax (NULL, names, NULL);
1602 g_ptr_array_sort (names, pstrcmp);
1603
1604 syntax = exec_edit_syntax_dialog (names, edit->syntax_type);
1605 if (syntax >= 0)
1606 {
1607 gboolean force_reload = FALSE;
1608 char *current_syntax;
1609 gboolean old_auto_syntax;
1610
1611 current_syntax = g_strdup (edit->syntax_type);
1612 old_auto_syntax = auto_syntax;
1613
1614 switch (syntax)
1615 {
1616 case 0:
1617 auto_syntax = TRUE;
1618 break;
1619 case 1:
1620 force_reload = TRUE;
1621 break;
1622 default:
1623 auto_syntax = FALSE;
1624 g_free (edit->syntax_type);
1625 edit->syntax_type = g_strdup (g_ptr_array_index (names, syntax - N_DFLT_ENTRIES));
1626 }
1627
1628
1629 if (force_reload || (auto_syntax && !old_auto_syntax) || old_auto_syntax
1630 || (current_syntax != NULL && edit->syntax_type != NULL
1631 && strcmp (current_syntax, edit->syntax_type) != 0))
1632 edit_load_syntax (edit, NULL, edit->syntax_type);
1633
1634 g_free (current_syntax);
1635 }
1636
1637 g_ptr_array_free (names, TRUE);
1638 }
1639
1640