1 /* editor syntax highlighting.
3 Copyright (C) 1996, 1997, 1998 the Free Software Foundation
5 Authors: 1998 Paul Sheer
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 #if defined(MIDNIGHT) || defined(GTK)
29 #include "coolwidget.h"
31 #if defined (HAVE_MAD) && ! defined (MIDNIGHT) && ! defined (GTK)
36 #define SYNTAX_MARKER_DENSITY 512
39 Mispelled words are flushed from the syntax highlighting rules
40 when they have been around longer than
41 TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
42 chars per second and say 3 chars + a space per word, we can
43 accumulate 450 words absolute max with a value of 60. This is
44 below this limit of 1024 words in a context.
46 #define TRANSIENT_WORD_TIME_OUT 60
48 #define UNKNOWN_FORMAT "unknown"
50 #if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH)
52 int option_syntax_highlighting
= 1;
53 int option_auto_spellcheck
= 1;
55 /* these three functions are called from the outside */
56 void edit_load_syntax (WEdit
* edit
, char **names
, char *type
);
57 void edit_free_syntax_rules (WEdit
* edit
);
58 void edit_get_syntax_color (WEdit
* edit
, long byte_index
, int *fg
, int *bg
);
61 static void *mad_syntax_malloc (size_t x
, char *file
, int line
)
62 #define syntax_malloc(x) mad_syntax_malloc (x, __FILE__, __LINE__)
64 static void *syntax_malloc (size_t x
)
69 p
= mad_alloc (x
, file
, line
);
77 #define syntax_free(x) {if(x){free(x);(x)=0;}}
79 static long compare_word_to_right (WEdit
* edit
, long i
, char *text
, char *whole_left
, char *whole_right
, int line_start
)
85 c
= edit_get_byte (edit
, i
- 1);
90 if (strchr (whole_left
, c
))
92 for (p
= (unsigned char *) text
, q
= p
+ strlen ((char *) p
); (unsigned long) p
< (unsigned long) q
; p
++, i
++) {
97 c
= edit_get_byte (edit
, i
);
100 if (!strchr (whole_right
, c
))
113 c
= edit_get_byte (edit
, i
);
116 if (*p
== *text
&& !p
[1]) /* handle eg '+' and @+@ keywords properly */
119 if (j
&& strchr ((char *) p
+ 1, c
)) /* c exists further down, so it will get matched later */
121 if (c
== '\n' || c
== '\t' || c
== ' ') {
132 if (!strchr (whole_right
, c
)) {
150 c
= edit_get_byte (edit
, i
);
151 for (j
= 0; p
[j
] != '\003'; j
++)
156 j
= c
; /* dummy command */
166 c
= edit_get_byte (edit
, i
);
167 for (; *p
!= '\004'; p
++)
172 for (; *p
!= '\004'; p
++);
175 if (*p
!= edit_get_byte (edit
, i
))
180 if (strchr (whole_right
, edit_get_byte (edit
, i
)))
186 if (*s < '\005' || *s == (unsigned char) c) \
190 static inline char *xx_strchr (const unsigned char *s
, int c
)
193 XXX XXX XXX XXX XXX XXX XXX XXX
;
194 XXX XXX XXX XXX XXX XXX XXX XXX
;
200 static inline struct syntax_rule
apply_rules_going_right (WEdit
* edit
, long i
, struct syntax_rule rule
)
202 struct context_rule
*r
;
203 int contextchanged
= 0, c
;
204 int found_right
= 0, found_left
= 0, keyword_foundleft
= 0, keyword_foundright
= 0;
207 struct syntax_rule _rule
= rule
;
208 if (!(c
= edit_get_byte (edit
, i
)))
210 is_end
= (rule
.end
== (unsigned char) i
);
211 /* check to turn off a keyword */
214 k
= edit
->rules
[_rule
.context
]->keyword
[_rule
.keyword
];
215 if (edit_get_byte (edit
, i
- 1) == '\n')
219 keyword_foundleft
= 1;
222 /* check to turn off a context */
223 if (_rule
.context
&& !_rule
.keyword
) {
225 r
= edit
->rules
[_rule
.context
];
226 if (r
->first_right
== c
&& !(rule
.border
& RULE_ON_RIGHT_BORDER
) && (e
= compare_word_to_right (edit
, i
, r
->right
, r
->whole_word_chars_left
, r
->whole_word_chars_right
, r
->line_start_right
)) > 0) {
229 _rule
.border
= RULE_ON_RIGHT_BORDER
;
230 if (r
->between_delimiters
)
232 } else if (is_end
&& rule
.border
& RULE_ON_RIGHT_BORDER
) {
233 /* always turn off a context at 4 */
236 if (!keyword_foundleft
)
238 } else if (is_end
&& rule
.border
& RULE_ON_LEFT_BORDER
) {
239 /* never turn off a context at 2 */
244 /* check to turn on a keyword */
245 if (!_rule
.keyword
) {
247 p
= (r
= edit
->rules
[_rule
.context
])->keyword_first_chars
;
248 while (*(p
= xx_strchr ((unsigned char *) p
+ 1, c
))) {
252 count
= (unsigned long) p
- (unsigned long) r
->keyword_first_chars
;
253 k
= r
->keyword
[count
];
254 e
= compare_word_to_right (edit
, i
, k
->keyword
, k
->whole_word_chars_left
, k
->whole_word_chars_right
, k
->line_start
);
258 _rule
.keyword
= count
;
259 keyword_foundright
= 1;
264 /* check to turn on a context */
265 if (!_rule
.context
) {
266 if (!found_left
&& is_end
) {
267 if (rule
.border
& RULE_ON_RIGHT_BORDER
) {
272 } else if (rule
.border
& RULE_ON_LEFT_BORDER
) {
273 r
= edit
->rules
[_rule
._context
];
275 if (r
->between_delimiters
) {
277 _rule
.context
= _rule
._context
;
280 if (r
->first_right
== c
&& (e
= compare_word_to_right (edit
, i
, r
->right
, r
->whole_word_chars_left
, r
->whole_word_chars_right
, r
->line_start_right
)) >= end
) {
283 _rule
.border
= RULE_ON_RIGHT_BORDER
;
291 struct context_rule
**rules
= edit
->rules
;
292 for (count
= 1; rules
[count
]; count
++) {
294 if (r
->first_left
== c
) {
296 e
= compare_word_to_right (edit
, i
, r
->left
, r
->whole_word_chars_left
, r
->whole_word_chars_right
, r
->line_start_left
);
297 if (e
>= end
&& (!_rule
.keyword
|| keyword_foundright
)) {
300 _rule
.border
= RULE_ON_LEFT_BORDER
;
301 _rule
._context
= count
;
302 if (!r
->between_delimiters
)
304 _rule
.context
= count
;
311 /* check again to turn on a keyword if the context switched */
312 if (contextchanged
&& !_rule
.keyword
) {
314 p
= (r
= edit
->rules
[_rule
.context
])->keyword_first_chars
;
315 while (*(p
= xx_strchr ((unsigned char *) p
+ 1, c
))) {
319 count
= (unsigned long) p
- (unsigned long) r
->keyword_first_chars
;
320 k
= r
->keyword
[count
];
321 e
= compare_word_to_right (edit
, i
, k
->keyword
, k
->whole_word_chars_left
, k
->whole_word_chars_right
, k
->line_start
);
324 _rule
.keyword
= count
;
332 static struct syntax_rule
edit_get_rule (WEdit
* edit
, long byte_index
)
335 if (byte_index
> edit
->last_get_rule
) {
336 for (i
= edit
->last_get_rule
+ 1; i
<= byte_index
; i
++) {
337 edit
->rule
= apply_rules_going_right (edit
, i
, edit
->rule
);
338 if (i
> (edit
->syntax_marker
? edit
->syntax_marker
->offset
+ SYNTAX_MARKER_DENSITY
: SYNTAX_MARKER_DENSITY
)) {
339 struct _syntax_marker
*s
;
340 s
= edit
->syntax_marker
;
341 edit
->syntax_marker
= syntax_malloc (sizeof (struct _syntax_marker
));
342 edit
->syntax_marker
->next
= s
;
343 edit
->syntax_marker
->offset
= i
;
344 edit
->syntax_marker
->rule
= edit
->rule
;
347 } else if (byte_index
< edit
->last_get_rule
) {
348 struct _syntax_marker
*s
;
350 if (!edit
->syntax_marker
) {
351 memset (&edit
->rule
, 0, sizeof (edit
->rule
));
352 for (i
= -1; i
<= byte_index
; i
++)
353 edit
->rule
= apply_rules_going_right (edit
, i
, edit
->rule
);
356 if (byte_index
>= edit
->syntax_marker
->offset
) {
357 edit
->rule
= edit
->syntax_marker
->rule
;
358 for (i
= edit
->syntax_marker
->offset
+ 1; i
<= byte_index
; i
++)
359 edit
->rule
= apply_rules_going_right (edit
, i
, edit
->rule
);
362 s
= edit
->syntax_marker
->next
;
363 syntax_free (edit
->syntax_marker
);
364 edit
->syntax_marker
= s
;
367 edit
->last_get_rule
= byte_index
;
371 static void translate_rule_to_color (WEdit
* edit
, struct syntax_rule rule
, int *fg
, int *bg
)
374 k
= edit
->rules
[rule
.context
]->keyword
[rule
.keyword
];
379 extern int use_colors
;
381 void edit_get_syntax_color (WEdit
* edit
, long byte_index
, int *fg
, int *bg
)
383 if (edit
->rules
&& byte_index
< edit
->last_byte
&&
384 option_syntax_highlighting
&& use_colors
) {
385 translate_rule_to_color (edit
, edit_get_rule (edit
, byte_index
), fg
, bg
);
388 *fg
= EDITOR_NORMAL_COLOR
;
398 Returns 0 on error/eof or a count of the number of bytes read
399 including the newline. Result must be free'd.
402 static int mad_read_one_line (char **line
, FILE * f
, char *file
, int line_
)
403 #define read_one_line(a,b) mad_read_one_line(a,b,__FILE__,__LINE__)
405 static int read_one_line (char **line
, FILE * f
)
409 int len
= 256, c
, r
= 0, i
= 0;
411 p
= mad_syntax_malloc (len
, file
, line_
);
413 p
= syntax_malloc (len
);
422 } else if (c
== '\n') {
423 r
= i
+ 1; /* extra 1 for the newline just read */
428 q
= syntax_malloc (len
* 2);
442 static char *strdup_convert (char *s
)
445 p
= r
= (char *) strdup (s
);
503 #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
505 static void get_args (char *l
, char **args
, int *argc
)
511 for (p
= l
+ 1; *p
&& whiteness (*p
); p
++);
514 for (l
= p
+ 1; *l
&& !whiteness (*l
); l
++);
516 *args
= strdup_convert (p
);
523 static void free_args (char **args
)
532 #define check_a {if(!*a){result=line;break;}}
533 #define check_not_a {if(*a){result=line;break;}}
537 int try_alloc_color_pair (char *fg
, char *bg
);
539 int this_try_alloc_color_pair (char *fg
, char *bg
)
541 char f
[80], b
[80], *p
;
562 return try_alloc_color_pair (fg
, bg
);
566 int allocate_color (WEdit
*edit
, gchar
*color
);
568 int this_allocate_color (WEdit
*edit
, char *fg
)
575 return allocate_color (edit
, 0);
576 p
= strchr (fg
, '/');
578 return allocate_color (edit
, fg
);
579 return allocate_color (edit
, p
+ 1);
582 int this_allocate_color (WEdit
*edit
, char *fg
)
589 return allocate_color (0);
590 p
= strchr (fg
, '/');
592 return allocate_color (fg
);
593 return allocate_color (p
+ 1);
596 #endif /* MIDNIGHT */
598 static char *error_file_name
= 0;
600 static FILE *open_include_file (char *filename
)
603 char p
[MAX_PATH_LEN
];
604 syntax_free (error_file_name
);
605 error_file_name
= (char *) strdup (filename
);
606 if (*filename
== '/')
607 return fopen (filename
, "r");
608 strcpy (p
, home_dir
);
609 strcat (p
, EDIT_DIR
"/");
610 strcat (p
, filename
);
611 syntax_free (error_file_name
);
612 error_file_name
= (char *) strdup (p
);
617 strcpy (p
, LIBDIR
"/syntax/");
620 strcat (p
, "/syntax/");
622 strcat (p
, filename
);
623 syntax_free (error_file_name
);
624 error_file_name
= (char *) strdup (p
);
625 return fopen (p
, "r");
628 /* returns line number on error */
629 static int edit_read_syntax_rules (WEdit
* edit
, FILE * f
)
633 char last_fg
[32] = "", last_bg
[32] = "";
634 char whole_right
[512];
635 char whole_left
[512];
636 char *args
[1024], *l
= 0;
637 int save_line
= 0, line
= 0;
638 struct context_rule
**r
, *c
= 0;
639 int num_words
= -1, num_contexts
= -1;
640 int argc
, result
= 0;
645 strcpy (whole_left
, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
646 strcpy (whole_right
, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
648 r
= edit
->rules
= syntax_malloc (MAX_CONTEXTS
* sizeof (struct context_rule
*));
654 if (!read_one_line (&l
, f
)) {
659 line
= save_line
+ 1;
660 syntax_free (error_file_name
);
663 if (!read_one_line (&l
, f
))
669 get_args (l
, args
, &argc
);
673 } else if (!strcmp (args
[0], "include")) {
674 if (g
|| argc
!= 2) {
679 f
= open_include_file (args
[1]);
681 syntax_free (error_file_name
);
687 } else if (!strcmp (args
[0], "wholechars")) {
689 if (!strcmp (*a
, "left")) {
691 strcpy (whole_left
, *a
);
692 } else if (!strcmp (*a
, "right")) {
694 strcpy (whole_right
, *a
);
696 strcpy (whole_left
, *a
);
697 strcpy (whole_right
, *a
);
701 } else if (!strcmp (args
[0], "context")) {
703 if (num_contexts
== -1) {
704 if (strcmp (*a
, "default")) { /* first context is the default */
709 c
= r
[0] = syntax_malloc (sizeof (struct context_rule
));
710 c
->left
= (char *) strdup (" ");
711 c
->right
= (char *) strdup (" ");
714 c
= r
[num_contexts
] = syntax_malloc (sizeof (struct context_rule
));
715 if (!strcmp (*a
, "exclusive")) {
717 c
->between_delimiters
= 1;
720 if (!strcmp (*a
, "whole")) {
722 c
->whole_word_chars_left
= (char *) strdup (whole_left
);
723 c
->whole_word_chars_right
= (char *) strdup (whole_right
);
724 } else if (!strcmp (*a
, "wholeleft")) {
726 c
->whole_word_chars_left
= (char *) strdup (whole_left
);
727 } else if (!strcmp (*a
, "wholeright")) {
729 c
->whole_word_chars_right
= (char *) strdup (whole_right
);
732 if (!strcmp (*a
, "linestart")) {
734 c
->line_start_left
= 1;
737 c
->left
= (char *) strdup (*a
++);
739 if (!strcmp (*a
, "linestart")) {
741 c
->line_start_right
= 1;
744 c
->right
= (char *) strdup (*a
++);
745 c
->first_left
= *c
->left
;
746 c
->first_right
= *c
->right
;
747 c
->single_char
= (strlen (c
->right
) == 1);
749 c
->keyword
= syntax_malloc (MAX_WORDS_PER_CONTEXT
* sizeof (struct key_word
*));
751 c
->max_words
= MAX_WORDS_PER_CONTEXT
;
754 c
->keyword
[0] = syntax_malloc (sizeof (struct key_word
));
761 strcpy (last_fg
, fg
? fg
: "");
762 strcpy (last_bg
, bg
? bg
: "");
764 c
->keyword
[0]->fg
= this_try_alloc_color_pair (fg
, bg
);
766 c
->keyword
[0]->fg
= this_allocate_color (edit
, fg
);
767 c
->keyword
[0]->bg
= this_allocate_color (edit
, bg
);
769 c
->keyword
[0]->keyword
= (char *) strdup (" ");
772 } else if (!strcmp (args
[0], "spellcheck")) {
778 } else if (!strcmp (args
[0], "keyword")) {
783 k
= r
[num_contexts
- 1]->keyword
[num_words
] = syntax_malloc (sizeof (struct key_word
));
784 if (!strcmp (*a
, "whole")) {
786 k
->whole_word_chars_left
= (char *) strdup (whole_left
);
787 k
->whole_word_chars_right
= (char *) strdup (whole_right
);
788 } else if (!strcmp (*a
, "wholeleft")) {
790 k
->whole_word_chars_left
= (char *) strdup (whole_left
);
791 } else if (!strcmp (*a
, "wholeright")) {
793 k
->whole_word_chars_right
= (char *) strdup (whole_right
);
796 if (!strcmp (*a
, "linestart")) {
801 if (!strcmp (*a
, "whole")) {
805 k
->keyword
= (char *) strdup (*a
++);
806 k
->first
= *k
->keyword
;
818 k
->fg
= this_try_alloc_color_pair (fg
, bg
);
820 k
->fg
= this_allocate_color (edit
, fg
);
821 k
->bg
= this_allocate_color (edit
, bg
);
825 } else if (!strncmp (args
[0], "#", 1)) {
826 /* do nothing for comment */
827 } else if (!strcmp (args
[0], "file")) {
829 } else { /* anything else is an error */
840 syntax_free (edit
->rules
);
845 if (num_contexts
== -1) {
851 char first_chars
[MAX_WORDS_PER_CONTEXT
+ 2], *p
;
852 for (i
= 0; edit
->rules
[i
]; i
++) {
856 for (j
= 1; c
->keyword
[j
]; j
++)
857 *p
++ = c
->keyword
[j
]->first
;
859 c
->keyword_first_chars
= syntax_malloc (strlen (first_chars
) + 2);
860 strcpy (c
->keyword_first_chars
, first_chars
);
867 #if !defined (GTK) && !defined (MIDNIGHT)
869 /* strdup and append c */
870 static char *strdupc (char *s
, int c
)
874 strcpy (t
= syntax_malloc ((l
= strlen (s
)) + 3), s
);
880 static void edit_syntax_clear_keyword (WEdit
* edit
, int context
, int j
)
882 struct context_rule
*c
;
883 struct _syntax_marker
*s
;
884 c
= edit
->rules
[context
];
885 /* first we clear any instances of this keyword in our cache chain (we used to just clear the cache chain, but this slows things down) */
886 for (s
= edit
->syntax_marker
; s
; s
= s
->next
)
887 if (s
->rule
.keyword
== j
)
889 else if (s
->rule
.keyword
> j
)
891 syntax_free (c
->keyword
[j
]->keyword
);
892 syntax_free (c
->keyword
[j
]->whole_word_chars_left
);
893 syntax_free (c
->keyword
[j
]->whole_word_chars_right
);
894 syntax_free (c
->keyword
[j
]);
895 memcpy (&c
->keyword
[j
], &c
->keyword
[j
+ 1], (MAX_WORDS_PER_CONTEXT
- j
- 1) * sizeof (struct keyword
*));
896 strcpy (&c
->keyword_first_chars
[j
], &c
->keyword_first_chars
[j
+ 1]);
900 FILE *spelling_pipe_in
= 0;
901 FILE *spelling_pipe_out
= 0;
902 pid_t ispell_pid
= 0;
905 /* adds a keyword for underlining into the keyword list for this context, returns 1 if too many words */
906 static int edit_syntax_add_keyword (WEdit
* edit
, char *keyword
, int context
, time_t t
)
910 struct context_rule
*c
;
911 c
= edit
->rules
[context
];
912 for (j
= 1; c
->keyword
[j
]; j
++) {
913 /* if a keyword has been around for more than TRANSIENT_WORD_TIME_OUT
914 seconds, then remove it - we don't want to run out of space or makes syntax highlighting to slow */
915 if (c
->keyword
[j
]->time
) {
916 if (c
->keyword
[j
]->time
+ TRANSIENT_WORD_TIME_OUT
< t
) {
917 edit
->force
|= REDRAW_PAGE
;
918 edit_syntax_clear_keyword (edit
, context
, j
);
923 /* are we out of space? */
924 if (j
>= MAX_WORDS_PER_CONTEXT
- 2)
926 /* add the new keyword and date it */
927 c
->keyword
[j
+ 1] = 0;
928 c
->keyword
[j
] = syntax_malloc (sizeof (struct key_word
));
930 c
->keyword
[j
]->fg
= SPELLING_ERROR
;
932 c
->keyword
[j
]->fg
= c
->keyword
[0]->fg
;
933 c
->keyword
[j
]->bg
= SPELLING_ERROR
;
935 c
->keyword
[j
]->keyword
= (char *) strdup (keyword
);
936 c
->keyword
[j
]->first
= *c
->keyword
[j
]->keyword
;
937 c
->keyword
[j
]->whole_word_chars_left
= (char *) strdup ("-'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ¡¢£¤¥¦§§¨©©ª«¬®®¯°±²³´µ¶¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ");
938 c
->keyword
[j
]->whole_word_chars_right
= (char *) strdup ("-'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ¡¢£¤¥¦§§¨©©ª«¬®®¯°±²³´µ¶¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ");
939 c
->keyword
[j
]->time
= t
;
940 s
= strdupc (c
->keyword_first_chars
, c
->keyword
[j
]->first
);
941 syntax_free (c
->keyword_first_chars
);
942 c
->keyword_first_chars
= s
;
946 /* checks spelling of the word at offset */
947 static int edit_check_spelling_at (WEdit
* edit
, long byte_index
)
951 unsigned char *p
, *q
;
955 struct context_rule
*c
;
957 if (!edit
->rules
|| byte_index
> edit
->last_byte
)
959 /* in what context are we */
960 context
= edit_get_rule (edit
, byte_index
).context
;
961 c
= edit
->rules
[context
];
962 /* does this context have `spellcheck' */
963 if (!edit
->rules
[context
]->spelling
)
965 /* find word start */
966 for (p1
= byte_index
- 1;; p1
--) {
967 ch
= edit_get_byte (edit
, p1
);
968 if (isalpha (ch
) || ch
== '-' || ch
== '\'')
974 for (p2
= byte_index
;; p2
++) {
975 ch
= edit_get_byte (edit
, p2
);
976 if (isalpha (ch
) || ch
== '-' || ch
== '\'')
983 q
= p
= syntax_malloc (p2
- p1
+ 2);
984 for (; p1
< p2
; p1
++)
985 *p
++ = edit_get_byte (edit
, p1
);
987 if (q
[0] == '-' || strlen ((char *) q
) > 40) { /* if you are using words over 40 characters, you are on your own */
992 for (j
= 1; c
->keyword
[j
]; j
++) {
993 /* if the keyword is present, then update its time only. if it is a fixed keyword from the rules file, then just return */
994 if (!strcmp (c
->keyword
[j
]->keyword
, (char *) q
)) {
995 if (c
->keyword
[j
]->time
)
996 c
->keyword
[j
]->time
= t
;
1001 /* feed it to ispell */
1002 fprintf (spelling_pipe_out
, "%s\n", (char *) q
);
1003 fflush (spelling_pipe_out
);
1004 /* what does ispell say? */
1006 r
= fgetc (spelling_pipe_in
);
1007 } while (r
== -1 && errno
== EINTR
);
1012 if (r
== '\n') { /* ispell sometimes returns just blank line if it is given bad characters */
1016 /* now read ispell output untill we get two blanks lines - we are not intersted in this part */
1018 c1
= fgetc (spelling_pipe_in
);
1019 } while (c1
== -1 && errno
== EINTR
);
1026 c2
= fgetc (spelling_pipe_in
);
1027 } while (c2
== -1 && errno
== EINTR
);
1028 if (c1
== '\n' && c2
== '\n')
1033 if (r
== '*' || r
== '+' || r
== '-') {
1037 /* not spelled ok - so add a syntax keyword for this word */
1038 edit_syntax_add_keyword (edit
, (char *) q
, context
, t
);
1043 char *option_alternate_dictionary
= "";
1045 int edit_check_spelling (WEdit
* edit
)
1047 if (!option_auto_spellcheck
)
1049 /* magic arg to close up shop */
1051 option_auto_spellcheck
= 0;
1052 goto close_spelling
;
1054 /* do we at least have a syntax rule struct to put new wrongly spelled keyword in for highlighting? */
1055 if (!edit
->rules
&& !edit
->explicit_syntax
)
1056 edit_load_syntax (edit
, 0, UNKNOWN_FORMAT
);
1058 option_auto_spellcheck
= 0;
1061 /* is ispell running? */
1062 if (!spelling_pipe_in
) {
1065 arg
[a
++] = "ispell";
1067 if (option_alternate_dictionary
)
1068 if (*option_alternate_dictionary
) {
1070 arg
[a
++] = option_alternate_dictionary
;
1074 /* start ispell process */
1075 ispell_pid
= triple_pipe_open (&in
, &out
, 0, 1, arg
[0], arg
);
1076 if (ispell_pid
< 1) {
1077 option_auto_spellcheck
= 0;
1079 CErrorDialog (0, 0, 0, _ (" Spelling Message "), "%s", _ (" Fail trying to open ispell program. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
1084 spelling_pipe_in
= (FILE *) fdopen (out
, "r");
1085 spelling_pipe_out
= (FILE *) fdopen (in
, "w");
1086 if (!spelling_pipe_in
|| !spelling_pipe_out
) {
1087 option_auto_spellcheck
= 0;
1088 CErrorDialog (0, 0, 0, _ (" Spelling Message "), "%s", _ (" Fail trying to open ispell pipes. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
1091 /* read the banner message */
1094 c1
= fgetc (spelling_pipe_in
);
1095 if (c1
== -1 && errno
!= EINTR
) {
1096 option_auto_spellcheck
= 0;
1097 CErrorDialog (0, 0, 0, _ (" Spelling Message "), "%s", _ (" Fail trying to read ispell pipes. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
1104 /* spellcheck the word under the cursor */
1105 if (edit_check_spelling_at (edit
, edit
->curs1
)) {
1106 CMessageDialog (0, 0, 0, 0, _ (" Spelling Message "), "%s", _ (" Error reading from ispell. \n Ispell is being restarted. "));
1108 fclose (spelling_pipe_in
);
1109 spelling_pipe_in
= 0;
1110 fclose (spelling_pipe_out
);
1111 spelling_pipe_out
= 0;
1112 kill (ispell_pid
, SIGKILL
);
1117 #else /* ! GTK && ! MIDNIGHT*/
1119 int edit_check_spelling (WEdit
* edit
)
1126 void (*syntax_change_callback
) (CWidget
*) = 0;
1128 void edit_set_syntax_change_callback (void (*callback
) (CWidget
*))
1130 syntax_change_callback
= callback
;
1133 void edit_free_syntax_rules (WEdit
* edit
)
1140 edit_get_rule (edit
, -1);
1141 syntax_free (edit
->syntax_type
);
1142 edit
->syntax_type
= 0;
1143 if (syntax_change_callback
)
1145 (*syntax_change_callback
) (&edit
->widget
);
1147 (*syntax_change_callback
) (edit
->widget
);
1149 for (i
= 0; edit
->rules
[i
]; i
++) {
1150 if (edit
->rules
[i
]->keyword
) {
1151 for (j
= 0; edit
->rules
[i
]->keyword
[j
]; j
++) {
1152 syntax_free (edit
->rules
[i
]->keyword
[j
]->keyword
);
1153 syntax_free (edit
->rules
[i
]->keyword
[j
]->whole_word_chars_left
);
1154 syntax_free (edit
->rules
[i
]->keyword
[j
]->whole_word_chars_right
);
1155 syntax_free (edit
->rules
[i
]->keyword
[j
]);
1158 syntax_free (edit
->rules
[i
]->left
);
1159 syntax_free (edit
->rules
[i
]->right
);
1160 syntax_free (edit
->rules
[i
]->whole_word_chars_left
);
1161 syntax_free (edit
->rules
[i
]->whole_word_chars_right
);
1162 syntax_free (edit
->rules
[i
]->keyword
);
1163 syntax_free (edit
->rules
[i
]->keyword_first_chars
);
1164 syntax_free (edit
->rules
[i
]);
1166 while (edit
->syntax_marker
) {
1167 struct _syntax_marker
*s
= edit
->syntax_marker
->next
;
1168 syntax_free (edit
->syntax_marker
);
1169 edit
->syntax_marker
= s
;
1171 syntax_free (edit
->rules
);
1174 #define CURRENT_SYNTAX_RULES_VERSION "62"
1176 static const char * const syntax_text
[] = {
1177 "# syntax rules version " CURRENT_SYNTAX_RULES_VERSION
,
1178 "# (after the slash is a Cooledit color, 0-26 or any of the X colors in rgb.txt)",
1196 "file gobledy_gook #\\sHelp\\ssupport\\sother\\sfile\\stypes",
1198 "file gobledy_gook #\\sby\\scoding\\srules\\sin\\s~/.cedit/syntax.",
1200 "file gobledy_gook #\\sSee\\sman/syntax\\sin\\sthe\\ssource\\sdistribution",
1202 "file gobledy_gook #\\sand\\sconsult\\sthe\\sman\\spage.",
1206 "file ..\\*\\\\.(diff|rej|patch)$ Diff\\sOutput ^diff",
1207 "include diff.syntax",
1209 "file ..\\*\\\\.lsm$ LSM\\sFile",
1210 "include lsm.syntax",
1212 "file ..\\*\\\\.sh$ Shell\\sScript ^#!\\s\\*/.\\*/(ksh|bash|sh|pdkzsh)",
1213 "include sh.syntax",
1215 "file ..\\*\\\\.(pl|PL|pm|PM])$ Perl\\sProgram ^#!\\s\\*/.\\*/perl",
1216 "include perl.syntax",
1218 "file ..\\*\\\\.(py|PY])$ Python\\sProgram ^#!\\s\\*/.\\*/python",
1219 "include python.syntax",
1221 "file ..\\*\\\\.(man|[0-9n]|[0-9]x)$ NROFF\\sSource",
1222 "include nroff.syntax",
1224 "file ..\\*\\\\.(htm|html|HTM|HTML)$ HTML\\sFile",
1225 "include html.syntax",
1227 "file ..\\*\\\\.(pp|PP|pas|PAS)$ Pascal\\sProgram",
1228 "include pascal.syntax",
1230 "file ..\\*\\\\.(ada|adb|ads|ADA|ADB|ADS)$ Ada\\sProgram",
1231 "include ada95.syntax",
1233 "file ..\\*\\\\.tex$ LaTeX\\s2.09\\sDocument",
1234 "include latex.syntax",
1236 "file ..\\*\\.(texi|texinfo|TEXI|TEXINFO)$ Texinfo\\sDocument",
1237 "include texinfo.syntax",
1239 "file ..\\*\\\\.([chC]|CC|cxx|cc|cpp|CPP|CXX)$ C/C\\+\\+\\sProgram",
1242 "file ..\\*\\\\.[fF]$ Fortran\\sProgram",
1243 "include fortran.syntax",
1245 "file ..\\*\\\\.i$ SWIG\\sSource",
1246 "include swig.syntax",
1248 "file ..\\*\\\\.(java|JAVA|Java|jav)$ Java\\sProgram",
1249 "include java.syntax",
1251 "file ..\\*\\\\.(st)$ SmallTalk\\sProgram",
1252 "include smalltalk.syntax",
1254 "file ..\\*\\\\.(ml|mli|mly|mll|mlp)$ ML\\sProgram",
1255 "include ml.syntax",
1257 "file ..\\*\\\\.m$ Matlab\\sor\\sOctave\\sFile",
1258 "include octave.syntax",
1260 "file .\\*ChangeLog$ GNU\\sDistribution\\sChangeLog\\sFile",
1261 "include changelog.syntax",
1263 "file .\\*[Mm]akefile[\\\\\\.a-z]\\*$ Makefile",
1264 "include makefile.syntax",
1266 "file Don_t_match_me Mail\\sfolder ^From\\s",
1267 "include mail.syntax",
1269 "file .\\*syntax$ Syntax\\sHighlighting\\sdefinitions",
1272 " keyword whole spellch\\eck yellow/24",
1273 " keyword whole keyw\\ord yellow/24",
1274 " keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17",
1275 " keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17",
1276 " keyword whole wh\\oleleft\\[\\t\\s\\]l\\inestart brightcyan/17",
1277 " keyword whole wh\\oleright\\[\\t\\s\\]l\\inestart brightcyan/17",
1278 " keyword whole l\\inestart\\[\\t\\s\\]wh\\ole",
1279 " keyword whole l\\inestart\\[\\t\\s\\]wh\\ole",
1280 " keyword whole l\\inestart\\[\\t\\s\\]wh\\oleleft",
1281 " keyword whole l\\inestart\\[\\t\\s\\]wh\\oleright",
1282 " keyword wholeleft whole\\s brightcyan/17",
1283 " keyword wholeleft whole\\t brightcyan/17",
1284 " keyword whole wh\\oleleft brightcyan/17",
1285 " keyword whole wh\\oleright brightcyan/17",
1286 " keyword whole lin\\[e\\]start brightcyan/17",
1287 " keyword whole c\\ontext\\[\\t\\s\\]exclusive brightred/18",
1288 " keyword whole c\\ontext\\[\\t\\s\\]default brightred/18",
1289 " keyword whole c\\ontext brightred/18",
1290 " keyword whole wh\\olechars\\[\\t\\s\\]left brightcyan/17",
1291 " keyword whole wh\\olechars\\[\\t\\s\\]right brightcyan/17",
1292 " keyword whole wh\\olechars brightcyan/17",
1293 " keyword whole f\\ile brightgreen/6",
1294 " keyword whole in\\clude brightred/18",
1296 " keyword whole 0 lightgray/0 blue/26",
1297 " keyword whole 1 lightgray/1 blue/26",
1298 " keyword whole 2 lightgray/2 blue/26",
1299 " keyword whole 3 lightgray/3 blue/26",
1300 " keyword whole 4 lightgray/4 blue/26",
1301 " keyword whole 5 lightgray/5 blue/26",
1302 " keyword whole 6 lightgray/6",
1303 " keyword whole 7 lightgray/7",
1304 " keyword whole 8 lightgray/8",
1305 " keyword whole 9 lightgray/9",
1306 " keyword whole 10 lightgray/10",
1307 " keyword whole 11 lightgray/11",
1308 " keyword whole 12 lightgray/12",
1309 " keyword whole 13 lightgray/13",
1310 " keyword whole 14 lightgray/14",
1311 " keyword whole 15 lightgray/15",
1312 " keyword whole 16 lightgray/16",
1313 " keyword whole 17 lightgray/17",
1314 " keyword whole 18 lightgray/18",
1315 " keyword whole 19 lightgray/19",
1316 " keyword whole 20 lightgray/20",
1317 " keyword whole 21 lightgray/21",
1318 " keyword whole 22 lightgray/22",
1319 " keyword whole 23 lightgray/23",
1320 " keyword whole 24 lightgray/24",
1321 " keyword whole 25 lightgray/25",
1322 " keyword whole 26 lightgray/26",
1324 " keyword wholeleft black\\/ black/0",
1325 " keyword wholeleft red\\/ red/DarkRed",
1326 " keyword wholeleft green\\/ green/green3",
1327 " keyword wholeleft brown\\/ brown/saddlebrown",
1328 " keyword wholeleft blue\\/ blue/blue3",
1329 " keyword wholeleft magenta\\/ magenta/magenta3",
1330 " keyword wholeleft cyan\\/ cyan/cyan3",
1331 " keyword wholeleft lightgray\\/ lightgray/lightgray",
1332 " keyword wholeleft gray\\/ gray/gray",
1333 " keyword wholeleft brightred\\/ brightred/red",
1334 " keyword wholeleft brightgreen\\/ brightgreen/green1",
1335 " keyword wholeleft yellow\\/ yellow/yellow",
1336 " keyword wholeleft brightblue\\/ brightblue/blue1",
1337 " keyword wholeleft brightmagenta\\/ brightmagenta/magenta",
1338 " keyword wholeleft brightcyan\\/ brightcyan/cyan1",
1339 " keyword wholeleft white\\/ white/26",
1341 "context linestart # \\n brown/22",
1343 "file .\\* " UNKNOWN_FORMAT
,
1344 "include unknown.syntax",
1349 FILE *upgrade_syntax_file (char *syntax_file
)
1354 f
= fopen (syntax_file
, "r");
1356 const char * const *syntax_line
;
1358 f
= fopen (syntax_file
, "w");
1361 for (syntax_line
= syntax_text
; *syntax_line
; syntax_line
++)
1362 fprintf (f
, "%s\n", *syntax_line
);
1364 return fopen (syntax_file
, "r");
1366 memset (line
, 0, sizeof (line
));
1367 fread (line
, sizeof (line
) - 1, 1, f
);
1368 if (!strstr (line
, "syntax rules version"))
1369 goto rename_rule_file
;
1370 p
= strstr (line
, "version") + strlen ("version") + 1;
1371 if (atoi (p
) < atoi (CURRENT_SYNTAX_RULES_VERSION
)) {
1375 strcpy (s
, syntax_file
);
1378 rename (syntax_file
, s
);
1379 unlink (syntax_file
); /* might rename() fail ? */
1380 #if defined(MIDNIGHT) || defined(GTK)
1381 edit_message_dialog (_(" Load Syntax Rules "), _(" Your syntax rule file is outdated \n A new rule file is being installed. \n Your old rule file has been saved with a .OLD extension. "));
1383 CMessageDialog (0, 20, 20, 0,_(" Load Syntax Rules "), _(" Your syntax rule file is outdated \n A new rule file is being installed. \n Your old rule file has been saved with a .OLD extension. "));
1385 goto rewrite_rule_file
;
1391 /* returns -1 on file error, line number on error in file syntax */
1392 static int edit_read_syntax_file (WEdit
* edit
, char **names
, char *syntax_file
, char *editor_file
, char *first_line
, char *type
)
1396 regmatch_t pmatch
[1];
1397 char *args
[1024], *l
= 0;
1402 f
= upgrade_syntax_file (syntax_file
);
1409 if (!read_one_line (&l
, f
))
1411 get_args (l
, args
, &argc
);
1414 /* looking for `file ...' lines only */
1415 if (strcmp (args
[0], "file")) {
1419 /* must have two args or report error */
1420 if (!args
[1] || !args
[2]) {
1425 /* 1: just collecting a list of names of rule sets */
1426 names
[count
++] = (char *) strdup (args
[2]);
1429 /* 2: rule set was explicitly specified by the caller */
1430 if (!strcmp (type
, args
[2]))
1432 } else if (editor_file
&& edit
) {
1433 /* 3: auto-detect rule set from regular expressions */
1435 if (regcomp (&r
, args
[1], REG_EXTENDED
)) {
1439 /* does filename match arg 1 ? */
1440 q
= !regexec (&r
, editor_file
, 1, pmatch
, 0);
1442 if (!q
&& args
[3]) {
1443 if (regcomp (&r
, args
[3], REG_EXTENDED
)) {
1447 /* does first line match arg 3 ? */
1448 q
= !regexec (&r
, first_line
, 1, pmatch
, 0);
1454 line_error
= edit_read_syntax_rules (edit
, f
);
1456 if (!error_file_name
) /* an included file */
1457 result
= line
+ line_error
;
1459 result
= line_error
;
1461 syntax_free (edit
->syntax_type
);
1462 edit
->syntax_type
= (char *) strdup (args
[2]);
1463 /* if there are no rules then turn off syntax highlighting for speed */
1464 if (!edit
->rules
[1])
1465 if (!edit
->rules
[0]->keyword
[1] && !edit
->rules
[0]->spelling
) {
1466 edit_free_syntax_rules (edit
);
1469 /* notify the callback of a change in rule set */
1470 if (syntax_change_callback
)
1472 (*syntax_change_callback
) (&edit
->widget
);
1474 (*syntax_change_callback
) (edit
->widget
);
1488 static char *get_first_editor_line (WEdit
* edit
)
1495 for (i
= 0; i
< 255; i
++) {
1496 s
[i
] = edit_get_byte (edit
, i
);
1506 /* loads rules into edit struct. one of edit or names must be zero. if
1507 edit is zero, a list of types will be stored into name. type may be zero
1508 in which case the type will be selected according to the filename. */
1509 void edit_load_syntax (WEdit
* edit
, char **names
, char *type
)
1514 edit_free_syntax_rules (edit
);
1517 if (!edit
->filename
)
1519 if (!*edit
->filename
&& !type
)
1522 f
= catstrs (home_dir
, SYNTAX_FILE
, 0);
1523 r
= edit_read_syntax_file (edit
, names
, f
, edit
? edit
->filename
: 0, get_first_editor_line (edit
), type
);
1525 edit_free_syntax_rules (edit
);
1526 edit_error_dialog (_ (" Load syntax file "), _ (" File access error "));
1531 edit_free_syntax_rules (edit
);
1532 sprintf (s
, _ (" Error in file %s on line %d "), error_file_name
? error_file_name
: f
, r
);
1533 edit_error_dialog (_ (" Load syntax file "), s
);
1534 syntax_free (error_file_name
);
1541 int option_syntax_highlighting
= 0;
1543 void edit_load_syntax (WEdit
* edit
, char **names
, char *type
)
1548 void edit_free_syntax_rules (WEdit
* edit
)
1553 void edit_get_syntax_color (WEdit
* edit
, long byte_index
, int *fg
, int *bg
)
1558 int edit_check_spelling (WEdit
* edit
)
1563 #endif /* !defined(MIDNIGHT) || defined(HAVE_SYNTAXH) */