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
12 * After printing an inline macro, eatspc_on() is called which forces
13 * troff_put() to ignore all whitespaces until the first
14 * non-space character. Some care is necessary when handling dots; if
15 * a dot appears just after a newline, it is a troff macro, otherwise
16 * it is a printable dot and should be escaped.
23 static int eatspc
; /* jump space chars */
24 static int gotnl
; /* last output char was a newline */
25 static int inblk
; /* inside a block */
27 static void eatspc_on(void)
33 static void troff_doc_beg(struct doc
*doc
)
37 static void troff_doc_end(struct doc
*doc
)
41 static void troff_put(struct doc
*doc
, char *s
)
50 while (*s
== ' ' || *s
== '\t' || *s
== '\n')
52 eatspc
= *s
== '\0'; /* more eatspc if s was space */
53 if (!gotnl
&& *s
== '.')
54 doc_write(doc
, "\\&");
55 else if (!eatspc
) /* exiting eatspc; set gotnl */
58 while (gotnl
&& *s
== '\n')
61 char *r
= strchr(s
, '\n');
62 r
= r
? r
+ 1 : strchr(s
, '\0');
63 doc_memcat(doc
, s
, r
- s
);
68 gotnl
= s
[-1] == '\n';
71 static void troff_head_beg(struct doc
*doc
, int level
)
75 troff_put(doc
, ".NH 1\n");
78 troff_put(doc
, ".NH 2\n");
81 troff_put(doc
, ".SH\n");
85 static void troff_head_end(struct doc
*doc
, int level
)
89 static void troff_par_beg(struct doc
*doc
)
91 troff_put(doc
, ".PP\n");
94 static void troff_par_end(struct doc
*doc
)
100 static void troff_list_beg(struct doc
*doc
, int mark
)
102 troff_put(doc
, "\n.br\n");
106 doc_write(doc
, ".RS\n");
109 static void troff_list_end(struct doc
*doc
)
112 doc_write(doc
, ".RE\n");
116 static void troff_item_beg(struct doc
*doc
, char *head
)
120 sprintf(b
, ".IP \"%s\" 1i\n", head
);
123 doc_write(doc
, ".IP \\(bu 2\n");
128 static void troff_item_end(struct doc
*doc
)
132 static void troff_block_beg(struct doc
*doc
, char *beg
)
135 troff_put(doc
, beg
? beg
: ".DS");
136 troff_put(doc
, "\n");
139 static void troff_block_end(struct doc
*doc
, char *end
)
141 troff_put(doc
, end
? end
: ".DE");
142 troff_put(doc
, "\n");
146 static void troff_put_txt(struct doc
*doc
, char *s
, char *m
)
151 troff_put(doc
, "\\f3");
153 troff_put(doc
, "\\fP");
156 troff_put(doc
, "\\f2");
158 troff_put(doc
, "\\fP");
164 troff_put(doc
, "\n.[[\n");
166 troff_put(doc
, "\n.]]\n");
170 troff_put(doc
, "\n.FS\n");
172 troff_put(doc
, "\n.FE\n");
176 sprintf(b
, "%c%s%c", m
[0], s
, m
[1]);
181 static void troff_table_beg(struct doc
*doc
, int columns
)
184 troff_put(doc
, ".TS\n");
186 troff_put(doc
, "allbox;\n");
187 for (i
= 0; i
< columns
; i
++)
188 troff_put(doc
, "c ");
189 troff_put(doc
, ".\n");
193 static void troff_table_end(struct doc
*doc
)
195 troff_put(doc
, ".TE\n");
198 /* a hack to identify the first entry in each row */
201 static void troff_row_beg(struct doc
*doc
)
206 static void troff_row_end(struct doc
*doc
)
208 troff_put(doc
, "\n");
211 static void troff_entry_beg(struct doc
*doc
)
214 troff_put(doc
, "\t");
215 troff_put(doc
, "T{\n");
218 static void troff_entry_end(struct doc
*doc
)
220 troff_put(doc
, "\nT}");
223 struct fmt_ops troff_ops
= {
224 .doc_beg
= troff_doc_beg
,
225 .doc_end
= troff_doc_end
,
226 .head_beg
= troff_head_beg
,
227 .head_end
= troff_head_end
,
228 .par_beg
= troff_par_beg
,
229 .par_end
= troff_par_end
,
230 .list_beg
= troff_list_beg
,
231 .list_end
= troff_list_end
,
232 .item_beg
= troff_item_beg
,
233 .item_end
= troff_item_end
,
234 .table_beg
= troff_table_beg
,
235 .table_end
= troff_table_end
,
236 .row_beg
= troff_row_beg
,
237 .row_end
= troff_row_end
,
238 .entry_beg
= troff_entry_beg
,
239 .entry_end
= troff_entry_end
,
240 .block_beg
= troff_block_beg
,
241 .block_end
= troff_block_end
,
243 .put_txt
= troff_put_txt