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