2 * man page backend for Halibut
10 static void man_text(FILE *, word
*, int newline
, int quote_props
);
11 static void man_codepara(FILE *, word
*);
13 #define QUOTE_INITCTRL 1 /* quote initial . and ' on a line */
14 #define QUOTE_QUOTES 2 /* quote double quotes by doubling them */
16 void man_backend(paragraph
*sourceform
, keywordlist
*keywords
,
22 IGNORE(keywords
); /* we don't happen to need this */
23 IGNORE(idx
); /* or this */
26 * Determine the output file name, and open the output file
28 * FIXME: want configurable output file names here. For the
29 * moment, we'll just call it `output.1'.
31 fp
= fopen("output.1", "w");
33 error(err_cantopenw
, "output.1");
37 /* Do the version ID */
38 for (p
= sourceform
; p
; p
= p
->next
)
39 if (p
->type
== para_VersionID
) {
40 fprintf(fp
, ".\\\" ");
41 man_text(fp
, p
->words
, TRUE
, 0);
44 /* FIXME: .TH name-of-program manual-section */
45 fprintf(fp
, ".TH FIXME 1\n");
49 /* Do the preamble and copyright */
51 for (p
= sourceform
; p
; p
= p
->next
)
52 if (p
->type
== para_Preamble
) {
53 fprintf(fp
, "%s", sep
);
54 man_text(fp
, p
->words
, TRUE
, 0);
57 for (p
= sourceform
; p
; p
= p
->next
)
58 if (p
->type
== para_Copyright
) {
59 fprintf(fp
, "%s", sep
);
60 man_text(fp
, p
->words
, TRUE
, 0);
67 * - figure out precisely what needs to be escaped.
68 * * A dot or apostrophe at the start of a line wants to be
69 * preceded by `\&', which is a zero-width space.
70 * * Literal backslashes always want doubling.
71 * * Within double quotes, a double quote needs doubling
74 * - work out what to do about hyphens / minuses...
76 for (p
= sourceform
; p
; p
= p
->next
) switch (p
->type
) {
78 * Things we ignore because we've already processed them or
79 * aren't going to touch them in this pass.
83 case para_Biblio
: /* only touch BiblioCited */
96 case para_UnnumberedChapter
:
99 fprintf(fp
, ".SH \"");
100 /* FIXME: disable this, at _least_ by default */
102 man_text(fp
, p
->kwtext
, FALSE
, QUOTE_QUOTES
);
104 man_text(fp
, p
->words
, FALSE
, QUOTE_QUOTES
);
112 fprintf(fp
, ".PP\n");
113 man_codepara(fp
, p
->words
);
120 fprintf(fp
, ".PP\n");
121 man_text(fp
, p
->words
, TRUE
, 0);
127 case para_Description
:
128 case para_BiblioCited
:
130 case para_NumberedList
:
131 if (p
->type
== para_Bullet
) {
132 fprintf(fp
, ".IP \"\\fBo\\fP\"\n"); /* FIXME: configurable? */
133 } else if (p
->type
== para_NumberedList
) {
134 fprintf(fp
, ".IP \"");
135 man_text(fp
, p
->kwtext
, FALSE
, QUOTE_QUOTES
);
137 } else if (p
->type
== para_Description
) {
139 * Do nothing; the .xP for this paragraph is the .IP
140 * which has come before it in the DescribedThing.
142 } else if (p
->type
== para_BiblioCited
) {
143 fprintf(fp
, ".IP \"");
144 man_text(fp
, p
->kwtext
, FALSE
, QUOTE_QUOTES
);
147 man_text(fp
, p
->words
, TRUE
, 0);
150 case para_DescribedThing
:
151 fprintf(fp
, ".IP \"");
152 man_text(fp
, p
->words
, FALSE
, QUOTE_QUOTES
);
163 fprintf(fp
, ".RS\n");
166 fprintf(fp
, ".RE\n");
177 * Convert a wide string into a string of chars. If `result' is
178 * non-NULL, mallocs the resulting string and stores a pointer to
179 * it in `*result'. If `result' is NULL, merely checks whether all
180 * characters in the string are feasible for the output character
183 * Return is nonzero if all characters are OK. If not all
184 * characters are OK but `result' is non-NULL, a result _will_
185 * still be generated!
187 * FIXME: Here is probably also a good place to do escaping sorts
188 * of things. I know I at least need to escape backslash, and full
189 * stops at the starts of words are probably trouble as well.
191 static int man_convert(wchar_t *s
, char **result
, int quote_props
) {
193 * FIXME. Currently this is ISO8859-1 only.
195 int doing
= (result
!= 0);
198 int plen
= 0, psize
= 0;
204 if ((c
>= 32 && c
<= 126) ||
205 (c
>= 160 && c
<= 255)) {
209 /* Char is not OK. */
211 outc
= 0xBF; /* approximate the good old DEC `uh?' */
214 if (plen
+3 >= psize
) {
216 p
= resize(p
, psize
);
218 if (plen
== 0 && (outc
== '.' || outc
== '\'') &&
219 (quote_props
& QUOTE_INITCTRL
)) {
221 * Control character (. or ') at the start of a
222 * line. Quote it by putting \& (troff zero-width
227 } else if (outc
== '\\') {
229 * Quote backslashes by doubling them, always.
232 } else if (outc
== '"' && (quote_props
& QUOTE_QUOTES
)) {
234 * Double quote within double quotes. Quote it by
243 p
= resize(p
, plen
+1);
250 static void man_rdaddwc(rdstringc
*rs
, word
*text
, word
*end
,
254 for (; text
&& text
!= end
; text
= text
->next
) switch (text
->type
) {
267 case word_WhiteSpace
:
270 case word_WkCodeSpace
:
274 case word_WkCodeQuote
:
275 assert(text
->type
!= word_CodeQuote
&&
276 text
->type
!= word_WkCodeQuote
);
277 if (towordstyle(text
->type
) == word_Emph
&&
278 (attraux(text
->aux
) == attr_First
||
279 attraux(text
->aux
) == attr_Only
))
281 else if (towordstyle(text
->type
) == word_Code
&&
282 (attraux(text
->aux
) == attr_First
||
283 attraux(text
->aux
) == attr_Only
))
285 if (removeattr(text
->type
) == word_Normal
) {
287 quote_props
&= ~QUOTE_INITCTRL
; /* not at start any more */
288 if (man_convert(text
->text
, &c
, quote_props
))
291 man_rdaddwc(rs
, text
->alt
, NULL
, quote_props
);
293 } else if (removeattr(text
->type
) == word_WhiteSpace
) {
295 } else if (removeattr(text
->type
) == word_Quote
) {
296 rdaddc(rs
, quoteaux(text
->aux
) == quote_Open ?
'`' : '\'');
297 /* FIXME: configurability */
299 if (towordstyle(text
->type
) == word_Emph
&&
300 (attraux(text
->aux
) == attr_Last
||
301 attraux(text
->aux
) == attr_Only
))
303 else if (towordstyle(text
->type
) == word_Code
&&
304 (attraux(text
->aux
) == attr_Last
||
305 attraux(text
->aux
) == attr_Only
))
311 static void man_text(FILE *fp
, word
*text
, int newline
, int quote_props
) {
312 rdstringc t
= { 0, 0, NULL
};
314 man_rdaddwc(&t
, text
, NULL
, quote_props
| QUOTE_INITCTRL
);
315 fprintf(fp
, "%s", t
.text
);
321 static void man_codepara(FILE *fp
, word
*text
) {
322 fprintf(fp
, ".nf\n");
323 for (; text
; text
= text
->next
) if (text
->type
== word_WeakCode
) {
325 man_convert(text
->text
, &c
, QUOTE_INITCTRL
);
326 fprintf(fp
, "%s\n", c
);
329 fprintf(fp
, ".fi\n");