8 #define LENGTH(vars) (sizeof(vars) / sizeof(vars[0]))
10 static char *markers
[] = {"**", "$$", "%%", "[]", "||", "//", "''", "``"};
14 int txt
; /* process inline markups in the block */
16 {".#1", ".#2", 1}, {".!1", ".!2"},
17 {".TS", ".TE", 1}, {".DS", ".DE", 1}, {".G1", ".G2"},
18 {".EQ", ".EN"}, {".PS", ".PE"}, {".[", ".]"}, {".de", ".."},
29 static struct fmt
*fmt_alloc(struct doc
*doc
, struct txt
*txt
,
30 struct fmt_ops
*ops
, int esc
)
32 struct fmt
*fmt
= xmalloc(sizeof(struct fmt
));
41 static void fmt_free(struct fmt
*fmt
)
46 static char *fmt_line(struct fmt
*fmt
, int line
)
48 char *s
= txt_line(fmt
->txt
, line
);
50 for (i
= 0; i
< fmt
->level
&& s
&& *s
; i
++)
55 static char *marker_char(char c
, char p
, char n
)
58 if (p
== '\\' || (p
&& isalnum(p
)) || isspace(n
))
60 for (i
= 0; i
< LENGTH(markers
); i
++)
61 if (markers
[i
][0] == c
)
66 static char *fillbuf(char *beg
, char *end
)
68 static char buf
[MAXLINE
];
69 memcpy(buf
, beg
, end
- beg
);
70 buf
[end
- beg
] = '\0';
74 static void put_text(struct fmt
*fmt
, char *s
)
80 if (s
[1] && s
[0] == fmt
->esc
) {
81 fmt
->ops
->put(fmt
->doc
, fillbuf(o
, s
));
82 fmt
->ops
->put(fmt
->doc
, fillbuf(s
+ 1, s
+ 2));
87 m
= marker_char(*s
, s
== _s
? 0 : s
[-1], s
[1]);
88 r
= m
? strchr(s
+ 1, m
[1]) : NULL
;
90 fmt
->ops
->put(fmt
->doc
, fillbuf(o
, s
));
91 fmt
->ops
->put_txt(fmt
->doc
, fillbuf(s
+ 1, r
), m
);
98 fmt
->ops
->put(fmt
->doc
, o
);
101 static void raw_line(struct fmt
*fmt
, char *s
)
103 fmt
->ops
->put(fmt
->doc
, s
);
106 static void put_line(struct fmt
*fmt
, int n
)
108 put_text(fmt
, fmt_line(fmt
, n
));
112 static void put_lines(struct fmt
*fmt
, int beg
, int end
)
115 for (i
= beg
; i
< end
; i
++)
119 static void raw_lines(struct fmt
*fmt
, int beg
, int end
)
122 for (i
= beg
; i
< end
; i
++) {
123 raw_line(fmt
, fmt_line(fmt
, i
));
128 static int indents(char *s
)
136 static int islist(char *first
, char *line
)
140 if (!first
|| strlen(first
) < 2)
142 if (first
[1] != ' ' || !strchr(signs
, first
[0]))
146 if (strlen(line
) < 2)
148 return line
[0] == first
[0] && line
[1] == first
[1];
151 static void fmt_handle(struct fmt
*fmt
, int beg
, int end
, int level
);
153 static int fmt_head(struct fmt
*fmt
, int beg
, int end
)
155 char *line
= fmt_line(fmt
, beg
);
156 char *next
= fmt_line(fmt
, beg
+ 1);
160 if (!next
|| !*line
|| beg
== end
|| fmt
->level
)
163 if (!c
|| !strchr(signs
, *next
))
168 fmt
->ops
->head_beg(fmt
->doc
, strchr(signs
, *next
) - signs
);
170 fmt
->ops
->head_end(fmt
->doc
, strchr(signs
, *next
) - signs
);
174 static int cmd_line(struct fmt
*fmt
, int i
)
176 return !fmt
->level
&& *fmt_line(fmt
, i
) == '.';
179 static int par_end(struct fmt
*fmt
, int beg
, int end
)
183 while (i
< end
&& (line
= fmt_line(fmt
, i
))) {
184 if (!*line
|| indents(line
) || islist(line
, NULL
) || cmd_line(fmt
, i
))
191 static int fmt_par(struct fmt
*fmt
, int beg
, int end
)
194 if (indents(fmt_line(fmt
, beg
)) || cmd_line(fmt
, beg
))
196 fmt
->ops
->par_beg(fmt
->doc
);
197 i
= par_end(fmt
, beg
, end
);
198 put_lines(fmt
, beg
, i
);
199 fmt
->ops
->par_end(fmt
->doc
);
203 static int fmt_rawline(struct fmt
*fmt
, int beg
, int end
)
205 if (*fmt_line(fmt
, beg
) != '.')
207 put_lines(fmt
, beg
, beg
+ 1);
211 static int min(int a
, int b
)
213 return a
< b
? a
: b
;
216 static int fmt_deindent(struct fmt
*fmt
, int n
, int indent
)
220 while ((line
= fmt_line(fmt
, n
))) {
221 if (*line
&& indents(line
) < indent
)
230 static int fmt_pre(struct fmt
*fmt
, int beg
, int end
)
232 int level
= indents(fmt_line(fmt
, beg
));
233 int next
= min(end
, fmt_deindent(fmt
, beg
+ 1, level
));
235 fmt
->ops
->block_beg(fmt
->doc
, NULL
);
236 raw_lines(fmt
, beg
, next
);
237 fmt
->ops
->block_end(fmt
->doc
, NULL
);
242 static int fmt_block(struct fmt
*fmt
, int beg
, int end
)
244 struct block
*blk
= NULL
;
249 line
= fmt_line(fmt
, beg
);
251 return fmt_pre(fmt
, beg
, end
);
252 for (i
= 0; i
< LENGTH(blocks
); i
++)
253 if (!strncmp(blocks
[i
].beg
, line
, strlen(blocks
[i
].beg
)))
258 while (next
< end
&& depth
> 0) {
259 line
= fmt_line(fmt
, next
++);
260 if (!strncmp(blk
->beg
, line
, strlen(blk
->beg
)))
262 if (!strncmp(blk
->end
, line
, strlen(blk
->end
)))
265 fmt
->ops
->block_beg(fmt
->doc
, fmt_line(fmt
, beg
));
266 if (beg
+ 1 < next
) {
268 put_lines(fmt
, beg
+ 1, next
- 1);
270 raw_lines(fmt
, beg
+ 1, next
- 1);
272 fmt
->ops
->block_end(fmt
->doc
, fmt_line(fmt
, next
- 1));
276 static char *listhead(char *s
, char *head
)
281 while (*s
&& *s
!= ':')
291 static int fmt_list(struct fmt
*fmt
, int beg
, int end
)
294 char *first
= fmt_line(fmt
, i
);
296 if (!islist(first
, NULL
))
298 fmt
->ops
->list_beg(fmt
->doc
, line
[0]);
299 while ((line
= fmt_line(fmt
, i
)) && islist(first
, line
)) {
300 int next
= min(end
, fmt_deindent(fmt
, i
+ 1, 2));
303 if (line
[0] == '+') {
304 line
= listhead(line
, lhead
);
305 fmt
->ops
->item_beg(fmt
->doc
, lhead
);
310 fmt
->ops
->item_beg(fmt
->doc
, NULL
);
314 i
= par_end(fmt
, i
, next
);
315 put_lines(fmt
, head
, i
);
318 fmt_handle(fmt
, i
, next
, 2);
320 fmt
->ops
->item_end(fmt
->doc
);
324 fmt
->ops
->list_end(fmt
->doc
);
329 static int fmt_table(struct fmt
*fmt
, int beg
, int end
)
331 char *hdr
= fmt_line(fmt
, beg
);
333 int row
= 0, col
= 0;
334 if (hdr
[0] != '.' || hdr
[1] != 'T' || hdr
[2] != '1')
336 fmt
->ops
->table_beg(fmt
->doc
, 0);
337 for (i
= beg
+ 1; i
< end
; i
++) {
338 char *cur
= fmt_line(fmt
, i
);
339 if (cur
[0] == '.' && cur
[1] == 'T' && cur
[2] == '2')
342 raw_line(fmt
, cur
+ 2);
346 if (strchr("_=\n", cur
[0])) {
348 fmt
->ops
->entry_end(fmt
->doc
);
350 fmt
->ops
->row_end(fmt
->doc
);
351 if (cur
[0] != '\n') {
358 if (strchr("#*-+", cur
[0])) {
360 fmt
->ops
->row_beg(fmt
->doc
);
363 fmt
->ops
->entry_end(fmt
->doc
);
365 fmt
->ops
->entry_beg(fmt
->doc
);
373 fmt
->ops
->entry_end(fmt
->doc
);
375 fmt
->ops
->row_end(fmt
->doc
);
376 fmt
->ops
->table_end(fmt
->doc
);
382 static int table_columns(char *line
)
385 for (n
= 0; *line
; n
++) {
386 while (*line
== '\t')
388 while (*line
&& *line
!= '\t')
394 static void table_row(struct fmt
*fmt
, char *s
)
396 if (*s
== '=' || *s
== '-')
398 fmt
->ops
->row_beg(fmt
->doc
);
401 while (*s
&& *s
!= '\t')
403 fmt
->ops
->entry_beg(fmt
->doc
);
404 put_text(fmt
, fillbuf(r
, s
));
405 fmt
->ops
->entry_end(fmt
->doc
);
409 fmt
->ops
->row_end(fmt
->doc
);
412 static int fmt_tableascii(struct fmt
*fmt
, int beg
, int end
)
416 if (*fmt_line(fmt
, beg
) != '=')
418 n
= table_columns(fmt_line(fmt
, beg
+ 1));
419 fmt
->ops
->table_beg(fmt
->doc
, n
);
420 for (i
= beg
+ 1; i
< end
; i
++) {
421 if (!fmt
->level
&& !*fmt_line(fmt
, i
))
423 table_row(fmt
, fmt_line(fmt
, i
));
425 fmt
->ops
->table_end(fmt
->doc
);
431 static int (*parts
[])(struct fmt
*fmt
, int beg
, int end
) = {
432 fmt_head
, fmt_list
, fmt_table
, fmt_tableascii
,
433 fmt_block
, fmt_rawline
436 static void fmt_handle(struct fmt
*fmt
, int beg
, int end
, int level
)
443 if (!*fmt_line(fmt
, line
)) {
444 put_line(fmt
, line
++);
447 for (i
= 0; i
< LENGTH(parts
); i
++)
448 if ((c
= parts
[i
](fmt
, line
, end
)))
450 /* start a paragraph only after a blank line */
451 if (!c
&& (line
== beg
|| !*fmt_line(fmt
, line
- 1)))
452 c
= fmt_par(fmt
, line
, end
);
455 put_line(fmt
, line
++);
460 void format(struct doc
*doc
, struct txt
*txt
, struct fmt_ops
*ops
, int esc
)
462 struct fmt
*fmt
= fmt_alloc(doc
, txt
, ops
, esc
);
463 fmt
->ops
->doc_beg(doc
);
464 fmt_handle(fmt
, 0, txt
->n
, 0);
465 fmt
->ops
->doc_end(doc
);