📄 bk_xhtml.c
字号:
}
fprintf(fp, "</body>\n\n</html>\n");
}
static void chm_dofooter(FILE * fp)
{
fprintf(fp, "</ul></BODY></HTML>\n");
}
/*
* Output the versionid paragraph. Typically this is a version control
* ID string (such as $Id...$ in RCS).
*/
static void xhtml_versionid(FILE * fp, word * text, int started)
{
rdstringc t = { 0, 0, NULL };
rdaddc(&t, '['); /* FIXME: configurability */
xhtml_rdaddwc(&t, text, NULL);
rdaddc(&t, ']'); /* FIXME: configurability */
if (started)
fprintf(fp, "<br>\n");
fprintf(fp, "%s\n", t.text);
sfree(t.text);
}
/* Is this an XHTML reserved character? */
static int xhtml_reservedchar(int c)
{
if (c == '&' || c == '<' || c == '>' || c == '"')
return TRUE;
else
return FALSE;
}
/*
* Convert a wide string into valid XHTML: Anything outside ASCII will
* be fixed up as an entity. Currently we don't worry about constraining the
* encoded character set, which we should probably do at some point (we can
* still fix up and return FALSE - see the last comment here). We also don't
* currently
*
* Because this is only used for words, spaces are HARD spaces (any other
* spaces will be word_Whitespace not word_Normal). So they become
* Unless hard_spaces is FALSE, of course (code paragraphs break the above
* rule).
*
* If `result' is non-NULL, mallocs the resulting string and stores a pointer to
* it in `*result'. If `result' is NULL, merely checks whether all
* characters in the string are feasible.
*
* Return is nonzero if all characters are OK. If not all
* characters are OK but `result' is non-NULL, a result _will_
* still be generated!
*/
static int xhtml_convert(wchar_t * s, char **result, int hard_spaces)
{
int doing = (result != 0);
int ok = TRUE;
char *p = NULL;
int plen = 0, psize = 0;
for (; *s; s++)
{
wchar_t c = *s;
#define ensure_size(i) if (i>=psize) { psize = i+256; p = resize(p, psize); }
if (((c == 32 && !hard_spaces)
|| (c > 32 && c <= 126 && !xhtml_reservedchar(c))))
{
/* Char is OK. */
if (doing)
{
ensure_size(plen);
p[plen++] = (char) c;
}
} else
{
/* Char needs fixing up. */
/* ok = FALSE; -- currently we never return FALSE; we
* might want to when considering a character set for the
* encoded document.
*/
if (doing)
{
if (c == 32)
{ /* a space in a word is a hard space */
ensure_size(plen + 7); /* includes space for the NUL, which is subsequently stomped on */
sprintf(p + plen, " ");
plen += 6;
} else
{
switch (c)
{
case '&':
ensure_size(plen + 6); /* includes space for the NUL, which is subsequently stomped on */
plen += sprintf(p + plen, "&");
break;
case '"':
ensure_size(plen + 7); /* includes space for the NUL, which is subsequently stomped on */
plen += sprintf(p + plen, """);
break;
case '<':
if (plen > 1 && *(s - 1) == '\\' && *(s - 2) == '\\')
{
ensure_size(--plen);
p[plen - 1] = (char) c;
p[plen] = 0;
} else
{
ensure_size(plen + 5); /* includes space for the NUL, which is subsequently stomped on */
plen += sprintf(p + plen, "<");
}
break;
case '>':
if (plen > 1 && *(s - 1) == '\\' && *(s - 2) == '\\')
{
ensure_size(--plen);
p[plen - 1] = (char) c;
p[plen] = 0;
} else
{
ensure_size(plen + 5); /* includes space for the NUL, which is subsequently stomped on */
plen += sprintf(p + plen, ">");
}
break;
default:
ensure_size(plen + 8); /* includes space for the NUL, which is subsequently stomped on */
plen += sprintf(p + plen, "&#%04i;", (int) c);
break;
}
}
}
}
}
if (doing)
{
p = resize(p, plen + 1);
p[plen] = '\0';
*result = p;
}
return ok;
}
/*
* This formats the given words as XHTML.
*/
static void xhtml_rdaddwc(rdstringc * rs, word * text, word * end)
{
char *c;
keyword *kwl;
xhtmlsection *sect;
indextag *itag;
int ti;
wchar_t *s;
for (; text && text != end; text = text->next)
{
switch (text->type)
{
case word_HyperLink:
xhtml_utostr(text->text, &c);
rdaddsc(rs, "<a href=\"");
if(chm_toc && *c == '.' && *(c+1) == '.')
rdaddsc(rs, c + 1);
else
rdaddsc(rs, c);
rdaddsc(rs, "\">");
sfree(c);
break;
case word_LocalHyperLink:
xhtml_utostr(text->text, &c);
rdaddsc(rs, "<a href=\"");
if (conf.rlink_prefix)
{
char *c2;
xhtml_utostr(conf.rlink_prefix, &c2);
rdaddsc(rs, c2);
sfree(c2);
}
rdaddsc(rs, c);
if (conf.rlink_suffix)
{
char *c2;
xhtml_utostr(conf.rlink_suffix, &c2);
rdaddsc(rs, c2);
sfree(c2);
}
rdaddsc(rs, "\">");
sfree(c);
break;
case word_UpperXref:
case word_LowerXref:
case word_FreeTextXref:
kwl = kw_lookup(keywords, text->text);
if (kwl)
{
sect = xhtml_find_section(kwl->para);
if (sect)
{
rdaddsc(rs, "<a href=\"");
rdaddsc(rs, sect->file->filename);
rdaddc(rs, '#');
rdaddsc(rs, sect->fragment);
rdaddsc(rs, "\">");
} else
{
rdaddsc(rs,
"<a href=\"Apologies.html\"><!-- probably a bibliography cross reference -->");
error(err_whatever,
"Couldn't locate cross-reference! (Probably a bibliography entry.)");
}
} else
{
rdaddsc(rs,
"<a href=\"Apologies.html\"><!-- unknown cross-reference -->");
error(err_whatever,
"Couldn't locate cross-reference! (Wasn't in source file.)");
}
break;
case word_IndexRef: /* in theory we could make an index target here */
/* rdaddsc(rs, "<a name=\"idx-");
xhtml_utostr(text->text, &c);
rdaddsc(rs, c);
sfree(c);
rdaddsc(rs, "\"></a>");*/
/* what we _do_ need to do is to fix up the backend data
* for any indexentry this points to.
*/
for (ti = 0;
(itag = (indextag *) index234(idx->tags, ti)) != NULL; ti++)
{
/* FIXME: really ustricmp() and not ustrcmp()? */
if (ustricmp(itag->name, text->text) == 0)
{
break;
}
}
if (itag != NULL)
{
if (itag->refs != NULL)
{
int i;
for (i = 0; i < itag->nrefs; i++)
{
xhtmlindex *idx_ref;
indexentry *ientry;
ientry = itag->refs[i];
if (ientry->backend_data == NULL)
{
idx_ref = (xhtmlindex *) smalloc(sizeof(xhtmlindex));
if (idx_ref == NULL)
fatal(err_nomemory);
idx_ref->nsection = 0;
idx_ref->size = 4;
idx_ref->sections =
(xhtmlsection **) smalloc(idx_ref->size *
sizeof(xhtmlsection *));
if (idx_ref->sections == NULL)
fatal(err_nomemory);
ientry->backend_data = idx_ref;
} else
{
idx_ref = ientry->backend_data;
if (idx_ref->nsection + 1 > idx_ref->size)
{
int new_size = idx_ref->size * 2;
idx_ref->sections =
srealloc(idx_ref->sections,
new_size * sizeof(xhtmlsection));
if (idx_ref->sections == NULL)
{
fatal(err_nomemory);
}
idx_ref->size = new_size;
}
}
idx_ref->sections[idx_ref->nsection++] = currentsection;
#if 0
#endif
}
} else
{
fatal(err_whatever, "Index tag had no entries!");
}
} else
{
fprintf(stderr, "Looking for index entry '%ls'\n", text->text);
fatal(err_whatever,
"Couldn't locate index entry! (Wasn't in index.)");
}
break;
case word_HyperEnd:
case word_XrefEnd:
rdaddsc(rs, "</a>");
break;
case word_Normal:
case word_Emph:
case word_Code:
case word_WeakCode:
case word_WhiteSpace:
case word_EmphSpace:
case word_CodeSpace:
case word_WkCodeSpace:
case word_Quote:
case word_EmphQuote:
case word_CodeQuote:
case word_WkCodeQuote:
assert(text->type != word_CodeQuote &&
text->type != word_WkCodeQuote);
if (towordstyle(text->type) == word_Emph &&
(attraux(text->aux) == attr_First ||
attraux(text->aux) == attr_Only))
rdaddsc(rs, "<em>");
else if ((towordstyle(text->type) == word_Code
|| towordstyle(text->type) == word_WeakCode)
&& (attraux(text->aux) == attr_First
|| attraux(text->aux) == attr_Only))
rdaddsc(rs, "<code>");
if (removeattr(text->type) == word_Normal)
{
static int dont_convert = 0;
if (dont_convert)
{
char buf[2] = " ";
dont_convert = 0;
s = text->text;
for (; *s; s++)
{
buf[0] = (char) *s;
rdaddsc(rs, buf);
}
buf[0] = 0;
rdaddsc(rs, buf);
} else
{
if (*text->text == '\\' && text->next
&& text->next->text && (*text->next->text == '&'
|| *text->next->text == '<'
|| *text->next->text == '>'
|| *text->next->text == '"'))
dont_convert = 1;
else
{
if (xhtml_convert(text->text, &c, TRUE)) /* spaces in the word are hard */
rdaddsc(rs, c);
else
xhtml_rdaddwc(rs, text->alt, NULL);
sfree(c);
}
}
} else if (removeattr(text->type) == word_WhiteSpace)
{
rdaddc(rs, ' ');
} else if (removeattr(text->type) == word_Quote)
{
rdaddsc(rs, """);
}
if (towordstyle(text->type) == word_Emph &&
(attraux(text->aux) == attr_Last ||
attraux(text->aux) == attr_Only))
rdaddsc(rs, "</em>");
else if ((towordstyle(text->type) == word_Code
|| towordstyle(text->type) == word_WeakCode)
&& (attraux(text->aux) == attr_Last
|| attraux(text->aux) == attr_Only))
rdaddsc(rs, "</code>");
break;
}
}
}
/* Output a heading, formatted as XHTML.
*/
static void xhtml_heading(FILE * fp, paragraph * p)
{
rdstringc t = { 0, 0, NULL };
word *tprefix = p->kwtext;
word *nprefix = p->kwtext2;
word *text = p->words;
int level = xhtml_para_level(p);
xhtmlsection *sect = xhtml_find_section(p);
xhtmlheadfmt *fmt;
char *fragment;
if (sect)
{
fragment = sect->fragment;
} else
{
if (p->type == para_Title)
fragment = "title";
else
{
fragment = ""; /* FIXME: what else can we do? */
error(err_whatever, "Couldn't locate heading cross-reference!");
}
}
if (p->type == para_Title)
fmt = NULL;
else if (level == 1)
fmt = &conf.fchapter;
else if (level - 1 < conf.nfsect)
fmt = &conf.fsect[level - 1];
else
fmt = &conf.fsect[conf.nfsect - 1];
if (fmt && fmt->just_numbers && nprefix)
{
xhtml_rdaddwc(&t, nprefix, NULL);
if (fmt)
{
char *c;
if (xhtml_convert(fmt->number_suffix, &c, FALSE))
{
rdaddsc(&t, c);
sfree(c);
}
}
} else if (fmt && !fmt->just_numbers && tprefix)
{
xhtml_rdaddwc(&t, tprefix, NULL);
if (fmt)
{
char *c;
if (xhtml_convert(fmt->number_suffix, &c, FALSE))
{
rdaddsc(&t, c);
sfree(c);
}
}
}
xhtml_rdaddwc(&t, text, NULL);
/*
* If we're outputting in single-file mode, we need to lower
* the level of each heading by one, because the overall
* document title will be sitting right at the top as an <h1>
* and so chapters and sections should start at <h2>.
*
* Even if not, the document title will come back from
* xhtml_para_level() as level zero, so we must increment that
* no matter what leaf_level is set to.
*/
if (conf.leaf_level == 0 || level == 0)
level++;
fprintf(fp, "<a name=\"%s\"></a><h%i>%s</h%i>\n", fragment, level,
t.text, level);
sfree(t.text);
}
/* Output a paragraph. Styles are handled by xhtml_rdaddwc().
* This looks pretty simple; I may have missed something ...
*/
static void xhtml_para(FILE * fp, word * text)
{
rdstringc out = { 0, 0, NULL };
xhtml_rdaddwc(&out, text, NULL);
fprintf(fp, "%s", out.text);
sfree(out.text);
}
/* Output a code paragraph. I'm treating this as preformatted, which
* may not be entirely correct. See xhtml_para() for my worries about
* this being overly-simple; however I think that most of the complexity
* of the text backend came entirely out of word wrapping anyway.
*/
static void xhtml_codepara(FILE * fp, word * text)
{
fprintf(fp, "<pre>");
for (; text; text = text->next)
if (text->type == word_WeakCode)
{
char *c;
xhtml_convert(text->text, &c, FALSE);
fprintf(fp, "%s\n", c);
sfree(c);
}
fprintf(fp, "</pre>\n");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -