8 #define LENGTH(vars) (sizeof(vars) / sizeof(vars[0]))
10 static char *markers
[] = {"**", "$$", "%%", "[]", "||", "//", "''", "``"};
11 static char *blocks
[][2] = {
12 {".EQ", ".EN"}, {".PS", ".PE"}, {".TS", ".TE"},
13 {".DS", ".DE"}, {".G1", ".G2"}, {".[", ".]"},
23 static struct fmt
*fmt_alloc(struct doc
*doc
, struct txt
*txt
,
26 struct fmt
*fmt
= xmalloc(sizeof(struct fmt
));
34 static void fmt_free(struct fmt
*fmt
)
39 static char *fmt_line(struct fmt
*fmt
, int line
)
41 char *s
= txt_line(fmt
->txt
, line
);
43 for (i
= 0; i
< fmt
->level
&& s
&& *s
; i
++)
48 static char *marker_char(char c
)
51 for (i
= 0; i
< LENGTH(markers
); i
++)
52 if (markers
[i
][0] == c
)
57 static char *possible_inline(char *s
)
64 if ((s
== home
|| isspace(*(s
- 1))) && !isspace(*(s
+ 1)))
65 if ((m
= marker_char(*s
)))
72 static char *fillbuf(char *beg
, char *end
)
74 static char buf
[MAXLINE
];
75 memcpy(buf
, beg
, end
- beg
);
76 buf
[end
- beg
] = '\0';
80 static char *fmt_put_inline(struct fmt
*fmt
, char *s
)
85 if (marker_char(*(s
+ 1))) {
86 fmt
->ops
->put(fmt
->doc
, fillbuf(s
+ 1, s
+ 2));
91 marker
= marker_char(*s
);
93 r
= strchr(s
+ 1, marker
[1]);
95 fmt
->ops
->put_txt(fmt
->doc
, fillbuf(s
+ 1, r
), marker
);
101 static void put_text(struct fmt
*fmt
, char *s
)
105 char *r
= possible_inline(s
);
108 fmt
->ops
->put(fmt
->doc
, fillbuf(done
, r
));
110 if ((r
= fmt_put_inline(fmt
, r
)))
115 fmt
->ops
->put(fmt
->doc
, done
);
118 static void raw_line(struct fmt
*fmt
, char *s
)
120 fmt
->ops
->put(fmt
->doc
, s
);
123 static void put_line(struct fmt
*fmt
, int n
)
125 put_text(fmt
, fmt_line(fmt
, n
));
129 static void put_lines(struct fmt
*fmt
, int beg
, int end
)
132 for (i
= beg
; i
< end
; i
++)
136 static void raw_lines(struct fmt
*fmt
, int beg
, int end
)
139 for (i
= beg
; i
< end
; i
++) {
140 raw_line(fmt
, fmt_line(fmt
, i
));
145 static int indents(char *s
)
153 static int islist(char *first
, char *line
)
157 if (!first
|| strlen(first
) < 2)
159 if (first
[1] != ' ' || !strchr(signs
, first
[0]))
163 if (strlen(line
) < 2)
165 return line
[0] == first
[0] && line
[1] == first
[1];
168 static void fmt_handle(struct fmt
*fmt
, int beg
, int end
, int level
);
170 static int fmt_head(struct fmt
*fmt
, int beg
, int end
)
172 char *line
= fmt_line(fmt
, beg
);
173 char *next
= fmt_line(fmt
, beg
+ 1);
177 if (!next
|| !*line
|| beg
== end
|| fmt
->level
)
180 if (!c
|| !strchr(signs
, *next
))
185 fmt
->ops
->head_beg(fmt
->doc
, strchr(signs
, *next
) - signs
);
187 fmt
->ops
->head_end(fmt
->doc
, strchr(signs
, *next
) - signs
);
191 static int cmd_line(struct fmt
*fmt
, int i
)
193 return !fmt
->level
&& *fmt_line(fmt
, i
) == '.';
196 static int par_end(struct fmt
*fmt
, int beg
, int end
)
200 while (i
< end
&& (line
= fmt_line(fmt
, i
))) {
201 if (!*line
|| indents(line
) || islist(line
, NULL
) || cmd_line(fmt
, i
))
208 static int fmt_par(struct fmt
*fmt
, int beg
, int end
)
211 if (indents(fmt_line(fmt
, beg
)) || cmd_line(fmt
, beg
))
213 fmt
->ops
->par_beg(fmt
->doc
);
214 i
= par_end(fmt
, beg
, end
);
215 put_lines(fmt
, beg
, i
);
216 fmt
->ops
->par_end(fmt
->doc
);
220 static int fmt_rawline(struct fmt
*fmt
, int beg
, int end
)
222 if (*fmt_line(fmt
, beg
) != '.')
224 raw_lines(fmt
, beg
, beg
+ 1);
228 static int min(int a
, int b
)
230 return a
< b
? a
: b
;
233 static int fmt_deindent(struct fmt
*fmt
, int n
, int indent
)
237 while ((line
= fmt_line(fmt
, n
))) {
238 if (*line
&& indents(line
) < indent
)
247 static int fmt_pre(struct fmt
*fmt
, int beg
, int end
)
249 int level
= indents(fmt_line(fmt
, beg
));
250 int next
= min(end
, fmt_deindent(fmt
, beg
+ 1, level
));
252 fmt
->ops
->block_beg(fmt
->doc
, NULL
);
253 raw_lines(fmt
, beg
, next
);
254 fmt
->ops
->block_end(fmt
->doc
, NULL
);
259 static int fmt_block(struct fmt
*fmt
, int beg
, int end
)
261 char *block_beg
= NULL
;
262 char *block_end
= NULL
;
267 line
= fmt_line(fmt
, beg
);
269 return fmt_pre(fmt
, beg
, end
);
272 for (i
= 0; i
< LENGTH(blocks
); i
++) {
273 block_beg
= blocks
[i
][0];
274 block_end
= blocks
[i
][1];
275 if (!strncmp(block_beg
, line
, strlen(block_beg
)))
278 if (i
== LENGTH(blocks
))
281 while (next
< end
&& depth
> 0) {
282 line
= fmt_line(fmt
, next
++);
283 if (!strncmp(block_beg
, line
, strlen(block_beg
)))
285 if (!strncmp(block_end
, line
, strlen(block_end
)))
288 fmt
->ops
->block_beg(fmt
->doc
, fmt_line(fmt
, beg
));
290 raw_lines(fmt
, beg
+ 1, next
- 1);
291 fmt
->ops
->block_end(fmt
->doc
, fmt_line(fmt
, next
- 1));
295 static int fmt_list(struct fmt
*fmt
, int beg
, int end
)
298 char *first
= fmt_line(fmt
, i
);
300 if (!islist(first
, NULL
))
302 fmt
->ops
->list_beg(fmt
->doc
);
303 while ((line
= fmt_line(fmt
, i
)) && islist(first
, line
)) {
304 int next
= min(end
, fmt_deindent(fmt
, i
+ 1, 2));
306 fmt
->ops
->item_beg(fmt
->doc
);
309 i
= par_end(fmt
, i
, next
);
310 put_lines(fmt
, head
, i
);
313 fmt_handle(fmt
, i
, next
, 2);
315 fmt
->ops
->item_end(fmt
->doc
);
319 fmt
->ops
->list_end(fmt
->doc
);
323 static int fmt_table(struct fmt
*fmt
, int beg
, int end
)
325 char *hdr
= fmt_line(fmt
, beg
);
327 int row
= 0, col
= 0;
328 if (hdr
[0] != '.' || hdr
[1] != 'T' || hdr
[2] != '1')
330 fmt
->ops
->table_beg(fmt
->doc
, 0);
331 for (i
= beg
+ 1; i
< end
; i
++) {
332 char *cur
= fmt_line(fmt
, i
);
333 if (cur
[0] == '.' && cur
[1] == 'T' && cur
[2] == '2')
336 raw_line(fmt
, cur
+ 2);
340 if (strchr("_=\n", cur
[0])) {
342 fmt
->ops
->entry_end(fmt
->doc
);
344 fmt
->ops
->row_end(fmt
->doc
);
345 if (cur
[0] != '\n') {
352 if (strchr("#*-+", cur
[0])) {
354 fmt
->ops
->row_beg(fmt
->doc
);
357 fmt
->ops
->entry_end(fmt
->doc
);
359 fmt
->ops
->entry_beg(fmt
->doc
);
367 fmt
->ops
->entry_end(fmt
->doc
);
369 fmt
->ops
->row_end(fmt
->doc
);
370 fmt
->ops
->table_end(fmt
->doc
);
374 static int (*parts
[])(struct fmt
*fmt
, int beg
, int end
) =
375 {fmt_head
, fmt_list
, fmt_table
, fmt_block
, fmt_rawline
, fmt_par
};
377 static void fmt_handle(struct fmt
*fmt
, int beg
, int end
, int level
)
384 if (!*fmt_line(fmt
, line
)) {
385 put_line(fmt
, line
++);
388 for (i
= 0; i
< LENGTH(parts
); i
++)
389 if ((c
= parts
[i
](fmt
, line
, end
)))
393 put_line(fmt
, line
++);
398 void format(struct doc
*doc
, struct txt
*txt
, struct fmt_ops
*ops
)
400 struct fmt
*fmt
= fmt_alloc(doc
, txt
, ops
);
401 fmt
->ops
->doc_beg(doc
);
402 fmt_handle(fmt
, 0, txt
->n
, 0);
403 fmt
->ops
->doc_end(doc
);