/* HTML source syntax highlighting
by Vlad Harchev
March 1999
*/
#include
#include
#include
#ifdef USE_PSRC
BOOL psrc_convert_string = FALSE;
PUBLIC BOOL psrc_view = FALSE;/* this is read by SGML_put_character - TRUE
when viewing pretty source */
PUBLIC BOOL LYpsrc = FALSE; /* this tells what will be shown on '\':
if TRUE, then pretty source, normal source view otherwise. Toggled by
-prettysrc commandline option. */
PUBLIC BOOL sgml_in_psrc_was_initialized;
PUBLIC BOOL psrc_nested_call;
PUBLIC BOOL psrc_first_tag;
/* tagspecs from lynx.cfg are read here. After .lss file is read (is with lss
support), the style cache and markup are created before entering the
mainloop. */
PUBLIC char* HTL_tagspecs[HTL_num_lexems] = {
/* these values are defaults. They are also listed in comments of distibution's
lynx.cfg.*/
#ifdef USE_COLOR_STYLE
"span.htmlsrc_comment:!span",
"span.htmlsrc_tag:!span",
"span.htmlsrc_attrib:!span",
"span.htmlsrc_attrval:!span",
"span.htmlsrc_abracket:!span",
"span.htmlsrc_entity:!span",
"span.htmlsrc_href:!span",
"span.htmlsrc_entire:!span",
"span.htmlsrc_badseq:!span",
"span.htmlsrc_badtag:!span",
"span.htmlsrc_badattr:!span",
"span.htmlsrc_sgmlspecial:!span"
#else
"b:!b",
"b:!b",
":",
"!b:b",
"b:!b",
"b:!b",
":",
":",
"b:!b",
":",
"!b:b",
"b:!b"
#endif
};
/* these are pointers since tagspec can be empty (the pointer will be NULL
in that case) */
PUBLIC HT_tagspec* lexem_start[HTL_num_lexems];
PUBLIC HT_tagspec* lexem_end[HTL_num_lexems];
PUBLIC int tagname_transform = 2;
PUBLIC int attrname_transform = 2;
PRIVATE int html_src_tag_index ARGS1(
char*, tagname)
{
HTTag* tag = SGMLFindTag(&HTML_dtd, tagname);
return (tag && tag != &HTTag_unrecognized ) ? tag - HTML_dtd.tags : -1;
}
typedef enum _html_src_check_state
{
HTSRC_CK_normal,
HTSRC_CK_seen_excl,
HTSRC_CK_after_tagname,
HTSRC_CK_seen_dot
} html_src_check_state;
PRIVATE void append_close_tag ARGS3(
char*, tagname,
HT_tagspec**, head,
HT_tagspec**, tail)
{
int idx, nattr;
HTTag* tag;
HT_tagspec* subj;
idx = html_src_tag_index(tagname);
tag = HTML_dtd.tags+idx;
nattr = tag->number_of_attributes;
if (idx == -1) {
fprintf(stderr,
"internal error: previous check didn't find bad HTML tag %s", tagname);
exit_immediately(-1);
}
subj = (HT_tagspec*) calloc( sizeof(*subj), 1);
subj->element = idx;
subj->present = (BOOL*)calloc( nattr*sizeof (BOOL), 1);
subj->value = (char**)calloc( nattr*sizeof (char*), 1);
subj->start = FALSE;
if (!*head) {
*head = subj; *tail = subj;
} else {
(*tail)->next = subj; *tail = subj;
}
}
/* this will allocate node, initialize all members, and node
append to the list, possibly modifying head and modifying tail */
PRIVATE void append_open_tag ARGS4(
char*, tagname,
char*, classname GCC_UNUSED,
HT_tagspec**, head,
HT_tagspec**, tail)
{
HT_tagspec* subj;
HTTag* tag;
#ifdef USE_COLOR_STYLE
int hcode;
#endif
append_close_tag(tagname, head, tail); /* initialize common members*/
subj = *tail;
subj->start = TRUE;
tag = HTML_dtd.tags+subj->element;
#ifdef USE_COLOR_STYLE
hcode = hash_code_lowercase_on_fly(tagname);
if (classname && *classname) {
# if 0
/*
* we don't provide a classname as attribute of that tag, since for plain
* formatting tags they are not used directly for anything except style -
* and we provide style value directly.
*/
int class_attr_idx = 0;
int n = tag->number_of_attributes;
attr* attrs = tag->attributes;
/*.... */ /* this is not implemented though it's easy */
# endif
hcode = hash_code_aggregate_char('.', hcode);
hcode = hash_code_aggregate_lower_str(classname, hcode);
StrAllocCopy(subj->class_name, classname);
} else {
subj->class_name = "";
}
subj->style = hcode;
#endif
}
/* returns 1 if incorrect */
PUBLIC int html_src_parse_tagspec ARGS4(
char*, ts,
HTlexem, lexem,
BOOL, checkonly,
BOOL, isstart)
{
char *p = ts;
char *tagstart = 0;
char *tagend = 0;
char *classstart;
char *classend;
char stop = FALSE, after_excl = FALSE;
html_src_check_state state = HTSRC_CK_normal;
HT_tagspec* head = NULL, *tail = NULL;
HT_tagspec** slot = ( isstart ? lexem_start : lexem_end ) +lexem;
while (!stop) {
switch (state) {
case HTSRC_CK_normal:
case HTSRC_CK_seen_excl:
switch (*p) {
case '\0': stop = TRUE; break;
case ' ': case '\t': break;
case '!':
if (state == HTSRC_CK_seen_excl)
return 1; /*second '!'*/
state = HTSRC_CK_seen_excl;
after_excl = TRUE;
break;
default:
if (isalpha(*p) || *p == '_') {
tagstart = p;
while (*p && ( isalpha(*p) || *p == '_') )
++p;
tagend = p;
state = HTSRC_CK_after_tagname;
} else
return 1;
continue;
}
break;
case HTSRC_CK_after_tagname:
switch (*p) {
case '\0': stop = TRUE;
case ' ':
case '\t':
{
char save = *tagend;
*tagend = '\0';
classstart = 0;
if (checkonly) {
int idx = html_src_tag_index(tagstart);
*tagend = save;
if (idx == -1)
return 1;
} else {
if (after_excl)
append_close_tag(tagstart, &head, &tail);
else
append_open_tag(tagstart, NULL, &head, &tail);
}
state = HTSRC_CK_normal;
after_excl = FALSE;
}
break;
case '.':
if (after_excl)
return 1;
state = HTSRC_CK_seen_dot;
break;
default:
return 1;
}
break;
case HTSRC_CK_seen_dot: {
switch (*p) {
case ' ':
case '\t':
break;
case '\0':
return 1;
default: {
char save, save1;
if ( isalpha(*p) || *p == '_' ) {
classstart = p;
while (*p && ( isalpha(*p) || *p == '_') ) ++p;
classend = p;
save = *classend;
*classend = '\0';
save1 = *tagend;
*tagend = '\0';
if (checkonly) {
int idx = html_src_tag_index(tagstart);
*tagend = save1; *classend = save;
if (idx == -1)
return 1;
} else {
append_open_tag(tagstart, classstart, &head, &tail);
}
state = HTSRC_CK_normal;after_excl = FALSE;
continue;
} else
return 1;
}
}/*of switch(*p)*/
break;
} /* of case HTSRC_CK_seen_dot: */
}/* of switch */
++p;
}
if (!checkonly)
*slot = head;
return 0;
}
/*it shouldn't fail anyway - since everything is checked before it's called. */
PUBLIC void HTMLSRC_init_caches NOARGS
{
int i;
char* p;
char buf[1000];
for (i = 0; i < HTL_num_lexems; ++i) {
if (HTL_tagspecs[i])
strcpy(buf, HTL_tagspecs[i]);
else
buf[0] = '\0';
if ((p = strchr(buf, ':')) != 0)
*p = '\0';
if (html_src_parse_tagspec(buf, i, FALSE, TRUE) ) {
fprintf(stderr, "internal error while caching 1st tagspec of %d lexem", i);
exit_immediately(-1);
}
if (html_src_parse_tagspec( p ? p+1 : NULL , i, FALSE, FALSE) ) {
fprintf(stderr, "internal error while caching 2nd tagspec of %d lexem", i);
exit_immediately(-1);
}
}
}
#endif /* ifdef USE_PSRC */