1 /*
2  *	Syntax highlighting DFA interpreter
3  *	Copyright
4  *		(C) 2004 Joseph H. Allen
5  *
6  *	This file is part of JOE (Joe's Own Editor)
7  */
8 
9 #include "types.h"
10 
11 /* Parse one line.  Returns new state.
12    'syntax' is the loaded syntax definition for this buffer.
13    'line' is advanced to start of next line.
14    Global array 'attr_buf' end up with coloring for each character of line.
15    'state' is initial parser state for the line (0 is initial state).
16 */
17 
18 int *attr_buf = 0;
19 int attr_size = 0;
20 
21 int stack_count = 0;
22 static int state_count = 0; /* Max transitions possible without cycling */
23 
24 struct high_syntax *ansi_syntax;
25 struct high_syntax *syntax_list;
26 
27 /* ANSI highlighter */
28 
29 #define IDLE 0
30 #define AFTER_ESC 1
31 #define AFTER_BRACK 2
32 #define IN_NUMBER 3
33 
ansi_parse(P * line,HIGHLIGHT_STATE h_state)34 static HIGHLIGHT_STATE ansi_parse(P *line, HIGHLIGHT_STATE h_state)
35 {
36 	int *attr = attr_buf;
37 	int *attr_end = attr_buf + attr_size;
38 	int c;
39 	int bold = 0; /* Save bold state for extended scheme colors */
40 
41 	int state = IDLE; /* h_state.saved_s[0]; */
42 	int accu = 0; /* h_state.saved_s[1]; */
43 	int current_attr = 0; /* (int)h_state.state; */ /* Do not let attributes cross lines - simplifies vt.c */
44 	// int new_attr = *(int *)(h_state.saved_s + 8);
45 
46 	int ansi_mode = line->b->o.ansi;
47 
48 	line->b->o.ansi = 0;
49 
50 	while ((c = pgetc(line)) != NO_MORE_DATA) {
51 		if (attr == attr_end) {
52 			if (!attr_buf) {
53 				attr_size = 1024;
54 				attr_buf = (int *)joe_malloc(SIZEOF(int) * attr_size);
55 				attr = attr_buf;
56 			} else {
57 				attr_buf = (int *)joe_realloc(attr_buf, SIZEOF(int) * (attr_size * 2));
58 				attr = attr_buf + attr_size;
59 				attr_size *= 2;
60 			}
61 			attr_end = attr_buf + attr_size;
62 		}
63 		*attr++ = current_attr;
64 		switch (state) {
65 			case IDLE: {
66 				if (c == 27) {
67 					state = AFTER_ESC;
68 				}
69 				break;
70 			} case AFTER_ESC: {
71 				if (c == '[') {
72 					state = AFTER_BRACK;
73 					// new_attr = (current_attr & (FG_MASK | BG_MASK));
74 				} else {
75 					state = IDLE;
76 				}
77 				break;
78 			} case AFTER_BRACK: {
79 				if (c == ';') {
80 					/* RESET */
81 					current_attr = 0;
82 					/* but stay in this state */
83 				} else if (c >= '0' && c <= '9') {
84 					accu = (char)(c - '0');
85 					state = IN_NUMBER;
86 				} else if (c == 'm') {
87 					/* APPLY NEW ATTRIBUTES */
88 					current_attr = 0;
89 					state = IDLE;
90 				} else {
91 					state = IDLE;
92 				}
93 				break;
94 			} case IN_NUMBER: {
95 				if (c == ';' || c == 'm') {
96 					if (accu == 0) {
97 						current_attr = 0;
98 						bold = 0;
99 					} else if (accu == 1) {
100 						current_attr |= BOLD;
101 						bold = 1;
102 					} else if (accu == 4) {
103 						current_attr |= UNDERLINE;
104 					} else if (accu == 5) {
105 						current_attr |= BLINK;
106 					} else if (accu == 7) {
107 						current_attr |= INVERSE;
108 					} else if (accu == 9) {
109 						current_attr |= CROSSED_OUT;
110 					} else if (accu == 21) {
111 						current_attr |= DOUBLE_UNDERLINE;
112 					} else if (accu >= 30 && accu <= 37) {
113 						if (bold && curschemeset && curschemeset->termcolors[accu - 22].type != COLORSPEC_TYPE_NONE) {
114 							/* Remapped extended color */
115 							current_attr = (current_attr & ~FG_MASK) | (curschemeset->termcolors[accu - 22].atr & FG_MASK & ~BOLD);
116 						} else if (curschemeset && curschemeset->termcolors[accu - 30].type != COLORSPEC_TYPE_NONE) {
117 							/* Remapped by scheme */
118 							current_attr = (current_attr & ~FG_MASK) | (curschemeset->termcolors[accu - 30].atr & FG_MASK);
119 						} else {
120 							current_attr = (current_attr & ~FG_MASK) | FG_NOT_DEFAULT | ((accu - 30) << FG_SHIFT) | (-bold & BOLD);
121 						}
122 					} else if (accu >= 40 && accu <= 47) {
123 						if (curschemeset && curschemeset->termcolors[accu - 40].type != COLORSPEC_TYPE_NONE) {
124 							/* Remapped by scheme */
125 							current_attr = (current_attr & ~BG_MASK) | (((curschemeset->termcolors[accu - 40].atr & FG_MASK) >> FG_SHIFT) << BG_SHIFT);
126 						} else {
127 							current_attr = (current_attr & ~BG_MASK) | BG_NOT_DEFAULT | ((accu - 40) << BG_SHIFT);
128 						}
129 					}
130 					if (c == ';') {
131 						accu = 0;
132 						state = IN_NUMBER;
133 					} else if (c == 'm') {
134 						state = IDLE;
135 					}
136 				} else if (c >= '0' && c <= '9') {
137 					accu = (char)(accu * 10 + c - '0');
138 				} else {
139 					state = IDLE;
140 				}
141 			}
142 		}
143 		if (c == '\n')
144 			break;
145 	}
146 	line->b->o.ansi = ansi_mode;
147 	/* h_state.saved_s[0] = state;
148 	h_state.saved_s[1] = accu;
149 	h_state.saved_s[2] = 0; */ /* Because we Zcmp(saved_s) */
150 	h_state.state = current_attr;
151 	return h_state;
152 }
153 
parse(struct high_syntax * syntax,P * line,HIGHLIGHT_STATE h_state,struct charmap * charmap)154 HIGHLIGHT_STATE parse(struct high_syntax *syntax,P *line,HIGHLIGHT_STATE h_state,struct charmap *charmap)
155 {
156 	struct high_frame *stack;
157 	struct high_state *h;
158 			/* Current state */
159 	int buf[SAVED_SIZE];		/* Name buffer (trunc after 23 characters) */
160 	int lbuf[3*SAVED_SIZE];		/* Lower case version of name buffer */
161 	int lsaved_s[3*SAVED_SIZE];	/* Lower case version of delimiter match buffer */
162 	int buf_idx;	/* Index into buffer */
163 	int c;		/* Current character */
164 	int *attr;
165 	int *attr_end;
166 	int buf_en;	/* Set for name buffering */
167 	int ofst;	/* record offset after we've stopped buffering */
168 	int mark1;	/* offset to mark start from current pos */
169 	int mark2;	/* offset to mark end from current pos */
170 	int mark_en;	/* set if marking */
171 	int recolor_delimiter_or_keyword;
172 
173 	/* Nothing should reference 'h' above here. */
174 	if (h_state.state < 0) {
175 		/* Indicates a previous error -- highlighting disabled */
176 		return h_state;
177 	}
178 
179 	if (syntax == ansi_syntax)
180 		return ansi_parse(line, h_state);
181 
182 	stack = h_state.stack;
183 	h = (stack ? stack->syntax : syntax)->states[h_state.state];
184 	buf_idx = 0;
185 	attr = attr_buf;
186 	attr_end = attr_buf + attr_size;
187 	buf_en = 0;
188 	ofst = 0;
189 	mark1 = 0;
190 	mark2 = 0;
191 	mark_en = 0;
192 
193 	buf[0]=0;	/* Forgot this originally... took 5 months to fix! */
194 
195 	/* Get next character */
196 	while((c=pgetc(line))!=NO_MORE_DATA) {
197 		struct high_cmd *cmd, *kw_cmd;
198 		int iters = -8; /* +8 extra iterations before cycle detect. */
199 		ptrdiff_t x;
200 
201 		/* If it isn't already, convert character to unicode */
202 		if (!charmap->type)
203 			c = to_uni(charmap, c);
204 
205 		/* Create or expand attribute array if necessary */
206 		if(attr==attr_end) {
207 			if(!attr_buf) {
208 				attr_size = 1024;
209 				attr_buf = (int *)joe_malloc(SIZEOF(int)*attr_size);
210 				attr = attr_buf;
211 			} else {
212 				attr_buf = (int *)joe_realloc(attr_buf,SIZEOF(int)*(attr_size*2));
213 				attr = attr_buf + attr_size;
214 				attr_size *= 2;
215 			}
216 			attr_end = attr_buf + attr_size;
217 		}
218 
219 		/* Advance to next attribute position (note attr[-1] below) */
220 		attr++;
221 
222 		/* Loop while noeat */
223 		do {
224 			/* Guard against infinite loops from buggy syntaxes */
225 			if (iters++ > state_count) {
226 				invalidate_state(&h_state);
227 				return h_state;
228 			}
229 
230 			/* Color with current state */
231 			attr[-1] = h->color;
232 
233 			/* Get command for this character */
234 			if (h->delim && h_state.saved_s && c == h_state.saved_s[0] && h_state.saved_s[1] && h_state.saved_s[2] == 0)
235 				cmd = h->delim;
236 			else if (h->same_delim && h_state.saved_s && h_state.saved_s[0] && c == h_state.saved_s[1] && h_state.saved_s[2] == 0)
237 				cmd = h->same_delim;
238 			else {
239 				cmd = (struct high_cmd *)rtree_lookup(&h->rtree, c);
240 				if (!cmd)
241 					cmd = h->dflt;
242 			}
243 
244 			/* Lowerize strings for case-insensitive matching */
245 			if (cmd->ignore) {
246 				lowerize(lbuf, SIZEOF(lbuf)/SIZEOF(lbuf[0]), buf);
247 				if (cmd->delim) {
248 					if (h_state.saved_s)
249 						lowerize(lsaved_s, SIZEOF(lsaved_s)/SIZEOF(lsaved_s[0]), h_state.saved_s);
250 					else
251 						lsaved_s[0] = 0;
252 				}
253 			}
254 
255 			/* Check for delimiter or keyword matches */
256 			recolor_delimiter_or_keyword = 0;
257 			if (cmd->delim && (cmd->ignore ? !Zcmp(lsaved_s,lbuf) : (h_state.saved_s && !Zcmp(h_state.saved_s,buf)))) {
258 				cmd = cmd->delim;
259 				recolor_delimiter_or_keyword = 1;
260 			} else if (cmd->keywords && (cmd->ignore ? (kw_cmd=(struct high_cmd *)Zhtfind(cmd->keywords,lbuf)) : (kw_cmd=(struct high_cmd *)Zhtfind(cmd->keywords,buf)))) {
261 				cmd = kw_cmd;
262 				recolor_delimiter_or_keyword = 1;
263 			}
264 
265 			/* Determine new state */
266 			if (cmd->call) {
267 				/* Call */
268 				struct high_frame **frame_ptr = stack ? &stack->child : &syntax->stack_base;
269 				/* Search for an existing stack frame for this call */
270 				while (*frame_ptr && !((*frame_ptr)->syntax == cmd->call && (*frame_ptr)->return_state == cmd->new_state))
271 					frame_ptr = &(*frame_ptr)->sibling;
272 				if (*frame_ptr)
273 					stack = *frame_ptr;
274 				else {
275 					struct high_frame *frame = (struct high_frame *)joe_malloc(SIZEOF(struct high_frame));
276 					frame->parent = stack;
277 					frame->child = 0;
278 					frame->sibling = 0;
279 					frame->syntax = cmd->call;
280 					frame->return_state = cmd->new_state;
281 					*frame_ptr = frame;
282 					stack = frame;
283 					++stack_count;
284 				}
285 				h = stack->syntax->states[0];
286 			} else if (cmd->rtn) {
287 				/* Return */
288 				if (stack) {
289 					h = stack->return_state;
290 					stack = stack->parent;
291 				} else
292 					/* Not in a subroutine, so ignore the return */
293 					h = cmd->new_state;
294 			} else if (cmd->reset) {
295 				h = syntax->states[0];
296 			} else {
297 				/* Normal edge */
298 				h = cmd->new_state;
299 			}
300 
301 			/* Recolor if necessary */
302 			if (recolor_delimiter_or_keyword)
303 				for(x= -(buf_idx+1);x<-1;++x)
304 					attr[x-ofst] = h->color;
305 			for(x=cmd->recolor;x<0;++x)
306 				if (attr + x >= attr_buf)
307 					attr[x] = h->color;
308 
309 			/* Mark recoloring */
310 			if (cmd->recolor_mark)
311 				for(x= -mark1;x<-mark2;++x)
312 					attr[x] = h->color;
313 
314 			/* Save string? */
315 			if (cmd->save_s) {
316 				h_state.saved_s = Zatom_add(buf);
317 			}
318 
319 			/* Save character? */
320 			if (cmd->save_c) {
321 				int bf[3];
322 				bf[1] = c;
323 				bf[2] = 0;
324 				if (c=='<')
325 					bf[0] = '>';
326 				else if (c=='(')
327 					bf[0] = ')';
328 				else if (c=='[')
329 					bf[0] = ']';
330 				else if (c=='{')
331 					bf[0] = '}';
332 				else if (c=='`')
333 					bf[0] = '\'';
334 				else
335 					bf[0] = c;
336 				h_state.saved_s = Zatom_add(bf);
337 			}
338 
339 			/* Start buffering? */
340 			if (cmd->start_buffering) {
341 				buf_idx = 0;
342 				buf_en = 1;
343 				ofst = 0;
344 			}
345 
346 			/* Stop buffering? */
347 			if (cmd->stop_buffering)
348 				buf_en = 0;
349 
350 			/* Set mark begin? */
351 			if (cmd->start_mark)
352 			{
353 				mark2 = 1;
354 				mark1 = 1;
355 				mark_en = 1;
356 			}
357 
358 			/* Set mark end? */
359 			if(cmd->stop_mark)
360 			{
361 				mark_en = 0;
362 				mark2 = 1;
363 			}
364 		} while(cmd->noeat);
365 
366 		/* Save character in buffer */
367 		if (buf_idx < (SAVED_SIZE - 1) && buf_en)
368 			buf[buf_idx++] = c;
369 		if (!buf_en)
370 			++ofst;
371 		buf[buf_idx] = 0;
372 
373 		/* Update mark pointers */
374 		++mark1;
375 		if(!mark_en)
376 			++mark2;
377 
378 		if(c=='\n')
379 			break;
380 	}
381 	/* Return new state */
382 	h_state.stack = stack;
383 	h_state.state = h->no;
384 	return h_state;
385 }
386 
387 /* Subroutines for load_dfa() */
388 
find_state(struct high_syntax * syntax,char * name)389 static struct high_state *find_state(struct high_syntax *syntax,char *name)
390 {
391 	struct high_state *state;
392 
393 	/* Find state */
394 	state = (struct high_state *)htfind(syntax->ht_states, name);
395 
396 	/* It doesn't exist, so create it */
397 	if(!state) {
398 		state=(struct high_state *)joe_malloc(SIZEOF(struct high_state));
399 		state->name = zdup(name);
400 		state->no = syntax->nstates;
401 		state->color = 0;
402 		state->colorp = NULL;
403 		/* Expand the state table if necessary */
404 		if (syntax->nstates==syntax->szstates)
405 			syntax->states=(struct high_state **)joe_realloc(syntax->states,SIZEOF(struct high_state *)*(syntax->szstates*=2));
406 		syntax->states[syntax->nstates++]=state;
407 		rtree_init(&state->rtree);
408 		state->dflt = &syntax->default_cmd;
409 		state->delim = 0;
410 		state->same_delim = 0;
411 		htadd(syntax->ht_states, state->name, state);
412 		++state_count;
413 	}
414 	return state;
415 }
416 
417 /* Build cmaps */
418 
build_cmaps(struct high_syntax * syntax)419 static void build_cmaps(struct high_syntax *syntax)
420 {
421 	int x;
422 	for (x = 0; x != syntax->ht_states->len; ++x) {
423 		HENTRY *p;
424 		for (p = syntax->ht_states->tab[x]; p; p = p->next) {
425 			struct high_state *st = (struct high_state *)p->val;
426 			rtree_opt(&st->rtree);
427 		}
428 	}
429 }
430 
431 /* Create empty command */
432 
iz_cmd(struct high_cmd * cmd)433 static void iz_cmd(struct high_cmd *cmd)
434 {
435 	cmd->noeat = 0;
436 	cmd->recolor = 0;
437 	cmd->start_buffering = 0;
438 	cmd->stop_buffering = 0;
439 	cmd->save_c = 0;
440 	cmd->save_s = 0;
441 	cmd->new_state = 0;
442 	cmd->keywords = 0;
443 	cmd->delim = 0;
444 	cmd->ignore = 0;
445 	cmd->start_mark = 0;
446 	cmd->stop_mark = 0;
447 	cmd->recolor_mark = 0;
448 	cmd->rtn = 0;
449 	cmd->reset = 0;
450 	cmd->call = 0;
451 }
452 
mkcmd()453 static struct high_cmd *mkcmd()
454 {
455 	struct high_cmd *cmd = (struct high_cmd *)joe_malloc(SIZEOF(struct high_cmd));
456 	iz_cmd(cmd);
457 	return cmd;
458 }
459 
find_color(struct color_def * colors,char * name,char * syn)460 static struct color_def *find_color(struct color_def *colors,char *name,char *syn)
461 {
462 	char bf[256];
463 	struct color_def *color;
464 	joe_snprintf_2(bf, SIZEOF(bf), "%s.%s", syn, name);
465 	for (color = colors; color; color = color->next)
466 		if (!zcmp(color->name,bf)) break;
467 	if (color)
468 		return color;
469 	for (color = colors; color; color = color->next)
470 		if (!zcmp(color->name,name)) break;
471 	return color;
472 }
473 
parse_syntax_color_def(struct color_def ** color_list,const char * p,char * name,int line)474 void parse_syntax_color_def(struct color_def **color_list,const char *p,char *name,int line)
475 {
476 	char bf[256];
477 	if(!parse_tows(&p, bf)) {
478 		struct color_def *color;
479 
480 		/* Find color */
481 		color=find_color(*color_list,bf,name);
482 
483 		/* If it doesn't exist, create it */
484 		if(!color) {
485 			color = (struct color_def *)joe_malloc(SIZEOF(struct color_def));
486 			color->name = atom_add(bf);
487 			color->next = *color_list;
488 			*color_list = color;
489 		} else {
490 			logerror_2(joe_gettext(_("%s %d: Class already defined\n")),name,line);
491 		}
492 
493 		parse_color_def(&p, color);
494 
495 		/* Older syntaxes had colors specified with color classes.  For backwards
496 		   compatibility, we'll try to map those into the scheme via the term_colors.
497 		   We preserve the parsed color_spec here because the scheme/syntax color
498 		   resolution procedure will overwrite color->spec. */
499 		memcpy(&color->orig, &color->spec, SIZEOF(struct color_spec));
500 	} else {
501 		logerror_2(joe_gettext(_("%s %d: Missing class name\n")),name,line);
502 	}
503 }
504 
505 
506 /* Dump sytnax file */
507 
dump_syntax(BW * bw)508 void dump_syntax(BW *bw)
509 {
510 	struct high_syntax *syntax;
511 	struct high_param *params;
512 	char buf[1024];
513 	joe_snprintf_1(buf, SIZEOF(buf), "Allocated %d stack frames\n", stack_count);
514 	binss(bw->cursor, buf);
515 	pnextl(bw->cursor);
516 	for (syntax = syntax_list; syntax; syntax = syntax->next) {
517 		int x;
518 		joe_snprintf_3(buf, SIZEOF(buf), "Syntax name=%s, subr=%s, nstates=%d\n",syntax->name,syntax->subr,(int)syntax->nstates);
519 		binss(bw->cursor, buf);
520 		pnextl(bw->cursor);
521 		zlcpy(buf, SIZEOF(buf), "params=(");
522 		for(params = syntax->params; params; params = params->next) {
523 			zlcat(buf, SIZEOF(buf), " ");
524 			zlcat(buf, SIZEOF(buf), params->name);
525 		}
526 		zlcat(buf, SIZEOF(buf), " )\n");
527 		binss(bw->cursor, buf);
528 		pnextl(bw->cursor);
529 		for(x=0;x!=syntax->nstates;++x) {
530 			struct high_state *s = syntax->states[x];
531 			joe_snprintf_2(buf, SIZEOF(buf), "   state %s %x\n",s->name,s->color);
532 			binss(bw->cursor, buf);
533 			pnextl(bw->cursor);
534 //			for (l = s->src; l; l = l->next) {
535 //				struct high_cmd *h = (struct high_cmd *)l->map;
536 //				joe_snprintf_4(buf, SIZEOF(buf), "     [%d-%d] -> %s %d\n",l->interval.first,l->interval.last,(h->new_state ? h->new_state->name : "ERROR! Unknown state!"),(int)h->recolor);
537 //				binss(bw->cursor, buf);
538 //				pnextl(bw->cursor);
539 //			}
540 			joe_snprintf_2(buf, SIZEOF(buf), "     default -> %s %d\n",(s->dflt->new_state ? s->dflt->new_state->name : "ERROR! Unknown state!"),(int)s->dflt->recolor);
541 			binss(bw->cursor, buf);
542 			pnextl(bw->cursor);
543 		}
544 	}
545 }
546 
parse_params(struct high_param * current_params,const char ** ptr,char * name,int line)547 static struct high_param *parse_params(struct high_param *current_params,const char **ptr,char *name,int line)
548 {
549 	const char *p = *ptr;
550 	char bf[256];
551 	struct high_param *params;
552 	struct high_param **param_ptr;
553 
554 	/* Propagate currently defined parameters */
555 	param_ptr = &params;
556 	while (current_params) {
557 		*param_ptr = (struct high_param *)joe_malloc(SIZEOF(struct high_param));
558 		(*param_ptr)->name = zdup(current_params->name);
559 		param_ptr = &(*param_ptr)->next;
560 		current_params = current_params->next;
561 	}
562 	*param_ptr = 0;
563 
564 	parse_ws(&p, '#');
565 	if (!parse_char(&p, '(')) {
566 		for (;;) {
567 			parse_ws(&p, '#');
568 			if (!parse_char(&p, ')'))
569 				break;
570 			else if (!parse_char(&p, '-')) {
571 				if (!parse_ident(&p,bf,SIZEOF(bf))) {
572 					int cmp = 0;
573 					param_ptr = &params;
574 					/* Parameters are sorted */
575 					while (*param_ptr && (cmp = zcmp(bf,(*param_ptr)->name)) > 0)
576 						param_ptr = &(*param_ptr)->next;
577 					if (*param_ptr && !cmp) {
578 						/* Remove this parameter */
579 						struct high_param *param = *param_ptr;
580 						*param_ptr = param->next;
581 						joe_free(param);
582 					}
583 				} else {
584 					logerror_2(joe_gettext(_("%s %d: Missing parameter name\n")),name,line);
585 				}
586 			} else if (!parse_ident(&p,bf,SIZEOF(bf))) {
587 				int cmp = 0;
588 				param_ptr = &params;
589 				/* Keep parameters sorted */
590 				while (*param_ptr && (cmp = zcmp(bf,(*param_ptr)->name)) > 0)
591 					param_ptr = &(*param_ptr)->next;
592 				/* Discard duplicates */
593 				if (!*param_ptr || cmp) {
594 					struct high_param *param = (struct high_param *)joe_malloc(SIZEOF(struct high_param));
595 					param->name = zdup(bf);
596 					param->next = *param_ptr;
597 					*param_ptr = param;
598 				}
599 			} else {
600 				logerror_2(joe_gettext(_("%s %d: Missing )\n")),name,line);
601 				break;
602 			}
603 		}
604 	}
605 
606 	*ptr = p;
607 	return params;
608 }
609 
610 
611 struct high_syntax *load_syntax_subr(const char *name,char *subr,struct high_param *params);
612 
613 /* Parse options */
614 
parse_options(struct high_syntax * syntax,struct high_cmd * cmd,JFILE * f,const char * p,int parsing_strings,char * name,int line)615 static int parse_options(struct high_syntax *syntax,struct high_cmd *cmd,JFILE *f,const char *p,int parsing_strings,char *name,int line)
616 {
617 	char buf[1024];
618 	char bf[256];
619 	char bf1[256];
620 
621 	while (parse_ws(&p,'#'), !parse_ident(&p,bf,SIZEOF(bf)))
622 		if(!zcmp(bf,"buffer")) {
623 			cmd->start_buffering = 1;
624 		} else if(!zcmp(bf,"hold")) {
625 			cmd->stop_buffering = 1;
626 		} else if(!zcmp(bf,"save_c")) {
627 			cmd->save_c = 1;
628 		} else if(!zcmp(bf,"save_s")) {
629 			cmd->save_s = 1;
630 		} else if(!zcmp(bf,"recolor")) {
631 			parse_ws(&p,'#');
632 			if(!parse_char(&p,'=')) {
633 				parse_ws(&p,'#');
634 				if(parse_diff(&p,&cmd->recolor))
635 					logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
636 			} else
637 				logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
638 		} else if(!zcmp(bf,"call")) {
639 			parse_ws(&p,'#');
640 			if(!parse_char(&p,'=')) {
641 				parse_ws(&p,'#');
642 				if (!parse_char(&p,'.')) {
643 					zlcpy(bf, SIZEOF(bf), syntax->name);
644 					goto subr;
645 				} else if (parse_ident(&p,bf,SIZEOF(bf)))
646 					logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
647 				else {
648 					if (!parse_char(&p,'.')) {
649 						subr:
650 						if (parse_ident(&p,bf1,SIZEOF(bf1)))
651 							logerror_2(joe_gettext(_("%s %d: Missing subroutine name\n")),name,line);
652 						cmd->call = load_syntax_subr(bf,bf1,parse_params(syntax->params,&p,name,line));
653 					} else
654 						cmd->call = load_syntax_subr(bf,0,parse_params(syntax->params,&p,name,line));
655 				}
656 			} else
657 				logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
658 		} else if(!zcmp(bf,"return")) {
659 			cmd->rtn = 1;
660 		} else if(!zcmp(bf,"reset")) {
661 			cmd->reset = 1;
662 		} else if(!parsing_strings && (!zcmp(bf,"strings") || !zcmp(bf,"istrings"))) {
663 			if (bf[0]=='i')
664 				cmd->ignore = 1;
665 			while(jfgets(buf,sizeof(buf),f)) {
666 				++line;
667 				p = buf;
668 				parse_ws(&p,'#');
669 				if (*p) {
670 					int kwbuf[256];
671 					int lkwbuf[256 * 3];
672 					if(!parse_field(&p,"done"))
673 						break;
674 					if(parse_Zstring(&p,kwbuf,SIZEOF(kwbuf)/SIZEOF(kwbuf[0])) >= 0) {
675 						parse_ws(&p,'#');
676 						if (cmd->ignore)
677 							lowerize(lkwbuf, SIZEOF(lkwbuf)/SIZEOF(lkwbuf[0]), kwbuf);
678 						if(!parse_ident(&p,bf1,SIZEOF(bf1))) {
679 							struct high_cmd *kw_cmd=mkcmd();
680 							kw_cmd->noeat=1;
681 							kw_cmd->new_state = find_state(syntax,bf1);
682 							if (kwbuf[0] == '&' && !kwbuf[1]) {
683 								cmd->delim = kw_cmd;
684 							} else {
685 								if(!cmd->keywords)
686 									cmd->keywords = Zhtmk(64);
687 								Zhtadd(cmd->keywords, (cmd->ignore ? Zdup(lkwbuf) : Zdup(kwbuf)), kw_cmd);
688 							}
689 							line = parse_options(syntax,kw_cmd,f,p,1,name,line);
690 						} else
691 							logerror_2(joe_gettext(_("%s %d: Missing state name\n")),name,line);
692 					} else
693 						logerror_2(joe_gettext(_("%s %d: Missing string\n")),name,line);
694 				}
695 			}
696 		} else if(!zcmp(bf,"noeat")) {
697 			cmd->noeat = 1;
698 		} else if(!zcmp(bf,"mark")) {
699 			cmd->start_mark = 1;
700 		} else if(!zcmp(bf,"markend")) {
701 			cmd->stop_mark = 1;
702 		} else if(!zcmp(bf,"recolormark")) {
703 			cmd->recolor_mark = 1;
704 		} else
705 			logerror_2(joe_gettext(_("%s %d: Unknown option\n")),name,line);
706 	return line;
707 }
708 
709 struct ifstack {
710 	struct ifstack *next;
711 	int ignore;	/* Ignore input lines if set */
712 	int skip;	/* Set to skip the else part */
713 	int else_part;	/* Set if we're in the else part */
714 	int line;
715 };
716 
717 /* Load dfa */
718 
load_dfa(struct high_syntax * syntax)719 static struct high_state *load_dfa(struct high_syntax *syntax)
720 {
721 	char name[1024];
722 	char buf[1024];
723 	char bf[256];
724 	const char *p;
725 	ptrdiff_t c;
726 	JFILE *f = 0;
727 	struct ifstack *stack=0;
728 	struct high_state *state=0;	/* Current state */
729 	struct high_state *first=0;	/* First state */
730 	int line = 0;
731 	int this_one = 0;
732 	int inside_subr = 0;
733 
734 	/* Load it */
735 	p = getenv("HOME");
736 	if (p) {
737 		joe_snprintf_2(name,SIZEOF(name),"%s/.joe/syntax/%s.jsf",p,syntax->name);
738 		f = jfopen(name,"r");
739 	}
740 
741 	if (!f) {
742 		joe_snprintf_2(name,SIZEOF(name),"%ssyntax/%s.jsf",JOEDATA,syntax->name);
743 		f = jfopen(name,"r");
744 	}
745 	if (!f) {
746 		joe_snprintf_1(name,SIZEOF(name),"*%s.jsf",syntax->name);
747 		f = jfopen(name,"r");
748 	}
749 	if (!f) {
750 		return 0;
751 	}
752 
753 	/* Parse file */
754 	while(jfgets(buf,SIZEOF(buf),f)) {
755 		++line;
756 		p = buf;
757 		c = parse_ws(&p,'#');
758 		if (!parse_char(&p, '.')) {
759 			if (!parse_ident(&p, bf, SIZEOF(bf))) {
760 				if (!zcmp(bf, "ifdef")) {
761 					struct ifstack *st = (struct ifstack *)joe_malloc(SIZEOF(struct ifstack));
762 					st->next = stack;
763 					st->else_part = 0;
764 					st->ignore = 1;
765 					st->skip = 1;
766 					st->line = line;
767 					if (!stack || !stack->ignore) {
768 						parse_ws(&p,'#');
769 						if (!parse_ident(&p, bf, SIZEOF(bf))) {
770 							struct high_param *param;
771 							for (param = syntax->params; param; param = param->next)
772 								if (!zcmp(param->name, bf)) {
773 									st->ignore = 0;
774 									break;
775 								}
776 							st->skip = 0;
777 						} else {
778 							logerror_2(joe_gettext(_("%s %d: missing parameter for ifdef\n")),name,line);
779 						}
780 					}
781 					stack = st;
782 				} else if (!zcmp(bf, "else")) {
783 					if (stack && !stack->else_part) {
784 						stack->else_part = 1;
785 						if (!stack->skip)
786 							stack->ignore = !stack->ignore;
787 					} else
788 						logerror_2(joe_gettext(_("%s %d: else with no matching if\n")),name,line);
789 				} else if (!zcmp(bf, "endif")) {
790 					if (stack) {
791 						struct ifstack *st = stack;
792 						stack = st->next;
793 						joe_free(st);
794 					} else
795 						logerror_2(joe_gettext(_("%s %d: endif with no matching if\n")),name,line);
796 				} else if (!zcmp(bf, "subr")) {
797 					parse_ws(&p, '#');
798 					if (parse_ident(&p, bf, SIZEOF(bf))) {
799 						logerror_2(joe_gettext(_("%s %d: Missing subroutine name\n")),name,line);
800 					} else {
801 						if (!stack || !stack->ignore) {
802 							inside_subr = 1;
803 							this_one = 0;
804 							if (syntax->subr && !zcmp(bf, syntax->subr))
805 								this_one = 1;
806 						}
807 					}
808 				} else if (!zcmp(bf, "end")) {
809 					if (!stack || !stack->ignore) {
810 						this_one = 0;
811 						inside_subr = 0;
812 					}
813 				} else {
814 					logerror_2(joe_gettext(_("%s %d: Unknown control statement\n")),name,line);
815 				}
816 			} else {
817 				logerror_2(joe_gettext(_("%s %d: Missing control statement name\n")),name,line);
818 			}
819 		} else if (stack && stack->ignore) {
820 			/* Ignore this line because of ifdef */
821 		} else if(!parse_char(&p, '=')) {
822 			/* Parse color */
823 			parse_syntax_color_def(&syntax->color,p,name,line);
824 		} else if ((syntax->subr && !this_one) || (!syntax->subr && inside_subr)) {
825 			/* Ignore this line because it's not the code we want */
826 		} else if(!parse_char(&p, ':')) {
827 			if(!parse_ident(&p, bf, SIZEOF(bf))) {
828 
829 				state = find_state(syntax,bf);
830 
831 				if (!first)
832 					first = state;
833 
834 				parse_ws(&p,'#');
835 				if(!parse_tows(&p,bf)) {
836 					struct color_def *color;
837 					for(color=syntax->color;color;color=color->next)
838 						if(!zcmp(color->name,bf))
839 							break;
840 					if(!color) {
841 						logerror_2(joe_gettext(_("%s %d: Unknown class\n")),name,line);
842 					}
843 
844 					state->color = 0;
845 					state->colorp = color;
846 					while(parse_ws(&p, '#'), !parse_ident(&p, bf, SIZEOF(bf))) {
847 						if(!zcmp(bf, "comment")) {
848 							state->color |= CONTEXT_COMMENT;
849 						} else if(!zcmp(bf, "string")) {
850 							state->color |= CONTEXT_STRING;
851 						} else {
852 							logerror_2(joe_gettext(_("%s %d: Unknown context\n")),name,line);
853 						}
854 					}
855 				} else
856 					logerror_2(joe_gettext(_("%s %d: Missing color for state definition\n")),name,line);
857 			} else
858 				logerror_2(joe_gettext(_("%s %d: Missing state name\n")),name,line);
859 		} else if(!parse_char(&p, '-')) {
860 			/* No. sync lines ignored */
861 		} else {
862 			c = parse_ws(&p,'#');
863 
864 			if (!c) {
865 			} else if (c=='"' || c=='*' || c=='&' || c =='%') {
866 				if (state) {
867 					struct high_cmd *cmd = mkcmd();
868 					if(!parse_field(&p, "*")) {
869 						state->dflt = cmd;
870 					} else if(!parse_field(&p, "&")) {
871 						state->delim = cmd;
872 					} else if(!parse_field(&p, "%")) {
873 						state->same_delim = cmd;
874 					} else {
875 						struct interval *array;
876 						ptrdiff_t size;
877 						++p;
878 						while(*p != '"' && !parse_class(&p, &array, &size)) {
879 							rtree_set(&state->rtree, array, size, cmd);
880 							/* logmessage_3("Interval add: %x - %x to %p\n", array[0].first, array[0].last, cmd); */
881 						}
882 						if (*p != '"')
883 							logerror_2(joe_gettext(_("%s %d: Bad string\n")),name,line);
884 						else
885 							++p;
886 						/* rtree_show(&state->rtree); */
887 					}
888 					/* Create command */
889 					parse_ws(&p,'#');
890 					if(!parse_ident(&p,bf,SIZEOF(bf))) {
891 						cmd->new_state = find_state(syntax,bf);
892 						line = parse_options(syntax,cmd,f,p,0,name,line);
893 					} else
894 						logerror_2(joe_gettext(_("%s %d: Missing jump\n")),name,line);
895 				} else
896 					logerror_2(joe_gettext(_("%s %d: No state\n")),name,line);
897 			} else
898 				logerror_2(joe_gettext(_("%s %d: Unknown character\n")),name,line);
899 		}
900 	}
901 
902 	while (stack) {
903 		struct ifstack *st = stack;
904 		stack = st->next;
905 		logerror_2(joe_gettext(_("%s %d: ifdef with no matching endif\n")),name,st->line);
906 		joe_free(st);
907 	}
908 
909 	jfclose(f);
910 
911 	/* Compile cmaps */
912 	build_cmaps(syntax);
913 
914 	return first;
915 }
916 
syntax_match(struct high_syntax * syntax,const char * name,const char * subr,struct high_param * params)917 static int syntax_match(struct high_syntax *syntax,const char *name,const char *subr,struct high_param *params)
918 {
919 	struct high_param *syntax_params;
920 	if (zcmp(syntax->name,name))
921 		return 0;
922 	if (!syntax->subr ^ !subr)
923 		return 0;
924 	if (subr && zcmp(syntax->subr,subr))
925 		return 0;
926 	syntax_params = syntax->params;
927 	while (syntax_params && params) {
928 		if (zcmp(syntax_params->name,params->name))
929 			return 0;
930 		syntax_params = syntax_params->next;
931 		params = params->next;
932 	}
933 	return syntax_params == params;
934 }
935 
load_syntax_subr(const char * name,char * subr,struct high_param * params)936 struct high_syntax *load_syntax_subr(const char *name,char *subr,struct high_param *params)
937 {
938 	struct high_syntax *syntax;	/* New syntax table */
939 
940 	/* Find syntax table */
941 
942 	/* Already loaded? */
943 	for(syntax=syntax_list;syntax;syntax=syntax->next)
944 		if(syntax_match(syntax,name,subr,params))
945 			return syntax;
946 
947 	/* Create new one */
948 	syntax = (struct high_syntax *)joe_malloc(SIZEOF(struct high_syntax));
949 	syntax->name = zdup(name);
950 	syntax->subr = subr ? zdup(subr) : 0;
951 	syntax->params = params;
952 	syntax->next = syntax_list;
953 	syntax->nstates = 0;
954 	syntax->color = 0;
955 	syntax->states = (struct high_state **)joe_malloc(SIZEOF(struct high_state *)*(syntax->szstates = 64));
956 	syntax->ht_states = htmk(syntax->szstates);
957 	iz_cmd(&syntax->default_cmd);
958 	syntax->default_cmd.reset = 1;
959 	syntax->stack_base = 0;
960 	syntax_list = syntax;
961 
962 	if (load_dfa(syntax)) {
963 		/* dump_syntax(syntax); */
964 		resolve_syntax_colors(curschemeset, syntax);
965 		return syntax;
966 	} else {
967 		if(syntax_list == syntax)
968 			syntax_list = syntax_list->next;
969 		else {
970 			struct high_syntax *syn;
971 			for(syn=syntax_list;syn->next!=syntax;syn=syn->next);
972 			syn->next = syntax->next;
973 		}
974 		htrm(syntax->ht_states);
975 		joe_free(syntax->name);
976 		joe_free(syntax->states);
977 		joe_free(syntax);
978 		return 0;
979 	}
980 }
981 
load_syntax(const char * name)982 struct high_syntax *load_syntax(const char *name)
983 {
984 	if (!ansi_syntax) {
985 		ansi_syntax = (struct high_syntax *)joe_calloc(1, SIZEOF(struct high_syntax));
986 		ansi_syntax->name = zdup("ansi");
987 	}
988 
989 	if (!name)
990 		return 0;
991 
992 	if (!zcmp(name, "ansi"))
993 		return ansi_syntax;
994 
995 	return load_syntax_subr(name,0,0);
996 }
997