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