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