1 /* -*- mode: C; mode: fold; -*- */
2 /* Copyright (c) 1992, 1998, 2000, 2002, 2003, 2004, 2005, 2006 John E. Davis
3 * This file is part of JED editor library source.
4 *
5 * You may distribute this file under the terms the GNU General Public
6 * License. See the file COPYING for more information.
7 */
8 #include "config.h"
9 #include "jed-feat.h"
10 /*{{{ Include Files */
11
12 #include <stdio.h>
13 #include <string.h>
14 #include "buffer.h"
15 #include "window.h"
16 #include "misc.h"
17 #include "cmds.h"
18 #include "display.h"
19 #include "ledit.h"
20 #include "screen.h"
21 #include "sysdep.h"
22 #include "search.h"
23 #include "paste.h"
24 #include "misc.h"
25 #include "indent.h"
26
27 /*}}}*/
28
29 /* Note: In this file, "UTF-8 ASCII safe" means that the routine will work
30 * properly as long as we are dealing with ASCII characters for quotes and
31 * comment strings.
32 *
33 * "UTF-8 WORD UNsafe" indicates that the routine is not safe when non-ASCII
34 * characters are given the word syntax.
35 *
36 * ASCII means character codes 0-127.
37 */
38 Syntax_Table_Type *Default_Syntax_Table;
39
40 static Syntax_Table_Type *Syntax_Tables;
41
42 /* UTF-8 ASCII safe */
find_comment_end(Syntax_Table_Type * table,unsigned char * p,unsigned char * pmax)43 static unsigned char *find_comment_end (Syntax_Table_Type *table,
44 unsigned char *p, unsigned char *pmax)
45 {
46 unsigned int len;
47 char *str;
48 unsigned char ch;
49 /* unsigned char quote; */
50
51 str = table->comment_stop;
52 len = table->comment_stop_len;
53
54 if ((str == NULL) || (len == 0))
55 return NULL;
56
57 pmax -= (len - 1);
58
59 ch = *str;
60 /* quote = table->quote_char; */
61
62 while (p < pmax)
63 {
64 if ((*p == ch)
65 && (0 == strncmp (str, (char *)p, len)))
66 return p + len;
67
68 p++;
69 }
70
71 return NULL;
72 }
73
74 /* UTF-8 ASCII safe */
find_string_end(Syntax_Table_Type * table,unsigned char * p,unsigned char * pmax,unsigned char ch)75 static unsigned char *find_string_end (Syntax_Table_Type *table,
76 unsigned char *p, unsigned char *pmax,
77 unsigned char ch)
78 {
79 unsigned char quote;
80
81 quote = table->quote_char;
82
83 while (p < pmax)
84 {
85 if (*p == quote)
86 {
87 p = jed_multibyte_chars_forward (p+1, pmax, 1, NULL, 0);
88 continue;
89 }
90 if (*p++ == ch)
91 return p;
92 }
93
94 return NULL;
95 }
96
97 /* UTF-8 ASCII safe */
is_fortran_comment(Line * l,Syntax_Table_Type * table)98 static int is_fortran_comment (Line *l, Syntax_Table_Type *table)
99 {
100 return l->len && table->fortran_comment_chars[l->data[0]];
101 }
102
103 /* UTF-8 WORD unsafe */
_jed_is_eol_comment_start(Syntax_Table_Type * table,Line * l,unsigned char * p,unsigned char * pmax,unsigned int * com)104 int _jed_is_eol_comment_start (Syntax_Table_Type *table, Line *l,
105 unsigned char *p, unsigned char *pmax, unsigned int *com)
106 {
107 unsigned int i;
108 int wsc;
109
110 if (p >= pmax)
111 return 0;
112
113 /* Most of the time, num_eol_comments is going to be <= 1, so just
114 * use table->whatever.
115 */
116 wsc = table->flags & EOL_COMMENT_NEEDS_WHITESPACE;
117
118 for (i = 0; i < table->num_eol_comments; i++)
119 {
120 if (*p != table->eol_comment_starts[i][0])
121 continue;
122
123 if (p + table->eol_comment_lens[i] > pmax)
124 continue;
125
126 if (0 == (table->flags & SYNTAX_NOT_CASE_SENSITIVE))
127 {
128 if (0 != strncmp ((char *) p, table->eol_comment_starts[i],
129 table->eol_comment_lens[i]))
130 continue;
131 }
132 else
133 {
134 if (0 != jed_case_strncmp ((char *) p, table->eol_comment_starts[i],
135 table->eol_comment_lens[i]))
136 continue;
137 }
138
139 if ((table->char_syntax[*p] & WORD_SYNTAX) || wsc)
140 {
141 unsigned char *p1;
142 unsigned char ch1;
143
144 p1 = p + table->eol_comment_lens[i];
145 if (p1 < pmax)
146 {
147 ch1 = *p1;
148 if (wsc)
149 {
150 if ((ch1 != ' ') && (ch1 != '\n') && (ch1 != '\t'))
151 {
152 /* This piece of code permits: #### */
153 if ((ch1 != *p)
154 || (table->char_syntax[ch1] & WORD_SYNTAX)
155 || (p1 != p + 1))
156 continue;
157 }
158 }
159 else if (table->char_syntax[ch1] & WORD_SYNTAX)
160 continue;
161 }
162
163 if (p > l->data)
164 {
165 ch1 = *(p-1);
166
167 if (wsc)
168 {
169 if ((ch1 != ' ') && (ch1 != '\t'))
170 {
171 /* This piece of code permits: #### */
172 if ((ch1 != *p)
173 || (table->char_syntax[ch1] & WORD_SYNTAX)
174 || (p1 != p + 1))
175 continue;
176 }
177 }
178 else if (table->char_syntax[ch1] & WORD_SYNTAX)
179 continue;
180 }
181 }
182
183 if (com != NULL)
184 *com = i;
185
186 return 1;
187 }
188
189 return 0;
190 }
191
parse_to_point1(Syntax_Table_Type * table,Line * l,unsigned char * pmax)192 static int parse_to_point1 (Syntax_Table_Type *table,
193 Line *l,
194 unsigned char *pmax)
195 {
196 unsigned char ch;
197 int quote, cc, flags;
198 unsigned char *p;
199 unsigned int lflags;
200 unsigned char com_start_char;
201 char *comment_start;
202 unsigned short *syntax;
203 unsigned char *sc;
204 unsigned char sgml_stop_char;
205
206 flags = table->flags;
207 p = l->data;
208
209 if (flags & FORTRAN_TYPE)
210 {
211 if (is_fortran_comment (l, table))
212 return JED_LINE_HAS_EOL_COMMENT;
213 }
214
215 sc = table->string_chars;
216 cc = table->char_char;
217 syntax = table->char_syntax;
218 sgml_stop_char = table->sgml_stop_char;
219
220 lflags = l->flags & JED_LINE_SYNTAX_BITS;
221
222 if (lflags)
223 {
224 if (lflags & JED_LINE_IN_COMMENT)
225 {
226 if (NULL == (p = find_comment_end (table, p, pmax)))
227 return JED_LINE_IN_COMMENT;
228 }
229 else if (lflags & JED_LINE_IN_STRING0)
230 {
231 if (NULL == (p = find_string_end (table, p, pmax, sc[0])))
232 return JED_LINE_IN_STRING0;
233 }
234 else if (lflags & JED_LINE_IN_STRING1)
235 {
236 if (NULL == (p = find_string_end (table, p, pmax, sc[1])))
237 return JED_LINE_IN_STRING1;
238 }
239 else if (lflags & JED_LINE_IN_HTML)
240 {
241 if (NULL == (p = find_string_end (table, p, pmax, sgml_stop_char)))
242 return JED_LINE_IN_HTML;
243 }
244 }
245
246 /* Now we should be out of comments, strings, etc... */
247 quote = table->quote_char;
248
249 comment_start = table->comment_start;
250
251 com_start_char = (comment_start == NULL) ? 0 : *comment_start;
252
253 while (p < pmax)
254 {
255 ch = *p;
256 if (ch == quote)
257 {
258 p += 2;
259 continue;
260 }
261
262 /* Search for a string delimiter, char delimiter, or comment start. */
263 #if 1
264 /* Check comment syntax first */
265 if (syntax[ch] & COMMENT_SYNTAX)
266 {
267 if ((ch == com_start_char)
268 && (comment_start != NULL)
269 && (p + table->comment_start_len <= pmax)
270 && (0 == strncmp ((char *) p, comment_start,
271 table->comment_start_len)))
272 {
273 p = find_comment_end (table, p + table->comment_start_len, pmax);
274 if (p == NULL)
275 return JED_LINE_IN_COMMENT;
276
277 continue;
278 }
279
280 if (_jed_is_eol_comment_start (table, l, p, pmax, NULL))
281 return JED_LINE_HAS_EOL_COMMENT;
282 }
283 #endif
284 if (syntax[ch] & (STRING_SYNTAX))
285 {
286 p = find_string_end (table, p + 1, pmax, ch);
287 if (p == NULL)
288 {
289 if (sc[0] == ch)
290 return JED_LINE_IN_STRING0;
291 if (sc[1] == ch)
292 return JED_LINE_IN_STRING1;
293 return JED_LINE_IN_STRING0;
294 }
295 continue;
296 }
297
298 if (syntax[ch] & HTML_START_SYNTAX)
299 {
300 p = find_string_end (table, p+1, pmax, table->sgml_stop_char);
301 if (p == NULL)
302 return JED_LINE_IN_HTML;
303 continue;
304 }
305 #if 0
306 if (0 == (syntax[ch] & COMMENT_SYNTAX))
307 {
308 p++;
309 continue;
310 }
311 if ((ch == com_start_char)
312 && (comment_start != NULL)
313 && (p + table->comment_start_len <= pmax)
314 && (0 == strncmp ((char *) p, comment_start,
315 table->comment_start_len)))
316 {
317 p = find_comment_end (table, p + table->comment_start_len, pmax);
318 if (p == NULL)
319 return JED_LINE_IN_COMMENT;
320
321 continue;
322 }
323
324 if (_jed_is_eol_comment_start (table, l, p, pmax, NULL))
325 return JED_LINE_HAS_EOL_COMMENT;
326 #endif
327
328 p++;
329 }
330
331 return 0;
332 }
333
goto_effective_eol(Syntax_Table_Type * table)334 static void goto_effective_eol (Syntax_Table_Type *table) /*{{{*/
335 {
336 unsigned int flags;
337 unsigned char *p, *pmax;
338 unsigned short *syntax;
339
340 flags = CLine->flags;
341 if (0 == (flags & JED_LINE_HAS_EOL_COMMENT))
342 {
343 eol ();
344 return;
345 }
346
347 if (table->flags & FORTRAN_TYPE)
348 {
349 bol ();
350
351 if (is_fortran_comment (CLine, table))
352 return;
353 }
354
355 if (0 == table->num_eol_comments)
356 {
357 /* ?? */
358 CLine->flags &= ~JED_LINE_HAS_EOL_COMMENT;
359 eol ();
360 return;
361 }
362
363 /* We know that there is an EOL style comment somewhere on this line. So,
364 * just search for it.
365 */
366 p = CLine->data;
367 pmax = CLine->data + CLine->len;
368
369 syntax = table->char_syntax;
370
371 while (p < pmax)
372 {
373 unsigned int i;
374
375 if ((syntax[*p] & COMMENT_SYNTAX)
376 && (_jed_is_eol_comment_start (table, CLine, p, pmax, &i)))
377 {
378 /* Is this really a comment? Perhaps is occurs in a string
379 * or in part of another word. Only one way to find out.
380 */
381 jed_position_point (p + table->eol_comment_lens[i]);
382 if (JED_LINE_HAS_EOL_COMMENT == parse_to_point1 (table, CLine,
383 p + table->eol_comment_lens[i]))
384 {
385 jed_position_point (p);
386 return; /* we are there */
387 }
388 }
389 p++;
390 }
391
392 /* ?? */
393 CLine->flags &= ~JED_LINE_HAS_EOL_COMMENT;
394 eol ();
395 }
396
397 /*}}}*/
398
setup_for_match(unsigned char ** pp,unsigned char * chp,unsigned char * want_chp)399 static Syntax_Table_Type *setup_for_match (unsigned char **pp,
400 unsigned char *chp,
401 unsigned char *want_chp)
402 {
403 register unsigned char ch, want_ch;
404 Syntax_Table_Type *table;
405
406 #if JED_HAS_LINE_ATTRIBUTES
407 /* Make sure that the line flags are ok. */
408 if (CBuf->min_unparsed_line_num)
409 jed_syntax_parse_buffer (0);
410 #endif
411
412 *pp = CLine->data + Point;
413
414 ch = *chp;
415 if (ch == 0) ch = **pp;
416
417 table = CBuf->syntax_table;
418
419 want_ch = 0;
420 if (table != NULL)
421 want_ch = table->matching_delim [ch];
422
423 if (want_ch == 0)
424 {
425 table = Default_Syntax_Table;
426 if (table != NULL)
427 want_ch = table->matching_delim [ch];
428 }
429
430 if (want_ch == 0)
431 return NULL;
432
433 *chp = ch;
434 *want_chp = want_ch;
435
436 return table;
437 }
438
is_quoted(unsigned char * pmin,unsigned char ** pp,unsigned char q)439 static int is_quoted (unsigned char *pmin, unsigned char **pp, unsigned char q)
440 {
441 unsigned char *p;
442 int iq;
443
444 iq = 0;
445 p = *pp;
446
447 while ((p >= pmin) && (*p == q))
448 {
449 p--;
450 iq = !iq;
451 }
452
453 if (iq)
454 *pp = p;
455
456 return iq;
457 }
458
goto_comment_begin(Syntax_Table_Type * table)459 static int goto_comment_begin (Syntax_Table_Type *table)
460 {
461 unsigned char *p, *pmin, *pmax;
462 unsigned char ch;
463 char *s;
464 unsigned int len;
465
466 if (NULL == (s = table->comment_start))
467 return -1;
468
469 len = table->comment_start_len;
470 ch = *s;
471
472 while (1)
473 {
474 pmin = CLine->data;
475 p = pmin + Point;
476 pmax = pmin + CLine->len;
477
478 while (p >= pmin)
479 {
480 if ((*p == ch)
481 && (p + len <= pmax)
482 && (0 == strncmp (s, (char *)p, len))
483 && (0 == parse_to_point1 (table, CLine, p)))
484 {
485 jed_position_point (p);
486 return 0;
487 }
488
489 p--;
490 }
491
492 if (0 == jed_up (1))
493 {
494 bol ();
495 return -1;
496 }
497 }
498 }
499
goto_comment_end(Syntax_Table_Type * table)500 static int goto_comment_end (Syntax_Table_Type *table)
501 {
502 unsigned char *p, *pmax;
503 unsigned char ch;
504 char *s;
505 unsigned int len;
506
507 if (NULL == (s = table->comment_stop))
508 return -1;
509
510 len = table->comment_stop_len;
511 ch = *s;
512
513 while (1)
514 {
515 p = CLine->data + Point;
516 pmax = CLine->data + CLine->len;
517
518 while (p < pmax)
519 {
520 if ((*p == ch)
521 && (p + len <= pmax)
522 && (0 == strncmp (s, (char *)p, len)))
523 {
524 jed_position_point (p + len);
525 return 0;
526 }
527 p++;
528 }
529
530 if (0 == jed_down (1))
531 {
532 eol ();
533 return -1;
534 }
535 }
536 }
537
538 /* Note that this routine may be called with p corresponding to Point = -1.
539 * This will happen when the end quote character is at the beginning of a
540 * line.
541 */
goto_string_begin(Syntax_Table_Type * table,unsigned char ch,unsigned char * p)542 static int goto_string_begin (Syntax_Table_Type *table,
543 unsigned char ch, unsigned char *p)
544 {
545 unsigned char *pmin;
546 unsigned char quote;
547
548 quote = table->quote_char;
549 pmin = CLine->data;
550
551 while (1)
552 {
553 while (p >= pmin)
554 {
555 if (*p-- == ch)
556 {
557 if ((p >= pmin)
558 && (*p == quote)
559 && (is_quoted (pmin, &p, quote)))
560 continue;
561
562 jed_position_point (p + 1);
563 return 0;
564 }
565 }
566
567 if ((table->flags & SINGLE_LINE_STRINGS)
568 || (0 == jed_up (1)))
569 {
570 bol ();
571 return -1;
572 }
573 pmin = CLine->data;
574 p = pmin + Point;
575 }
576 }
577
goto_string_end(Syntax_Table_Type * table,unsigned char ch)578 static int goto_string_end (Syntax_Table_Type *table, unsigned char ch)
579 {
580 unsigned char *p, *pmax;
581 unsigned char quote;
582
583 quote = table->quote_char;
584 while (1)
585 {
586 p = CLine->data + Point;
587 pmax = CLine->data + CLine->len;
588 while (p < pmax)
589 {
590 if (*p == ch)
591 {
592 jed_position_point (p + 1); /* go around it */
593 return 0;
594 }
595 if (*p == quote) p++;
596 p++;
597 }
598
599 if ((table->flags & SINGLE_LINE_STRINGS)
600 || (0 == jed_down (1)))
601 {
602 eol ();
603 return -1;
604 }
605 }
606 }
607
608 /* Go backward looking for the matching ch--- not the char that matches ch.
609 * Rather, ch is the matching character.
610 * This routine returns:
611 * 1 if found and leaves the point on the match
612 * -2 if not found but we appear to be in a comment. In this case, the point
613 * if left at the beginning of the comment
614 * -1 Not found but we appear to be in a string. This leaves the point at the
615 * beginning of the string.
616 * 0 if not found. The point is left where we gave up
617 * 2 if went back too far
618 * count is the number of lines to go back
619 */
620
backward_goto_match(int count,unsigned char ch)621 static int backward_goto_match (int count, unsigned char ch) /*{{{*/
622 {
623 unsigned char *p, *pmin, want_ch;
624 unsigned short *syntax;
625 int in_string, in_comment, in_html, level;
626 int quote;
627 Syntax_Table_Type *table;
628 unsigned int this_syntax;
629 unsigned char *pmax;
630 unsigned char com_start_char, com_stop_char;
631 unsigned char sgml_start_char, sgml_stop_char;
632
633 if (NULL == (table = setup_for_match (&p, &ch, &want_ch)))
634 return 0;
635
636 syntax = table->char_syntax;
637 quote = table->quote_char;
638
639 level = 1;
640
641 /* Get some context */
642 in_string = 0; in_comment = 0;
643 switch (parse_to_point1 (table, CLine, CLine->data + Point))
644 {
645 case JED_LINE_HAS_EOL_COMMENT:
646 case JED_LINE_IN_COMMENT:
647 in_comment = 1;
648 break;
649
650 case JED_LINE_IN_STRING0:
651 in_string = (int) table->string_chars[0];
652 break;
653 case JED_LINE_IN_STRING1:
654 in_string = (int) table->string_chars[1];
655 break;
656 case JED_LINE_IN_HTML:
657 in_html = 1;
658 break;
659 }
660 Point--;
661
662 if (table->comment_start != NULL)
663 com_start_char = (unsigned char) table->comment_start[0];
664 else
665 com_start_char = 0;
666
667 if (table->comment_stop != NULL)
668 com_stop_char = (unsigned char) table->comment_stop[0];
669 else com_stop_char = 0;
670
671 sgml_start_char = table->sgml_start_char;
672 sgml_stop_char = table->sgml_stop_char;
673
674 /* FIXME: handle sgml_start/stop_char */
675 pmax = CLine->data + CLine->len;
676 while (count)
677 {
678 pmin = CLine->data;
679 p = pmin + Point;
680
681 /* This loop here is where it all happens. In this loop, we are
682 * either in a string, a comment, or in code. If we are in a string
683 * or comment, then that is where we started. So, upon hitting the
684 * left boundary of the string or comment, quit parsing and return.
685 * If in code, then skip all comments and strings because the match
686 * must be in code.
687 */
688 while (p >= pmin)
689 {
690 ch = *p--;
691
692 if ((syntax[ch] & SYNTAX_MASK) == 0) continue;
693
694 /* Check to see if it is quoted. */
695 if ((p >= pmin) && (*p == quote))
696 {
697 if (is_quoted (pmin, &p, quote))
698 continue;
699 }
700
701 this_syntax = syntax[ch];
702
703 /* Check for strings and characters since those occur quite
704 * frequently.
705 */
706 if (this_syntax & STRING_SYNTAX)
707 {
708 /* a string is meaningless in a comment */
709 if (in_comment) continue;
710 if (in_string)
711 {
712 if (in_string == (int) ch)
713 {
714 /* Match not found. Leave point at beginning
715 * of string and return -1.
716 */
717 /* Some syntaxes permit double quotes in a string
718 * to represent a single quote. Allow that here.
719 */
720 if ((p < pmin) || ((int)*p != in_string))
721 {
722 jed_position_point (p + 1);
723 return -1;
724 }
725 p--;
726 }
727 continue;
728 }
729
730 jed_position_point (p);
731
732 if (-1 == goto_string_begin (table, ch, p))
733 {
734 /* Can't find it. This should not happen except in the
735 * case of a run-away character.
736 */
737 return 0;
738 }
739
740 pmin = CLine->data;
741 pmax = pmin + CLine->len;
742 p = pmin + (Point - 1);
743 continue;
744 }
745
746 /* Before checking for comments, check for matching
747 * delimiters to give those a priority.
748 */
749 if (this_syntax & OPEN_DELIM_SYNTAX)
750 {
751 if (level == 1)
752 {
753 jed_position_point (p+1);
754 if (ch == want_ch) return 1;
755 return 0;
756 }
757 level--;
758 /* Drop down through because the open delimiter may also
759 * be a comment character as in HTML and PASCAL.
760 */
761 }
762
763 if (this_syntax & CLOSE_DELIM_SYNTAX)
764 {
765 level++;
766 /* Drop */
767 }
768
769 /* The last thing to check is a comment. */
770 if ((0 == (this_syntax & COMMENT_SYNTAX))
771 || (in_string))
772 continue;
773
774 if (in_comment)
775 {
776 /* Just look for the character that denotes the start
777 * of the comment. In C++ this is complicated by something
778 * like "*(no space)//". If you use such a construct then
779 * you lose.
780 */
781 p++;
782 if (_jed_is_eol_comment_start (table, CLine, p, pmax, NULL))
783 {
784 jed_position_point (p);
785 return -2;
786 }
787
788 if ((ch == com_start_char)
789 && (table->comment_start != NULL)
790 && (p + table->comment_start_len <= pmax)
791 && (0 == strncmp ((char *) p, table->comment_start, table->comment_start_len)))
792 {
793 jed_position_point (p);
794 return -2;
795 }
796 p--;
797 continue;
798 }
799
800 /* We are not in a comment but we may be moving into the tail
801 * end of one. I am not going to consider eol type comments
802 * here because if this is coded correctly and the algorithm
803 * works, then that was already handled.
804 */
805 if (ch != com_stop_char)
806 continue;
807
808 p++;
809 if ((table->comment_stop == NULL)
810 || (p + table->comment_stop_len > pmax)
811 || (0 != strncmp ((char *) p, table->comment_stop, table->comment_stop_len)))
812 {
813 p--;
814 continue;
815 }
816
817 jed_position_point (p);
818 if (-1 == goto_comment_begin (table))
819 return 0;
820
821 pmin = CLine->data;
822 pmax = pmin + CLine->len;
823 p = pmin + (Point - 1);
824 }
825
826 if (0 == jed_up (1))
827 {
828 bol ();
829 break;
830 }
831 count--;
832 if (table->flags & SINGLE_LINE_STRINGS)
833 in_string = 0;
834 goto_effective_eol (table);
835 pmax = CLine->data + Point;
836 }
837
838 /* What have we learned? */
839
840 if (Point < 0) Point = 0;
841 if (count == 0)
842 {
843 /* In this case, we went back as far as permitted. Nothing much can be
844 * said.
845 */
846 bol ();
847 return 2;
848 }
849
850 if (in_string) return -1;
851 if (in_comment) return -2;
852
853 /* If we are here, then we have a mismatch */
854 return 0;
855 }
856
857 /*}}}*/
858
forward_goto_match(unsigned char ch)859 static int forward_goto_match (unsigned char ch) /*{{{*/
860 {
861 unsigned char *p, *pmax, want_ch;
862 unsigned short *syntax;
863 int in_string, in_comment, level;
864 unsigned int this_syntax;
865 Syntax_Table_Type *table;
866 unsigned char com_start_char;
867
868 if (NULL == (table = setup_for_match (&p, &ch, &want_ch)))
869 return 0;
870
871 syntax = table->char_syntax;
872
873 /* Here we go */
874
875 in_string = 0; in_comment = 0;
876 switch (parse_to_point1 (table, CLine, CLine->data + Point))
877 {
878 case JED_LINE_HAS_EOL_COMMENT:
879 in_comment = JED_LINE_HAS_EOL_COMMENT;
880 break;
881
882 case JED_LINE_IN_COMMENT:
883 in_comment = JED_LINE_IN_COMMENT;
884 break;
885
886 case JED_LINE_IN_STRING0:
887 in_string = (int) table->string_chars[0];
888 break;
889 case JED_LINE_IN_STRING1:
890 in_string = (int) table->string_chars[1];
891 break;
892 }
893
894 com_start_char = 0;
895
896 if (table->comment_start != NULL)
897 com_start_char = (unsigned char) table->comment_start[0];
898
899 level = 1;
900
901 Point++;
902 while (1)
903 {
904 p = CLine->data + Point;
905 pmax = CLine->data + CLine->len;
906
907 while (p < pmax)
908 {
909 ch = *p++;
910
911 if ((syntax[ch] & SYNTAX_MASK) == 0) continue;
912
913 this_syntax = syntax[ch];
914
915 if (this_syntax & COMMENT_SYNTAX)
916 {
917 if (in_string) continue;
918
919 if (in_comment == JED_LINE_IN_COMMENT)
920 {
921 p--;
922 if ((table->comment_stop != NULL)
923 && (p + table->comment_stop_len <= pmax)
924 && (0 == strncmp ((char *) p, table->comment_stop, table->comment_start_len)))
925 {
926 p += table->comment_stop_len;
927 in_comment = 0;
928 continue;
929 }
930 p++;
931 continue;
932 }
933
934 /* We may have run into a comment. If so, go around */
935 if (in_comment == 0)
936 {
937 p--;
938 if ((ch == com_start_char)
939 && (table->comment_start != NULL)
940 && (p + table->comment_start_len <= pmax)
941 && (0 == strncmp ((char *) p, table->comment_start, table->comment_start_len)))
942 {
943 jed_position_point (p);
944 if (-1 == goto_comment_end (table))
945 return 0;
946
947 p = CLine->data + Point;
948 pmax = CLine->data + CLine->len;
949 continue;
950 }
951
952 if (_jed_is_eol_comment_start (table, CLine, p, pmax, NULL))
953 {
954 p = pmax;
955 continue;
956 }
957 p++;
958 }
959 /* drop */
960 }
961
962 if (this_syntax & STRING_SYNTAX)
963 {
964 /* string/char */
965 if (in_comment) continue;
966 if (in_string)
967 {
968 if ((int) ch == in_string)
969 {
970 /* Some syntaxes permit double quotes in a string
971 * to represent a single quote. Allow that here.
972 */
973 if ((p >= pmax) || ((int)*p != in_string))
974 in_string = 0;
975 else
976 p++; /* skip second quote */
977 }
978 }
979 else
980 {
981 jed_position_point (p);
982 if (-1 == goto_string_end (table, ch))
983 return -1;
984
985 p = CLine->data + Point;
986 pmax = CLine->data + CLine->len;
987 }
988 continue;
989 }
990
991 if (this_syntax & OPEN_DELIM_SYNTAX)
992 {
993 level++;
994 continue;
995 }
996
997 if (this_syntax & CLOSE_DELIM_SYNTAX)
998 {
999 if (level == 1)
1000 {
1001 jed_position_point (p-1);
1002 if (ch == want_ch) return 1;
1003 return 0;
1004 }
1005 level--;
1006 continue;
1007 }
1008
1009 if (this_syntax & QUOTE_SYNTAX) p++; /* skip next char */
1010 }
1011 /* END OF MAIN LOOP: while (p < pmax) */
1012
1013 if (in_comment == JED_LINE_HAS_EOL_COMMENT)
1014 return -2;
1015
1016 /* Move to the next line. */
1017 while (1)
1018 {
1019 if (0 == jed_down (1))
1020 {
1021 eol ();
1022 if (in_string) return -1;
1023 if (in_comment) return -2;
1024
1025 /* If we are here, then we have a mismatch */
1026 return 0;
1027 }
1028
1029 if (table->flags & SINGLE_LINE_STRINGS)
1030 in_string = 0;
1031
1032 if ((0 == (table->flags & FORTRAN_TYPE))
1033 || (0 == is_fortran_comment (CLine, table)))
1034 break;
1035 }
1036 }
1037 }
1038
1039 /*}}}*/
1040
find_matching_delimiter_1(unsigned char ch,int nlines)1041 static int find_matching_delimiter_1 (unsigned char ch, int nlines)
1042 {
1043 unsigned char want_ch;
1044 Syntax_Table_Type *table;
1045 unsigned char *p;
1046
1047 table = setup_for_match (&p, &ch, &want_ch);
1048 if (table == NULL)
1049 return 0;
1050
1051 if (table->char_syntax[ch] & OPEN_DELIM_SYNTAX)
1052 return forward_goto_match (ch);
1053 else
1054 return backward_goto_match (nlines, ch);
1055 }
1056
find_matching_delimiter(int * ch)1057 static int find_matching_delimiter (int *ch)
1058 {
1059 return find_matching_delimiter_1 ((unsigned char) *ch, 5000);
1060 }
1061
goto_match(void)1062 int goto_match (void) /*{{{*/
1063 {
1064 if (1 != find_matching_delimiter_1 (0, LineNum))
1065 {
1066 if (!IN_MINI_WINDOW) msg_error("Mismatch!!");
1067 return 0;
1068 }
1069 return 1;
1070 }
1071
1072 /*}}}*/
1073
parse_to_point(void)1074 static int parse_to_point (void) /*{{{*/
1075 {
1076 Syntax_Table_Type *table = CBuf->syntax_table;
1077 if (table == NULL) return 0;
1078 #if JED_HAS_LINE_ATTRIBUTES
1079 jed_syntax_parse_buffer (0);
1080 #endif
1081
1082 switch (parse_to_point1 (table, CLine, CLine->data + Point))
1083 {
1084 case JED_LINE_IN_COMMENT:
1085 case JED_LINE_HAS_EOL_COMMENT:
1086 return -2;
1087 case JED_LINE_IN_STRING0:
1088 case JED_LINE_IN_STRING1:
1089 return -1;
1090 }
1091
1092 return 0;
1093 }
1094
1095 /*}}}*/
1096
1097 /* blink the matching fence. This assumes that the window is ok */
blink_match(void)1098 void blink_match (void) /*{{{*/
1099 {
1100 Line *save;
1101 int pnt, code, matchp;
1102 unsigned int l;
1103 char buf[600], strbuf[256];
1104
1105 if (!Blink_Flag || (Repeat_Factor != NULL) || Batch) return;
1106 if (JWindow->trashed) update((Line *) NULL, 0, 0, 0);
1107 if (JWindow->trashed) return;
1108 pnt = Point;
1109 save = CLine;
1110 l = LineNum;
1111
1112 if (Point) Point--;
1113 code = backward_goto_match (1000, 0);
1114
1115 if (code == 0)
1116 {
1117 if ((! (CBuf->modes == WRAP_MODE)) && (!IN_MINI_WINDOW))
1118 message("Mismatch??");
1119 }
1120 else if ((code == 1) && is_line_visible (LineNum))
1121 {
1122 point_cursor(0);
1123 input_pending(&Number_Ten);
1124 Point = pnt;
1125 CLine = save;
1126 LineNum = l;
1127 point_cursor(0);
1128 return;
1129 }
1130 else if (code == 1)
1131 {
1132 unsigned int len;
1133
1134 matchp = Point;
1135 bol ();
1136 strcpy(buf, "Matches ");
1137 (void) jed_skip_whitespace();
1138 if ((matchp == Point) && jed_up(1))
1139 {
1140 bol ();
1141 safe_strcat (buf,
1142 make_line_string(strbuf, sizeof(strbuf)),
1143 sizeof (buf));
1144 jed_down(1);
1145 }
1146
1147 safe_strcat(buf,
1148 make_line_string(strbuf, sizeof (strbuf)),
1149 sizeof(buf));
1150
1151 /* Apparantly there are some who think that it is a bug to see
1152 * ^J in the mini-buffer. Sigh.
1153 */
1154 len = strlen (buf);
1155 if (len && (buf[len - 1] == '\n'))
1156 buf[len - 1] = 0;
1157
1158 message(buf);
1159 }
1160 Point = pnt;
1161 CLine = save;
1162 LineNum = l;
1163 }
1164
1165 /*}}}*/
1166
jed_find_syntax_table(char * name,int err)1167 Syntax_Table_Type *jed_find_syntax_table (char *name, int err) /*{{{*/
1168 {
1169 Syntax_Table_Type *table = Syntax_Tables;
1170 while (table != NULL)
1171 {
1172 if (!strcmp (table->name, name)) return table;
1173 table = table->next;
1174 }
1175 if (err) msg_error ("Syntax table undefined.");
1176 return table;
1177 }
1178
1179 /*}}}*/
1180
set_syntax_flags(char * name,int * flags)1181 static void set_syntax_flags (char *name, int *flags) /*{{{*/
1182 {
1183 Syntax_Table_Type *table;
1184
1185 table = jed_find_syntax_table (name, 1);
1186 if (table == NULL) return;
1187
1188 table->flags |= *flags & 0xFF;
1189 }
1190
1191 /*}}}*/
1192
1193 /* UTF-8 WORD UNsafe */
define_syntax(int * what,char * name)1194 static void define_syntax (int *what, char *name) /*{{{*/
1195 {
1196 Syntax_Table_Type *table;
1197 int c2;
1198 unsigned int i;
1199 char *s1 = NULL, *s2 = NULL;
1200 unsigned char lut[256], *s;
1201
1202 table = jed_find_syntax_table (name, 1);
1203 if (table == NULL) return;
1204
1205 switch (*what)
1206 {
1207 case '%':
1208 if (SLang_pop_slstring (&s2)) break;
1209 if (SLang_pop_slstring (&s1)) break;
1210
1211 table->char_syntax[(unsigned char) *s1] |= COMMENT_SYNTAX;
1212
1213 if ((*s2 == 0) || (*s2 == '\n'))
1214 {
1215 SLang_free_slstring (s2);
1216
1217 i = table->num_eol_comments;
1218 if (i == MAX_EOL_COMMENTS)
1219 {
1220 SLang_free_slstring (s1);
1221 return;
1222 }
1223
1224 table->eol_comment_starts[i] = s1;
1225 table->eol_comment_lens[i] = strlen (s1);
1226 table->num_eol_comments = i + 1;
1227 return;
1228 }
1229
1230 table->char_syntax[(unsigned char) *s2] |= COMMENT_SYNTAX;
1231
1232 SLang_free_slstring (table->comment_start);
1233 SLang_free_slstring (table->comment_stop);
1234 table->comment_start = s1;
1235 table->comment_stop = s2;
1236 table->comment_start_len = strlen (s1);
1237 table->comment_stop_len = strlen (s2);
1238 return;
1239
1240 case '\\':
1241 if (SLang_pop_integer (&c2)) break;
1242 table->char_syntax[(unsigned char) c2] |= QUOTE_SYNTAX;
1243 table->quote_char = (unsigned char) c2;
1244 break;
1245
1246 case '#':
1247 if (SLang_pop_integer (&c2)) break;
1248 table->preprocess = (unsigned char) c2;
1249 break;
1250
1251 case '\'':
1252 if (SLang_pop_integer (&c2)) break;
1253 table->char_syntax[(unsigned char) c2] |= STRING_SYNTAX;
1254 table->char_char = (unsigned char) c2;
1255 break;
1256 case '"':
1257 if (SLang_pop_integer (&c2)) break;
1258 if (table->num_string_chars == MAX_STRING_CHARS)
1259 break;
1260 table->char_syntax[(unsigned char) c2] |= STRING_SYNTAX;
1261 table->string_chars[table->num_string_chars++] = (unsigned char) c2;
1262 break;
1263
1264 case '<':
1265 case '>':
1266 if (SLang_pop_slstring (&s1)) break;
1267 s2 = s1;
1268 while (*s2 != 0)
1269 {
1270 if (*(s2 + 1) == 0) break;
1271 table->char_syntax[(unsigned char) *s2] |= HTML_START_SYNTAX;
1272 table->char_syntax[(unsigned char) *(s2 + 1)] |= HTML_END_SYNTAX;
1273 s2 += 2;
1274 }
1275 table->sgml_start_char = *s1;
1276 if (*s1 != 0)
1277 table->sgml_stop_char = s1[1];
1278 else
1279 table->sgml_stop_char = 0;
1280 s2 = NULL;
1281 break;
1282
1283 case '(':
1284 case ')':
1285 if (SLang_pop_slstring (&s2)) break;
1286 if (SLang_pop_slstring (&s1)) break;
1287
1288 i = strlen (s1);
1289 if (i != strlen (s2))
1290 {
1291 msg_error ("Delimiter set does not match.");
1292 }
1293 while (i > 0)
1294 {
1295 unsigned char ch1, ch2;
1296 i--;
1297 ch1 = (unsigned char) s1[i]; ch2 = (unsigned char) s2[i];
1298 table->char_syntax[ch1] |= OPEN_DELIM_SYNTAX;
1299 table->char_syntax[ch2] |= CLOSE_DELIM_SYNTAX;
1300 table->matching_delim[ch2] = ch1;
1301 table->matching_delim[ch1] = ch2;
1302 }
1303 break;
1304
1305 case '+':
1306 if (SLang_pop_slstring (&s1)) break;
1307 for (i = 0; i < 256; i++) table->char_syntax[i] &= ~OP_SYNTAX;
1308
1309 s = (unsigned char *) s1;
1310 while (*s)
1311 {
1312 table->char_syntax[*s] |= OP_SYNTAX;
1313 s++;
1314 }
1315 break;
1316
1317 case '0':
1318 if (SLang_pop_slstring (&s1)) break;
1319 SLmake_lut (lut, (unsigned char *) s1, 0);
1320
1321 for (i = 0; i < 256; i++)
1322 {
1323 if (lut[i]) table->char_syntax[i] |= NUMBER_SYNTAX;
1324 else table->char_syntax[i] &= ~NUMBER_SYNTAX;
1325 }
1326 break;
1327
1328 case ',':
1329 if (SLang_pop_slstring (&s1)) break;
1330 s = (unsigned char *) s1;
1331 for (i = 0; i < 256; i++) table->char_syntax[i] &= ~DELIM_SYNTAX;
1332 while (*s)
1333 {
1334 table->char_syntax[*s] |= DELIM_SYNTAX;
1335 s++;
1336 }
1337 break;
1338
1339 case 'w':
1340 if (SLang_pop_slstring (&s1)) break;
1341 SLmake_lut (lut, (unsigned char *) s1, 0);
1342
1343 for (i = 0; i < 256; i++)
1344 {
1345 if (lut[i]) table->char_syntax[i] |= WORD_SYNTAX;
1346 else table->char_syntax[i] &= ~WORD_SYNTAX;
1347 }
1348 break;
1349
1350 default:
1351 msg_error ("Bad parameter to define_syntax");
1352 }
1353
1354 if (s1 != NULL) SLang_free_slstring (s1);
1355 if (s2 != NULL) SLang_free_slstring (s2);
1356 }
1357
1358 /*}}}*/
1359
set_fortran_comment_style(char * table_name,char * str)1360 static void set_fortran_comment_style (char *table_name, char *str)
1361 {
1362 Syntax_Table_Type *table;
1363 int reverse;
1364
1365 if (NULL == (table = jed_find_syntax_table (table_name, 1)))
1366 return;
1367
1368 reverse = 0;
1369 if ((*str == '^') && (str[1] != 0))
1370 {
1371 str++;
1372 reverse = 1;
1373 }
1374 SLmake_lut(table->fortran_comment_chars, (unsigned char *) str, reverse);
1375 }
1376
use_syntax_table(char * s)1377 static void use_syntax_table (char *s) /*{{{*/
1378 {
1379 Syntax_Table_Type *table;
1380
1381 if ((s == NULL) || (*s == 0))
1382 {
1383 s = "";
1384 table = Default_Syntax_Table;
1385 }
1386 else
1387 {
1388 table = jed_find_syntax_table (s, 1);
1389 if (table == NULL) return;
1390 }
1391 CBuf->syntax_table = table;
1392
1393 (void) SLang_run_hooks ("use_syntax_table_hook", 1, s);
1394 }
1395
1396 /*}}}*/
1397
1398 /* Clears everything except for the name, and links to other tables */
clear_syntax_table(Syntax_Table_Type * t)1399 static void clear_syntax_table (Syntax_Table_Type *t)
1400 {
1401 unsigned int i;
1402 char *name;
1403 Syntax_Table_Type *next;
1404
1405 for (i = 0; i < t->num_eol_comments; i++)
1406 SLang_free_slstring (t->eol_comment_starts[i]);
1407 SLang_free_slstring (t->comment_start);
1408 SLang_free_slstring (t->comment_stop);
1409
1410 #if JED_HAS_DFA_SYNTAX
1411 if (t->init_dfa_callback != NULL)
1412 SLang_free_function (t->init_dfa_callback);
1413 if (t->hilite != NULL)
1414 jed_dfa_free_highlight_table (t->hilite);
1415 #endif
1416
1417 for (i = 0; i < MAX_KEYWORD_TABLES; i++)
1418 {
1419 unsigned int j;
1420 for (j = 0; j < MAX_KEYWORD_LEN; j++)
1421 {
1422 char *kwds = t->keywords[i][j];
1423 if (kwds != NULL)
1424 SLang_free_slstring (kwds);
1425 }
1426 }
1427
1428 next = t->next;
1429 name = t->name;
1430 memset ((char *)t, 0, sizeof (Syntax_Table_Type));
1431 t->next = next;
1432 t->name = name;
1433 }
1434
allocate_syntax_table(char * name)1435 static Syntax_Table_Type *allocate_syntax_table (char *name)
1436 {
1437 Syntax_Table_Type *table;
1438
1439 if (NULL == (table = (Syntax_Table_Type *) jed_malloc0 (sizeof (Syntax_Table_Type))))
1440 return NULL;
1441
1442 if (NULL == (name = SLang_create_slstring (name)))
1443 {
1444 SLfree ((char *) table);
1445 return NULL;
1446 }
1447 table->name = name;
1448 return table;
1449 }
1450
1451
create_syntax_table(char * name)1452 static void create_syntax_table (char *name) /*{{{*/
1453 {
1454 Syntax_Table_Type *table;
1455
1456 if (NULL != (table = jed_find_syntax_table (name, 0)))
1457 {
1458 clear_syntax_table (table);
1459 return;
1460 }
1461
1462 if (NULL == (table = allocate_syntax_table (name)))
1463 return;
1464
1465 table->next = Syntax_Tables;
1466 Syntax_Tables = table;
1467 }
1468
1469
init_syntax_tables(void)1470 void init_syntax_tables (void) /*{{{*/
1471 {
1472 unsigned short *a;
1473 unsigned char *m;
1474
1475 Default_Syntax_Table = allocate_syntax_table ("DEFAULT");
1476 if (Default_Syntax_Table == NULL) return;
1477
1478 a = Default_Syntax_Table->char_syntax;
1479 m = Default_Syntax_Table->matching_delim;
1480
1481 a [(unsigned char) '['] = OPEN_DELIM_SYNTAX; m[(unsigned char) '['] = ']';
1482 a [(unsigned char) ']'] = CLOSE_DELIM_SYNTAX; m[(unsigned char) ']'] = '[';
1483 a [(unsigned char) '('] = OPEN_DELIM_SYNTAX; m[(unsigned char) '('] = ')';
1484 a [(unsigned char) ')'] = CLOSE_DELIM_SYNTAX; m[(unsigned char) ')'] = '(';
1485 a [(unsigned char) '{'] = OPEN_DELIM_SYNTAX; m[(unsigned char) '{'] = '}';
1486 a [(unsigned char) '}'] = CLOSE_DELIM_SYNTAX; m[(unsigned char) '}'] = '{';
1487 }
1488
1489 /*}}}*/
1490
1491 /* Currently this assumes byte-semantics. It should be changed to assume character
1492 * semantics.
1493 */
define_keywords(char * name,char * kwords,int * lenp,int * tbl_nump)1494 static void define_keywords (char *name, char *kwords, int *lenp, int *tbl_nump) /*{{{*/
1495 {
1496 char *kw;
1497 int len;
1498 int kwlen;
1499 unsigned int table_number = (unsigned int) *tbl_nump;
1500 Syntax_Table_Type *table = jed_find_syntax_table (name, 1);
1501
1502 if (table == NULL) return;
1503
1504 if (table_number >= MAX_KEYWORD_TABLES)
1505 {
1506 msg_error ("Table number too high.");
1507 return;
1508 }
1509
1510 len = *lenp;
1511
1512 if ((len < 1) || (len > MAX_KEYWORD_LEN))
1513 {
1514 msg_error ("Keyword length not supported.");
1515 return;
1516 }
1517
1518 kwlen = strlen (kwords);
1519 if (kwlen % len)
1520 {
1521 msg_error ("Keyword list is improperly formed.");
1522 return;
1523 }
1524
1525 len--;
1526 kw = table->keywords[table_number][len];
1527 if (kw == NULL) SLang_push_string ("");
1528 else
1529 {
1530 SLang_push_string (kw);
1531 SLang_free_slstring (kw);
1532 }
1533
1534 table->keywords[table_number][len] = SLang_create_slstring (kwords);
1535 }
1536
1537 /*}}}*/
1538
1539 #if JED_HAS_LINE_ATTRIBUTES
syntax_parse_lines(Syntax_Table_Type * table,Line * l,unsigned int num)1540 static void syntax_parse_lines (Syntax_Table_Type *table, Line *l, unsigned int num)
1541 {
1542 int state;
1543
1544 if (l == NULL)
1545 return;
1546
1547 if (l->prev != NULL)
1548 {
1549 l = l->prev;
1550 num++;
1551 }
1552
1553 while (1)
1554 {
1555 state = parse_to_point1 (table, l, l->data + l->len);
1556 if (state == JED_LINE_HAS_EOL_COMMENT)
1557 {
1558 l->flags |= state;
1559 state = 0;
1560 }
1561 if (((state == JED_LINE_IN_STRING0) || (state == JED_LINE_IN_STRING1))
1562 && (table->flags & SINGLE_LINE_STRINGS))
1563 state = 0;
1564
1565 l = l->next;
1566
1567 if (l == NULL)
1568 break;
1569
1570 if (num == 0)
1571 {
1572 if (state == (int) (l->flags & JED_LINE_SYNTAX_BITS))
1573 return;
1574 }
1575 else num--;
1576
1577 l->flags &= ~JED_LINE_SYNTAX_BITS;
1578 l->flags |= state;
1579 }
1580 }
1581
jed_syntax_parse_buffer(int do_all)1582 void jed_syntax_parse_buffer (int do_all)
1583 {
1584 unsigned int min_line_num;
1585 unsigned int max_line_num;
1586 int n;
1587 int is_narrow;
1588 Line *l;
1589 Syntax_Table_Type *table;
1590 unsigned int undo_bit = 0;
1591 SLang_Name_Type *color_region_hook = NULL;
1592
1593 if (CBuf->buffer_hooks != NULL)
1594 color_region_hook = CBuf->buffer_hooks->color_region_hook;
1595
1596 table = CBuf->syntax_table;
1597 if ((table == NULL) && (color_region_hook == NULL))
1598 {
1599 CBuf->min_unparsed_line_num = 0;
1600 CBuf->max_unparsed_line_num = 0;
1601 return;
1602 }
1603
1604 min_line_num = CBuf->min_unparsed_line_num;
1605 max_line_num = CBuf->max_unparsed_line_num;
1606
1607 if (min_line_num == 0)
1608 {
1609 if (do_all)
1610 return;
1611 }
1612
1613 is_narrow = (CBuf->narrow != NULL);
1614 if (is_narrow)
1615 {
1616 /* yuk--- a major hack: turn off undo temporally */
1617 undo_bit = CBuf->flags & UNDO_ENABLED;
1618 CBuf->flags &= ~UNDO_ENABLED;
1619
1620 jed_push_narrow ();
1621 jed_widen_whole_buffer (CBuf);
1622 }
1623
1624 CBuf->beg->flags &= ~JED_LINE_SYNTAX_BITS; /* 0.99-17.98 */
1625
1626 if (do_all)
1627 {
1628 min_line_num = 1;
1629 max_line_num = Max_LineNum;
1630 }
1631
1632 if (color_region_hook != NULL)
1633 {
1634 (void) SLang_start_arg_list ();
1635 if ((0 == SLang_push_integer ((int) min_line_num))
1636 && (0 == SLang_push_integer ((int) max_line_num))
1637 && (0 == SLang_end_arg_list ()))
1638 {
1639 if (-1 == SLexecute_function (color_region_hook))
1640 CBuf->buffer_hooks->color_region_hook = NULL;
1641 }
1642 }
1643 else
1644 {
1645 n = (int) min_line_num;
1646
1647 push_spot ();
1648 goto_line (&n);
1649 l = CLine;
1650 pop_spot ();
1651
1652 syntax_parse_lines (table, l, 1 + (unsigned int) (max_line_num - min_line_num));
1653 }
1654
1655 if (is_narrow)
1656 {
1657 jed_pop_narrow ();
1658 CBuf->flags |= undo_bit; /* hack */
1659 }
1660
1661 CBuf->min_unparsed_line_num = CBuf->max_unparsed_line_num = 0;
1662 }
1663 #endif
1664
what_syntax_table(void)1665 static char *what_syntax_table (void)
1666 {
1667 Syntax_Table_Type *s;
1668
1669 if ((NULL == (s = CBuf->syntax_table))
1670 && (NULL == (s = Default_Syntax_Table)))
1671 return NULL;
1672
1673 return s->name; /* not thread safe */
1674 }
1675
1676 static SLang_Intrin_Fun_Type Intrinsics [] =
1677 {
1678 MAKE_INTRINSIC("parse_to_point", parse_to_point, INT_TYPE, 0),
1679 MAKE_INTRINSIC_SI("set_syntax_flags", set_syntax_flags, VOID_TYPE),
1680 MAKE_INTRINSIC_IS("define_syntax", define_syntax, VOID_TYPE),
1681 MAKE_INTRINSIC_S("use_syntax_table", use_syntax_table, VOID_TYPE),
1682 MAKE_INTRINSIC_0("what_syntax_table", what_syntax_table, STRING_TYPE),
1683 MAKE_INTRINSIC_S("create_syntax_table", create_syntax_table, VOID_TYPE),
1684 MAKE_INTRINSIC_4("define_keywords_n", define_keywords, VOID_TYPE, STRING_TYPE, STRING_TYPE, INT_TYPE, INT_TYPE),
1685 MAKE_INTRINSIC_SS("set_fortran_comment_chars", set_fortran_comment_style, SLANG_VOID_TYPE),
1686 MAKE_INTRINSIC_I("find_matching_delimiter", find_matching_delimiter, INT_TYPE),
1687 SLANG_END_INTRIN_FUN_TABLE
1688 };
1689
jed_init_syntax(void)1690 int jed_init_syntax (void)
1691 {
1692 #if JED_HAS_DFA_SYNTAX
1693 if (-1 == jed_init_dfa_syntax ())
1694 return -1;
1695 #endif
1696
1697 return SLadd_intrin_fun_table (Intrinsics, NULL);
1698 }
1699