, , ) are left explicitly unclosed by this render engine.
wasDOC TAGS
-----------
There are basically two types of tag.
First; those that have punctuation immediately following the introducing vbar.
These are text highlight flags and generally continue up to the first
alphabetic or period, escape or vbar character. They are intended as terse
and syntactically efficient mechanisms to highlight narrative text.
Second; an alphabetic keyword follows the introducing vbar. The keyword
optionally can have trailing highlight and formatting punctuation and allied
characters. For this purpose the heading tags (|0..|4 and |9) are considered
keyword tags. A keyword tag commonly (but by no means exclusively) operates on
an immediately following, vbar terminated parameter. Sometimes more than one.
No white-space is permitted between the keyword tag and any parameter. Source
documents may be made more readable by judicious use of the line-escape (\).
The markup syntax has a lot of commonality but ultimately is pragmatic and some
inconsistency is sprinkled throughout the application. Highlight and
formatting characters similarly have much in common but ultimately prostrate
themselves before what was necessary and worked. And, of course, the absence
of a detailed design at the outset tends to manifest itself.
Brief mnemonic for tags:
|*bolded text|
|/italicised text|
|-strikethrough text|
|_underscored text|
|=monospace text|
|>>no wrap|
|<
#include
#include
#include
#include
#include
#ifndef STYLE_DEFAULT
#define STYLE_DEFAULT "\n"
#endif
char styleDefault [] = STYLE_DEFAULT;
extern int dbug,
CgiPlusCount,
isCgi,
isCgiPlus;
extern char CopyrightDate [],
SoftwareID [],
SoftwareVersion [];
/*****************************************************************************/
/*
Parse the source text markup rendering the HTML document.
*/
int renderParse (struct wasdoc_st *docptr)
{
static char vtime [18];
static $DESCRIPTOR (vtimeDsc, vtime);
static $DESCRIPTOR (faoDsc, "!17%D\0");
int ch, error, idx, length;
char *aptr, *cptr, *sptr, *rowptr = NULL, *tagptr, *tptr, *zptr;
char buf [1024],
frag [128];
/*********/
/* begin */
/*********/
if (dbug>0) dbugThis (FI_LI, "renderParse()");
docptr->asis = docptr->insightAt = docptr->noescape = 0;
memset (docptr->section, 0, sizeof(docptr->section));
for (idx = 0; idx < docptr->flagCount; idx++) free (docptr->flags[idx]);
docptr->flagCount = 0;
docptr->conditional[docptr->conLevel = 0] = 1;
if (!(tptr = docptr->text)) RETURN_FI_LI (docptr, ENXIO)
/* to be applied to the whole document it needs to be handled up-front */
for (cptr = tptr; *cptr && *cptr != '\n'; cptr++);
while (*cptr == '\n') cptr++;
if (MATCH12 (cptr, "|set|insight"))
{
error = renderSet (docptr, cptr+5);
if (error) { SET_FI_LI (docptr); goto param_error; }
}
aptr = sptr = zptr = NULL;
for (;;)
{
if (!docptr->hsize)
{
/* experiential factor applied to initial memory allocation */
wasDocHtmlBuffer (docptr, (int)((float)docptr->tsize * EXP_FACTOR));
DOC_HTML (docptr, sptr, zptr)
if (!docptr->hlength)
{
sys$fao (&faoDsc, 0, &vtimeDsc, 0);
DOC_PUT (docptr, tptr, sptr);
error = wasDocHtmlPrint (docptr,
"\n\
\n\
\n\
\n\
NOTE: SOME FUNCTIONALITY EMPLOYS JAVASCRIPT \n\
\n\
\n",
SoftwareID,
isCgi ? " CGI" : "",
isCgiPlus ? "plus" : "",
docptr->isDynamic ? " CLI" : "",
CopyrightDate,
vtime);
if (error) GOTO_FI_LI (docptr, insert_error)
DOC_GET (docptr, tptr, sptr, zptr);
}
/* must follow the */
if (docptr->insight >= 2)
{
DOC_PUT (docptr, tptr, sptr);
wasDocInsight (docptr, "BEGIN");
if (docptr->insight >= 2)
wasDocInsight (docptr, "%d/%d bytes",
docptr->hlength, docptr->hsize);
DOC_GET (docptr, tptr, sptr, zptr);
}
}
else
{
DOC_PUT (docptr, tptr, sptr);
wasDocHtmlBuffer (docptr, 0);
DOC_GET (docptr, tptr, sptr, zptr);
}
/* this pointer is used as a low-cost "concatenate this string" */
if (aptr) while (*aptr && sptr < zptr) *sptr++ = *aptr++;
if (sptr >= zptr) continue;
/* Th-th-th-that's all folks! */
if (!*tptr) break;
if (docptr->conditional[docptr->conLevel] <= 0)
{
/******************/
/* not processing */
/******************/
while (*tptr)
{
while (*tptr && *tptr != '|') tptr++;
if (!*tptr) break;
if (MATCH4 (tptr, "|if|") ||
MATCH6 (tptr, "|elif|") ||
MATCH6 (tptr, "|else|") ||
MATCH7 (tptr, "|endif|"))
{
DOC_PUT (docptr, tptr, sptr);
error = renderCondition (docptr);
if (error) GOTO_FI_LI (docptr, conditional_error)
DOC_GET (docptr, tptr, sptr, zptr);
if (docptr->conditional[docptr->conLevel] > 0) break;
}
else
if (MATCH7 (tptr, "|break|"))
{
for (cptr = "\n\n"; *cptr; *sptr++ = *cptr++);
tptr = docptr->text + docptr->tlength;
DOC_PUT (docptr, tptr, sptr);
break;
}
else
if (MATCH6 (tptr, "|exit|"))
{
for (cptr = "\n\n"; *cptr; *sptr++ = *cptr++);
DOC_PUT (docptr, tptr, sptr);
return (EFAIL);
}
else
tptr++;
}
continue;
}
if (!isspace(*tptr))
{
if (!(*tptr == '|' && (MATCH5 (tptr, "|set|") ||
MATCH7 (tptr, "|style|"))))
{
/* provide default wasDOC style if not yet otherwise specified */
if (!docptr->styled)
{
DOC_PUT (docptr, tptr, sptr);
renderStyle (docptr, NULL);
DOC_GET (docptr, tptr, sptr, zptr);
aptr = " \n";
continue;
}
}
}
if (docptr->asis)
{
/********/
/* asis */
/********/
/* as-is only terminated by \n||||\n (i.e 4 on a line by itself) */
while (*tptr && sptr < zptr)
{
if (*tptr == '\n')
{
if (MATCH7 (tptr, "\n\\||||\n"))
{
/* seems obvious this is needed if to be documented :-) */
*sptr++ = *tptr++;
tptr++;
}
else
if (MATCH6 (tptr, "\n||||\n"))
{
if (docptr->insight >= 4)
{
DOC_PUT (docptr, tptr, sptr);
renderInsightTag (docptr);
DOC_GET (docptr, tptr, sptr, zptr);
}
/* 1 is "standalone" while 2 is a */
if (docptr->asis == 2)
{
if (docptr->stindex > 0)
{
if (MATCH4 (docptr->cstack[docptr->stindex], "||||"))
{
/* turn it into a
closure */
aptr = "
";
docptr->stindex--;
}
}
}
tptr += 6;
docptr->asis = 0;
break;
}
}
*sptr++ = *tptr++;
}
continue;
}
if (docptr->noescape)
{
/******************/
/* no-HTML-escape */
/******************/
/* can only be terminated by || or |!"| */
while (*tptr && sptr < zptr)
{
if (docptr->insight >= 2)
if (MATCH4 (tptr, "\\/
*/
if (docptr->noescape == 1) tptr += 2;
docptr->noescape = 0;
break;
}
if (MATCH4 (tptr, "|!\"|"))
{
/* ditto */
if (docptr->noescape == 1) tptr += 4;
docptr->noescape = 0;
break;
}
if (*tptr == '\n')
{
if (MATCH3 (tptr, "\n|\n"))
{
/* a non-breaking newline */
tptr += 2;
}
}
*sptr++ = *tptr++;
}
continue;
}
while (*tptr && *tptr != '|' && sptr < zptr)
{
/***************/
/* HTML escape */
/***************/
if (docptr->insight >= 2)
if (MATCH4 (tptr, "\\')
{
tptr++;
/* ditto */
for (cptr = ">"; *cptr; *sptr++ = *cptr++);
continue;
}
if (*tptr == '&')
{
tptr++;
/* ditto */
for (cptr = "&"; *cptr; *sptr++ = *cptr++);
continue;
}
if (*tptr == '\"')
{
tptr++;
/* ditto */
for (cptr = """; *cptr; *sptr++ = *cptr++);
continue;
}
if (*tptr == '\\')
{
if (MATCH2 (tptr, "\\\n"))
{
/* escaped newline - no newline at all */
tptr += 2;
continue;
}
if (MATCH2 (tptr, "\\ "))
{
/* escaped space */
tptr += 2;
/* using the buffer margin so not concerned about overflow */
for (cptr = " "; *cptr; *sptr++ = *cptr++);
continue;
}
if (MATCH2 (tptr, "\\|"))
{
/* escaped bar */
tptr += 2;
/* ditto */
for (cptr = "|"; *cptr; *sptr++ = *cptr++);
continue;
}
if (MATCH4 (tptr, "\\\\\\\\"))
{
/* four consecutive backslashes just ignore */
tptr += 4;
continue;
}
if (!MATCH2 (tptr, "\\\0"))
{
/* escape any other character */
tptr++;
*sptr++ = *tptr++;
continue;
}
}
if (MATCH2 (tptr, "//") && *(tptr-1) == '\n')
{
/* line begins with // */
while (*tptr && *tptr != '\n') tptr++;
while (*tptr && *tptr == '\n') tptr++;
continue;
}
if (*tptr == '\n')
{
if (MATCH3 (tptr, "\n|\n"))
{
/* a non-breaking newline */
tptr += 2;
}
}
*sptr++ = *tptr++;
}
if (!*tptr) break;
/* if buffer space exhausted */
if (sptr >= zptr) continue;
/*****************/
/* must be a '|' */
/*****************/
if (ENDTAG (tptr))
{
/***************/
/* end element */
/***************/
tagptr = tptr;
if (MATCH2 (tptr, "||"))
tptr += 2;
else
if (MATCH2 (tptr, "|!"))
{
/* documented end */
if (isspace(*(tptr+2))) GOTO_FI_LI (docptr, EINVAL_error)
for (cptr = tptr + 2;
*cptr && *cptr != '\n' && *cptr != '|';
cptr++);
if (*cptr != '|') GOTO_FI_LI (docptr, EINVAL_error)
tptr = cptr + 1;
}
else
tptr++;
if (!docptr->stindex) GOTO_FI_LI (docptr, stack_uflow)
aptr = docptr->cstack[docptr->stindex];
if (MATCH10 (aptr, "title[0])
{
/* append the closure so that navig8HeadingFull() will work */
while (*aptr) *sptr++ = *aptr++;
*sptr = '\0';
/* look backwards for the start of the heading */
for (cptr = sptr; cptr > docptr->html; cptr--)
{
if (*cptr != '<') continue;
if (!MATCH2 (cptr, "html) GOTO_FI_LI (docptr, EILSEQ_error)
/* get the main heading */
navig8HeadingMain (cptr, docptr->mainh, sizeof(docptr->mainh));
/* get plain text title */
cptr = navig8GetHeadingId (cptr, frag);
navig8HeadingText (cptr, docptr->title, sizeof(docptr->title));
}
if (docptr->notable == NOTE_HEADING)
{
/* explicit heading has been provided so now in |note| text */
docptr->notable = NOTE_TEXT;
for (cptr = aptr; *cptr; *sptr++ = *cptr++);
aptr = "\n ";
}
}
if (MATCH8 (aptr, ""))
{
if (docptr->table) docptr->table--;
/* for the outermost table cancel any row highlight */
if (!docptr->table) docptr->rowlight = 0;
}
if (MATCH6 (aptr, "<-div>"))
{
/* faux tag; reset any flag and convert to a div closure */
if (!docptr->bfindex) GOTO_FI_LI (docptr, stack_uflow)
docptr->bflag[docptr->bfindex--] = 0;
aptr = "
";
}
if (MATCH7 (aptr, "<-note>"))
{
/* faux tag similar in purpose to above */
if (!docptr->bfindex) GOTO_FI_LI (docptr, stack_uflow)
docptr->notable = 0;
docptr->bflag[docptr->bfindex--] = 0;
aptr = "
\n
";
}
if (dbug>0)
dbugThis (FI_LI, "|| {%s} {%s}",
aptr, dbugMax(docptr->tstack[docptr->stindex]));
/* already checked the stack depth above */
docptr->stindex--;
if (aptr) while (*aptr && sptr < zptr) *sptr++ = *aptr++;
if (docptr->insight >= 4)
{
/* note use of tagptr to document the end tag */
DOC_PUT (docptr, tagptr, sptr);
renderInsightTag (docptr);
DOC_GET (docptr, tagptr, sptr, zptr);
}
continue;
}
/*****************/
/* special cases */
/*****************/
if (docptr->insight >= 4)
{
if (MATCH5 (tptr, "|...|") ||
MATCH5 (tptr, "|:::|"))
{
DOC_PUT (docptr, tptr, sptr);
renderInsightTag (docptr);
DOC_GET (docptr, tptr, sptr, zptr);
}
}
/* must be parsed before table |. */
if (MATCH5 (tptr, "|...|"))
{
tptr += 5;
aptr = "…";
continue;
}
if (MATCH5 (tptr, "|:::|"))
{
tptr += 5;
aptr = "⋮";
continue;
}
if (docptr->table)
{
/********************/
/* table processing */
/********************/
if (MATCH2 (tptr, "|~") ||
MATCH4 (tptr, "|row") ||
MATCH3 (tptr, "|tr"))
{
/*******/
/* row */
/*******/
/* table insight is messy! */
rowptr = tptr;
/* compress intervening white-space */
while (sptr > docptr->html && isspace(*(sptr-1))) sptr--;
if (*(sptr-1) == '>')
{
/* ensuring that empty elements work with CSS :empty */
for (cptr = sptr-1; cptr > docptr->html && *cptr != '<'; cptr--);
if (!MATCH4 (cptr, " docptr->html && isspace(*(sptr-1))) sptr--;
if (*(sptr-1) == '>')
{
/* ensuring that empty elements work with CSS :empty */
for (cptr = sptr-1; cptr > docptr->html && *cptr != '<'; cptr--);
if (!MATCH4 (cptr, " insight >= 4)
{
/* table insight is messy! */
if (rowptr)
{
DOC_PUT (docptr, rowptr, sptr);
renderInsightTag (docptr);
DOC_GET (docptr, rowptr, sptr, zptr);
rowptr = NULL;
}
DOC_PUT (docptr, tagptr, sptr);
renderInsightTag (docptr);
DOC_GET (docptr, tagptr, sptr, zptr);
}
continue;
}
if (MATCH2 (tptr, "|.") ||
(MATCH3 (tptr, "|td") && ispunct(tptr[3])) ||
(MATCH3 (tptr, "|td") && isdigit(tptr[3])) ||
(MATCH5 (tptr, "|data") && ispunct(tptr[5])) ||
(MATCH5 (tptr, "|data") && isdigit(tptr[5])))
{
/********/
/* data */
/********/
tagptr = tptr;
/* compress intervening white-space */
while (sptr > docptr->html && isspace(*(sptr-1))) sptr--;
if (*(sptr-1) == '>')
{
/* ensuring that empty elements work with CSS :empty */
for (cptr = sptr-1; cptr > docptr->html && *cptr != '<'; cptr--);
if (!MATCH4 (cptr, " insight >= 4)
{
/* table insight is messy! */
if (rowptr)
{
DOC_PUT (docptr, rowptr, sptr);
renderInsightTag (docptr);
DOC_GET (docptr, rowptr, sptr, zptr);
rowptr = NULL;
}
DOC_PUT (docptr, tagptr, sptr);
renderInsightTag (docptr);
DOC_GET (docptr, tagptr, sptr, zptr);
}
continue;
}
}
else
if (MATCH2 (tptr, "|~") || MATCH2 (tptr, "|:") || MATCH2 (tptr, "|."))
GOTO_FI_LI (docptr, outside_table_error)
else
if ((MATCH3 (tptr, "|tr") && ispunct(tptr[3])) ||
(MATCH4 (tptr, "|row") && ispunct(tptr[4])))
GOTO_FI_LI (docptr, outside_table_error)
else
if ((MATCH3 (tptr, "|th") && ispunct(tptr[3])) ||
(MATCH5 (tptr, "|head") && ispunct(tptr[5])))
GOTO_FI_LI (docptr, outside_table_error)
else
if ((MATCH3 (tptr, "|td") && ispunct(tptr[3])) ||
(MATCH5 (tptr, "|data") && ispunct(tptr[5])))
GOTO_FI_LI (docptr, outside_table_error)
/* a few cycles could have been saved by stepping over the '|' */
/* just seemed to make the tags clearer in the code left in :-/ */
/*********/
/* other */
/*********/
if (docptr->insight >= 4)
{
DOC_PUT (docptr, tptr, sptr);
renderInsightTag (docptr);
DOC_GET (docptr, tptr, sptr, zptr);
}
if (MATCH2 (tptr, "|\""))
{
/* 1 is "standalone" and 2 is a / */
docptr->noescape = 1;
tptr += 2;
continue;
}
if (MATCH2 (tptr, "|\\"))
{
/* leading backslash; ignore the rest of the tag */
for (tptr++; *tptr; tptr++)
{
if (MATCH2 (tptr, "\\|"))
tptr += 2;
else
if (*tptr == '|' && ENDTAG (tptr))
break;
}
if (!*tptr) break;
if (MATCH2 (tptr, "||")) tptr++;
tptr++;
continue;
}
/* especially this one needs to be before "strike" */
if (MATCH3 (tptr, "|-|"))
{
tptr += 3;
aptr = "–";
continue;
}
if (MATCH4 (tptr, "|--|"))
{
tptr += 4;
aptr = "—";
continue;
}
if (MATCH3 (tptr, "|//"))
{
/* comment (must come before "|/" - italic) */
if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow)
docptr->tstack[docptr->stindex] = tptr;
docptr->cstack[docptr->stindex] = " -->";
aptr = "";
continue;
}
if (MATCH7 (tptr, "|index|"))
{
/* insert a marker for where the INDEX will be */
tptr += 7;
if (MATCH2 (tptr, "||")) tptr++;
tptr++;
aptr = "";
continue;
}
if (MATCH7 (tptr, "|break|"))
{
for (cptr = "\n\n"; *cptr; *sptr++ = *cptr++);
tptr = docptr->text + docptr->tlength;
DOC_PUT (docptr, tptr, sptr);
break;
}
if (MATCH6 (tptr, "|exit|"))
{
for (cptr = "\n\n"; *cptr; *sptr++ = *cptr++);
DOC_PUT (docptr, tptr, sptr);
return (EFAIL);
}
if (MATCH10 (tptr, "|insight!|"))
{
tptr += 10;
DOC_PUT (docptr, tptr, sptr)
renderInsightStack (docptr);
DOC_GET (docptr, tptr, sptr, zptr)
continue;
}
if (MATCH10 (tptr, "|insight@|"))
{
tptr += 10;
if (docptr->isDynamic && docptr->insight)
{
aptr =
"
\n\
\n\
\n\
\n\
\n";
docptr->insightAt = 1;
}
continue;
}
/***********/
/* unknown */
/***********/
GOTO_FI_LI (docptr, unknown_tag)
}
/*******/
/* end */
/*******/
if (docptr->stindex > 0) GOTO_FI_LI (docptr, unbalanced_error)
DOC_PUT (docptr, tptr, sptr)
if (docptr->chunked <= 0)
wasDocHtmlPrint (docptr, "
%s \n", docptr->title);
if (docptr->insight >= 5) wasDocInsight (docptr, "anchor headings");
cptr = "Heading";
if (error = navig8AnchorHeadings (docptr)) goto post_condition_error;
if (docptr->insight >= 5) wasDocInsight (docptr, "resolve references");
cptr = "Reference";
if (error = navig8ReferAll (docptr)) goto post_condition_error;
if (docptr->insight >= 5) wasDocInsight (docptr, "paginate");
cptr = "Paginate";
if (error = navig8Paginate (docptr)) goto post_condition_error;
if (docptr->insight >= 5) wasDocInsight (docptr, "secondary TOC");
cptr = "TOC2";
if (error = navig8SubTOC (docptr)) goto post_condition_error;
if (docptr->insight >= 5) wasDocInsight (docptr, "primary TOC");
cptr = "TOC";
if (error = navig8TOC (docptr)) goto post_condition_error;
if (docptr->insight >= 5) wasDocInsight (docptr, "Index");
cptr = "Index";
if (error = navig8Index (docptr)) goto post_condition_error;
if (docptr->insight >= 2) wasDocInsight (docptr, "END");
return (0);
EILSEQ_error:
error = EILSEQ;
goto post_condition_error;
post_condition_error:
aptr = docptr->html + docptr->hparse;
DOC_PUT (docptr, tptr, sptr)
renderErrorReport (docptr,
"\n
%s post processing error %s \
at "%s "%s
\n",
cptr, strerror(error), renderLineEscape(aptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
DOC_GET (docptr, tptr, sptr, zptr)
return (error);
unknown_tag:
DOC_PUT (docptr, tptr, sptr)
renderErrorReport (docptr,
"
Unknown tag "%s " at \
"%s "%s
\n",
renderTag(tptr), renderLine(docptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
DOC_GET (docptr, tptr, sptr, zptr)
return (error);
insert_error:
DOC_PUT (docptr, tptr, sptr)
renderErrorReport (docptr,
"\n
Insert failed %s at \
"%s "%s
\n",
strerror(error), renderLine(docptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
DOC_GET (docptr, tptr, sptr, zptr)
return (error);
EINVAL_error:
error = EINVAL;
goto param_error;
param_error:
DOC_PUT (docptr, tptr, sptr)
renderErrorReport (docptr,
"\n
Parameter error %s at \
\"%s \"%s
\n",
strerror(error), renderLine(docptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
DOC_GET (docptr, tptr, sptr, zptr)
return (error);
vms_status_error:
DOC_PUT (docptr, tptr, sptr)
renderErrorReport (docptr,
"\n
VMS status %%X%08.08X error %s at \
\"%s \"%s
\n",
error, strerror(0,error), renderLine(docptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
DOC_GET (docptr, tptr, sptr, zptr)
return (error);
outside_table_error:
DOC_PUT (docptr, tptr, sptr)
renderErrorReport (docptr,
"\n
Tag "%s " used outside table at \
"%s "%s
\n",
renderTag(tptr), renderLine(docptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
DOC_GET (docptr, tptr, sptr, zptr)
return (error);
stack_oflow:
DOC_PUT (docptr, tptr, sptr)
renderErrorReport (docptr,
"\n
Overflow at "%s "%s
\n",
renderLine(docptr));
renderErrorReport (docptr, NULL);
DOC_GET (docptr, tptr, sptr, zptr)
return (error);
stack_uflow:
DOC_PUT (docptr, tptr, sptr)
renderErrorReport (docptr,
"\n
Underflow at "%s "%s
\n",
renderLine(docptr), renderSource(docptr));
renderErrorReport (docptr, NULL);
DOC_GET (docptr, tptr, sptr, zptr)
return (error);
conditional_error:
if (!error)
cptr = "unbalanced";
else
cptr = strerror(error);
DOC_PUT (docptr, tptr, sptr)
renderErrorReport (docptr,
"
Conditional %s at \
"%s "%s
",
cptr, renderLine(docptr), renderSource(docptr));
renderErrorReport (docptr, NULL);
DOC_GET (docptr, tptr, sptr, zptr)
return (error);
unbalanced_error:
DOC_PUT (docptr, tptr, sptr)
renderErrorReport (docptr,
"
Unbalanced at "%s "%s",
renderLine(docptr), renderSource(docptr));
while (docptr->stindex)
{
renderErrorReport (docptr, " %d "%s "",
docptr->stindex, renderLine(docptr));
docptr->stindex--;
}
renderErrorReport (docptr, "
");
renderErrorReport (docptr, NULL);
DOC_GET (docptr, tptr, sptr, zptr)
return (error);
}
/*****************************************************************************/
/*
If the primary document reports an error in some indeterminate state (e.g.
inside a heading, monospace, italic, table, etc.) to get the error report out a
markup-clean environment is needed. Hence the IFRAME. The iframe is populated
using JavaScript.
An initial call sets up the dynamic created IFRAME and formats an initial
report line. Subsequent calls can add lines to the report. A final "cleanup"
call (mandatory) loses and displays the report.
*/
int renderErrorReport
(
struct wasdoc_st *docptr,
char *fmt,
...
)
{
static int init = 0;
int cnt, linum, retval, size;
char *aptr, *bptr, *fiptr, *cptr, *sptr, *tptr, *zptr;
char finame [64];
va_list args;
if (!fmt)
{
/* end call */
wasDocHtmlPrint (docptr, "\n");
init = 0;
return (0);
}
va_start (args, fmt);
size = vsnprintf (NULL, 0, fmt, args);
va_end (args);
if (size < 0) return (errno);
bptr = calloc (1, size);
if (!bptr) exit (vaxc$errno);
va_start (args, fmt);
retval = vsprintf (bptr, fmt, args);
va_end (args);
if (retval < 0) return (retval);
if (retval != size) exit (SS$_BUGCHECK);
/* escape any forbiddens in the string */
cnt = 0;
for (cptr = bptr; *cptr; cptr++)
if (*cptr == '\n' || *cptr == '\'' || *cptr == '\\') cnt++;
if (cnt)
{
aptr = sptr = calloc (1, size + cnt);
if (!aptr) exit (vaxc$errno);
for (cptr = bptr; *cptr; cptr++)
{
if (*cptr == '\n' || *cptr == '\'' || *cptr == '\\') *sptr++ = '\\';
if (*cptr == '\n')
*sptr++ = 'n';
else
if (isprint(*cptr))
*sptr++ = *cptr;
}
free (bptr);
bptr = aptr;
}
if (!init)
{
if (fiptr = docptr->fiptr)
{
while (*fiptr) fiptr++;
while (*(fiptr-1) != ']' && fiptr > docptr->fiptr) fiptr--;
zptr = (sptr = finame) + sizeof(finame)-1;
while (*fiptr && *fiptr != ';' && sptr < zptr) *sptr++ = *fiptr++;
*sptr = '\0';
}
linum = docptr->linum;
wasDocHtmlPrint (docptr, "",
fiptr ? finame : "(null)", linum);
}
wasDocHtmlPrint (docptr,
"\n
\n\
\n", bptr);
init = 1;
free (bptr);
return (0);
}
/*****************************************************************************/
/*
Return a pointer to the tag as a string.
*/
char* renderTag (char *tptr)
{
static char buf [32+1];
char *sptr, *zptr;
zptr = (sptr = buf) + sizeof(buf)-2;
if (*tptr == '|') *sptr++ = *tptr++;
if (isalpha(*tptr))
{
while (*tptr && *tptr != '|' && sptr < zptr) *sptr++ = *tptr++;
*sptr++ = '|';
}
else
if (isdigit(*tptr))
while (*tptr && isdigit(*tptr)&& sptr < zptr) *sptr++ = *tptr++;
else
*sptr++ = *tptr;
*sptr = '\0';
return (buf);
}
/*****************************************************************************/
/*
Return a pointer to the line as a string. Call pointing at start of line.
*/
char* renderLine (struct wasdoc_st *docptr)
{
static char buf [96];
char *cptr, *sptr, *zptr;
if (dbug>0) dbugThis (FI_LI, "renderLine() {%s}",
dbugMax(docptr->text + docptr->tparse));
zptr = (sptr = buf) + sizeof(buf)-1;
cptr = docptr->text + docptr->tparse;
while (*cptr && *cptr != '\n') cptr++;
while (*cptr == '\n') cptr++;
while (cptr > docptr->text && *(cptr-1) == '\n') cptr--;
while (cptr > docptr->text && *(cptr-1) != '\n') cptr--;
while (*cptr && *cptr != '\n' && sptr < zptr) *sptr++ = *cptr++;
*sptr = '\0';
if (dbug>0) dbugThis (FI_LI, "{%s}", buf);
return (buf);
}
/*****************************************************************************/
/*
Return a pointer to a buffer containing the line number and source file name
(see ConditionFile()).
*/
char* renderSource (struct wasdoc_st *docptr)
{
static char buf [128];
int clnum = 0, slnum = 0;
char *cptr, *sptr, *tptr, *tzptr, *zptr;
char sname [96];
strcpy (buf, " BUGCHECK!");
strcpy (sname, " BUGCHECK!");
tzptr = docptr->text + docptr->tparse;
for (tptr = docptr->text; *tptr && tptr < tzptr; tptr++)
{
if (*tptr == '\n') clnum++;
if (*tptr != '\\') continue;
if (!MATCH4 (tptr, "\\' :
for (cptr = ">"; *cptr && sptr < zptr; *sptr++ = *cptr++);
break;
case '&' :
for (cptr = "&"; *cptr && sptr < zptr; *sptr++ = *cptr++);
break;
default: *sptr++ = *hptr;
}
hptr++;
}
*sptr = '\0';
return (buf);
}
/*****************************************************************************/
/*
Evaluate the conditional depending on the current conditioning status.
Returns ECHILD on underflow, E2BIG on overflow, and EINVAL if unknown.
The docptr->conditional datum has the value
1) when processing
-1) has processed but hit |elif| or |else| and so no longer
0) not processing
Document content is only processed when it has a value > 0. So if an |elif|
hits a 1 at its own level then that level goes to -1. Same for an |else|.
The condition processor parses all levels in nested conditionals, even when not
actually processing more nested levels due to non-processing less nested
levels, and so should catch and report syntactic errors of all levels.
*/
int renderCondition (struct wasdoc_st *docptr)
{
int error = 0, elif = 0, insight, isnot = 0, minus1, yes = 0;
char *aptr, *bptr, *cptr, *tptr;
char buf [1024];
tptr = docptr->text + docptr->tparse;
if (dbug>0)
dbugThis (FI_LI, "renderCondition() %d %d {%s}",
docptr->conLevel, docptr->conditional[docptr->conLevel],
dbugMax(tptr));
/* some processing determined by the preceding level */
if (docptr->conLevel)
minus1 = docptr->conditional[docptr->conLevel-1];
else
minus1 = 1;
/* if deeper not processing then no insight unless 5 or more */
insight = docptr->insight;
if (minus1 <= 0)
if (docptr->insight < 5)
docptr->insight = 0;
if ((elif = MATCH6 (tptr, "|elif|")) && !docptr->conLevel)
error = ECHILD;
else
if (MATCH4 (tptr, "|if|") || elif)
{
tptr += 4;
if (elif) tptr += 2;
docptr->tparse = tptr - docptr->text;
error = renderGetParam (docptr, buf, sizeof(buf));
if (error) return (EINVAL);
tptr = docptr->text + docptr->tparse;
if (MATCH2 (tptr, "||")) tptr++;
if (*tptr == '|') tptr++;
if (docptr->insight >= 4)
wasDocInsight (docptr, "%s", buf);
bptr = buf;
if (*bptr == '!')
{
isnot = 1;
bptr++;
}
else
if (MATCH2 (bptr, "\\!"))
bptr++;
if (!bptr[0])
/* no conditional is false */
yes = 0;
else
if (MATCH2 (bptr, "0"))
yes = 0;
else
if (MATCH2 (bptr, "1"))
yes = 1;
else
if (MATCH8 (bptr, "dynamic"))
yes = docptr->isDynamic;
else
if (MATCH7 (bptr, "static"))
yes = docptr->isStatic;
else
if (MATCH7 (bptr, "single"))
yes = !docptr->chunked;
else
if (MATCH6 (bptr, "multi"))
yes = docptr->chunked;
else
if (MATCH5 (bptr, "hide"))
yes = CgiLibVarNull("WWW_FORM_NOHIDE") != NULL;
else
if (MATCH5 (bptr, "wasd"))
yes = CgiLibEnvironmentIsWasd();
else
if (MATCH7 (bptr, "apache"))
yes = CgiLibEnvironmentIsApache();
else
if (MATCH4 (bptr, "osu"))
yes = CgiLibEnvironmentIsOsu();
else
if (MATCH4 (bptr, "cgi="))
{
if (isCgi || isCgiPlus)
{
/*
[:] */
for (aptr = bptr + 4; *aptr && *aptr != ':'; aptr++);
if (*aptr) *aptr++ = '\0';
cptr = CgiLibVarNull (bptr+4);
yes = testCondition (docptr, cptr, aptr);
}
else
yes = 0;
}
else
if (MATCH4 (bptr, "lnm="))
{
/* [;][:] */
for (aptr = bptr + 4; *aptr && *aptr != ':'; aptr++);
if (*aptr) *aptr++ = '\0';
cptr = renderTrnLnm (docptr, bptr+7, 0);
yes = testCondition (docptr, cptr, aptr);
}
else
if (MATCH6 (bptr, "spawn="))
{
/* spawn=[:] */
for (aptr = cptr = bptr + 6; *aptr && *aptr != ':'; aptr++)
{
/* escape to allow ':' in the spawn command */
if (*aptr == '\\' && *(aptr+1) == ':') aptr++;
*cptr++ = *aptr;
}
if (*aptr) *aptr++ = '\0';
*cptr = '\0';
yes = SpawnCommand (docptr, bptr+6, aptr) < 0;
}
else
if (MATCH4 (bptr, "syi="))
{
if (isCgi || isCgiPlus)
{
/* [:] */
for (aptr = bptr + 4; *aptr && *aptr != ':'; aptr++);
if (*aptr) *aptr++ = '\0';
cptr = renderGetSyi (docptr, bptr+4);
yes = testCondition (docptr, cptr, aptr);
}
else
yes = 0;
}
else
if (MATCH5 (bptr, "time:"))
yes = testTime (docptr, bptr+5);
else
if (MATCH8 (bptr, "insight:"))
{
/* is insight enabled is it at this value */
if (isdigit(bptr[8]))
yes = atoi(bptr+8) >= docptr->insight;
else
yes = docptr->insight > 0;
}
else
if (isupper(bptr[0]))
{
/* [:] */
for (aptr = bptr; *aptr && *aptr != ':'; aptr++);
if (*aptr) *aptr++ = '\0';
cptr = renderFlag (docptr, bptr, 0);
if (cptr)
{
if (*aptr)
yes = testCondition (docptr, cptr, aptr);
else
{
while (cptr && isspace(*cptr)) cptr++;
if (isdigit(*cptr))
yes = atoi(cptr);
else
yes = !*cptr;
}
}
else
error = EINVAL;
}
else
error = EINVAL;
if (!error)
{
if (minus1 > 0)
{
/* deeper is processing */
if (isnot) yes = !yes;
if (elif)
if (docptr->conditional[docptr->conLevel] == 0)
docptr->conditional[docptr->conLevel] = yes;
else
docptr->conditional[docptr->conLevel] = -1;
else
if (docptr->conditional[docptr->conLevel] > 0)
if (docptr->conLevel < CONDITION_MAX)
docptr->conditional[++docptr->conLevel] = yes;
else
error = E2BIG;
else
docptr->conditional[++docptr->conLevel] = -1;
}
else
{
/* deeper is NOT processing */
if (elif)
docptr->conditional[docptr->conLevel] = -1;
else
if (docptr->conLevel < CONDITION_MAX)
docptr->conditional[++docptr->conLevel] = -1;
else
error = E2BIG;
}
}
}
else
if (MATCH6 (tptr, "|else|"))
{
if (docptr->insight >= 4) wasDocInsight (docptr, "|else|");
if (!docptr->conLevel)
error = ECHILD;
else
if (minus1 > 0)
/* deeper is processing */
if (docptr->conditional[docptr->conLevel] == 0)
docptr->conditional[docptr->conLevel] = 1;
else
docptr->conditional[docptr->conLevel] = -1;
else
/* deeper is NOT processing */
docptr->conditional[docptr->conLevel] = -1;
tptr += 6;
}
else
if (MATCH7 (tptr, "|endif|"))
{
if (docptr->insight >= 4) wasDocInsight (docptr, "|endif|");
if (!docptr->conLevel)
error = ECHILD;
else
docptr->conditional[docptr->conLevel--] = 0;
tptr += 7;
}
else
error = EINVAL;
if (docptr->insight >= 4)
wasDocInsight (docptr, "%s%d/%d",
docptr->conditional[docptr->conLevel] > 0 ? "✓" : "✗",
docptr->conLevel, docptr->conditional[docptr->conLevel]);
if (*tptr == '\n') tptr++;
docptr->tparse = tptr - docptr->text;
docptr->insight = insight;
if (dbug>0)
dbugThis (FI_LI, "%d %d {%s}",
docptr->conLevel, docptr->conditional[docptr->conLevel],
dbugMax(tptr));
return (error);
}
/*****************************************************************************/
/*
Copy a bar-delimited string into the supplied buffer.
Return 0 for success or any other errno for error.
*/
int renderGetParam
(
struct wasdoc_st *docptr,
char *buf,
int size
)
{
char *sptr, *tptr, *zptr;
buf[0] = '\0';
/* look slightly behind to check if one might not be supplied */
tptr = docptr->text + docptr->tparse - 1;
if (dbug>0) dbugThis (FI_LI, "renderGetParam() {%s}", dbugMax(tptr));
if (ENDTAG (tptr) && !MATCH2 (tptr, "|!")) return (0);
tptr++;
zptr = (sptr = buf) + size - 1;
if (zptr <= sptr) RETURN_FI_LI (docptr, ERANGE)
while (*tptr && *tptr != '|' && sptr < zptr)
{
if (*tptr == '\\')
{
tptr++;
if (*tptr == '\n')
{
tptr++;
continue;
}
if (!*tptr) break;
}
*sptr++ = *tptr++;
}
if (*tptr != '|') RETURN_FI_LI (docptr, EINVAL)
if (sptr >= zptr) RETURN_FI_LI (docptr, ERANGE)
*sptr = '\0';
docptr->tparse = tptr - docptr->text;
return (0);
}
/*****************************************************************************/
/*
Set document characteristic.
*/
int renderSet
(
struct wasdoc_st *docptr,
char *param
)
{
int error = 0, number;
char *cptr, *sptr, *tptr, *zptr;
if (dbug>0) dbugThis (FI_LI, "renderSet() {%s}", dbugMax(param));
if (MATCH8 (param, "chunked="))
{
/* 1 enables, 0 let the client decide, -1 disables */
int chunked;
chunked = atoi(param+8);
if (chunked < 0 || !docptr->chunked) docptr->chunked = chunked;
}
else
if (MATCH9 (param, "idx=cols="))
{
/* number of colmns in the index */
number = atoi(param+9);
if (number == 1 || number == 2 || number == 3 || number == 4)
docptr->setIdxCols = number;
else
error = EINVAL;
}
else
if (MATCH8 (param, "insight="))
{
/* is explicitly looked for *very* early in document processing */
if (docptr->insight = atoi(param+8))
if (cptr = CgiLibVarNull ("FORM_INSIGHT"))
docptr->insight = atoi(cptr);
}
else
if (MATCH7 (param, "locale="))
{
if (MATCH0 (param, "locale=ctype=", 13)) {
if (!setlocale (LC_CTYPE, param+13)) error = errno;
}
else
if (MATCH7 (param, "locale=") && isdigit(param[7]) && param[8] == '=') {
if (!setlocale (atoi(param+8), param+10)) error = errno;
}
else
if (MATCH7 (param, "locale=")) {
if (!setlocale (LC_ALL, param+7)) error = errno;
}
}
else
if (MATCH9 (param, "navigate="))
{
/* leading integer can enable/disable navigation icons */
cptr = param + 9;
if (isdigit(*cptr))
{
docptr->setNavigate = atoi(cptr);
while (isdigit(*cptr)) cptr++;
if (*cptr == '|') cptr++;
}
if (!*cptr) return (0);
/* navigation icons, |||| */
if (*cptr != '|')
{
zptr = (sptr = docptr->iconBack) + sizeof(docptr->iconBack)-1;
while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++;
*sptr = '\0';
while (*cptr && *cptr != '|') cptr++;
}
if (*cptr) cptr++;
if (*cptr != '|')
{
zptr = (sptr = docptr->iconPrev) + sizeof(docptr->iconPrev)-1;
while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++;
*sptr = '\0';
while (*cptr && *cptr != '|') cptr++;
}
if (*cptr) cptr++;
if (*cptr != '|')
{
zptr = (sptr = docptr->iconTop) + sizeof(docptr->iconTop)-1;
while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++;
*sptr = '\0';
while (*cptr && *cptr != '|') cptr++;
}
if (*cptr) cptr++;
if (*cptr != '|')
{
zptr = (sptr = docptr->iconNext) + sizeof(docptr->iconNext)-1;
while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++;
*sptr = '\0';
while (*cptr && *cptr != '|') cptr++;
}
if (*cptr) cptr++;
if (*cptr != '|')
{
zptr = (sptr = docptr->iconForw) + sizeof(docptr->iconForw)-1;
while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++;
*sptr = '\0';
while (*cptr && *cptr != '|') cptr++;
}
}
else
if (MATCH5 (param, "note="))
{
/* explicitly set the default title of a note */
zptr = (sptr = docptr->setNote) + sizeof(docptr->setNote)-1;
for (cptr = param + 5; *cptr && sptr < zptr; *sptr++ = *cptr++);
*sptr = '\0';
}
else
if (MATCH9 (param, "paginate="))
{
/* enable automatic pagination */
docptr->setPaginate = atoi(param+9);
}
else
if (MATCH10 (param, "table=margin="))
{
/* table margin (+, -, \0) */
docptr->setTabMargin = param[13];
docptr->bflag[docptr->bfindex] &= ~BFLAG_CENTER;
}
else
if (MATCH6 (param, "title="))
{
/* explicitly set the title of the document */
zptr = (sptr = docptr->title) + sizeof(docptr->title)-1;
for (cptr = param + 6; *cptr && sptr < zptr; *sptr++ = *cptr++);
*sptr = '\0';
}
else
if (MATCH5 (param, "toc2="))
{
/* whether a secondry TOC is generated */
docptr->setToc2 = atoi(param+5);
}
else
if (MATCH9 (param, "toc=cols="))
{
/* number of colmns in table of content */
number = atoi(param+9);
if (number == 1 || number == 2 || number == 3 || number == 4)
docptr->setTocCols = number;
else
error = EINVAL;
}
else
if (MATCH11 (param, "toc=format="))
{
/* explicitly set the format of the TOC */
zptr = (sptr = docptr->setTocForm) + sizeof(docptr->setTocForm)-1;
for (cptr = param + 11; *cptr && sptr < zptr; *sptr++ = *cptr++);
*sptr = '\0';
}
else
if (isupper (param[0]))
{
/* setting a flag */
if (!renderFlag (docptr, param, 1)) error = EINVAL;
}
else
error = EINVAL;
return (error);
}
/*****************************************************************************/
/*
Flags begin with an upper-case alphabetic, have all upper-case alphabetics and
digits. Flag strings are |set|FLAG[=|]| by renderSet().
Search the array of flags strings for the specified flag. Can set a new
flag, reset an existing flag, and also just search for a flag. If the
parameter contains an equate symbol (=) then it's considered to be a (re)set.
A set/reset returns a pointer for success or a NULL if something failed.
If not found return NULL to indicate that.
If found and if the flag has a value return a pointer to that (even if empty).
*/
char* renderFlag
(
struct wasdoc_st *docptr,
char *flag,
int set
)
{
int idx;
char *cptr, *sptr;
if (dbug>0) dbugThis (FI_LI, "renderFlag() %d {%s}", set, flag);
/* search for an existing flag */
for (idx = 0; idx < docptr->flagCount; idx++)
{
sptr = flag;
for (cptr = docptr->flags[idx];
*cptr && *cptr != '=' && *sptr && *sptr != '=';
cptr++, sptr++)
if (*cptr != *sptr) break;
if (*cptr && *cptr != '=') continue;
if (*sptr && *sptr != '=') continue;
break;
}
if (idx >= docptr->flagCount)
{
/* not found */
if (!set) return (NULL);
/* check not an empty name and is all upper */
for (cptr = flag;
*cptr && *cptr != '=' && (isupper(*cptr) || isdigit(*cptr));
cptr++);
if (cptr == flag) return (NULL);
if (*cptr && *cptr != '=' && !isupper(*cptr) && !isdigit(*cptr))
return (NULL);
/* set a new flag */
if (docptr->flagCount >= FLAG_MAX) RETURN_FI_LI (docptr, NULL)
docptr->flags[docptr->flagCount] = calloc (strlen(flag), 1);
if (!docptr->flags[docptr->flagCount]) RETURN_FI_LI (docptr, NULL)
strcpy (docptr->flags[docptr->flagCount], flag);
docptr->flagCount++;
for (cptr = flag; *cptr && *cptr != '='; cptr++);
if (*cptr) cptr++;
return (cptr);
}
/* if reset an existing flag */
if (*sptr)
{
free (docptr->flags[idx]);
docptr->flags[idx] = calloc (strlen(flag), 1);
if (!docptr->flags[idx]) RETURN_FI_LI (docptr, NULL)
strcpy (docptr->flags[idx], flag);
for (cptr = flag; *cptr && *cptr != '='; cptr++);
if (*cptr) cptr++;
return (cptr);
}
/* if just searching for a flag */
if (*cptr) cptr++;
return (cptr);
}
/*****************************************************************************/
/*
The navig8TOC() looks at the section integers. The |1..|4 represent the
primary TOC hierarchy. |0 represents a secondary heading without a
primary TOC. |0 is transformed into an heading. Cross-reference |9 into
a .
Prefixing any section digit (01, 02, 03, 04) with a zero represents a heading
without a primary TOC entry.
*/
int renderInsertHeading (struct wasdoc_st *docptr)
{
int error;
char ch, zero;
char *aptr, *cptr, *sptr, *tptr, *zptr;
if (dbug>0) dbugThis (FI_LI, "renderInsertHeading()");
tptr = docptr->text + docptr->tparse;
if (tptr[0] != '|') RETURN_FI_LI (docptr, EILSEQ)
if (docptr->stindex >= STACK_MAX) RETURN_FI_LI (docptr, ERANGE)
docptr->tstack[++docptr->stindex] = tptr;
/* leading zero suppresses primary TOC entry */
cptr = tptr + 1;
if (cptr[0] == '0' && isdigit(cptr[1]))
zero = 1;
else
zero = 0;
switch (*cptr)
{
case '0' : docptr->section[5]++;
docptr->section[6] = 0;
docptr->cstack[docptr->stindex] = " ";
cptr = "section[5]++;
else
{
docptr->section[1]++;
docptr->chunkTotal++;
docptr->section[2] = docptr->section[3] =
docptr->section[4] = docptr->section[5] =
docptr->section[6] = 0;
}
docptr->cstack[docptr->stindex] = "";
cptr = "section[5]++;
else
{
docptr->section[2]++;
docptr->section[3] = docptr->section[4] =
docptr->section[5] = docptr->section[6] = 0;
}
docptr->cstack[docptr->stindex] = "";
cptr = "section[5]++;
else
{
docptr->section[3]++;
docptr->section[4] = docptr->section[5] =
docptr->section[6] = 0;
}
docptr->cstack[docptr->stindex] = "";
cptr = "section[5]++;
else
{
docptr->section[4]++;
docptr->section[5] = docptr->section[6] = 0;
}
docptr->cstack[docptr->stindex] = "";
cptr = "section[6]++;
docptr->cstack[docptr->stindex] = "";
cptr = "\n",
docptr->section[1], docptr->section[2],
docptr->section[3], docptr->section[4],
docptr->section[5], docptr->section[6]);
error = renderInsertTag (docptr, cptr);
if (error) return (error);
/* the heading text - id component */
wasDocHtmlPrint (docptr,
"",
docptr->section[1], docptr->section[2],
docptr->section[3], docptr->section[4],
docptr->section[5], docptr->section[6]);
if (!(docptr->setTocForm[0] >= '1' &&
docptr->setTocForm[0] <= '9')) ch = '\0';
switch (ch)
{
case '1' : wasDocHtmlPrint (docptr,
"%d. ",
docptr->section[1]);
docptr->finalH1 = docptr->section[1];
break;
case '2' : wasDocHtmlPrint (docptr,
"%d.%d ",
docptr->section[1],
docptr->section[2]);
break;
case '3' : wasDocHtmlPrint (docptr,
"%d.%d.%d ",
docptr->section[1],
docptr->section[2],
docptr->section[3]);
break;
case '4' : wasDocHtmlPrint (docptr,
"%d.%d.%d.%d ",
docptr->section[1],
docptr->section[2],
docptr->section[3],
docptr->section[4]);
break;
default : wasDocHtmlPrint (docptr,
"");
}
return (0);
}
/*****************************************************************************/
/*
Closure of heading.
*/
int renderCloseHeading (struct wasdoc_st *docptr)
{
char *cptr, *sptr, *tptr, *zptr;
char frag [FRAGID_SIZE];
DOC_GET (docptr, tptr, sptr, zptr);
/* look backwards for the start of the heading */
for (cptr = sptr; cptr > docptr->html; cptr--)
{
if (*cptr != '<') continue;
if (!MATCH2 (cptr, "html) RETURN_FI_LI (docptr, EILSEQ)
cptr = navig8SkipHeadingId (cptr);
/* first heading will be used as the default document title */
if (!docptr->title[0])
navig8HeadingText (cptr, docptr->title, sizeof(docptr->title));
DOC_PUT (docptr, tptr, sptr);
return (0);
}
/*****************************************************************************/
/*
*/
int renderInsertNote (struct wasdoc_st *docptr)
{
int error;
char *cptr;
if (dbug>0) dbugThis (FI_LI, "renderInsertNote()");
/* use the default heading */
if (!*(cptr = docptr->setNote)) cptr = DEFAULT_NOTE;
/* a note is implemented as a level 6 heading */
docptr->section[6]++;
error = wasDocHtmlPrint (docptr,
" \n\
\
%s \n\
\n",
docptr->section[1], docptr->section[2],
docptr->section[3], docptr->section[4],
docptr->section[5], docptr->section[6],
docptr->section[1], docptr->section[2],
docptr->section[3], docptr->section[4],
docptr->section[5], docptr->section[6],
cptr);
return (error);
}
/*****************************************************************************/
/*
The parameter URL can be absolute, relative or in-document fragment generated
from a heading title.
*/
int renderInsertLink
(
struct wasdoc_st *docptr,
char *param,
char *text
)
{
char *cptr, *sptr, *tptr, *zptr;
char param2 [256];
if (dbug>0) dbugThis (FI_LI, "renderInsertLink() {%s} {%s}",
param, dbugMax(text));
tptr = docptr->text + docptr->tparse;
/* look for what might be another document (TWO fragment hashes!) */
for (cptr = param; *cptr; cptr++)
if (MATCH2 (cptr, "##")) break;
if (!*cptr)
{
/* look for what might be a URL */
for (cptr = param; *cptr && isalpha(*cptr); cptr++);
}
if (MATCH3 (cptr, "://") || MATCH7 (param, "mailto:"))
{
/* looks like a URL scheme */
renderInsertText (docptr, param, 1);
}
else
if (MATCH2 (cptr, "##"))
{
/* another document, munge the URI */
zptr = (sptr = param2) + sizeof(param2)-1;
/* any trailing chunk faux "directory" must be allowed for */
if (docptr->chunked && docptr->isDynamic)
if (MATCH2 (param, "./") || MATCH3 (param, "../"))
for (cptr = "../"; *cptr; *sptr++ = *cptr++);
/* essentially make it ODS-2 compliant */
for (cptr = param; *cptr && *cptr != '#'; cptr++)
if (isalnum(*cptr) || *cptr == '-' || *cptr == '$' ||
*cptr == '.' || *cptr == '/')
*sptr++ = tolower(*cptr);
else
*sptr++ = '_';
if (cptr[0] == '#' && cptr[1] == '#' && cptr[2]) *sptr++ = *cptr++;
*sptr = '\0';
/* insert the URL */
renderInsertText (docptr, param2, 1);
/* now the fragment if not empty */
if (cptr[0] == '#' && cptr[1])
renderInsertText (docptr, cptr+1, 2);
}
else
if (param[0] == '#')
{
/* explicit fragment */
renderInsertText (docptr, param, 2);
}
else
if (param[0] == '/' ||
MATCH2 (param, "./") ||
MATCH3 (param, "../"))
{
/* relative URL */
renderInsertText (docptr, param, 1);
}
else
{
/* to fragment ID added via heading */
if (ENDTAG (text))
/* indicates the reference descriptor should be substituted */
cptr = "", 1);
}
return (0);
}
/*****************************************************************************/
/*
The parameter URL can be absolute or relative.
*/
int renderInsertUrl
(
struct wasdoc_st *docptr,
char *param
)
{
char ch;
char *cptr, *sptr, *zptr;
char uri [256];
if (dbug>0) dbugThis (FI_LI, "renderInsertUrl() {%s}", param);
/* look for what might be a URL */
for (cptr = param;
*cptr && (isalpha(*cptr) || !MATCH3(cptr,"://"));
cptr++);
if (MATCH3(cptr,"://") || MATCH7 (param, "mailto:"))
{
/* looks like a URL scheme */
renderInsertText (docptr, param, 1);
}
else
if (isalnum(*param) ||
MATCH2 (param, "./") ||
MATCH3 (param, "../"))
{
/* relative to the document location (which may be a script) */
if (docptr->isDynamic)
{
zptr = (sptr = uri) + sizeof(uri)-1;
for (cptr = docptr->pinfo; *cptr && sptr < zptr; *sptr++ = *cptr++);
*sptr = '\0';
while (sptr > uri && *sptr != '/') sptr--;
if (MATCH2 (cptr = param, "./")) cptr += 2;
while (sptr > uri)
{
if (!MATCH3 (cptr, "../")) break;
if (sptr > uri) sptr--;
while (sptr > uri && *sptr != '/') sptr--;
cptr += 3;
}
if (sptr == uri) RETURN_FI_LI (docptr, EINVAL)
if (sptr < zptr) *sptr++ = '/';
while (*cptr && sptr < zptr) *sptr++ = *cptr++;
*sptr = '\0';
if (sptr >= zptr) RETURN_FI_LI (docptr, EOVERFLOW)
renderInsertText (docptr, uri, 1);
}
else
renderInsertText (docptr, param, 1);
}
else
renderInsertText (docptr, param, 1);
return (0);
}
/*****************************************************************************/
/*
Insert the specified item into the HTML, escaped as required.
*/
int renderInsertOther
(
struct wasdoc_st *docptr,
char *param
)
{
static char RepeatFao [] = "!#*?\0";
static $DESCRIPTOR (DateFaoDsc, "!%D\0");
static $DESCRIPTOR (DateWidthFaoDsc, "!#%D\0");
static $DESCRIPTOR (TimeFaoDsc, "!%T\0");
static $DESCRIPTOR (TimeWidthFaoDsc, "!#%T\0");
static $DESCRIPTOR (RepeatFaoDsc, RepeatFao);
int error, noescape, ignore = 0, number = 0, status, trim = 0;
char *cptr, *sptr;
char buf [256];
time_t t;
struct tm *tmp;
$DESCRIPTOR (bdsc, buf);
if (dbug>0) dbugThis (FI_LI, "renderInsertOther() {%s}", param);
if (!param[0]) RETURN_FI_LI (docptr, EINVAL)
*(cptr = buf) = '\0';
if (MATCH4 (param, "cgi="))
{
noescape = docptr->noescape;
cptr = param + 4;
while (*cptr == '!' || *cptr == '\"')
{
if (*cptr == '!') ignore = *cptr++;
if (*cptr == '\"') noescape = *cptr++;
}
cptr = CgiLibVarNull (cptr);
if (!cptr)
if (ignore)
{
wasDocInsertStatus (docptr, 0, EINVAL);
return (0);
}
else
RETURN_FI_LI (docptr, EINVAL)
}
else
if (MATCH4 (param, "env="))
{
noescape = docptr->noescape;
cptr = param + 4;
while (*cptr == '!' || *cptr == '\"')
{
if (*cptr == '!') ignore = *cptr++;
if (*cptr == '\"') noescape = *cptr++;
}
cptr = getenv (cptr);
if (!cptr)
if (ignore)
{
wasDocInsertStatus (docptr, 0, EINVAL);
return (0);
}
else
RETURN_FI_LI (docptr, EINVAL)
}
else
if (MATCH4 (param, "fao="))
{
param += 4;
cptr = buf;
noescape = docptr->noescape;
if (isdigit(*param))
{
number = atoi(param);
if (number > sizeof(buf)-1) number = sizeof(buf)-1;
while (isdigit(*param)) param++;
}
if (MATCH2 (param, "%D"))
if (number)
sys$fao (&DateWidthFaoDsc, 0, &bdsc, number, 0);
else
sys$fao (&DateFaoDsc, 0, &bdsc, 0);
else
if (MATCH2 (param, "%T"))
if (number)
sys$fao (&TimeWidthFaoDsc, 0, &bdsc, number, 0);
else
sys$fao (&TimeFaoDsc, 0, &bdsc, 0);
else
if (param[0] == '*' && param[1])
{
RepeatFao[3] = param[1];
sys$fao (&RepeatFaoDsc, 0, &bdsc, number, 0);
}
else
cptr = NULL;
}
else
if (MATCH5 (param, "file="))
return (renderInsertFile (docptr, param+5, 0));
else
if (MATCH12 (param, "locale=ctype"))
cptr = setlocale (LC_CTYPE, NULL);
else
if (MATCH7 (param, "locale="))
cptr = setlocale (atoi(param+8), NULL);
else
if (MATCH7 (param, "locale"))
cptr = setlocale (LC_ALL, NULL);
else
if (MATCH8 (param, "include="))
return (renderIncludeFile (docptr, param+8));
else
if (MATCH8 (param, "Include="))
return (0);
else
if (MATCH6 (param, "spawn="))
return (SpawnCommand (docptr, param+6, NULL));
else
if (MATCH4 (param, "syi="))
cptr = renderGetSyi (docptr, param+4);
else
if (MATCH4 (param, "time"))
{
if (param[4] == '=')
cptr = param + 5;
else
cptr = "%a, %d %b %Y %T %z";
t = time(NULL);
tmp = localtime(&t);
if (!tmp) RETURN_FI_LI (docptr, EINVAL)
if (!strftime (buf, sizeof(buf), cptr, tmp))
RETURN_FI_LI (docptr, EINVAL)
cptr = buf;
}
else
if (MATCH4 (param, "lnm="))
{
int report = 0;
noescape = docptr->noescape;
for (cptr = sptr = param + 4; *cptr == '!' || *cptr == '\"'; cptr++)
{
if (*cptr == '!') report = 1;
if (*cptr == '\"') noescape = 1;
}
cptr = renderTrnLnm (docptr, cptr, report);
}
else
if (MATCH7 (param, "wasdoc="))
{
if (MATCH8 (param+7, "version"))
cptr = SoftwareVersion;
else
if (MATCH8 (param+7, "software"))
cptr = SoftwareID;
else
if (MATCH5 (param+7, "path"))
cptr = docptr->pinfo;
else
if (MATCH10 (param+7, "directory"))
cptr = docptr->dname;
}
else
if (isupper(param[0]))
{
/* insert the flag value */
noescape = 1;
cptr = renderFlag (docptr, param, 0);
}
if (!cptr || !*cptr) RETURN_FI_LI (docptr, EINVAL)
renderInsertText (docptr, cptr, noescape);
return (0);
}
/*****************************************************************************/
/*
Insert the content of the specified file into the HTML, escaped as required.
*/
int renderInsertFile
(
struct wasdoc_st *docptr,
char *fname,
int noescape
)
{
int bytes, error, ignore = 0, status;
char *cptr, *fnptr, *sptr, *zptr;
FILE *ifptr;
stat_t fstatbuf;
if (dbug>0) dbugThis (FI_LI, "renderInsertFile() %d {%s}", noescape, fname);
if (!noescape) noescape = docptr->noescape ? 1 : 0;
fnptr = fname;
while (*fnptr == '!' || *fnptr == '\"')
{
if (*fnptr == '!') ignore = *fnptr++;
if (*fnptr == '\"') noescape = *fnptr++;
}
if (!*fnptr)
{
/* empty specification means include self */
renderInsertText (docptr, docptr->text, noescape);
return (0);
}
cptr = getenv("PATH");
chdir (docptr->dname);
ifptr = fopen (fnptr, "r");
error = errno;
chdir (cptr);
if (!ifptr)
{
if (!ignore) return (error);
if (*fnptr == '/')
wasDocInsertStatus (docptr, 0, error);
else
wasDocInsertStatus (docptr, vaxc$errno, 0);
return (0);
}
if (fstat (fileno(ifptr), &fstatbuf) < 0)
{
error = errno;
status = vaxc$errno;
fclose (ifptr);
if (!ignore) return (error);
if (*fnptr == '/')
wasDocInsertStatus (docptr, 0, error);
else
wasDocInsertStatus (docptr, status, 0);
return (0);
}
/* extra bytes allow EOF when reading past the EOF */
bytes = fstatbuf.st_size;
bytes += 32;
cptr = sptr = calloc (1, bytes);
if (!cptr) exit (vaxc$errno);
/* read the entire file into memory */
while (fgets (sptr, bytes-(sptr-cptr), ifptr))
while (*sptr) sptr++;
fclose (ifptr);
renderInsertText (docptr, cptr, noescape);
free (cptr);
return (0);
}
/*****************************************************************************/
/*
Insert the content of the specified file into the source TEXT at the current
parse position. The parser will then just continue with the included text.
If it has a ".css" type then we'll assume style has been set.
*/
int renderIncludeFile
(
struct wasdoc_st *docptr,
char *fname
)
{
static char asis1 [] = "\n|asis|\n",
asis2 [] = "||||\n";
int asis = 0, bytes, error, ignore = 0;
char *aptr, *cptr, *fnptr, *sptr, *tptr, *zptr;
FILE *ifptr;
stat_t fstatbuf;
if (dbug>0) dbugThis (FI_LI, "renderIncludeFile() {%s}", fname);
fnptr = fname;
while (*fnptr == '!' || *fnptr == '\"')
{
if (*fnptr == '!') ignore = *fnptr++;
if (*fnptr == '\"') asis = *fnptr++;
}
/* if file extension is ".css" then assume the document has been styled */
for (cptr = fnptr; *cptr; cptr++);
while (cptr > fnptr && *cptr != '.' && !MATCH2((cptr-1), "^.")) cptr--;
if (!strcasecmp (cptr, ".css")) docptr->styled = 1;
if (dbug>0) dbugThis (FI_LI, "{%s}\n", fnptr);
cptr = getenv("PATH");
chdir (docptr->dname);
ifptr = fopen (fnptr, "r");
error = errno;
chdir (cptr);
if (!ifptr)
{
if (!ignore) return (error);
if (*fnptr == '/')
wasDocInsertStatus (docptr, 0, error);
else
wasDocInsertStatus (docptr, vaxc$errno, 0);
return (0);
}
if (fstat (fileno(ifptr), &fstatbuf) < 0)
{
error = errno;
fclose (ifptr);
if (ignore) return (0);
return (error);
}
/* extra bytes allow EOF when reading past the EOF */
bytes = fstatbuf.st_size + 32;
aptr = sptr = calloc (1, bytes);
if (!cptr) exit (vaxc$errno);
/* read the entire file into memory */
while (fgets (sptr, bytes-(sptr-aptr), ifptr))
while (*sptr) sptr++;
fclose (ifptr);
/* adjust bytes to reflect the actual content */
bytes = sptr - aptr;
docptr->tsize += bytes;
if (asis)
{
asis = sizeof(asis1)-1 + sizeof(asis2)-1;
docptr->tsize += asis;
}
docptr->text = realloc (docptr->text, docptr->tsize);
if (!docptr->text) exit (vaxc$errno);
/* current parse position should be just before the end of the tag */
tptr = docptr->text + docptr->tparse;
if (MATCH2 (tptr, "||")) tptr++;
if (*tptr == '|') tptr++;
if (isspace(*tptr)) tptr++;
/* first move the current content up */
memmove (tptr + bytes + asis,
sptr = tptr,
docptr->tlength - (tptr - docptr->text));
/* then insert the text into the space created */
if (asis) for (cptr = asis1; *cptr; *sptr++ = *cptr++);
memmove (sptr, aptr, bytes);
sptr += bytes;
if (asis) for (cptr = asis2; *cptr; *sptr++ = *cptr++);
free (aptr);
if (isspace(*(tptr-1))) tptr--;
docptr->tparse = tptr - docptr->text;
docptr->tlength += bytes + asis;
return (0);
}
/*****************************************************************************/
/*
Insert (append) the supplied text to the HTML.
By default HTML forbidden, the |, and the " characters are escaped.
Parameter |munge| can be 1 for text to be inserted as-is (not escaped).
The |munge| can be 2 for text to be lower-case alphanumerics only (after
escaping). Used for inserting fragment IDs.
*/
int renderInsertText
(
struct wasdoc_st *docptr,
char *text,
int munge
)
{
char *cptr, *sptr, *tptr, *zptr;
if (dbug>0) dbugThis (FI_LI, "renderInsertText() %d {%s}", munge, text);
if (!text) return (0);
tptr = text;
cptr = "";
sptr = docptr->html + docptr->hlength;
zptr = docptr->html + docptr->hzsize;
while (*tptr)
{
if (sptr >= zptr)
{
wasDocHtmlBuffer (docptr, -1);
DOC_HTML (docptr, sptr, zptr)
}
if (munge == 1)
while (*tptr && sptr < zptr) *sptr++ = *tptr++;
else
while (*tptr && sptr < zptr)
{
cptr = "";
if (*tptr == '<')
cptr = "<";
else
if (*tptr == '>')
cptr = ">";
else
if (*tptr == '&')
cptr = "&";
else
if (*tptr == '\"')
cptr = """;
else
if (*tptr == '|')
cptr = "|";
else
*sptr++ = *tptr;
tptr++;
/* zptr always has elbow-room following it */
while (*cptr) *sptr++ = *cptr++;
}
*sptr = '\0';
}
if (munge == 2)
{
zptr = sptr;
for (cptr = sptr = docptr->html + docptr->hlength; cptr < zptr; cptr++)
if (isalnum(*cptr)) *sptr++ = tolower(*cptr);
*sptr = '\0';
}
docptr->hlength = sptr - docptr->html;
return (0);
}
/*****************************************************************************/
/*
Insert a tag and any tag attributes into the HTML. An attribute (&-introduced
and |-delimited) string can be used. Characters may be escaped. It a style
string. Return zero for success or an error code.
*/
int renderInsertTag
(
struct wasdoc_st *docptr,
char *tag
)
{
int div = 0, clidx, head = 0, idx, image = 0, link = 0,
linkimg = 0, list = 0, noescape = 0, note = 0, span = 0,
table = 0, tabr = 0, tabh = 0, tabd = 0, tenths = 0;
char *cptr, *sptr, *tptr, *zptr;
char *align = "", *backlight = "", *blank = "", *bold = "", *inblock = "",
*indent = "", *italic = "", *wrap = "", *mono = "", *strike = "",
*tabauto = "", *target = "", *under = "", *valign = "", *zero = "";
char *class [8];
char colspan [32] = "", empad [32] = "", fname[64], rowspan [32] = "";
for (clidx = 0; (clidx * sizeof(char*)) < sizeof(class); clidx++)
class[clidx] = NULL;
clidx = 0;
DOC_GET (docptr, tptr, sptr, zptr);
if (dbug>0) dbugThis (FI_LI, "renderInsertTag() {%s} {%}",
tag, dbugMax(tptr));
if (!(span = MATCH5 (tag, "bflag[++docptr->bfindex] = 0;
if (span)
{
cptr = "bflag[docptr->bfindex] & BFLAG_CENTER) tabauto = " tabauto";
}
else
if (tabr)
{
if (MATCH2 (tptr, "|~")) tptr++;
cptr = "notable == NOTE_HEADING)
cptr = " class=\"head center";
else
cptr = " class=\"head";
}
}
if (cptr)
{
while (*cptr && sptr < zptr) *sptr++ = *cptr++;
/* span over the tag characters */
if (head)
for (tptr++; isdigit(*tptr); tptr++);
else
for (tptr++; isalpha(*tptr); tptr++);
}
for (; *tptr; tptr++)
{
/* special case, cross-reference elipsis */
if (head && MATCH3 (tptr, "...")) break;
if (MATCH2 (tptr, "\\\n"))
{
tptr++;
continue;
}
if ((tabd || tabh) && *tptr >= '1' && *tptr <= '9')
{
/* table heads and data are allowed digits */
if (tabh || tabd)
{
if (!colspan[0])
sprintf (colspan, " colspan=\"%c\"", *tptr);
else
sprintf (rowspan, " rowspan=\"%c\"", *tptr);
}
continue;
}
/* vbar or period or not-punctuation ends markup */
if (*tptr == '|' || *tptr == '.' ||
*tptr == '\\' || !ispunct(*tptr)) break;
/* and if a table element then a space too */
if ((tabr || tabd || tabh) && isspace(*tptr)) break;
if (*tptr == '*')
bold = " bold";
else
if (*tptr == '/')
italic = " italic";
else
if (*tptr == '_')
under = " under";
else
if (*tptr == '=')
mono = " monosp";
else
if (*tptr == '-' && span)
strike = " strike";
else
if (*tptr == '-' && !span)
indent = " noindent";
else
if (*tptr == '+' && !span)
indent = " indent";
else
if (MATCH2 (tptr, "<<"))
{
wrap = " prewrap";
tptr++;
}
else
if (MATCH2 (tptr, ">>"))
{
wrap = " nowrap";
tptr++;
}
else
if (MATCH2 (tptr, "><"))
{
if (table)
tabauto = " tabauto";
else
align = " center";
if (div) docptr->bflag[docptr->bfindex] |= BFLAG_CENTER;
tptr++;
}
else
if (*tptr == '>')
{
align = " right";
if (div) docptr->bflag[docptr->bfindex] &= ~BFLAG_CENTER;
}
else
if (*tptr == '<')
{
align = " left";
if (div) docptr->bflag[docptr->bfindex] &= ~BFLAG_CENTER;
}
else
if (MATCH2 (tptr, "#+"))
{
/* vertical align top */
valign = " valtop";
tptr++;
}
else
if (MATCH2 (tptr, "#="))
{
/* vertical align middle */
valign = " valmid";
tptr++;
}
else
if (MATCH2 (tptr, "#-"))
{
/* vertical align bottom */
valign = " valbot";
tptr++;
}
else
if (MATCH2 (tptr, "#*"))
{
/* enable row highlight only for any outermost table */
if (tabr && docptr->table == 1 && !docptr->rowlight)
docptr->rowlight++;
else
/* otherwise apply a backlight to the element */
if (!tabr)
backlight = " backlight";
tptr++;
}
else
if (MATCH3 (tptr, "#^*"))
{
/* make this row the same highlight as the previous row */
if (tabr && docptr->table == 1)
if (docptr->rowlight & 1)
docptr->rowlight--;
else
if (docptr->rowlight)
docptr->rowlight++;
tptr += 2;
}
else
if (MATCH3 (tptr, "#!*"))
{
/* disable row highlight only for any outermost table */
if (tabr && docptr->table == 1) docptr->rowlight = 0;
tptr += 2;
}
else
if (MATCH3 (tptr, "#1*"))
{
/* one-shot to any element but escpecially for table row */
backlight = " backlight";
tptr += 2;
}
else
if (MATCH2 (tptr, "##"))
{
/* padding in 0.1 ems */
tptr++;
tenths = atoi(tptr+1);
while (isdigit (*(tptr+1))) tptr++;
if (tenths) sprintf (empad, "padding:%1.1fem;", (float)tenths / 10.0);
}
else
if (MATCH3 (tptr, "#::"))
{
/* inline-block */
inblock = " inblock";
tptr + 2;
}
else
if (*tptr == '#')
{
if (list)
zero = " list0";
else
if (tabr || tabh || tabd)
zero = " tab0";
else
zero = " display0";
}
else
if (*tptr == '%')
{
if (link)
{
if (!linkimg) blank = " blank";
target = " target=\"_blank\"";
}
else
if (image)
{
/* % used to create a link to the image, see |image| */
tptr++;
if (*tptr == '%') tptr++;
}
}
else
if (*tptr == '\'')
{
/* single quote - append this class */
if (tptr[1] == '_' || isalpha(tptr[1]))
{
class[clidx] = tptr + 1;
if ((clidx * sizeof(char*)) < sizeof(class)) clidx++;
if (tptr[1] == '_') tptr++;
while (isalnum(tptr[1])) tptr++;
}
}
else
if (*tptr == '\"')
/* 1 is "standalone" and 2 is a / */
noescape = docptr->noescape = 2;
else
if (*tptr == '&') /* rest of string is style */
break;
}
/* apply row highlight only for any outermost table */
if (tabr && docptr->rowlight && docptr->table == 1)
if (docptr->rowlight++ & 1)
backlight = " backlight";
for (cptr = align; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = backlight; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = blank; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = bold; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = inblock; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = indent; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = italic; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = mono; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = strike; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = tabauto; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = under; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = valign; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = wrap; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = zero; *cptr && sptr < zptr; *sptr++ = *cptr++);
/* append additional explicitly specified class names */
for (clidx = 0; (clidx * sizeof(char*)) < sizeof(class); clidx++)
if (class[clidx])
{
if (sptr < zptr) *sptr++ = ' ';
for (cptr = class[clidx];
*cptr && (*cptr == '_' || isalnum(*cptr)) && sptr < zptr;
*sptr++ = *cptr++);
}
/* end of classes */
if (sptr < zptr) *sptr++ = '\"';
/* links can have additional attributes */
for (cptr = target; *cptr && sptr < zptr; *sptr++ = *cptr++);
/* table rows and columns can have additional attributes */
for (cptr = colspan; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = rowspan; *cptr && sptr < zptr; *sptr++ = *cptr++);
if (*tptr == '&' || empad[0])
{
/* append style string */
for (cptr = " style=\""; *cptr && sptr < zptr; *sptr++ = *cptr++);
if (*tptr == '&')
{
for (tptr++; *tptr && sptr < zptr;)
{
if (MATCH2 (tptr, "\\\n"))
{
tptr++;
continue;
}
if (*tptr == '|') break;
if (MATCH2 (tptr, ";.") || MATCH2 (tptr, ";\\"))
{
*sptr++ = *tptr++;
if (MATCH2 (tptr, "\\\n")) continue;
break;
}
if (*tptr == '\\' && tptr[1]) tptr++;
*sptr++ = *tptr++;
}
}
for (cptr = empad; *cptr && sptr < zptr; *sptr++ = *cptr++);
if (sptr < zptr) *sptr++ = '\"';
}
if (image)
for (cptr = " src=\""; *cptr && sptr < zptr; *sptr++ = *cptr++);
else
if (link)
for (cptr = " href=\""; *cptr && sptr < zptr; *sptr++ = *cptr++);
else
if (sptr < zptr)
*sptr++ = '>';
*sptr = '\0';
if (!(head && MATCH3 (tptr, "...")))
{
if (*tptr == '.')
tptr++;
else
/* a " flag must be terminated by a period */
if (noescape && *tptr != '\\' && *tptr != '|')
RETURN_FI_LI (docptr, EINVAL)
}
if (dbug>0) dbugThis (FI_LI, "end{%s}", dbugMax(tptr));
DOC_PUT (docptr, tptr, sptr);
if (sptr >= zptr)
return (EINVAL);
else
return (0);
}
/*****************************************************************************/
/*
Set document style element.
If parameter is NULL then default style.
*/
int renderStyle
(
struct wasdoc_st *docptr,
char *param
)
{
int error = 0;
char *cptr, *sptr, *zptr;
if (dbug>0) dbugThis (FI_LI, "renderStyle() {%s}", param);
if (!param || MATCH7 (param, "default"))
{
if (!docptr->styled) error = renderInsertText (docptr, styleDefault, 1);
docptr->styled = 1;
}
else
if (MATCH6 (param, "chunk="))
{
if (docptr->chunked)
error = wasDocHtmlPrint (docptr,
"",
param+6);
}
else
if (MATCH5 (param, "file="))
{
error = renderInsertFile (docptr, param+5, 1);
docptr->styled = 1;
}
else
if (MATCH6 (param, "sheet="))
{
error = wasDocHtmlPrint (docptr,
" \n",
param + 6);
docptr->styled = 1;
}
else
{
for (cptr = param; *cptr && *cptr != '=' && *cptr != '{'; cptr++);
if (*cptr == '=')
error = EINVAL;
else
error = wasDocHtmlPrint (docptr,
"",
param);
}
return (error);
}
/*****************************************************************************/
/*
Translate a logical name. The parameter name can followed by a semi-colon and
a table name, otherwise LNM$FILE_DEV is used. Returns a pointer to the value
or NULL if an error (including not existing). Document insight can show the
status returned.
*/
char* renderTrnLnm
(
struct wasdoc_st *docptr,
char *param,
int report
)
{
static unsigned short slen;
static char value [256];
static $DESCRIPTOR (nameDsc, "");
static $DESCRIPTOR (tableDsc, "");
static struct {
short int buf_len;
short int item;
void *buf_addr;
unsigned short *ret_len;
} items [] =
{
{ 255, LNM$_STRING, value, &slen },
{ 0,0,0,0 }
};
int status;
char *cptr;
if (dbug>0) fprintf (stdout, "renderTrnLnm() %s\n", param);
/* [;]*/
for (cptr = param; *cptr && *cptr != ';'; cptr++);
nameDsc.dsc$a_pointer = param;
nameDsc.dsc$w_length = cptr - nameDsc.dsc$a_pointer;
if (*cptr == ';')
{
tableDsc.dsc$a_pointer = ++cptr;
while (*cptr) cptr++;
tableDsc.dsc$w_length = cptr - tableDsc.dsc$a_pointer;
}
else
{
tableDsc.dsc$a_pointer = "LNM$FILE_DEV";
tableDsc.dsc$w_length = 12;
}
status = sys$trnlnm (0, &tableDsc, &nameDsc, 0, &items);
if (dbug>0) fprintf (stdout, "sys$trnlnm() %%X%08.08X\n", status);
if (!(status & 1))
{
if (!report)
{
if (docptr->insight >= 5) wasDocInsight (docptr, "%%X%08.08X", status);
return (NULL);
}
sprintf (value, "%%X%08.08X", status);
}
else
value[slen] = '\0';
if (docptr->insight >= 5) wasDocInsight (docptr, "%s", value);
return (value);
}
/*****************************************************************************/
/*
Copy a string where a '|' terminates and the '\' escapes the next character.
*/
int renderGetEscaped
(
char *string,
char *buf,
int size
)
{
char *cptr, *sptr, *zptr;
zptr = (sptr = buf) + size - 1;
if (sptr > zptr) return (EOVERFLOW);
for (cptr = string; *cptr && sptr < zptr; cptr++)
{
if (*cptr == '|') break;
if (*cptr == '\\' && cptr[1]) cptr++;
*sptr++ = *cptr;
}
*sptr = '\0';
if (sptr > zptr) return (EOVERFLOW);
return (0);
}
/*****************************************************************************/
/*
Return a pointer the string representation of the specified $GETSYI item.
Return NULL on error. Definitely not reentrant.
*/
char* renderGetSyi
(
struct wasdoc_st *docptr,
char *param
)
{
static int PrevCgiPlusCount;
static ulong SyiClusterEVotes,
SyiClusterMember,
SyiClusterNodes,
SyiClusterQuorum,
SyiClusterVotes,
SyiMemSize,
SyiPageSize;
static ulong SyiBootTime [2],
time64 [2],
upTime64 [2];
static char bootTime [24],
clevotes [16],
clmember [16],
clnodes [16],
clquorum [16],
clvotes [16],
memSize [16],
SyiArchName [16],
SyiHwName [64],
SyiNodeName [16],
SyiVersion [12],
upTime [24];
static struct
{
short buf_len;
short item;
char *buf_addr;
short *short_ret_len;
}
SyiItem [] =
{
{ sizeof(SyiArchName), SYI$_ARCH_NAME, (char*)&SyiArchName, 0 },
{ sizeof(SyiBootTime), SYI$_BOOTTIME, (char*)&SyiBootTime, 0 },
{ sizeof(SyiClusterEVotes), SYI$_CLUSTER_EVOTES, (char*)&SyiClusterEVotes, 0 },
{ sizeof(SyiClusterMember), SYI$_CLUSTER_MEMBER, (char*)&SyiClusterMember, 0 },
{ sizeof(SyiClusterNodes), SYI$_CLUSTER_NODES, (char*)&SyiClusterNodes, 0 },
{ sizeof(SyiClusterQuorum), SYI$_CLUSTER_QUORUM, (char*)&SyiClusterQuorum, 0 },
{ sizeof(SyiClusterVotes), SYI$_CLUSTER_VOTES, (char*)&SyiClusterVotes, 0 },
{ sizeof(SyiHwName), SYI$_HW_NAME, (char*)&SyiHwName, 0 },
{ sizeof(SyiMemSize), SYI$_MEMSIZE, (char*)&SyiMemSize, 0 },
{ sizeof(SyiNodeName), SYI$_NODENAME, (char*)&SyiNodeName, 0 },
{ sizeof(SyiPageSize), SYI$_PAGE_SIZE, (char*)&SyiPageSize, 0 },
{ sizeof(SyiVersion), SYI$_VERSION, (char*)&SyiVersion, 0 },
{ 0,0,0,0 }
};
$DESCRIPTOR (bootFaoDsc, "!20%D\0");
$DESCRIPTOR (bootTimeDsc, bootTime);
$DESCRIPTOR (upFaoDsc, "!%D");
$DESCRIPTOR (upTimeDsc, upTime);
int status;
short slen;
double fmem;
char *cptr = NULL;
if (dbug>0) dbugThis (FI_LI, "renderGetSyi() {%s}", param);
if (!param[0]) return (NULL);
if (CgiPlusCount > PrevCgiPlusCount)
{
PrevCgiPlusCount = CgiPlusCount;
SyiArchName[0] = '\0';
}
if (!SyiArchName[0])
if ((status = sys$getsyi (0, 0, 0, &SyiItem, 0, 0, 0)) & 1)
{
fmem = (double)SyiMemSize * (double)SyiPageSize;
if (fmem >= 1073741824.0)
sprintf (memSize, "%.02fGB", fmem / 1073741824.0);
else
if (fmem >= 1048576.0)
sprintf (memSize, "%.02fMB", fmem / 1048576.0);
else
sprintf (memSize, "%.02fkB", fmem / 1024.0);
sys$fao (&bootFaoDsc, 0, &bootTimeDsc, &SyiBootTime);
sys$gettim (&time64);
lib$sub_times (&time64, &SyiBootTime, &upTime64);
sys$fao (&upFaoDsc, &slen, &upTimeDsc, &upTime64);
upTime[slen-3] = '\0';
}
else
{
sprintf (SyiArchName, "%%X%08.08X", status);
strcpy (bootTime, SyiArchName);
strcpy (memSize, SyiArchName);
strcpy (SyiHwName, SyiArchName);
strcpy (SyiNodeName, SyiArchName);
strcpy (SyiVersion, SyiArchName);
strcpy (upTime, SyiArchName);
SyiMemSize = 0;
}
if (MATCH7 (param, "arch_name"))
cptr = SyiArchName;
else
if (MATCH8 (param, "cluster="))
{
if (MATCH6 (param+8, "evotes"))
sprintf (cptr = clevotes, "%d", SyiClusterEVotes);
else
if (MATCH6 (param+8, "member"))
sprintf (cptr = clmember, "%d", SyiClusterMember);
else
if (MATCH5 (param+8, "nodes"))
sprintf (cptr = clnodes, "%d", SyiClusterNodes);
else
if (MATCH6 (param+8, "quorum"))
sprintf (cptr = clquorum, "%d", SyiClusterQuorum);
else
if (MATCH5 (param+8, "votes"))
sprintf (cptr = clvotes, "%d", SyiClusterVotes);
}
else
if (MATCH8 (param, "boottime"))
cptr = bootTime;
else
if (MATCH7 (param, "hw_name"))
cptr = SyiHwName;
else
if (MATCH7 (param, "memsize"))
cptr = memSize;
else
if (MATCH8 (param, "nodename"))
cptr = SyiNodeName;
else
if (MATCH6 (param, "uptime"))
cptr = upTime;
else
if (MATCH7 (param, "version"))
cptr = SyiVersion;
if (!cptr || !*cptr) return (NULL);
return (cptr);
}
/*****************************************************************************/
/*
Delineate a tag. See module prologue for a description of tag syntax.
*/
void renderInsightTag (struct wasdoc_st *docptr)
{
char *aptr, *cptr, *sptr, *tptr, *zptr;
char buf [256];
tptr = docptr->text + docptr->tparse;
if (dbug>0) dbugThis (FI_LI, "renderInsightTag() {%s}", dbugMax(tptr));
if (MATCH6 (tptr, "\n||||\n"))
{
wasDocInsight (docptr, "||||");
return;
}
if (MATCH2 (tptr, "||") ||
MATCH2 (tptr, "| ") ||
MATCH2 (tptr, "|\n") ||
MATCH2 (tptr, "|\t"))
{
wasDocInsight (docptr, "||");
return;
}
if (MATCH2 (tptr, "|!"))
{
for (cptr = tptr + 2; *cptr && *cptr != '|'; cptr++);
wasDocInsight (docptr, "%*.*s", cptr-tptr+1, cptr-tptr+1, tptr);
return;
}
if (MATCH5 (tptr, "|...|") ||
MATCH5 (tptr, "|:::|"))
{
wasDocInsight (docptr, "%5.5s", tptr);
return;
}
if (MATCH4 (tptr, "|--|"))
{
wasDocInsight (docptr, "%4.4s", tptr);
return;
}
if (MATCH3 (tptr, "|-|") ||
MATCH3 (tptr, "|^+") ||
MATCH3 (tptr, "|^-"))
{
wasDocInsight (docptr, "%3.3s", tptr);
return;
}
if (MATCH3 (tptr, "|^ ") ||
MATCH3 (tptr, "|^\t") ||
MATCH3 (tptr, "|^\n"))
{
wasDocInsight (docptr, "%2.2s", tptr);
return;
}
if (MATCH2 (tptr, "|0") ||
MATCH2 (tptr, "|1") ||
MATCH2 (tptr, "|2") ||
MATCH2 (tptr, "|3") ||
MATCH2 (tptr, "|4") ||
MATCH2 (tptr, "|9"))
{
if (docptr->insight >= 5)
{
for (cptr = tptr + 1; *cptr && *cptr != '|'; cptr++);
wasDocInsight (docptr, "%*.*s|", cptr-tptr, cptr-tptr, tptr);
}
else
if (docptr->insight >= 4)
{
for (cptr = tptr + 1; *cptr && !isalpha(*cptr); cptr++);
wasDocInsight (docptr, "%*.*s|", cptr-tptr, cptr-tptr, tptr);
}
else
wasDocInsight (docptr, "%2.2s", tptr);
return;
}
if (MATCH2 (tptr, "|~") ||
MATCH2 (tptr, "|:") ||
MATCH2 (tptr, "|.") ||
MATCH2 (tptr, "|&"))
{
if (docptr->insight >= 5)
for (cptr = tptr; *cptr && !isspace(*cptr); cptr++);
else
cptr = tptr + 2;
wasDocInsight (docptr, "%*.*s", cptr-tptr, cptr-tptr, tptr);
return;
}
if (*tptr == '|' && ispunct(tptr[1]))
{
zptr = (sptr = buf) + sizeof(buf)-1;
*sptr++ = *tptr++;
for (cptr = tptr; *cptr && sptr < zptr; cptr++)
{
if (*cptr == '&' || *cptr == '\\' || *cptr == '.' || *cptr == '|')
{
if (*cptr == '&') *sptr++ = *cptr;
break;
}
if (*cptr == '\'')
{
*sptr++ = *cptr;
for (cptr++; isalpha(*cptr); cptr++);
continue;
}
if (isalpha(*cptr)) break;
*sptr++ = *cptr;
}
*sptr = '\0';
wasDocInsight (docptr, "%s", buf);
return;
}
if ((MATCH5 (tptr, "|asis") && ispunct(tptr[5])) ||
(MATCH6 (tptr, "|block") && ispunct(tptr[6])) ||
(MATCH6 (tptr, "|break")&& ispunct(tptr[6])) ||
(MATCH7 (tptr, "|bullet") && ispunct(tptr[7])) ||
(MATCH5 (tptr, "|code") && ispunct(tptr[5])) ||
(MATCH5 (tptr, "|data") && ispunct(tptr[5])) ||
(MATCH5 (tptr, "|elif") && ispunct(tptr[5])) ||
(MATCH5 (tptr, "|else") && ispunct(tptr[5])) ||
(MATCH6 (tptr, "|endif") && ispunct(tptr[6])) ||
(MATCH8 (tptr, "|example") && ispunct(tptr[8])) ||
(MATCH5 (tptr, "|exit") && ispunct(tptr[5])) ||
(MATCH5 (tptr, "|head") && ispunct(tptr[5])) ||
(MATCH5 (tptr, "|hide") && ispunct(tptr[5])) ||
(MATCH6 (tptr, "|image") && ispunct(tptr[6])) ||
(MATCH6 (tptr, "|index") && ispunct(tptr[6])) ||
(MATCH7 (tptr, "|insert") && ispunct(tptr[7])) ||
(MATCH9 (tptr, "|insight!") && ispunct(tptr[9])) ||
(MATCH9 (tptr, "|insight@") && ispunct(tptr[9])) ||
(MATCH3 (tptr, "|if") && ispunct(tptr[3])) ||
(MATCH7 (tptr, "|inline") && ispunct(tptr[7])) ||
(MATCH6 (tptr, "|insert") && ispunct(tptr[6])) ||
(MATCH5 (tptr, "|item") && ispunct(tptr[5])) ||
(MATCH3 (tptr, "|li") && ispunct(tptr[3])) ||
(MATCH5 (tptr, "|link") && ispunct(tptr[5])) ||
(MATCH7 (tptr, "|mailto") && ispunct(tptr[7])) ||
(MATCH5 (tptr, "|mono") && ispunct(tptr[5])) ||
(MATCH5 (tptr, "|note") && ispunct(tptr[5])) ||
(MATCH8 (tptr, "|noprint") && ispunct(tptr[8])) ||
(MATCH7 (tptr, "|number") && ispunct(tptr[7])) ||
(MATCH3 (tptr, "|ol") && ispunct(tptr[3])) ||
(MATCH6 (tptr, "|ppage") && ispunct(tptr[6])) ||
(MATCH6 (tptr, "|print") && ispunct(tptr[6])) ||
(MATCH5 (tptr, "|prop") && ispunct(tptr[5])) ||
(MATCH6 (tptr, "|quote") && ispunct(tptr[6])) ||
(MATCH4 (tptr, "|row") && ispunct(tptr[4])) ||
(MATCH3 (tptr, "|tr") && ispunct(tptr[3])) ||
(MATCH4 (tptr, "|set") && ispunct(tptr[4])) ||
(MATCH7 (tptr, "|simple") && ispunct(tptr[7])) ||
(MATCH3 (tptr, "|sl") && ispunct(tptr[3])) ||
(MATCH6 (tptr, "|style") && ispunct(tptr[6])) ||
(MATCH6 (tptr, "|table") && ispunct(tptr[6])) ||
(MATCH8 (tptr, "|tabular") && ispunct(tptr[8])) ||
(MATCH4 (tptr, "|toc") && ispunct(tptr[4])) ||
(MATCH3 (tptr, "|ul") && ispunct(tptr[3])))
{
if (docptr->insight >= 5)
{
if (MATCH4 (tptr, "|set") ||
MATCH6 (tptr, "|style"))
{
for (cptr = tptr + 1; *cptr && *cptr != '|'; cptr++);
if (*cptr) cptr++;
while (*cptr && *cptr != '|') cptr++;
}
else
for (cptr = tptr + 1; *cptr; cptr++)
if (*cptr == '\\' || *cptr == '.' || *cptr == '|') break;
}
else
for (cptr = tptr + 1; isalpha(*cptr); cptr++);
wasDocInsight (docptr, "%*.*s|", cptr-tptr, cptr-tptr, tptr);
return;
}
cptr = tptr + 1;
if (*cptr == '%') cptr++;
while (*cptr && cptr < tptr+8 && isalpha(*cptr)) cptr++;
if (MATCH3 (cptr, "://"))
{
wasDocInsight (docptr, "|link|");
return;
}
wasDocInsight (docptr, "\?\?\?");
}
/*****************************************************************************/
/*
Display the source text file name.
*/
void renderInsightSource
(
struct wasdoc_st *docptr,
char *tptr
)
{
char *cptr;
for (cptr = tptr; *cptr && *cptr != ' '; cptr++);
wasDocInsight (docptr, "%*.*s", cptr-tptr, cptr-tptr, tptr);
}
/*****************************************************************************/
/*
Document the stack contents.
*/
void renderInsightStack (struct wasdoc_st *docptr)
{
int idx;
char *aptr, *cptr, *sptr, *zptr;
char buf [1024];
for (idx = 1; idx < STACK_MAX && docptr->cstack[idx]; idx++);
idx--;
for (; idx; idx--)
{
if (!docptr->cstack[idx]) continue;
zptr = (sptr = buf) + sizeof(buf)-1;
sptr += sprintf (sptr, "☰%d%s",
idx, idx == docptr->stindex ? "✓ ※" :
" ※");
for (cptr = docptr->cstack[idx]; *cptr && *cptr != '\n'; cptr++)
{
aptr = NULL;
if (*cptr == '<') aptr = "<";
if (*cptr == '>') aptr = ">";
if (*cptr == '&') aptr = "&";
if (aptr)
while (*aptr && sptr < zptr) *sptr++ = *aptr++;
else
if (sptr < zptr)
*sptr++ = *cptr;
}
for (cptr = " ※"; *cptr && sptr < zptr; *sptr++ = *cptr++);
for (cptr = docptr->tstack[idx]; *cptr && *cptr != '\n'; cptr++)
{
aptr = NULL;
if (*cptr == '<') aptr = "<";
if (*cptr == '>') aptr = ">";
if (*cptr == '&') aptr = "&";
if (aptr)
while (*aptr && sptr < zptr) *sptr++ = *aptr++;
else
if (sptr < zptr)
*sptr++ = *cptr;
}
*sptr = '\0';
wasDocInsight (docptr, "%s", buf);
}
}
/*****************************************************************************/