/*
* Syntax highlighting DFA interpreter
* Copyright
* (C) 2004 Joseph H. Allen
*
* This file is part of JOE (Joe's Own Editor)
*/
#include "types.h"
/* Parse one line. Returns new state.
'syntax' is the loaded syntax definition for this buffer.
'line' is advanced to start of next line.
Global array 'attr_buf' end up with coloring for each character of line.
'state' is initial parser state for the line (0 is initial state).
*/
int *attr_buf = 0;
int attr_size = 0;
int stack_count = 0;
static int state_count = 0; /* Max transitions possible without cycling */
struct high_syntax *ansi_syntax;
struct high_syntax *syntax_list;
/* ANSI highlighter */
#define IDLE 0
#define AFTER_ESC 1
#define AFTER_BRACK 2
#define IN_NUMBER 3
static HIGHLIGHT_STATE ansi_parse(P *line, HIGHLIGHT_STATE h_state)
{
int *attr = attr_buf;
int *attr_end = attr_buf + attr_size;
int c;
int bold = 0; /* Save bold state for extended scheme colors */
int state = IDLE; /* h_state.saved_s[0]; */
int accu = 0; /* h_state.saved_s[1]; */
int current_attr = 0; /* (int)h_state.state; */ /* Do not let attributes cross lines - simplifies vt.c */
// int new_attr = *(int *)(h_state.saved_s + 8);
int ansi_mode = line->b->o.ansi;
line->b->o.ansi = 0;
while ((c = pgetc(line)) != NO_MORE_DATA) {
if (attr == attr_end) {
if (!attr_buf) {
attr_size = 1024;
attr_buf = (int *)joe_malloc(SIZEOF(int) * attr_size);
attr = attr_buf;
} else {
attr_buf = (int *)joe_realloc(attr_buf, SIZEOF(int) * (attr_size * 2));
attr = attr_buf + attr_size;
attr_size *= 2;
}
attr_end = attr_buf + attr_size;
}
*attr++ = current_attr;
switch (state) {
case IDLE: {
if (c == 27) {
state = AFTER_ESC;
}
break;
} case AFTER_ESC: {
if (c == '[') {
state = AFTER_BRACK;
// new_attr = (current_attr & (FG_MASK | BG_MASK));
} else {
state = IDLE;
}
break;
} case AFTER_BRACK: {
if (c == ';') {
/* RESET */
current_attr = 0;
/* but stay in this state */
} else if (c >= '0' && c <= '9') {
accu = (char)(c - '0');
state = IN_NUMBER;
} else if (c == 'm') {
/* APPLY NEW ATTRIBUTES */
current_attr = 0;
state = IDLE;
} else {
state = IDLE;
}
break;
} case IN_NUMBER: {
if (c == ';' || c == 'm') {
if (accu == 0) {
current_attr = 0;
bold = 0;
} else if (accu == 1) {
current_attr |= BOLD;
bold = 1;
} else if (accu == 4) {
current_attr |= UNDERLINE;
} else if (accu == 5) {
current_attr |= BLINK;
} else if (accu == 7) {
current_attr |= INVERSE;
} else if (accu == 9) {
current_attr |= CROSSED_OUT;
} else if (accu == 21) {
current_attr |= DOUBLE_UNDERLINE;
} else if (accu >= 30 && accu <= 37) {
if (bold && curschemeset && curschemeset->termcolors[accu - 22].type != COLORSPEC_TYPE_NONE) {
/* Remapped extended color */
current_attr = (current_attr & ~FG_MASK) | (curschemeset->termcolors[accu - 22].atr & FG_MASK & ~BOLD);
} else if (curschemeset && curschemeset->termcolors[accu - 30].type != COLORSPEC_TYPE_NONE) {
/* Remapped by scheme */
current_attr = (current_attr & ~FG_MASK) | (curschemeset->termcolors[accu - 30].atr & FG_MASK);
} else {
current_attr = (current_attr & ~FG_MASK) | FG_NOT_DEFAULT | ((accu - 30) << FG_SHIFT) | (-bold & BOLD);
}
} else if (accu >= 40 && accu <= 47) {
if (curschemeset && curschemeset->termcolors[accu - 40].type != COLORSPEC_TYPE_NONE) {
/* Remapped by scheme */
current_attr = (current_attr & ~BG_MASK) | (((curschemeset->termcolors[accu - 40].atr & FG_MASK) >> FG_SHIFT) << BG_SHIFT);
} else {
current_attr = (current_attr & ~BG_MASK) | BG_NOT_DEFAULT | ((accu - 40) << BG_SHIFT);
}
}
if (c == ';') {
accu = 0;
state = IN_NUMBER;
} else if (c == 'm') {
state = IDLE;
}
} else if (c >= '0' && c <= '9') {
accu = (char)(accu * 10 + c - '0');
} else {
state = IDLE;
}
}
}
if (c == '\n')
break;
}
line->b->o.ansi = ansi_mode;
/* h_state.saved_s[0] = state;
h_state.saved_s[1] = accu;
h_state.saved_s[2] = 0; */ /* Because we Zcmp(saved_s) */
h_state.state = current_attr;
return h_state;
}
HIGHLIGHT_STATE parse(struct high_syntax *syntax,P *line,HIGHLIGHT_STATE h_state,struct charmap *charmap)
{
struct high_frame *stack;
struct high_state *h;
/* Current state */
int buf[SAVED_SIZE]; /* Name buffer (trunc after 23 characters) */
int lbuf[3*SAVED_SIZE]; /* Lower case version of name buffer */
int lsaved_s[3*SAVED_SIZE]; /* Lower case version of delimiter match buffer */
int buf_idx; /* Index into buffer */
int c; /* Current character */
int *attr;
int *attr_end;
int buf_en; /* Set for name buffering */
int ofst; /* record offset after we've stopped buffering */
int mark1; /* offset to mark start from current pos */
int mark2; /* offset to mark end from current pos */
int mark_en; /* set if marking */
int recolor_delimiter_or_keyword;
/* Nothing should reference 'h' above here. */
if (h_state.state < 0) {
/* Indicates a previous error -- highlighting disabled */
return h_state;
}
if (syntax == ansi_syntax)
return ansi_parse(line, h_state);
stack = h_state.stack;
h = (stack ? stack->syntax : syntax)->states[h_state.state];
buf_idx = 0;
attr = attr_buf;
attr_end = attr_buf + attr_size;
buf_en = 0;
ofst = 0;
mark1 = 0;
mark2 = 0;
mark_en = 0;
buf[0]=0; /* Forgot this originally... took 5 months to fix! */
/* Get next character */
while((c=pgetc(line))!=NO_MORE_DATA) {
struct high_cmd *cmd, *kw_cmd;
int iters = -8; /* +8 extra iterations before cycle detect. */
ptrdiff_t x;
/* If it isn't already, convert character to unicode */
if (!charmap->type)
c = to_uni(charmap, c);
/* Create or expand attribute array if necessary */
if(attr==attr_end) {
if(!attr_buf) {
attr_size = 1024;
attr_buf = (int *)joe_malloc(SIZEOF(int)*attr_size);
attr = attr_buf;
} else {
attr_buf = (int *)joe_realloc(attr_buf,SIZEOF(int)*(attr_size*2));
attr = attr_buf + attr_size;
attr_size *= 2;
}
attr_end = attr_buf + attr_size;
}
/* Advance to next attribute position (note attr[-1] below) */
attr++;
/* Loop while noeat */
do {
/* Guard against infinite loops from buggy syntaxes */
if (iters++ > state_count) {
invalidate_state(&h_state);
return h_state;
}
/* Color with current state */
attr[-1] = h->color;
/* Get command for this character */
if (h->delim && h_state.saved_s && c == h_state.saved_s[0] && h_state.saved_s[1] && h_state.saved_s[2] == 0)
cmd = h->delim;
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)
cmd = h->same_delim;
else {
cmd = (struct high_cmd *)rtree_lookup(&h->rtree, c);
if (!cmd)
cmd = h->dflt;
}
/* Lowerize strings for case-insensitive matching */
if (cmd->ignore) {
lowerize(lbuf, SIZEOF(lbuf)/SIZEOF(lbuf[0]), buf);
if (cmd->delim) {
if (h_state.saved_s)
lowerize(lsaved_s, SIZEOF(lsaved_s)/SIZEOF(lsaved_s[0]), h_state.saved_s);
else
lsaved_s[0] = 0;
}
}
/* Check for delimiter or keyword matches */
recolor_delimiter_or_keyword = 0;
if (cmd->delim && (cmd->ignore ? !Zcmp(lsaved_s,lbuf) : (h_state.saved_s && !Zcmp(h_state.saved_s,buf)))) {
cmd = cmd->delim;
recolor_delimiter_or_keyword = 1;
} else if (cmd->keywords && (cmd->ignore ? (kw_cmd=(struct high_cmd *)Zhtfind(cmd->keywords,lbuf)) : (kw_cmd=(struct high_cmd *)Zhtfind(cmd->keywords,buf)))) {
cmd = kw_cmd;
recolor_delimiter_or_keyword = 1;
}
/* Determine new state */
if (cmd->call) {
/* Call */
struct high_frame **frame_ptr = stack ? &stack->child : &syntax->stack_base;
/* Search for an existing stack frame for this call */
while (*frame_ptr && !((*frame_ptr)->syntax == cmd->call && (*frame_ptr)->return_state == cmd->new_state))
frame_ptr = &(*frame_ptr)->sibling;
if (*frame_ptr)
stack = *frame_ptr;
else {
struct high_frame *frame = (struct high_frame *)joe_malloc(SIZEOF(struct high_frame));
frame->parent = stack;
frame->child = 0;
frame->sibling = 0;
frame->syntax = cmd->call;
frame->return_state = cmd->new_state;
*frame_ptr = frame;
stack = frame;
++stack_count;
}
h = stack->syntax->states[0];
} else if (cmd->rtn) {
/* Return */
if (stack) {
h = stack->return_state;
stack = stack->parent;
} else
/* Not in a subroutine, so ignore the return */
h = cmd->new_state;
} else if (cmd->reset) {
h = syntax->states[0];
} else {
/* Normal edge */
h = cmd->new_state;
}
/* Recolor if necessary */
if (recolor_delimiter_or_keyword)
for(x= -(buf_idx+1);x<-1;++x)
attr[x-ofst] = h->color;
for(x=cmd->recolor;x<0;++x)
if (attr + x >= attr_buf)
attr[x] = h->color;
/* Mark recoloring */
if (cmd->recolor_mark)
for(x= -mark1;x<-mark2;++x)
attr[x] = h->color;
/* Save string? */
if (cmd->save_s) {
h_state.saved_s = Zatom_add(buf);
}
/* Save character? */
if (cmd->save_c) {
int bf[3];
bf[1] = c;
bf[2] = 0;
if (c=='<')
bf[0] = '>';
else if (c=='(')
bf[0] = ')';
else if (c=='[')
bf[0] = ']';
else if (c=='{')
bf[0] = '}';
else if (c=='`')
bf[0] = '\'';
else
bf[0] = c;
h_state.saved_s = Zatom_add(bf);
}
/* Start buffering? */
if (cmd->start_buffering) {
buf_idx = 0;
buf_en = 1;
ofst = 0;
}
/* Stop buffering? */
if (cmd->stop_buffering)
buf_en = 0;
/* Set mark begin? */
if (cmd->start_mark)
{
mark2 = 1;
mark1 = 1;
mark_en = 1;
}
/* Set mark end? */
if(cmd->stop_mark)
{
mark_en = 0;
mark2 = 1;
}
} while(cmd->noeat);
/* Save character in buffer */
if (buf_idx < (SAVED_SIZE - 1) && buf_en)
buf[buf_idx++] = c;
if (!buf_en)
++ofst;
buf[buf_idx] = 0;
/* Update mark pointers */
++mark1;
if(!mark_en)
++mark2;
if(c=='\n')
break;
}
/* Return new state */
h_state.stack = stack;
h_state.state = h->no;
return h_state;
}
/* Subroutines for load_dfa() */
static struct high_state *find_state(struct high_syntax *syntax,char *name)
{
struct high_state *state;
/* Find state */
state = (struct high_state *)htfind(syntax->ht_states, name);
/* It doesn't exist, so create it */
if(!state) {
state=(struct high_state *)joe_malloc(SIZEOF(struct high_state));
state->name = zdup(name);
state->no = syntax->nstates;
state->color = 0;
state->colorp = NULL;
/* Expand the state table if necessary */
if (syntax->nstates==syntax->szstates)
syntax->states=(struct high_state **)joe_realloc(syntax->states,SIZEOF(struct high_state *)*(syntax->szstates*=2));
syntax->states[syntax->nstates++]=state;
rtree_init(&state->rtree);
state->dflt = &syntax->default_cmd;
state->delim = 0;
state->same_delim = 0;
htadd(syntax->ht_states, state->name, state);
++state_count;
}
return state;
}
/* Build cmaps */
static void build_cmaps(struct high_syntax *syntax)
{
int x;
for (x = 0; x != syntax->ht_states->len; ++x) {
HENTRY *p;
for (p = syntax->ht_states->tab[x]; p; p = p->next) {
struct high_state *st = (struct high_state *)p->val;
rtree_opt(&st->rtree);
}
}
}
/* Create empty command */
static void iz_cmd(struct high_cmd *cmd)
{
cmd->noeat = 0;
cmd->recolor = 0;
cmd->start_buffering = 0;
cmd->stop_buffering = 0;
cmd->save_c = 0;
cmd->save_s = 0;
cmd->new_state = 0;
cmd->keywords = 0;
cmd->delim = 0;
cmd->ignore = 0;
cmd->start_mark = 0;
cmd->stop_mark = 0;
cmd->recolor_mark = 0;
cmd->rtn = 0;
cmd->reset = 0;
cmd->call = 0;
}
static struct high_cmd *mkcmd()
{
struct high_cmd *cmd = (struct high_cmd *)joe_malloc(SIZEOF(struct high_cmd));
iz_cmd(cmd);
return cmd;
}
static struct color_def *find_color(struct color_def *colors,char *name,char *syn)
{
char bf[256];
struct color_def *color;
joe_snprintf_2(bf, SIZEOF(bf), "%s.%s", syn, name);
for (color = colors; color; color = color->next)
if (!zcmp(color->name,bf)) break;
if (color)
return color;
for (color = colors; color; color = color->next)
if (!zcmp(color->name,name)) break;
return color;
}
void parse_syntax_color_def(struct color_def **color_list,const char *p,char *name,int line)
{
char bf[256];
if(!parse_tows(&p, bf)) {
struct color_def *color;
/* Find color */
color=find_color(*color_list,bf,name);
/* If it doesn't exist, create it */
if(!color) {
color = (struct color_def *)joe_malloc(SIZEOF(struct color_def));
color->name = atom_add(bf);
color->next = *color_list;
*color_list = color;
} else {
logerror_2(joe_gettext(_("%s %d: Class already defined\n")),name,line);
}
parse_color_def(&p, color);
/* Older syntaxes had colors specified with color classes. For backwards
compatibility, we'll try to map those into the scheme via the term_colors.
We preserve the parsed color_spec here because the scheme/syntax color
resolution procedure will overwrite color->spec. */
memcpy(&color->orig, &color->spec, SIZEOF(struct color_spec));
} else {
logerror_2(joe_gettext(_("%s %d: Missing class name\n")),name,line);
}
}
/* Dump sytnax file */
void dump_syntax(BW *bw)
{
struct high_syntax *syntax;
struct high_param *params;
char buf[1024];
joe_snprintf_1(buf, SIZEOF(buf), "Allocated %d stack frames\n", stack_count);
binss(bw->cursor, buf);
pnextl(bw->cursor);
for (syntax = syntax_list; syntax; syntax = syntax->next) {
int x;
joe_snprintf_3(buf, SIZEOF(buf), "Syntax name=%s, subr=%s, nstates=%d\n",syntax->name,syntax->subr,(int)syntax->nstates);
binss(bw->cursor, buf);
pnextl(bw->cursor);
zlcpy(buf, SIZEOF(buf), "params=(");
for(params = syntax->params; params; params = params->next) {
zlcat(buf, SIZEOF(buf), " ");
zlcat(buf, SIZEOF(buf), params->name);
}
zlcat(buf, SIZEOF(buf), " )\n");
binss(bw->cursor, buf);
pnextl(bw->cursor);
for(x=0;x!=syntax->nstates;++x) {
struct high_state *s = syntax->states[x];
joe_snprintf_2(buf, SIZEOF(buf), " state %s %x\n",s->name,s->color);
binss(bw->cursor, buf);
pnextl(bw->cursor);
// for (l = s->src; l; l = l->next) {
// struct high_cmd *h = (struct high_cmd *)l->map;
// 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);
// binss(bw->cursor, buf);
// pnextl(bw->cursor);
// }
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);
binss(bw->cursor, buf);
pnextl(bw->cursor);
}
}
}
static struct high_param *parse_params(struct high_param *current_params,const char **ptr,char *name,int line)
{
const char *p = *ptr;
char bf[256];
struct high_param *params;
struct high_param **param_ptr;
/* Propagate currently defined parameters */
param_ptr = ¶ms;
while (current_params) {
*param_ptr = (struct high_param *)joe_malloc(SIZEOF(struct high_param));
(*param_ptr)->name = zdup(current_params->name);
param_ptr = &(*param_ptr)->next;
current_params = current_params->next;
}
*param_ptr = 0;
parse_ws(&p, '#');
if (!parse_char(&p, '(')) {
for (;;) {
parse_ws(&p, '#');
if (!parse_char(&p, ')'))
break;
else if (!parse_char(&p, '-')) {
if (!parse_ident(&p,bf,SIZEOF(bf))) {
int cmp = 0;
param_ptr = ¶ms;
/* Parameters are sorted */
while (*param_ptr && (cmp = zcmp(bf,(*param_ptr)->name)) > 0)
param_ptr = &(*param_ptr)->next;
if (*param_ptr && !cmp) {
/* Remove this parameter */
struct high_param *param = *param_ptr;
*param_ptr = param->next;
joe_free(param);
}
} else {
logerror_2(joe_gettext(_("%s %d: Missing parameter name\n")),name,line);
}
} else if (!parse_ident(&p,bf,SIZEOF(bf))) {
int cmp = 0;
param_ptr = ¶ms;
/* Keep parameters sorted */
while (*param_ptr && (cmp = zcmp(bf,(*param_ptr)->name)) > 0)
param_ptr = &(*param_ptr)->next;
/* Discard duplicates */
if (!*param_ptr || cmp) {
struct high_param *param = (struct high_param *)joe_malloc(SIZEOF(struct high_param));
param->name = zdup(bf);
param->next = *param_ptr;
*param_ptr = param;
}
} else {
logerror_2(joe_gettext(_("%s %d: Missing )\n")),name,line);
break;
}
}
}
*ptr = p;
return params;
}
struct high_syntax *load_syntax_subr(const char *name,char *subr,struct high_param *params);
/* Parse options */
static int parse_options(struct high_syntax *syntax,struct high_cmd *cmd,JFILE *f,const char *p,int parsing_strings,char *name,int line)
{
char buf[1024];
char bf[256];
char bf1[256];
while (parse_ws(&p,'#'), !parse_ident(&p,bf,SIZEOF(bf)))
if(!zcmp(bf,"buffer")) {
cmd->start_buffering = 1;
} else if(!zcmp(bf,"hold")) {
cmd->stop_buffering = 1;
} else if(!zcmp(bf,"save_c")) {
cmd->save_c = 1;
} else if(!zcmp(bf,"save_s")) {
cmd->save_s = 1;
} else if(!zcmp(bf,"recolor")) {
parse_ws(&p,'#');
if(!parse_char(&p,'=')) {
parse_ws(&p,'#');
if(parse_diff(&p,&cmd->recolor))
logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
} else
logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
} else if(!zcmp(bf,"call")) {
parse_ws(&p,'#');
if(!parse_char(&p,'=')) {
parse_ws(&p,'#');
if (!parse_char(&p,'.')) {
zlcpy(bf, SIZEOF(bf), syntax->name);
goto subr;
} else if (parse_ident(&p,bf,SIZEOF(bf)))
logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
else {
if (!parse_char(&p,'.')) {
subr:
if (parse_ident(&p,bf1,SIZEOF(bf1)))
logerror_2(joe_gettext(_("%s %d: Missing subroutine name\n")),name,line);
cmd->call = load_syntax_subr(bf,bf1,parse_params(syntax->params,&p,name,line));
} else
cmd->call = load_syntax_subr(bf,0,parse_params(syntax->params,&p,name,line));
}
} else
logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
} else if(!zcmp(bf,"return")) {
cmd->rtn = 1;
} else if(!zcmp(bf,"reset")) {
cmd->reset = 1;
} else if(!parsing_strings && (!zcmp(bf,"strings") || !zcmp(bf,"istrings"))) {
if (bf[0]=='i')
cmd->ignore = 1;
while(jfgets(buf,sizeof(buf),f)) {
++line;
p = buf;
parse_ws(&p,'#');
if (*p) {
int kwbuf[256];
int lkwbuf[256 * 3];
if(!parse_field(&p,"done"))
break;
if(parse_Zstring(&p,kwbuf,SIZEOF(kwbuf)/SIZEOF(kwbuf[0])) >= 0) {
parse_ws(&p,'#');
if (cmd->ignore)
lowerize(lkwbuf, SIZEOF(lkwbuf)/SIZEOF(lkwbuf[0]), kwbuf);
if(!parse_ident(&p,bf1,SIZEOF(bf1))) {
struct high_cmd *kw_cmd=mkcmd();
kw_cmd->noeat=1;
kw_cmd->new_state = find_state(syntax,bf1);
if (kwbuf[0] == '&' && !kwbuf[1]) {
cmd->delim = kw_cmd;
} else {
if(!cmd->keywords)
cmd->keywords = Zhtmk(64);
Zhtadd(cmd->keywords, (cmd->ignore ? Zdup(lkwbuf) : Zdup(kwbuf)), kw_cmd);
}
line = parse_options(syntax,kw_cmd,f,p,1,name,line);
} else
logerror_2(joe_gettext(_("%s %d: Missing state name\n")),name,line);
} else
logerror_2(joe_gettext(_("%s %d: Missing string\n")),name,line);
}
}
} else if(!zcmp(bf,"noeat")) {
cmd->noeat = 1;
} else if(!zcmp(bf,"mark")) {
cmd->start_mark = 1;
} else if(!zcmp(bf,"markend")) {
cmd->stop_mark = 1;
} else if(!zcmp(bf,"recolormark")) {
cmd->recolor_mark = 1;
} else
logerror_2(joe_gettext(_("%s %d: Unknown option\n")),name,line);
return line;
}
struct ifstack {
struct ifstack *next;
int ignore; /* Ignore input lines if set */
int skip; /* Set to skip the else part */
int else_part; /* Set if we're in the else part */
int line;
};
/* Load dfa */
static struct high_state *load_dfa(struct high_syntax *syntax)
{
char name[1024];
char buf[1024];
char bf[256];
const char *p;
ptrdiff_t c;
JFILE *f = 0;
struct ifstack *stack=0;
struct high_state *state=0; /* Current state */
struct high_state *first=0; /* First state */
int line = 0;
int this_one = 0;
int inside_subr = 0;
/* Load it */
p = getenv("HOME");
if (p) {
joe_snprintf_2(name,SIZEOF(name),"%s/.joe/syntax/%s.jsf",p,syntax->name);
f = jfopen(name,"r");
}
if (!f) {
joe_snprintf_2(name,SIZEOF(name),"%ssyntax/%s.jsf",JOEDATA,syntax->name);
f = jfopen(name,"r");
}
if (!f) {
joe_snprintf_1(name,SIZEOF(name),"*%s.jsf",syntax->name);
f = jfopen(name,"r");
}
if (!f) {
return 0;
}
/* Parse file */
while(jfgets(buf,SIZEOF(buf),f)) {
++line;
p = buf;
c = parse_ws(&p,'#');
if (!parse_char(&p, '.')) {
if (!parse_ident(&p, bf, SIZEOF(bf))) {
if (!zcmp(bf, "ifdef")) {
struct ifstack *st = (struct ifstack *)joe_malloc(SIZEOF(struct ifstack));
st->next = stack;
st->else_part = 0;
st->ignore = 1;
st->skip = 1;
st->line = line;
if (!stack || !stack->ignore) {
parse_ws(&p,'#');
if (!parse_ident(&p, bf, SIZEOF(bf))) {
struct high_param *param;
for (param = syntax->params; param; param = param->next)
if (!zcmp(param->name, bf)) {
st->ignore = 0;
break;
}
st->skip = 0;
} else {
logerror_2(joe_gettext(_("%s %d: missing parameter for ifdef\n")),name,line);
}
}
stack = st;
} else if (!zcmp(bf, "else")) {
if (stack && !stack->else_part) {
stack->else_part = 1;
if (!stack->skip)
stack->ignore = !stack->ignore;
} else
logerror_2(joe_gettext(_("%s %d: else with no matching if\n")),name,line);
} else if (!zcmp(bf, "endif")) {
if (stack) {
struct ifstack *st = stack;
stack = st->next;
joe_free(st);
} else
logerror_2(joe_gettext(_("%s %d: endif with no matching if\n")),name,line);
} else if (!zcmp(bf, "subr")) {
parse_ws(&p, '#');
if (parse_ident(&p, bf, SIZEOF(bf))) {
logerror_2(joe_gettext(_("%s %d: Missing subroutine name\n")),name,line);
} else {
if (!stack || !stack->ignore) {
inside_subr = 1;
this_one = 0;
if (syntax->subr && !zcmp(bf, syntax->subr))
this_one = 1;
}
}
} else if (!zcmp(bf, "end")) {
if (!stack || !stack->ignore) {
this_one = 0;
inside_subr = 0;
}
} else {
logerror_2(joe_gettext(_("%s %d: Unknown control statement\n")),name,line);
}
} else {
logerror_2(joe_gettext(_("%s %d: Missing control statement name\n")),name,line);
}
} else if (stack && stack->ignore) {
/* Ignore this line because of ifdef */
} else if(!parse_char(&p, '=')) {
/* Parse color */
parse_syntax_color_def(&syntax->color,p,name,line);
} else if ((syntax->subr && !this_one) || (!syntax->subr && inside_subr)) {
/* Ignore this line because it's not the code we want */
} else if(!parse_char(&p, ':')) {
if(!parse_ident(&p, bf, SIZEOF(bf))) {
state = find_state(syntax,bf);
if (!first)
first = state;
parse_ws(&p,'#');
if(!parse_tows(&p,bf)) {
struct color_def *color;
for(color=syntax->color;color;color=color->next)
if(!zcmp(color->name,bf))
break;
if(!color) {
logerror_2(joe_gettext(_("%s %d: Unknown class\n")),name,line);
}
state->color = 0;
state->colorp = color;
while(parse_ws(&p, '#'), !parse_ident(&p, bf, SIZEOF(bf))) {
if(!zcmp(bf, "comment")) {
state->color |= CONTEXT_COMMENT;
} else if(!zcmp(bf, "string")) {
state->color |= CONTEXT_STRING;
} else {
logerror_2(joe_gettext(_("%s %d: Unknown context\n")),name,line);
}
}
} else
logerror_2(joe_gettext(_("%s %d: Missing color for state definition\n")),name,line);
} else
logerror_2(joe_gettext(_("%s %d: Missing state name\n")),name,line);
} else if(!parse_char(&p, '-')) {
/* No. sync lines ignored */
} else {
c = parse_ws(&p,'#');
if (!c) {
} else if (c=='"' || c=='*' || c=='&' || c =='%') {
if (state) {
struct high_cmd *cmd = mkcmd();
if(!parse_field(&p, "*")) {
state->dflt = cmd;
} else if(!parse_field(&p, "&")) {
state->delim = cmd;
} else if(!parse_field(&p, "%")) {
state->same_delim = cmd;
} else {
struct interval *array;
ptrdiff_t size;
++p;
while(*p != '"' && !parse_class(&p, &array, &size)) {
rtree_set(&state->rtree, array, size, cmd);
/* logmessage_3("Interval add: %x - %x to %p\n", array[0].first, array[0].last, cmd); */
}
if (*p != '"')
logerror_2(joe_gettext(_("%s %d: Bad string\n")),name,line);
else
++p;
/* rtree_show(&state->rtree); */
}
/* Create command */
parse_ws(&p,'#');
if(!parse_ident(&p,bf,SIZEOF(bf))) {
cmd->new_state = find_state(syntax,bf);
line = parse_options(syntax,cmd,f,p,0,name,line);
} else
logerror_2(joe_gettext(_("%s %d: Missing jump\n")),name,line);
} else
logerror_2(joe_gettext(_("%s %d: No state\n")),name,line);
} else
logerror_2(joe_gettext(_("%s %d: Unknown character\n")),name,line);
}
}
while (stack) {
struct ifstack *st = stack;
stack = st->next;
logerror_2(joe_gettext(_("%s %d: ifdef with no matching endif\n")),name,st->line);
joe_free(st);
}
jfclose(f);
/* Compile cmaps */
build_cmaps(syntax);
return first;
}
static int syntax_match(struct high_syntax *syntax,const char *name,const char *subr,struct high_param *params)
{
struct high_param *syntax_params;
if (zcmp(syntax->name,name))
return 0;
if (!syntax->subr ^ !subr)
return 0;
if (subr && zcmp(syntax->subr,subr))
return 0;
syntax_params = syntax->params;
while (syntax_params && params) {
if (zcmp(syntax_params->name,params->name))
return 0;
syntax_params = syntax_params->next;
params = params->next;
}
return syntax_params == params;
}
struct high_syntax *load_syntax_subr(const char *name,char *subr,struct high_param *params)
{
struct high_syntax *syntax; /* New syntax table */
/* Find syntax table */
/* Already loaded? */
for(syntax=syntax_list;syntax;syntax=syntax->next)
if(syntax_match(syntax,name,subr,params))
return syntax;
/* Create new one */
syntax = (struct high_syntax *)joe_malloc(SIZEOF(struct high_syntax));
syntax->name = zdup(name);
syntax->subr = subr ? zdup(subr) : 0;
syntax->params = params;
syntax->next = syntax_list;
syntax->nstates = 0;
syntax->color = 0;
syntax->states = (struct high_state **)joe_malloc(SIZEOF(struct high_state *)*(syntax->szstates = 64));
syntax->ht_states = htmk(syntax->szstates);
iz_cmd(&syntax->default_cmd);
syntax->default_cmd.reset = 1;
syntax->stack_base = 0;
syntax_list = syntax;
if (load_dfa(syntax)) {
/* dump_syntax(syntax); */
resolve_syntax_colors(curschemeset, syntax);
return syntax;
} else {
if(syntax_list == syntax)
syntax_list = syntax_list->next;
else {
struct high_syntax *syn;
for(syn=syntax_list;syn->next!=syntax;syn=syn->next);
syn->next = syntax->next;
}
htrm(syntax->ht_states);
joe_free(syntax->name);
joe_free(syntax->states);
joe_free(syntax);
return 0;
}
}
struct high_syntax *load_syntax(const char *name)
{
if (!ansi_syntax) {
ansi_syntax = (struct high_syntax *)joe_calloc(1, SIZEOF(struct high_syntax));
ansi_syntax->name = zdup("ansi");
}
if (!name)
return 0;
if (!zcmp(name, "ansi"))
return ansi_syntax;
return load_syntax_subr(name,0,0);
}