, , ) 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 "cgilib.h"
#ifndef STYLE_DEFAULT
#define STYLE_DEFAULT "\n"
#endif
char styleDefault [] = STYLE_DEFAULT;
extern int bvbar, 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>1) 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, SS$_NOSUCHOBJECT)
/* 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; }
}
for (;;)
{
if (HMORE(docptr)) wasDocMoreHtml (docptr);
if (!docptr->hlength)
{
sys$fao (&faoDsc, 0, &vtimeDsc, 0);
error = wasDocPrintf (docptr,
"\n\
\n\
\n\
\n\
NOTE: SOME FUNCTIONALITY EMPLOYS JAVASCRIPT \n\
\n\
\n",
SoftwareID,
isCgi ? " CGI" : "",
isCgiPlus ? "plus" : "",
docptr->isDynamic ? " CLI" : "",
CopyrightDate,
vtime);
if (docptr->errorValue) GOTO_FI_LI (docptr, insert_error)
/* must follow the */
if (docptr->insight >= 2)
{
wasDocInsight (docptr, "BEGIN");
if (docptr->insight >= 2)
wasDocInsight (docptr, "%d/%d bytes",
docptr->hlength, docptr->hsize);
}
}
/* 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|"))
{
TPUT (docptr, tptr);
error = renderCondition (docptr);
if (error) GOTO_FI_LI (docptr, conditional_error)
TGET (docptr, tptr);
if (docptr->conditional[docptr->conLevel] > 0) break;
}
else
if (MATCH7 (tptr, "|break|"))
{
wasDocAsIs (docptr, "\n\n");
break;
}
else
if (MATCH6 (tptr, "|exit|"))
{
wasDocAsIs (docptr, "\n\n");
return (SS$_ABORT);
}
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)
{
renderStyle (docptr, NULL);
continue;
}
}
}
if (docptr->asis)
{
/********/
/* asis */
/********/
/* as-is only terminated by \n||||\n (i.e 4 on a line by itself) */
while (*tptr)
{
if (HMORE(docptr)) wasDocMoreHtml (docptr);
if (*tptr == '\n')
{
if (MATCH7 (tptr, "\n\\||||\n"))
{
/* seems obvious this is needed if to be documented :-) */
HONE (docptr, tptr);
}
else
if (MATCH6 (tptr, "\n||||\n"))
{
if (docptr->insight >= 4) renderInsightTag (docptr);
/* 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 */
wasDocAsIs (docptr, "
");
docptr->stindex--;
}
}
}
tptr += 6;
docptr->asis = 0;
break;
}
}
HONE (docptr, tptr);
}
continue;
}
if (docptr->noescape)
{
/******************/
/* no-HTML-escape */
/******************/
/* can only be terminated by || or |!"| */
while (*tptr)
{
if (HMORE(docptr)) wasDocMoreHtml (docptr);
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;
}
}
HONE (docptr, tptr);
}
continue;
}
while (*tptr && *tptr != '|')
{
/***************/
/* HTML escape */
/***************/
if (HMORE(docptr)) wasDocMoreHtml (docptr);
if (docptr->insight >= 2)
if (MATCH4 (tptr, "\\')
{
tptr++;
wasDocAsIs (docptr, ">");
continue;
}
if (*tptr == '&')
{
tptr++;
wasDocAsIs (docptr, "&");
continue;
}
if (*tptr == '\"')
{
tptr++;
wasDocAsIs (docptr, """);
continue;
}
if (*tptr == '$')
{
/* wasDOC uses back-to-back $s for control sequences */
tptr++;
wasDocAsIs (docptr, "$");
continue;
}
if (*tptr == '\\')
{
if (MATCH2 (tptr, "\\\n"))
{
/* escaped newline - no newline at all */
tptr += 2;
continue;
}
if (MATCH2 (tptr, "\\ "))
{
/* escaped space */
tptr += 2;
wasDocAsIs (docptr, " ");
continue;
}
if (MATCH2 (tptr, "\\|"))
{
/* escaped bar */
tptr += 2;
wasDocAsIs (docptr, "|");
continue;
}
if (MATCH4 (tptr, "\\\\\\\\"))
{
/* four consecutive backslashes just ignore */
tptr += 4;
continue;
}
if (!MATCH2 (tptr, "\\\0"))
{
/* escape any other character */
tptr++;
HONE (docptr, 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;
}
}
HONE (docptr, tptr);
}
if (!*tptr) break;
/*****************/
/* 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, BADPARAM_error)
for (cptr = tptr + 2;
*cptr && *cptr != '\n' && *cptr != '|';
cptr++);
if (*cptr != '|') GOTO_FI_LI (docptr, BADPARAM_error)
tptr = cptr + 1;
}
else
tptr++;
if (!docptr->stindex) GOTO_FI_LI (docptr, stack_uflow)
aptr = docptr->cstack[docptr->stindex];
if (MATCH3 (aptr, "notable == NOTE_HEADING)
{
/* explicit heading has been provided so now in |note| text */
docptr->notable = NOTE_TEXT;
wasDocAsIs (docptr, "\n
");
}
}
else
if (MATCH8 (aptr, ""))
{
if (docptr->table) docptr->table--;
/* for the outermost table cancel any row highlight */
if (!docptr->table) docptr->rowlight = 0;
wasDocAsIs (docptr, aptr);
}
else
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;
wasDocAsIs (docptr, "");
}
else
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;
wasDocAsIs (docptr, "
\n
");
}
else
if (aptr)
wasDocAsIs (docptr, aptr);
/* already checked the stack depth above */
docptr->stindex--;
if (docptr->insight >= 4) renderInsightTag (docptr);
continue;
}
/*****************/
/* special cases */
/*****************/
if (docptr->insight >= 4)
if (MATCH5 (tptr, "|...|") ||
MATCH5 (tptr, "|:::|")) renderInsightTag (docptr);
/* must be parsed before table |. */
if (MATCH5 (tptr, "|...|"))
{
tptr += 5;
wasDocAsIs (docptr, "…");
continue;
}
if (MATCH5 (tptr, "|:::|"))
{
tptr += 5;
wasDocAsIs (docptr, "⋮");
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 */
cptr = renderTrimWhite (docptr);
/* ensuring that empty elements work with CSS :empty */
if (!MATCH4 (cptr, "insight >= 4)
{
/* table insight is messy! */
if (rowptr)
{
renderInsightTag (docptr);
rowptr = NULL;
}
renderInsightTag (docptr);
}
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 */
cptr = renderTrimWhite (docptr);
/* ensuring that empty elements work with CSS :empty */
if (!MATCH4 (cptr, " insight >= 4)
{
/* table insight is messy! */
if (rowptr)
{
renderInsightTag (docptr);
rowptr = NULL;
}
renderInsightTag (docptr);
}
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) renderInsightTag (docptr);
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;
wasDocAsIs (docptr, "–");
continue;
}
if (MATCH4 (tptr, "|--|"))
{
tptr += 4;
wasDocAsIs (docptr, "—");
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] = " -->";
wasDocAsIs (docptr, "");
continue;
}
if (MATCH7 (tptr, "|index|"))
{
/* insert a marker for where the INDEX will be */
tptr += 7;
if (MATCH2 (tptr, "||")) tptr++;
tptr++;
wasDocAsIs (docptr, "");
continue;
}
if (MATCH7 (tptr, "|break|"))
{
wasDocAsIs (docptr, "\n\n");
TPUT (docptr, tptr);
break;
}
if (MATCH6 (tptr, "|exit|"))
{
wasDocAsIs (docptr, "\n\n");
TPUT (docptr, tptr);
return (SS$_ABORT);
}
if (MATCH10 (tptr, "|insight!|"))
{
tptr += 10;
TPUT (docptr, tptr);
renderInsightStack (docptr);
TGET (docptr, tptr);
continue;
}
if (MATCH10 (tptr, "|insight@|"))
{
tptr += 10;
if (docptr->isDynamic && docptr->insight)
{
wasDocAsIs (docptr,
"
\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)
if (pass2 (docptr) < 0)
{
TPUT (docptr, tptr);
if (docptr->errorValue == SS$_NOSUCHOBJECT)
renderErrorReport (docptr,
"\n
Link target %s not found
\n",
docptr->pass2At);
else
{
cptr = strdup (strerror(EVMSERR,docptr->errorValue));
*cptr = toupper(*cptr);
renderErrorReport (docptr, "\n
%s %s
\n",
cptr, docptr->pass2At);
free (cptr);
}
renderErrorReport (docptr, NULL);
return (docptr->errorValue);
}
if (docptr->insight >= 2) wasDocInsight (docptr, "END");
return (0);
post_condition_error:
aptr = docptr->html + docptr->hparse;
TPUT (docptr, tptr);
renderErrorReport (docptr,
"\n
%s post processing error %s \
at "%s " %s
\n",
cptr, strerror(EVMSERR,error), renderLineEscape(aptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
return (error);
unknown_tag:
TPUT (docptr, tptr);
renderErrorReport (docptr,
"
Unknown tag "%s " at \
"%s " %s
\n",
renderTag(tptr), renderLine(docptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
return (error);
insert_error:
TPUT (docptr, tptr);
renderErrorReport (docptr,
"\n
Insert failed %s at \
"%s " %s
\n",
strerror(EVMSERR,error), renderLine(docptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
return (error);
BADPARAM_error:
error = SS$_BADPARAM;
goto param_error;
param_error:
TPUT (docptr, tptr);
renderErrorReport (docptr,
"\n
Parameter error %s at \
\"%s \" %s
\n",
strerror(EVMSERR,error), renderLine(docptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
return (error);
vms_status_error:
TPUT (docptr, tptr);
renderErrorReport (docptr,
"\n
VMS status %%X%08.08X error %s at \
\"%s \" %s
\n",
error, strerror(EVMSERR,error), renderLine(docptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
return (error);
outside_table_error:
TPUT (docptr, tptr);
renderErrorReport (docptr,
"\n
Tag "%s " used outside table at \
"%s " %s
\n",
renderTag(tptr), renderLine(docptr),
renderSource(docptr));
renderErrorReport (docptr, NULL);
return (error);
stack_oflow:
TPUT (docptr, tptr);
renderErrorReport (docptr,
"\n
Overflow at "%s "%s
\n",
renderLine(docptr));
renderErrorReport (docptr, NULL);
return (error);
stack_uflow:
TPUT (docptr, tptr);
renderErrorReport (docptr,
"\n
Underflow at "%s " %s
\n",
renderLine(docptr), renderSource(docptr));
renderErrorReport (docptr, NULL);
return (error);
conditional_error:
if (!error)
cptr = "unbalanced";
else
cptr = strerror(EVMSERR,error);
TPUT (docptr, tptr);
renderErrorReport (docptr,
"
Conditional %s at \
"%s " %s
",
cptr, renderLine(docptr), renderSource(docptr));
renderErrorReport (docptr, NULL);
return (error);
unbalanced_error:
TPUT (docptr, tptr);
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);
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 (dbug>2) dbugThis (FI_LI, "renderErrorReport() %s", dbugMax(fmt));
if (!fmt)
{
/* end call */
wasDocPrintf (docptr, "\n");
init = 0;
return (0);
}
va_start (args, fmt);
size = vsnprintf (NULL, 0, fmt, args);
va_end (args);
if (size < 0) return (vaxc$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) wasDocBugcheck(FI_LI);
/* 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;
wasDocPrintf (docptr, "",
fiptr ? finame : "(null)", linum);
}
wasDocPrintf (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+3];
char *sptr, *zptr;
if (dbug>2) dbugThis (FI_LI, "renderTag() %s", dbugMax(tptr));
zptr = (sptr = buf) + sizeof(buf)-3;
*sptr++ = bvbar;
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++ = bvbar;
*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>2) 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';
cptr = dbugAll (buf);
if (dbug>2) dbugThis (FI_LI, "%s", cptr);
return (cptr);
}
/*****************************************************************************/
/*
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 = 1, 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 SS$_BADPARAM 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];
TGET (docptr, tptr);
if (dbug>1)
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 += 3;
if (elif) tptr += 2;
if (ENDTAG(tptr))
buf[0] = '\0';
else
{
tptr++;
TPUT (docptr, tptr);
renderGetParam (docptr, buf, sizeof(buf));
TGET (docptr, tptr);
}
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 = SS$_BADPARAM;
}
else
error = SS$_BADPARAM;
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 = SS$_BADPARAM;
if (docptr->insight >= 4)
wasDocInsight (docptr, "%s%d/%d",
docptr->conditional[docptr->conLevel] > 0 ? "✓" : "✗",
docptr->conLevel, docptr->conditional[docptr->conLevel]);
if (*tptr == '\n') tptr++;
TPUT (docptr, tptr);
docptr->insight = insight;
if (dbug>1)
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 vaxc%errno for error.
*/
int renderGetParam
(
struct wasdoc_st *docptr,
char *buf,
int size
)
{
char *sptr, *tptr, *zptr;
TGET (docptr, tptr);
if (dbug>1) dbugThis (FI_LI, "renderGetParam() %s", dbugMax(tptr));
if (size) buf[0] = '\0';
/* look slightly behind to check if one might not be supplied */
if (ENDTAG (tptr-1) && !MATCH2 (tptr-1, "|!")) return (0);
zptr = (sptr = buf) + size - 1;
if (zptr <= sptr) RETURN_FI_LI (docptr, SS$_RESULTOVF)
while (*tptr && *tptr != '|' && sptr < zptr)
{
if (*tptr == '\\')
{
tptr++;
if (*tptr == '\n')
{
tptr++;
continue;
}
if (!*tptr) break;
}
*sptr++ = *tptr++;
}
if (*tptr != '|') RETURN_FI_LI (docptr, SS$_BADPARAM)
if (sptr >= zptr) RETURN_FI_LI (docptr, SS$_RESULTOVF)
*sptr = '\0';
TPUT (docptr, tptr);
return (0);
}
/*****************************************************************************/
/*
Set document characteristic.
*/
int renderSet
(
struct wasdoc_st *docptr,
char *param
)
{
int error = 0, number;
char *cptr, *sptr, *tptr, *zptr;
if (dbug>1) 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 (MATCH6 (param, "found="))
{
/* explicitly set the default of 'this "in" that' */
zptr = (sptr = docptr->setFoundIn) + sizeof(docptr->setFoundIn)-1;
for (cptr = param + 6; *cptr && sptr < zptr; *sptr++ = *cptr++);
*sptr = '\0';
}
else
if (MATCH9 (param, "idx=cols="))
{
/* number of columns in the index */
number = atoi(param+9);
if (number == 1 || number == 2 || number == 3 || number == 4)
docptr->setIdxCols = number;
else
error = SS$_BADPARAM;
}
else
if (MATCH9 (param, "idx=sort="))
{
/* index entries sorted is 1, unsorted is 0 */
docptr->setIdxSort = atoi(param+9);
}
else
if (MATCH12 (param, "idx=collate="))
{
/* collation characters for index (26 Latin alphabetics default) */
zptr = (sptr = docptr->idxCollate) + sizeof(docptr->idxCollate)-1;
/* if plus then append to existing collation, otherwise replace */
cptr = param + 12;
if (*cptr == '+')
{
for (sptr = docptr->idxCollate; *sptr; sptr++);
cptr++;
}
while (*cptr && sptr < zptr) *sptr++ = *cptr++;
*sptr = '\0';
}
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 = vaxc$errno;
}
else
if (MATCH7 (param, "locale=") && isdigit(param[7]) && param[8] == '=') {
if (!setlocale (atoi(param+8), param+10)) error = vaxc$errno;
}
else
if (MATCH7 (param, "locale=")) {
if (!setlocale (LC_ALL, param+7)) error = vaxc$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 (MATCH12 (param, "toc2=next=cols="))
{
/* number of columns in NEXT secondary table of content */
number = atoi(cptr = param+15);
if (number == 1 || number == 2 || number == 3 || number == 4)
/* propagate into second pass */
wasDocPrintf (docptr, "", param);
else
error = SS$_BADPARAM;
}
else
if (MATCH10 (param, "toc2=cols="))
{
/* number of columns in secondary table of content */
number = atoi(cptr = param+10);
if (number == 1 || number == 2 || number == 3 || number == 4)
{
docptr->setToc2Cols = number;
while (*cptr && isdigit(*cptr)) cptr++;
while (*cptr && !isdigit(*cptr)) cptr++;
if (isdigit(*cptr))
if ((number = atoi(cptr)) <= 100)
docptr->setToc2ColsWidth = number;
}
else
error = SS$_BADPARAM;
}
else
if (MATCH5 (param, "toc2="))
{
/* whether a secondary TOC is generated */
cptr = param+5;
if (isdigit(*cptr))
docptr->setToc2 = atoi(param+5);
else
error = SS$_BADPARAM;
}
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 = SS$_BADPARAM;
}
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 = SS$_BADPARAM;
}
else
error = SS$_BADPARAM;
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>1) dbugThis (FI_LI, "renderFlag() %d %s", set, dbugAll(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 |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 = 0;
char nine9, zero0, zero1, zero2, zero3, zero4, zero9;
char *cptr, *tptr;
if (dbug>1) dbugThis (FI_LI, "renderInsertHeading()");
TGET (docptr, tptr);
if (tptr[0] != '|') RETURN_FI_LI (docptr, SS$_FORMAT)
if (docptr->stindex >= STACK_MAX) RETURN_FI_LI (docptr, SS$_RESULTOVF)
docptr->tstack[++docptr->stindex] = tptr;
/* leading zero suppresses primary TOC entry */
cptr = tptr + 1;
/* bit sloppy and inefficient but */
zero0 = MATCH2(cptr, "00");
zero1 = MATCH2(cptr, "01");
zero2 = MATCH2(cptr, "02");
zero3 = MATCH2(cptr, "03");
zero4 = MATCH2(cptr, "04");
zero9 = MATCH2(cptr, "09");
nine9 = MATCH2(cptr, "99");
if (isdigit(*cptr) && isdigit(*(cptr+1))) cptr++;
/* first visible heading becomes top of document */
if (*cptr >= '0' && *cptr <= '4')
if (!(docptr->section[1] || docptr->section[2] || docptr->section[3] ||
docptr->section[4] || docptr->section[5]))
wasDocAsIs (docptr, " \n");
switch (*cptr)
{
case '0' : if (zero0)
docptr->section[5] = SECTION_NOT_IN;
else
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] = SECTION_NO_INDEX;
else
if (nine9)
docptr->section[6] = SECTION_NOT_IN;
else
docptr->section[6]++;
docptr->cstack[docptr->stindex] = "";
cptr = "",
renderNumericId(docptr->section));
if (error) RETURN_FI_LI (docptr, error);
error = renderInsertTag (docptr, cptr);
if (error) return (error);
return (0);
}
/*****************************************************************************/
/*
*/
int renderInsertNote (struct wasdoc_st *docptr)
{
int error;
char *cptr;
if (dbug>1) 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 = wasDocPrintf (docptr,
"\
%s \n\
\n",
renderNumericId(docptr->section), 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 *cptr, *sptr, *zptr;
char param2 [512];
if (dbug>1) dbugThis (FI_LI, "renderInsertLink() %s", dbugAll(param));
for (cptr = param; *cptr && isalpha(*cptr); cptr++);
if (MATCH3 (cptr, "://") || MATCH7 (param, "mailto:"))
{
/* looks like a URL scheme */
wasDocAsIs (docptr, param);
}
else
if (strstr (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 != '#' && sptr < zptr; cptr++)
{
if (isalnum(*cptr) || *cptr == '-' || *cptr == '$' ||
*cptr == '.' || *cptr == '/')
*sptr++ = tolower(*cptr);
else
*sptr++ = '_';
}
if (MATCH3 (cptr, "##\0"))
{
for (cptr = "#0."; *cptr && sptr < zptr; *sptr++ = *cptr++);
*sptr = '\0';
wasDocAsIs (docptr, param2);
}
else
if (MATCH2 (cptr, "##"))
{
for (cptr++; *cptr && sptr < zptr; *sptr++ = *cptr++);
*sptr = '\0';
wasDocAsIs (docptr, param2);
renderFragment (docptr);
}
}
else
if (param[0] == '#')
{
/* explicit fragment */
wasDocEntify (docptr, param);
renderFragment (docptr);
}
else
if (param[0] == '/' ||
MATCH2 (param, "./") ||
MATCH3 (param, "../"))
{
/* any trailing chunk faux "directory" must be allowed for */
if (docptr->chunked && docptr->isDynamic)
if (MATCH2 (param, "./") || MATCH3 (param, "../"))
wasDocAsIs (docptr, "../");
/* relative URL */
wasDocEntify (docptr, param);
renderFragment (docptr);
}
else
{
/* to fragment ID added via heading */
wasDocPrintf (docptr, "");
}
return (0);
}
/*****************************************************************************/
/*
Create a link to another document like "Heading Name in Document Name".
The parameter looks like "##++in++".
*/
int renderInsertLinkIn
(
struct wasdoc_st *docptr,
char *param,
int target
)
{
char *cptr, *sptr, *zptr;
char heading [256],
inof [256],
title [256],
url [256];
if (dbug>1) dbugThis (FI_LI, "renderInsertLinkIn() %d %s",
target, dbugAll(param));
zptr = (sptr = url) + sizeof(url)-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 && !MATCH2(cptr,"##") && sptr < zptr; cptr++)
{
if (isalnum(*cptr) || *cptr == '-' || *cptr == '$' ||
*cptr == '.' || *cptr == '/')
*sptr++ = tolower(*cptr);
else
*sptr++ = '_';
}
*sptr = '\0';
if (*cptr != '#' || sptr >= zptr || !url[0])
RETURN_FI_LI (docptr, SS$_BADPARAM)
zptr = (sptr = heading) + sizeof(heading)-1;
for (cptr+=2; *cptr && !MATCH2(cptr,"++") && sptr < zptr; *sptr++ = *cptr++)
if (*cptr == '\\' && *(cptr+1)) cptr++;
*sptr = '\0';
if (*cptr != '+' || !heading[0] || sptr >= zptr)
RETURN_FI_LI (docptr, SS$_BADPARAM)
zptr = (sptr = inof) + sizeof(inof)-1;
for (cptr+=2; *cptr && !MATCH2(cptr,"++") && sptr < zptr; *sptr++ = *cptr++)
if (*cptr == '\\' && *(cptr+1)) cptr++;
*sptr = '\0';
if (*cptr != '+' || !inof[0] || sptr >= zptr)
RETURN_FI_LI (docptr, SS$_BADPARAM)
zptr = (sptr = title) + sizeof(title)-1;
for (cptr+=2; *cptr && sptr < zptr; *sptr++ = *cptr++)
if (*cptr == '\\' && *(cptr+1)) cptr++;
*sptr = '\0';
if (sptr >= zptr || !title[0]) RETURN_FI_LI (docptr, SS$_BADPARAM)
/* the ");
wasDocAsIs (docptr, heading);
wasDocAsIs (docptr, " ");
wasDocAsIs (docptr, inof);
if (target)
wasDocAsIs (docptr, " ");
wasDocAsIs (docptr, title);
wasDocAsIs (docptr, " ");
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>1) dbugThis (FI_LI, "renderInsertUrl() %s", dbugAll(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 */
wasDocAsIs (docptr, param);
}
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, SS$_BADPARAM)
if (sptr < zptr) *sptr++ = '/';
while (*cptr && sptr < zptr) *sptr++ = *cptr++;
*sptr = '\0';
if (sptr >= zptr) RETURN_FI_LI (docptr, SS$_RESULTOVF)
wasDocAsIs (docptr, uri);
}
else
wasDocAsIs (docptr, param);
}
else
wasDocAsIs (docptr, param);
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>1) dbugThis (FI_LI, "renderInsertOther() %s", dbugAll(param));
if (!param[0]) RETURN_FI_LI (docptr, SS$_BADPARAM)
*(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, SS$_BADPARAM);
return (0);
}
else
RETURN_FI_LI (docptr, SS$_BADPARAM)
}
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, SS$_BADPARAM);
return (0);
}
else
RETURN_FI_LI (docptr, SS$_BADPARAM)
}
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, SS$_BADPARAM)
if (!strftime (buf, sizeof(buf), cptr, tmp))
RETURN_FI_LI (docptr, SS$_BADPARAM)
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, SS$_BADPARAM)
if (noescape)
wasDocAsIs (docptr, cptr);
else
wasDocEntify (docptr, cptr);
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;
char *cptr, *fnptr, *sptr, *zptr;
FILE *ifptr;
stat_t fstatbuf;
if (dbug>1) dbugThis (FI_LI, "renderInsertFile() %d %s",
noescape, dbugAll(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 */
if (noescape)
wasDocAsIs (docptr, docptr->text);
else
wasDocEntify (docptr, docptr->text);
return (0);
}
cptr = getenv("PATH");
chdir (docptr->dname);
ifptr = fopen (fnptr, "r");
error = vaxc$errno;
chdir (cptr);
if (!ifptr)
{
if (!ignore) return (error);
wasDocInsertStatus (docptr, error);
return (0);
}
if (fstat (fileno(ifptr), &fstatbuf) < 0)
{
error = vaxc$errno;
fclose (ifptr);
if (!ignore) return (error);
wasDocInsertStatus (docptr, error);
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);
if (noescape)
wasDocAsIs (docptr, cptr);
else
wasDocEntify (docptr, cptr);
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>1) dbugThis (FI_LI, "renderIncludeFile() %s", dbugAll(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>1) dbugThis (FI_LI, "%s\n", dbugAll(fnptr));
cptr = getenv("PATH");
chdir (docptr->dname);
ifptr = fopen (fnptr, "r");
error = vaxc$errno;
chdir (cptr);
if (!ifptr)
{
if (!ignore) return (error);
wasDocInsertStatus (docptr, error);
return (0);
}
if (fstat (fileno(ifptr), &fstatbuf) < 0)
{
error = vaxc$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);
}
/*****************************************************************************/
/*
The trailing document text needs to be reduced to an alphanumeric ID
(fragment). It is bounded by a leading hash. Squash it down to that ID and
adjust the document length.
*/
void renderFragment (struct wasdoc_st *docptr)
{
char *aptr, *cptr, *sptr;
for (sptr = docptr->html + docptr->hlength;
sptr > docptr->html && *sptr != '#' && *sptr != '\"' && *sptr != '>';
sptr--);
if (dbug>1) dbugThis (FI_LI, "renderFragment() %s", dbugAll(aptr = sptr));
if (*sptr != '#') return;
for (cptr = ++sptr; *cptr; cptr++)
if (isalnum (*cptr)) *sptr++ = tolower(*cptr);
*sptr = '\0';
if (dbug>1) dbugThis (FI_LI, "%s", dbugAll(aptr));
docptr->hlength = sptr - docptr->html;
}
/*****************************************************************************/
/*
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;
if (HMORE (docptr)) wasDocMoreHtml (docptr);
tptr = docptr->text + docptr->tparse;
sptr = docptr->html + docptr->hlength;
/* right to the end of the buffer */
zptr = docptr->html + docptr->hsize;
if (dbug>1) dbugThis (FI_LI, "renderInsertTag() %c%s%c %s",
bvbar, tag, bvbar, 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;
}
if (*tptr == '&') break; /* rest of string is style */
/* 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;
}
/* 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, SS$_BADPARAM)
}
if (dbug>1) dbugThis (FI_LI, "%s", dbugMax(tptr));
docptr->tparse = tptr - docptr->text;
docptr->hlength = sptr - docptr->html;
if (HMORE (docptr)) wasDocMoreHtml (docptr);
if (sptr >= zptr)
return (SS$_BADPARAM);
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>1) dbugThis (FI_LI, "renderStyle() %s", dbugAll(param));
if (!param || MATCH7 (param, "default"))
{
if (!docptr->styled) wasDocAsIs (docptr, styleDefault);
docptr->styled = 1;
}
else
if (MATCH6 (param, "chunk="))
{
if (docptr->chunked)
wasDocPrintf (docptr,
"",
param+6);
}
else
if (MATCH5 (param, "file="))
{
renderInsertFile (docptr, param+5, 1);
docptr->styled = 1;
}
else
if (MATCH6 (param, "sheet="))
{
wasDocPrintf (docptr,
" \n",
param + 6);
docptr->styled = 1;
}
else
{
for (cptr = param; *cptr && *cptr != '=' && *cptr != '{'; cptr++);
if (*cptr == '=')
error = SS$_BADPARAM;
else
wasDocPrintf (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>1) 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>1) 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 (SS$_RESULTOVF);
for (cptr = string; *cptr && sptr < zptr; cptr++)
{
if (*cptr == '|') break;
if (*cptr == '\\' && cptr[1]) cptr++;
*sptr++ = *cptr;
}
*sptr = '\0';
if (sptr > zptr) return (SS$_RESULTOVF);
return (0);
}
/*****************************************************************************/
/*
Remove preceding white-space.
*/
char* renderTrimWhite (struct wasdoc_st *docptr)
{
char *cptr;
while (docptr->hlength && isspace(docptr->html[docptr->hlength-1]))
docptr->hlength--;
docptr->html[docptr->hlength] = '\0';
cptr = docptr->html + docptr->hlength;
if (docptr->hlength) cptr--;
return (cptr);
}
/*****************************************************************************/
/*
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>1) dbugThis (FI_LI, "renderGetSyi() %s", dbugAll(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);
}
/*****************************************************************************/
/*
"n." or "n.n" or "n.n.n" or ...
*/
char* renderNumericId (int *digit6)
{
static char buf [48];
int cnt, idx;
char *sptr;
sptr = buf;
for (cnt = 6; cnt > 1 && !digit6[cnt]; cnt--);
for (idx = 1; idx <= cnt; idx++)
sptr += sprintf (sptr, "%d.", digit6[idx]);
if (cnt > 1) *(sptr-1) = '\0';
if (dbug>1) dbugThis (FI_LI, "renderNumericId() %s", buf);
return (buf);
}
/*****************************************************************************/
/*
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>1) 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, "|draw") && 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);
}
}
/*****************************************************************************/