16 static struct doc
*doc_alloc(int fd
, struct txt
*txt
, struct fmt_ops
*ops
)
18 struct doc
*doc
= xmalloc(sizeof(struct doc
));
26 static void doc_free(struct doc
*doc
)
31 static char *doc_line(struct doc
*doc
, int line
)
33 char *s
= txt_line(doc
->txt
, line
);
35 for (i
= 0; i
< doc
->level
&& s
&& *s
; i
++)
40 static char *possible_inline(char *s
) {
41 char *signs
= "*$@%\\h";
44 if (strchr(signs
, *s
) && !isspace(*(s
+ 1)))
45 if (s
== home
|| isspace(*(s
- 1)))
52 static void fillbuf(char *buf
, int len
, char *beg
, char *end
)
54 int n
= len
- 1 < end
- beg
? len
- 1 : end
- beg
;
59 static int startswith(char *heystack
, char *needle
)
61 while (*needle
!= '\0' && *needle
== *heystack
++)
66 static char *doc_put_inline(struct doc
*doc
, char *s
)
72 r
= strchr(s
+ 1, *s
);
74 fillbuf(buf
, LENGTH(buf
), s
+ 1, r
);
75 doc
->ops
->put_emph(doc
->fd
, buf
);
80 r
= strchr(s
+ 1, *s
);
82 fillbuf(buf
, LENGTH(buf
), s
, r
+ 1);
83 doc
->ops
->put_raw(doc
->fd
, buf
);
88 r
= strchr(s
+ 1, *s
);
90 fillbuf(buf
, LENGTH(buf
), s
+ 1, r
);
91 doc
->ops
->put_raw(doc
->fd
, buf
);
96 for (r
= s
+ 1; isalnum(*r
); r
++);
98 fillbuf(buf
, LENGTH(buf
), s
+ 1, r
);
99 doc
->ops
->put_ref(doc
->fd
, buf
);
103 if (strchr("*$@%\\", *(s
+ 1))) {
104 fillbuf(buf
, LENGTH(buf
), s
+ 1, s
+ 2);
105 doc
->ops
->put(doc
->fd
, buf
);
110 if (startswith(s
, "http://") || startswith(s
, "ftp://")) {
111 char desc
[1024] = "";
112 for (r
= s
; *r
&& !isspace(*r
); r
++);
113 fillbuf(buf
, LENGTH(buf
), s
, r
);
114 if (*r
&& (*r
== '(' || *++r
== '(')) {
115 char *d
= strchr(r
, ')');
117 fillbuf(desc
, LENGTH(desc
),
122 doc
->ops
->put_url(doc
->fd
, buf
, desc
);
132 static void put_text(struct doc
*doc
, char *s
)
137 char *r
= possible_inline(s
);
140 fillbuf(buf
, LENGTH(buf
), done
, r
);
141 doc
->ops
->put(doc
->fd
, buf
);
143 if ((r
= doc_put_inline(doc
, r
)))
148 doc
->ops
->put(doc
->fd
, done
);
151 static void raw_line(struct doc
*doc
, char *s
)
153 doc
->ops
->put(doc
->fd
, s
);
156 static void put_line(struct doc
*doc
, int n
)
158 put_text(doc
, doc_line(doc
, n
));
162 static void put_lines(struct doc
*doc
, int beg
, int end
)
165 for (i
= beg
; i
< end
; i
++)
169 static void raw_lines(struct doc
*doc
, int beg
, int end
)
172 for (i
= beg
; i
< end
; i
++) {
173 raw_line(doc
, doc_line(doc
, i
));
178 static int indents(char *s
)
186 static int islist(char *first
, char *line
)
190 if (!first
|| strlen(first
) < 2)
192 if (first
[1] != ' ' || !strchr(signs
, first
[0]))
196 if (strlen(line
) < 2)
198 return line
[0] == first
[0] && line
[1] == first
[1];
201 static void doc_handle(struct doc
*doc
, int beg
, int end
, int level
);
203 static int doc_head(struct doc
*doc
, int beg
, int end
)
205 char *line
= doc_line(doc
, beg
);
206 char *next
= doc_line(doc
, beg
+ 1);
210 if (!next
|| !*line
|| beg
== end
|| doc
->level
)
213 if (!c
|| !strchr(signs
, *next
))
218 doc
->ops
->head_beg(doc
->fd
, strchr(signs
, *next
) - signs
);
220 doc
->ops
->head_end(doc
->fd
, strchr(signs
, *next
) - signs
);
224 static int par_end(struct doc
*doc
, int beg
, int end
)
228 while (i
< end
&& (line
= doc_line(doc
, i
))) {
229 if (!*line
|| indents(line
) || islist(line
, NULL
))
236 static int doc_par(struct doc
*doc
, int beg
, int end
)
239 if (indents(doc_line(doc
, beg
)))
241 doc
->ops
->par_beg(doc
->fd
);
242 i
= par_end(doc
, beg
, end
);
243 put_lines(doc
, beg
, i
);
244 doc
->ops
->par_end(doc
->fd
);
248 static int min(int a
, int b
)
250 return a
< b
? a
: b
;
253 static int doc_deindent(struct doc
*doc
, int n
, int indent
)
257 while ((line
= doc_line(doc
, n
))) {
258 if (*line
&& indents(line
) < indent
)
267 static int doc_block(struct doc
*doc
, int beg
, int end
)
269 int level
= indents(doc_line(doc
, beg
));
273 next
= min(end
, doc_deindent(doc
, beg
+ 1, level
));
274 doc_handle(doc
, beg
, next
, level
);
278 static int doc_list(struct doc
*doc
, int beg
, int end
)
281 char *first
= doc_line(doc
, i
);
283 if (!islist(first
, NULL
))
285 doc
->ops
->list_beg(doc
->fd
);
286 while ((line
= doc_line(doc
, i
)) && islist(first
, line
)) {
287 int next
= min(end
, doc_deindent(doc
, i
+ 1, 2));
289 doc
->ops
->item_beg(doc
->fd
);
292 i
= par_end(doc
, i
, next
);
293 put_lines(doc
, head
, i
);
296 doc_handle(doc
, i
, next
, 2);
298 doc
->ops
->item_end(doc
->fd
);
302 doc
->ops
->list_end(doc
->fd
);
306 static int doc_pre(struct doc
*doc
, int beg
, int end
)
310 doc
->ops
->pre_beg(doc
->fd
);
311 raw_lines(doc
, beg
, end
);
312 doc
->ops
->pre_end(doc
->fd
);
316 static int doc_formula(struct doc
*doc
, int beg
, int end
)
319 if (!doc
->level
|| *doc_line(doc
, beg
) != '$')
321 doc
->ops
->formula_beg(doc
->fd
);
322 for (i
= beg
; i
< end
; i
++) {
323 char *line
= doc_line(doc
, i
);
330 doc
->ops
->formula_end(doc
->fd
);
334 static int doc_raw(struct doc
*doc
, int beg
, int end
)
336 if (!doc
->level
|| *doc_line(doc
, beg
) != '%')
338 raw_line(doc
, doc_line(doc
, beg
) + 1);
340 raw_lines(doc
, beg
+ 1, end
);
344 static int (*parts
[])(struct doc
*doc
, int beg
, int end
) =
345 {doc_head
, doc_list
, doc_formula
, doc_raw
,
346 doc_pre
, doc_par
, doc_block
};
348 static void doc_handle(struct doc
*doc
, int beg
, int end
, int level
)
355 if (!*doc_line(doc
, line
)) {
356 put_line(doc
, line
++);
359 for (i
= 0; i
< LENGTH(parts
); i
++)
360 if ((c
= parts
[i
](doc
, line
, end
)))
364 put_line(doc
, line
++);
369 void fmt(int fd
, struct txt
*txt
, struct fmt_ops
*ops
)
371 struct doc
*doc
= doc_alloc(fd
, txt
, ops
);
372 doc
->ops
->doc_beg(fd
);
373 doc_handle(doc
, 0, txt
->n
, 0);
374 doc
->ops
->doc_end(fd
);