diff options
| -rw-r--r-- | bk_man.c | 162 | ||||
| -rw-r--r-- | bk_whlp.c | 54 | ||||
| -rw-r--r-- | bk_xhtml.c | 61 | ||||
| -rw-r--r-- | input.c | 11 | ||||
| -rw-r--r-- | inputs/test.but | 7 |
5 files changed, 243 insertions, 52 deletions
@@ -9,6 +9,51 @@ static void man_text(FILE *, word *, int newline, int quote_props); static void man_codepara(FILE *, word *); +static int man_convert(wchar_t *s, int maxlen, + char **result, int quote_props); + +typedef struct { + wchar_t *th; + int headnumbers; + int mindepth; +} manconfig; + +static manconfig man_configure(paragraph *source) { + manconfig ret; + + /* + * Defaults. + */ + ret.th = NULL; + ret.headnumbers = FALSE; + ret.mindepth = 0; + + for (; source; source = source->next) { + if (source->type == para_Config) { + if (!ustricmp(source->keyword, L"man-identity")) { + wchar_t *wp, *ep; + + wp = uadv(source->keyword); + ep = wp; + while (*ep) + ep = uadv(ep); + ret.th = mknewa(wchar_t, ep - wp + 1); + memcpy(ret.th, wp, (ep - wp + 1) * sizeof(wchar_t)); + } else if (!ustricmp(source->keyword, L"man-headnumbers")) { + ret.headnumbers = utob(uadv(source->keyword)); + } else if (!ustricmp(source->keyword, L"man-mindepth")) { + ret.mindepth = utoi(uadv(source->keyword)); + } + } + } + + return ret; +} + +static void man_conf_cleanup(manconfig cf) +{ + sfree(cf.th); +} #define QUOTE_INITCTRL 1 /* quote initial . and ' on a line */ #define QUOTE_QUOTES 2 /* quote double quotes by doubling them */ @@ -18,10 +63,13 @@ void man_backend(paragraph *sourceform, keywordlist *keywords, paragraph *p; FILE *fp; char const *sep; + manconfig conf; IGNORE(keywords); /* we don't happen to need this */ IGNORE(idx); /* or this */ + conf = man_configure(sourceform); + /* * Determine the output file name, and open the output file * @@ -41,8 +89,23 @@ void man_backend(paragraph *sourceform, keywordlist *keywords, man_text(fp, p->words, TRUE, 0); } - /* FIXME: .TH name-of-program manual-section */ - fprintf(fp, ".TH FIXME 1\n"); + /* .TH name-of-program manual-section */ + { + char *c; + if (conf.th && *conf.th) { + wchar_t *wp; + fprintf(fp, ".TH"); + + for (wp = conf.th; *wp; wp = uadv(wp)) { + fputs(" \"", fp); + man_convert(wp, 0, &c, QUOTE_QUOTES); + fputs(c, fp); + sfree(c); + fputc('"', fp); + } + fputc('\n', fp); + } + } fprintf(fp, ".UC\n"); @@ -61,18 +124,6 @@ void man_backend(paragraph *sourceform, keywordlist *keywords, sep = "\n"; } - /* - * FIXME: - * - * - figure out precisely what needs to be escaped. - * * A dot or apostrophe at the start of a line wants to be - * preceded by `\&', which is a zero-width space. - * * Literal backslashes always want doubling. - * * Within double quotes, a double quote needs doubling - * too. - * - * - work out what to do about hyphens / minuses... - */ for (p = sourceform; p; p = p->next) switch (p->type) { /* * Things we ignore because we've already processed them or @@ -96,14 +147,25 @@ void man_backend(paragraph *sourceform, keywordlist *keywords, case para_UnnumberedChapter: case para_Heading: case para_Subsect: - fprintf(fp, ".SH \""); - /* FIXME: disable this, at _least_ by default */ - if (p->kwtext) - man_text(fp, p->kwtext, FALSE, QUOTE_QUOTES); - fprintf(fp, " "); - man_text(fp, p->words, FALSE, QUOTE_QUOTES); - fprintf(fp, "\"\n"); - break; + { + int depth; + if (p->type == para_Subsect) + depth = p->aux + 2; + else if (p->type == para_Heading) + depth = 1; + else + depth = 0; + if (depth >= conf.mindepth) { + fprintf(fp, ".SH \""); + if (conf.headnumbers && p->kwtext) { + man_text(fp, p->kwtext, FALSE, QUOTE_QUOTES); + fprintf(fp, " "); + } + man_text(fp, p->words, FALSE, QUOTE_QUOTES); + fprintf(fp, "\"\n"); + } + break; + } /* * Code paragraphs. @@ -155,8 +217,10 @@ void man_backend(paragraph *sourceform, keywordlist *keywords, case para_Rule: /* - * FIXME. + * This isn't terribly good. Anyone who wants to do better + * should feel free! */ + fprintf(fp, ".PP\n----------------------------------------\n"); break; case para_LcontPush: @@ -171,6 +235,7 @@ void man_backend(paragraph *sourceform, keywordlist *keywords, * Tidy up. */ fclose(fp); + man_conf_cleanup(conf); } /* @@ -188,7 +253,8 @@ void man_backend(paragraph *sourceform, keywordlist *keywords, * of things. I know I at least need to escape backslash, and full * stops at the starts of words are probably trouble as well. */ -static int man_convert(wchar_t *s, char **result, int quote_props) { +static int man_convert(wchar_t *s, int maxlen, + char **result, int quote_props) { /* * FIXME. Currently this is ISO8859-1 only. */ @@ -197,7 +263,10 @@ static int man_convert(wchar_t *s, char **result, int quote_props) { char *p = NULL; int plen = 0, psize = 0; - for (; *s; s++) { + if (maxlen <= 0) + maxlen = -1; + + for (; *s && maxlen != 0; s++, maxlen--) { wchar_t c = *s; char outc; @@ -278,14 +347,15 @@ static void man_rdaddwc(rdstringc *rs, word *text, word *end, (attraux(text->aux) == attr_First || attraux(text->aux) == attr_Only)) rdaddsc(rs, "\\fI"); - else if (towordstyle(text->type) == word_Code && + else if ((towordstyle(text->type) == word_Code || + towordstyle(text->type) == word_WeakCode) && (attraux(text->aux) == attr_First || attraux(text->aux) == attr_Only)) rdaddsc(rs, "\\fB"); if (removeattr(text->type) == word_Normal) { if (rs->pos > 0) quote_props &= ~QUOTE_INITCTRL; /* not at start any more */ - if (man_convert(text->text, &c, quote_props)) + if (man_convert(text->text, 0, &c, quote_props)) rdaddsc(rs, c); else man_rdaddwc(rs, text->alt, NULL, quote_props); @@ -293,14 +363,16 @@ static void man_rdaddwc(rdstringc *rs, word *text, word *end, } else if (removeattr(text->type) == word_WhiteSpace) { rdaddc(rs, ' '); } else if (removeattr(text->type) == word_Quote) { - rdaddc(rs, quoteaux(text->aux) == quote_Open ? '`' : '\''); - /* FIXME: configurability */ + rdaddc(rs, '"'); + if (quote_props & QUOTE_QUOTES) + rdaddc(rs, '"'); } if (towordstyle(text->type) == word_Emph && (attraux(text->aux) == attr_Last || attraux(text->aux) == attr_Only)) rdaddsc(rs, "\\fP"); - else if (towordstyle(text->type) == word_Code && + else if ((towordstyle(text->type) == word_Code || + towordstyle(text->type) == word_WeakCode) && (attraux(text->aux) == attr_Last || attraux(text->aux) == attr_Only)) rdaddsc(rs, "\\fP"); @@ -322,7 +394,35 @@ static void man_codepara(FILE *fp, word *text) { fprintf(fp, ".nf\n"); for (; text; text = text->next) if (text->type == word_WeakCode) { char *c; - man_convert(text->text, &c, QUOTE_INITCTRL); + wchar_t *t, *e; + int quote_props = QUOTE_INITCTRL; + + t = text->text; + if (text->next && text->next->type == word_Emph) { + e = text->next->text; + text = text->next; + } else + e = NULL; + + while (e && *e && *t) { + int n; + int ec = *e; + + for (n = 0; t[n] && e[n] && e[n] == ec; n++); + if (ec == 'i') + fprintf(fp, "\\fI"); + else if (ec == 'b') + fprintf(fp, "\\fB"); + man_convert(t, n, &c, quote_props); + quote_props &= ~QUOTE_INITCTRL; + fprintf(fp, "%s", c); + sfree(c); + if (ec == 'i' || ec == 'b') + fprintf(fp, "\\fP"); + t += n; + e += n; + } + man_convert(t, 0, &c, quote_props); fprintf(fp, "%s\n", c); sfree(c); } @@ -28,6 +28,8 @@ enum { FONT_NORMAL, FONT_EMPH, FONT_CODE, + FONT_ITAL_CODE, + FONT_BOLD_CODE, FONT_TITLE, FONT_TITLE_EMPH, FONT_TITLE_CODE, @@ -35,7 +37,8 @@ enum { }; static void whlp_rdaddwc(rdstringc *rs, word *text); -static int whlp_convert(wchar_t *s, char **result, int hard_spaces); +static int whlp_convert(wchar_t *s, int maxlen, + char **result, int hard_spaces); static void whlp_mkparagraph(struct bk_whlp_state *state, int font, word *text, int subsidiary); static void whlp_navmenu(struct bk_whlp_state *state, paragraph *p); @@ -73,6 +76,10 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, WHLP_FONT_ITALIC, 0, 0, 0); whlp_create_font(h, "Courier New", WHLP_FONTFAM_FIXED, 24, 0, 0, 0, 0); + whlp_create_font(h, "Courier New", WHLP_FONTFAM_FIXED, 24, + WHLP_FONT_ITALIC, 0, 0, 0); + whlp_create_font(h, "Courier New", WHLP_FONTFAM_FIXED, 24, + WHLP_FONT_BOLD, 0, 0, 0); whlp_create_font(h, "Arial", WHLP_FONTFAM_SERIF, 30, WHLP_FONT_BOLD, 0, 0, 0); whlp_create_font(h, "Arial", WHLP_FONTFAM_SERIF, 30, @@ -91,7 +98,7 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, if (p->type == para_Config && p->parent) { if (!ustricmp(p->keyword, L"winhelp-topic")) { char *topicname; - whlp_convert(uadv(p->keyword), &topicname, 0); + whlp_convert(uadv(p->keyword), 0, &topicname, 0); /* Store the topic name in the private_data field of the * containing section. */ p->parent->private_data = topicname; @@ -396,14 +403,41 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, */ { word *w; + wchar_t *t, *e; char *c; - for (w = p->words; w; w = w->next) { + + for (w = p->words; w; w = w->next) if (w->type == word_WeakCode) { + t = w->text; + if (w->next && w->next->type == word_Emph) { + w = w->next; + e = w->text; + } else + e = NULL; + if (!w->next) whlp_para_attr(h, WHLP_PARA_SPACEBELOW, 12); + whlp_para_attr(h, WHLP_PARA_LEFTINDENT, 72*nesting); whlp_begin_para(h, WHLP_PARA_SCROLL); + while (e && *e && *t) { + int n; + int ec = *e; + + for (n = 0; t[n] && e[n] && e[n] == ec; n++); + if (ec == 'i') + whlp_set_font(h, FONT_ITAL_CODE); + else if (ec == 'b') + whlp_set_font(h, FONT_BOLD_CODE); + else + whlp_set_font(h, FONT_CODE); + whlp_convert(t, n, &c, FALSE); + whlp_text(h, c); + sfree(c); + t += n; + e += n; + } whlp_set_font(h, FONT_CODE); - whlp_convert(w->text, &c, FALSE); + whlp_convert(t, 0, &c, FALSE); whlp_text(h, c); sfree(c); whlp_end_para(h); @@ -546,7 +580,7 @@ static void whlp_mkparagraph(struct bk_whlp_state *state, whlp_set_font(state->h, newfont); } if (removeattr(text->type) == word_Normal) { - if (whlp_convert(text->text, &c, TRUE)) + if (whlp_convert(text->text, 0, &c, TRUE)) whlp_text(state->h, c); else whlp_mkparagraph(state, deffont, text->alt, FALSE); @@ -589,7 +623,7 @@ static void whlp_rdaddwc(rdstringc *rs, word *text) { assert(text->type != word_CodeQuote && text->type != word_WkCodeQuote); if (removeattr(text->type) == word_Normal) { - if (whlp_convert(text->text, &c, FALSE)) + if (whlp_convert(text->text, 0, &c, FALSE)) rdaddsc(rs, c); else whlp_rdaddwc(rs, text->alt); @@ -615,7 +649,8 @@ static void whlp_rdaddwc(rdstringc *rs, word *text) { * characters are OK but `result' is non-NULL, a result _will_ * still be generated! */ -static int whlp_convert(wchar_t *s, char **result, int hard_spaces) { +static int whlp_convert(wchar_t *s, int maxlen, + char **result, int hard_spaces) { /* * FIXME. Currently this is ISO8859-1 only. */ @@ -624,7 +659,10 @@ static int whlp_convert(wchar_t *s, char **result, int hard_spaces) { char *p = NULL; int plen = 0, psize = 0; - for (; *s; s++) { + if (maxlen <= 0) + maxlen = -1; + + for (; *s && maxlen != 0; s++, maxlen--) { wchar_t c = *s; char outc; @@ -94,7 +94,7 @@ static void xhtml_utostr(wchar_t *, char **); static int xhtml_para_level(paragraph *); static int xhtml_reservedchar(int); -static int xhtml_convert(wchar_t *, char **, int); +static int xhtml_convert(wchar_t *, int, char **, int); static void xhtml_rdaddwc(rdstringc *, word *, word *); static void xhtml_para(FILE *, word *); static void xhtml_codepara(FILE *, word *); @@ -1331,13 +1331,17 @@ static int xhtml_reservedchar(int c) * 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) { +static int xhtml_convert(wchar_t *s, int maxlen, char **result, + int hard_spaces) { int doing = (result != 0); int ok = TRUE; char *p = NULL; int plen = 0, psize = 0; - for (; *s; s++) { + if (maxlen <= 0) + maxlen = -1; + + for (; *s && maxlen != 0; s++, maxlen--) { wchar_t c = *s; #define ensure_size(i) if (i>=psize) { psize = i+256; p = resize(p, psize); } @@ -1504,7 +1508,7 @@ static void xhtml_rdaddwc(rdstringc *rs, word *text, word *end) { rdaddsc(rs, "<code>"); if (removeattr(text->type) == word_Normal) { - if (xhtml_convert(text->text, &c, TRUE)) /* spaces in the word are hard */ + if (xhtml_convert(text->text, 0, &c, TRUE)) /* spaces in the word are hard */ rdaddsc(rs, c); else xhtml_rdaddwc(rs, text->alt, NULL); @@ -1564,7 +1568,7 @@ static void xhtml_heading(FILE *fp, paragraph *p) xhtml_rdaddwc(&t, nprefix, NULL); if (fmt) { char *c; - if (xhtml_convert(fmt->number_suffix, &c, FALSE)) { + if (xhtml_convert(fmt->number_suffix, 0, &c, FALSE)) { rdaddsc(&t, c); sfree(c); } @@ -1573,7 +1577,7 @@ static void xhtml_heading(FILE *fp, paragraph *p) xhtml_rdaddwc(&t, tprefix, NULL); if (fmt) { char *c; - if (xhtml_convert(fmt->number_suffix, &c, FALSE)) { + if (xhtml_convert(fmt->number_suffix, 0, &c, FALSE)) { rdaddsc(&t, c); sfree(c); } @@ -1616,10 +1620,49 @@ static void xhtml_codepara(FILE *fp, word *text) { fprintf(fp, "<pre>"); for (; text; text = text->next) if (text->type == word_WeakCode) { + word *here, *next; char *c; - xhtml_convert(text->text, &c, FALSE); - fprintf(fp, "%s\n", c); - sfree(c); + + /* + * See if this WeakCode is followed by an Emph to indicate + * emphasis. + */ + here = text; + if (text->next && text->next->type == word_Emph) { + next = text = text->next; + } else + next = NULL; + + if (next) { + wchar_t *t, *e; + int n; + + t = here->text; + e = next->text; + + while (*e) { + int ec = *e; + + for (n = 0; t[n] && e[n] && e[n] == ec; n++); + xhtml_convert(t, n, &c, FALSE); + fprintf(fp, "%s%s%s", + (ec == 'i' ? "<em>" : ec == 'b' ? "<b>" : ""), + c, + (ec == 'i' ? "</em>" : ec == 'b' ? "</b>" : "")); + sfree(c); + + t += n; + e += n; + } + + xhtml_convert(t, 0, &c, FALSE); + fprintf(fp, "%s\n", c); + sfree(c); + } else { + xhtml_convert(here->text, 0, &c, FALSE); + fprintf(fp, "%s\n", c); + sfree(c); + } } fprintf(fp, "</pre>\n"); } @@ -569,11 +569,13 @@ static void read_file(paragraph ***ret, input *in, indexdata *idx) { * Parse code paragraphs separately. */ if (t.type == tok_cmd && t.cmd == c_c && !isbrace(in)) { + int wtype = word_WeakCode; + par.type = para_Code; par.fpos = t.pos; while (1) { dtor(t), t = get_codepar_token(in); - wd.type = word_WeakCode; + wd.type = wtype; wd.breaks = FALSE; /* shouldn't need this... */ wd.text = ustrdup(t.text); wd.alt = NULL; @@ -588,7 +590,12 @@ static void read_file(paragraph ***ret, input *in, indexdata *idx) { } if (t.type == tok_eop || t.type == tok_eof) break; - else if (t.type != tok_cmd || t.cmd != c_c) { + else if (t.type == tok_cmd && t.cmd == c_c) + wtype = word_WeakCode; + else if (t.type == tok_cmd && t.cmd == c_e && + wtype == word_WeakCode) + wtype = word_Emph; + else { error(err_brokencodepara, &t.pos); prev_para_type = par.type; addpara(par, ret); diff --git a/inputs/test.but b/inputs/test.but index 059567e..cfefbdb 100644 --- a/inputs/test.but +++ b/inputs/test.but @@ -3,8 +3,8 @@ See If Wrapping Titles Works OK. In Fact This Title Will Span Three Lines, Not Just Two. How's That For Ludicrous? \cfg{xhtml-leaf-smallest-contents}{2} - \cfg{xhtml-leaf-contains-contents}{true} +\cfg{man-headnumbers}{true} \preamble This manual is a small joke effort, designed to use every feature \#{ comment } that Halibut's input format supports. Creation @@ -19,7 +19,7 @@ a bit] \define{coopt} co\u00F6{-o}pt -\versionid $Id: test.but,v 1.20 2004/03/23 20:10:23 simon Exp $ +\versionid $Id: test.but,v 1.21 2004/03/24 19:23:21 simon Exp $ \C{ch\\ap} First chapter title; for similar wrapping reasons this chapter title will be ludicrously long. I wonder how much more @@ -57,6 +57,9 @@ Here's a code paragraph: \c Two blank lines precede this one. \c Two leading spaces \c We can use \ { and } with impunity here. +\c We can use discretionary bold and italic in code paragraphs! +\e bbbb iiiiii +\c Isn't that ludicrous? This is a list: |