2 * The main challenge in troff backend is managing unnecessary spaces:
3 * + no newline should appear in the output, except in blocks
4 * + no excess whitespace should appear after inline dot commands
7 * troff_put() manages white spaces:
8 * + gotnl: is set when the last character is a newline
9 * + eatspc: when one, ignore as much space as possible
10 * + inblk: we are in a block and no whitespace processing should be done
11 * + refer: right after .]] refer macro
13 * After printing an inline macro, eatspc_on() is called which forces
14 * troff_put() to ignore all whitespaces until the first
15 * non-space character. Some care is necessary when handling dots; if
16 * a dot appears just after a newline, it is a troff macro, otherwise
17 * it is a printable dot and should be escaped.
25 static int eatspc
; /* jump space chars */
26 static int gotnl
; /* last output char was a newline */
27 static int inblk
; /* inside a block */
28 static int refer
; /* right after refer .]] */
30 static void eatspc_on(void)
36 static void troff_doc_beg(struct doc
*doc
)
40 static void troff_doc_end(struct doc
*doc
)
44 static void troff_put(struct doc
*doc
, char *s
)
54 while (*s
&& !isspace(*s
))
56 doc_memcat(doc
, r
, s
- r
);
61 while (*s
== ' ' || *s
== '\t' || *s
== '\n')
63 eatspc
= *s
== '\0'; /* more eatspc if s was space */
64 if (!gotnl
&& *s
== '.')
65 doc_write(doc
, "\\&");
66 else if (!eatspc
) /* exiting eatspc; set gotnl */
69 while (gotnl
&& *s
== '\n')
72 char *r
= strchr(s
, '\n');
73 r
= r
? r
+ 1 : strchr(s
, '\0');
74 doc_memcat(doc
, s
, r
- s
);
79 gotnl
= s
[-1] == '\n';
82 static void troff_head_beg(struct doc
*doc
, int level
)
86 troff_put(doc
, ".NH 1\n");
89 troff_put(doc
, ".NH 2\n");
92 troff_put(doc
, ".SH\n");
96 static void troff_head_end(struct doc
*doc
, int level
)
100 static void troff_par_beg(struct doc
*doc
)
102 troff_put(doc
, ".PP\n");
105 static void troff_par_end(struct doc
*doc
)
111 static void troff_list_beg(struct doc
*doc
, int mark
)
113 troff_put(doc
, "\n.br\n");
116 troff_put(doc
, ".RS\n");
119 static void troff_list_end(struct doc
*doc
)
122 troff_put(doc
, ".RE\n");
126 static void troff_item_beg(struct doc
*doc
, char *head
)
130 sprintf(b
, ".IP \"%s\" 1i\n", head
);
133 troff_put(doc
, ".IP \\(bu 2\n");
138 static void troff_item_end(struct doc
*doc
)
142 static void troff_block_beg(struct doc
*doc
, char *beg
)
145 troff_put(doc
, beg
? beg
: ".DS");
146 troff_put(doc
, "\n");
149 static void troff_block_end(struct doc
*doc
, char *end
)
151 troff_put(doc
, end
? end
: ".DE");
152 troff_put(doc
, "\n");
156 static void troff_put_txt(struct doc
*doc
, char *s
, char *m
)
161 troff_put(doc
, "\\f3");
163 troff_put(doc
, "\\fP");
166 troff_put(doc
, "\\f2");
168 troff_put(doc
, "\\fP");
174 troff_put(doc
, "\n.[[\n");
176 troff_put(doc
, "\n.]]");
181 troff_put(doc
, "\n.FS\n");
183 troff_put(doc
, "\n.FE\n");
187 sprintf(b
, "%c%s%c", m
[0], s
, m
[1]);
192 static void troff_table_beg(struct doc
*doc
, int columns
)
195 troff_put(doc
, ".TS\n");
197 troff_put(doc
, "allbox;\n");
198 for (i
= 0; i
< columns
; i
++)
199 troff_put(doc
, "c ");
200 troff_put(doc
, ".\n");
204 static void troff_table_end(struct doc
*doc
)
206 troff_put(doc
, ".TE\n");
209 /* a hack to identify the first entry in each row */
212 static void troff_row_beg(struct doc
*doc
)
217 static void troff_row_end(struct doc
*doc
)
219 troff_put(doc
, "\n");
222 static void troff_entry_beg(struct doc
*doc
)
225 troff_put(doc
, "\t");
226 troff_put(doc
, "T{\n");
229 static void troff_entry_end(struct doc
*doc
)
231 troff_put(doc
, "\nT}");
234 struct fmt_ops troff_ops
= {
235 .doc_beg
= troff_doc_beg
,
236 .doc_end
= troff_doc_end
,
237 .head_beg
= troff_head_beg
,
238 .head_end
= troff_head_end
,
239 .par_beg
= troff_par_beg
,
240 .par_end
= troff_par_end
,
241 .list_beg
= troff_list_beg
,
242 .list_end
= troff_list_end
,
243 .item_beg
= troff_item_beg
,
244 .item_end
= troff_item_end
,
245 .table_beg
= troff_table_beg
,
246 .table_end
= troff_table_end
,
247 .row_beg
= troff_row_beg
,
248 .row_end
= troff_row_end
,
249 .entry_beg
= troff_entry_beg
,
250 .entry_end
= troff_entry_end
,
251 .block_beg
= troff_block_beg
,
252 .block_end
= troff_block_end
,
254 .put_txt
= troff_put_txt