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