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