]>
git.cameronkatri.com Git - mandoc.git/blob - roff.c
1 /* $Id: roff.c,v 1.33 2008/12/02 13:20:24 kristaps Exp $ */
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/param.h>
20 #include <sys/types.h>
31 #include "libmdocml.h"
34 /* FIXME: First letters of quoted-text interpreted in rofffindtok. */
35 /* FIXME: `No' not implemented. */
36 /* TODO: warn if Pp occurs before/after Sh etc. (see mdoc.samples). */
37 /* TODO: warn about "X section only" macros. */
38 /* TODO: warn about empty lists. */
39 /* TODO: (warn) some sections need specific elements. */
40 /* TODO: (warn) NAME section has particular order. */
41 /* TODO: unify empty-content tags a la <br />. */
42 /* TODO: macros with a set number of arguments? */
44 #define ROFF_MAXARG 32
58 #define ROFFCALL_ARGS \
59 int tok, struct rofftree *tree, \
60 char *argv[], enum roffd type
65 int (*cb
)(ROFFCALL_ARGS
); /* Callback. */
66 const int *args
; /* Args (or NULL). */
67 const int *parents
; /* Limit to parents. */
68 const int *children
; /* Limit to kids. */
69 int ctx
; /* Blk-close node. */
70 enum rofftype type
; /* Type of macro. */
72 #define ROFF_PARSED (1 << 0) /* "Parsed". */
73 #define ROFF_CALLABLE (1 << 1) /* "Callable". */
74 #define ROFF_SHALLOW (1 << 2) /* Nesting block. */
75 #define ROFF_LSCOPE (1 << 3) /* Line scope. */
80 #define ROFF_VALUE (1 << 0) /* Has a value. */
84 int tok
; /* Token id. */
85 struct roffnode
*parent
; /* Parent (or NULL). */
89 struct roffnode
*last
; /* Last parsed node. */
90 char *cur
; /* Line start. */
91 struct tm tm
; /* `Dd' results. */
92 char os
[64]; /* `Os' results. */
93 char title
[64]; /* `Dt' results. */
94 char section
[64]; /* `Dt' results. */
95 char volume
[64]; /* `Dt' results. */
97 #define ROFF_PRELUDE (1 << 1) /* In roff prelude. */
98 #define ROFF_PRELUDE_Os (1 << 2) /* `Os' is parsed. */
99 #define ROFF_PRELUDE_Dt (1 << 3) /* `Dt' is parsed. */
100 #define ROFF_PRELUDE_Dd (1 << 4) /* `Dd' is parsed. */
101 #define ROFF_BODY (1 << 5) /* In roff body. */
102 struct roffcb cb
; /* Callbacks. */
103 void *arg
; /* Callbacks' arg. */
106 static int roff_Dd(ROFFCALL_ARGS
);
107 static int roff_Dt(ROFFCALL_ARGS
);
108 static int roff_Os(ROFFCALL_ARGS
);
109 static int roff_Ns(ROFFCALL_ARGS
);
110 static int roff_Sm(ROFFCALL_ARGS
);
111 static int roff_layout(ROFFCALL_ARGS
);
112 static int roff_text(ROFFCALL_ARGS
);
113 static int roff_noop(ROFFCALL_ARGS
);
114 static int roff_depr(ROFFCALL_ARGS
);
115 static struct roffnode
*roffnode_new(int, struct rofftree
*);
116 static void roffnode_free(struct rofftree
*);
117 static void roff_warn(const struct rofftree
*,
118 const char *, char *, ...);
119 static void roff_err(const struct rofftree
*,
120 const char *, char *, ...);
121 static int roffpurgepunct(struct rofftree
*, char **);
122 static int roffscan(int, const int *);
123 static int rofffindtok(const char *);
124 static int rofffindarg(const char *);
125 static int rofffindcallable(const char *);
126 static int roffargs(const struct rofftree
*,
127 int, char *, char **);
128 static int roffargok(int, int);
129 static int roffnextopt(const struct rofftree
*,
130 int, char ***, char **);
131 static int roffparseopts(struct rofftree
*, int,
132 char ***, int *, char **);
133 static int roffcall(struct rofftree
*, int, char **);
134 static int roffparse(struct rofftree
*, char *);
135 static int textparse(const struct rofftree
*, char *);
138 static size_t strlcat(char *, const char *, size_t);
139 static size_t strlcpy(char *, const char *, size_t);
140 extern int vsnprintf(char *, size_t,
141 const char *, va_list);
142 extern char *strptime(const char *, const char *,
147 static const int roffarg_An
[] = { ROFF_Split
, ROFF_Nosplit
, ROFF_ARGMAX
};
148 static const int roffarg_Bd
[] = { ROFF_Ragged
, ROFF_Unfilled
, ROFF_Literal
,
149 ROFF_File
, ROFF_Offset
, ROFF_Filled
, ROFF_Compact
, ROFF_ARGMAX
};
150 static const int roffarg_Bk
[] = { ROFF_Words
, ROFF_ARGMAX
};
151 static const int roffarg_Ex
[] = { ROFF_Std
, ROFF_ARGMAX
};
152 static const int roffarg_Rv
[] = { ROFF_Std
, ROFF_ARGMAX
};
153 static const int roffarg_Bl
[] = { ROFF_Bullet
, ROFF_Dash
, ROFF_Hyphen
,
154 ROFF_Item
, ROFF_Enum
, ROFF_Tag
, ROFF_Diag
, ROFF_Hang
, ROFF_Ohang
,
155 ROFF_Inset
, ROFF_Column
, ROFF_Offset
, ROFF_Width
, ROFF_Compact
,
157 static const int roffarg_St
[] = { ROFF_p1003_1_88
, ROFF_p1003_1_90
,
158 ROFF_p1003_1_96
, ROFF_p1003_1_2001
, ROFF_p1003_1_2004
, ROFF_p1003_1
,
159 ROFF_p1003_1b
, ROFF_p1003_1b_93
, ROFF_p1003_1c_95
, ROFF_p1003_1g_2000
,
160 ROFF_p1003_2_92
, ROFF_p1387_2_95
, ROFF_p1003_2
, ROFF_p1387_2
,
161 ROFF_isoC_90
, ROFF_isoC_amd1
, ROFF_isoC_tcor1
, ROFF_isoC_tcor2
,
162 ROFF_isoC_99
, ROFF_ansiC
, ROFF_ansiC_89
, ROFF_ansiC_99
, ROFF_ieee754
,
163 ROFF_iso8802_3
, ROFF_xpg3
, ROFF_xpg4
, ROFF_xpg4_2
, ROFF_xpg4_3
,
164 ROFF_xbd5
, ROFF_xcu5
, ROFF_xsh5
, ROFF_xns5
, ROFF_xns5_2d2_0
,
165 ROFF_xcurses4_2
, ROFF_susv2
, ROFF_susv3
, ROFF_svid4
, ROFF_ARGMAX
};
167 static const int roffchild_Bl
[] = { ROFF_It
, ROFF_El
, ROFF_MAX
};
168 static const int roffchild_Fo
[] = { ROFF_Fa
, ROFF_Fc
, ROFF_MAX
};
169 static const int roffchild_Rs
[] = { ROFF_Re
, ROFF__A
, ROFF__B
, ROFF__D
,
170 ROFF__I
, ROFF__J
, ROFF__N
, ROFF__O
, ROFF__P
, ROFF__R
, ROFF__T
, ROFF__V
,
173 static const int roffparent_El
[] = { ROFF_Bl
, ROFF_It
, ROFF_MAX
};
174 static const int roffparent_Fc
[] = { ROFF_Fo
, ROFF_Fa
, ROFF_MAX
};
175 static const int roffparent_Oc
[] = { ROFF_Oo
, ROFF_MAX
};
176 static const int roffparent_It
[] = { ROFF_Bl
, ROFF_It
, ROFF_MAX
};
177 static const int roffparent_Re
[] = { ROFF_Rs
, ROFF_MAX
};
179 static const struct rofftok tokens
[ROFF_MAX
] = {
180 { roff_noop
, NULL
, NULL
, NULL
, 0, ROFF_COMMENT
, 0 }, /* \" */
181 { roff_Dd
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Dd */
182 { roff_Dt
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Dt */
183 { roff_Os
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Os */
184 { roff_layout
, NULL
, NULL
, NULL
, ROFF_Sh
, ROFF_LAYOUT
, 0 }, /* Sh */
185 { roff_layout
, NULL
, NULL
, NULL
, ROFF_Ss
, ROFF_LAYOUT
, 0 }, /* Ss */
186 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Pp */ /* XXX 0 args */
187 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_LSCOPE
}, /* D1 */
188 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_LSCOPE
}, /* Dl */
189 { roff_layout
, roffarg_Bd
, NULL
, NULL
, 0, ROFF_LAYOUT
, 0 }, /* Bd */
190 { roff_noop
, NULL
, NULL
, NULL
, ROFF_Bd
, ROFF_LAYOUT
, 0 }, /* Ed */
191 { roff_layout
, roffarg_Bl
, NULL
, roffchild_Bl
, 0, ROFF_LAYOUT
, 0 }, /* Bl */
192 { roff_noop
, NULL
, roffparent_El
, NULL
, ROFF_Bl
, ROFF_LAYOUT
, 0 }, /* El */
193 { roff_layout
, NULL
, roffparent_It
, NULL
, ROFF_It
, ROFF_LAYOUT
, ROFF_PARSED
| ROFF_SHALLOW
}, /* It */
194 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Ad */ /* FIXME */
195 { roff_text
, roffarg_An
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* An */
196 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Ar */
197 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Cd */ /* XXX man.4 only */
198 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Cm */
199 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Dv */ /* XXX needs arg */
200 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Er */ /* XXX needs arg */
201 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Ev */ /* XXX needs arg */
202 { roff_text
, roffarg_Ex
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Ex */
203 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Fa */ /* XXX needs arg */
204 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Fd */
205 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Fl */
206 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Fn */ /* XXX needs arg */ /* FIXME */
207 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* Ft */
208 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Ic */ /* XXX needs arg */
209 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* In */
210 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Li */
211 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Nd */
212 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Nm */ /* FIXME */
213 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
| ROFF_LSCOPE
}, /* Op */
214 { roff_depr
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Ot */
215 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Pa */
216 { roff_text
, roffarg_Rv
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Rv */
217 { roff_text
, roffarg_St
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* St */
218 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Va */
219 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Vt */ /* XXX needs arg */
220 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Xr */ /* XXX needs arg */
221 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* %A */
222 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* %B */
223 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* %D */
224 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* %I */
225 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* %J */
226 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* %N */
227 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* %O */
228 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* %P */
229 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* %R */
230 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* %T */
231 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* %V */
232 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Ac */
233 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Ao */
234 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
| ROFF_LSCOPE
}, /* Aq */
235 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* At */ /* XXX at most 2 args */
236 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Bc */
237 { roff_layout
, NULL
, NULL
, NULL
, 0, ROFF_LAYOUT
, 0 }, /* Bf */ /* FIXME */
238 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Bo */
239 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
| ROFF_LSCOPE
}, /* Bq */
240 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* Bsx */
241 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* Bx */
242 { NULL
, NULL
, NULL
, NULL
, 0, ROFF_SPECIAL
, 0 }, /* Db */
243 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Dc */
244 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Do */
245 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
| ROFF_LSCOPE
}, /* Dq */
246 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Ec */
247 { roff_noop
, NULL
, NULL
, NULL
, ROFF_Bf
, ROFF_LAYOUT
, 0 }, /* Ef */
248 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Em */ /* XXX needs arg */
249 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Eo */
250 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* Fx */
251 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* Ms */
252 { NULL
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* No */
253 { roff_Ns
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Ns */
254 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* Nx */
255 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* Ox */
256 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Pc */
257 { NULL
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* Pf */
258 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Po */
259 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
| ROFF_LSCOPE
}, /* Pq */
260 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Qc */
261 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Ql */
262 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Qo */
263 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
| ROFF_LSCOPE
}, /* Qq */
264 { roff_noop
, NULL
, roffparent_Re
, NULL
, ROFF_Rs
, ROFF_LAYOUT
, 0 }, /* Re */
265 { roff_layout
, NULL
, NULL
, roffchild_Rs
, 0, ROFF_LAYOUT
, 0 }, /* Rs */
266 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Sc */
267 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* So */
268 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
| ROFF_LSCOPE
}, /* Sq */
269 { roff_Sm
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Sm */
270 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Sx */
271 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Sy */
272 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Tn */
273 { roff_text
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
}, /* Ux */
274 { NULL
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Xc */
275 { NULL
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
}, /* Xo */
276 { roff_layout
, NULL
, NULL
, roffchild_Fo
, 0, ROFF_LAYOUT
, 0 }, /* Fo */
277 { roff_noop
, NULL
, roffparent_Fc
, NULL
, ROFF_Fo
, ROFF_LAYOUT
, 0 }, /* Fc */
278 { roff_layout
, NULL
, NULL
, NULL
, 0, ROFF_LAYOUT
, 0 }, /* Oo */
279 { roff_noop
, NULL
, roffparent_Oc
, NULL
, ROFF_Oo
, ROFF_LAYOUT
, 0 }, /* Oc */
280 { roff_layout
, roffarg_Bk
, NULL
, NULL
, 0, ROFF_LAYOUT
, 0 }, /* Bk */
281 { roff_noop
, NULL
, NULL
, NULL
, ROFF_Bk
, ROFF_LAYOUT
, 0 }, /* Ek */
282 { NULL
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Bt */
283 { NULL
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Hf */
284 { roff_depr
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Fr */
285 { NULL
, NULL
, NULL
, NULL
, 0, ROFF_TEXT
, 0 }, /* Ud */
288 static const int tokenargs
[ROFF_ARGMAX
] = {
290 0, ROFF_VALUE
, ROFF_VALUE
, 0,
306 const char *const toknamesp
[ROFF_MAX
] = {
307 "\\\"", "Dd", "Dt", "Os",
308 "Sh", "Ss", "Pp", "D1",
309 "Dl", "Bd", "Ed", "Bl",
310 "El", "It", "Ad", "An",
311 "Ar", "Cd", "Cm", "Dv",
312 "Er", "Ev", "Ex", "Fa",
313 "Fd", "Fl", "Fn", "Ft",
314 "Ic", "In", "Li", "Nd",
315 "Nm", "Op", "Ot", "Pa",
316 "Rv", "St", "Va", "Vt",
318 "Xr", "\%A", "\%B", "\%D",
320 "\%I", "\%J", "\%N", "\%O",
322 "\%P", "\%R", "\%T", "\%V",
323 "Ac", "Ao", "Aq", "At",
324 "Bc", "Bf", "Bo", "Bq",
325 "Bsx", "Bx", "Db", "Dc",
326 "Do", "Dq", "Ec", "Ef",
327 "Em", "Eo", "Fx", "Ms",
328 "No", "Ns", "Nx", "Ox",
329 "Pc", "Pf", "Po", "Pq",
330 "Qc", "Ql", "Qo", "Qq",
331 "Re", "Rs", "Sc", "So",
332 "Sq", "Sm", "Sx", "Sy",
333 "Tn", "Ux", "Xc", "Xo",
334 "Fo", "Fc", "Oo", "Oc",
335 "Bk", "Ek", "Bt", "Hf",
339 const char *const tokargnamesp
[ROFF_ARGMAX
] = {
340 "split", "nosplit", "ragged",
341 "unfilled", "literal", "file",
342 "offset", "bullet", "dash",
343 "hyphen", "item", "enum",
344 "tag", "diag", "hang",
345 "ohang", "inset", "column",
346 "width", "compact", "std",
347 "p1003.1-88", "p1003.1-90", "p1003.1-96",
348 "p1003.1-2001", "p1003.1-2004", "p1003.1",
349 "p1003.1b", "p1003.1b-93", "p1003.1c-95",
350 "p1003.1g-2000", "p1003.2-92", "p1387.2-95",
351 "p1003.2", "p1387.2", "isoC-90",
352 "isoC-amd1", "isoC-tcor1", "isoC-tcor2",
353 "isoC-99", "ansiC", "ansiC-89",
354 "ansiC-99", "ieee754", "iso8802-3",
355 "xpg3", "xpg4", "xpg4.2",
356 "xpg4.3", "xbd5", "xcu5",
357 "xsh5", "xns5", "xns5.2d2.0",
358 "xcurses4.2", "susv2", "susv3",
359 "svid4", "filled", "words",
362 const char *const *toknames
= toknamesp
;
363 const char *const *tokargnames
= tokargnamesp
;
367 roff_free(struct rofftree
*tree
, int flush
)
379 if (ROFF_PRELUDE
& tree
->state
) {
380 roff_err(tree
, NULL
, "prelude never finished");
384 for (n
= tree
->last
; n
; n
= n
->parent
) {
385 if (0 != tokens
[n
->tok
].ctx
)
387 roff_err(tree
, NULL
, "closing explicit scope `%s'",
394 if ( ! (*tokens
[t
].cb
)(t
, tree
, NULL
, ROFF_EXIT
))
398 if ( ! (*tree
->cb
.rofftail
)(tree
->arg
))
410 return(error
? 0 : 1);
415 roff_alloc(const struct roffcb
*cb
, void *args
)
417 struct rofftree
*tree
;
422 if (NULL
== (tree
= calloc(1, sizeof(struct rofftree
))))
425 tree
->state
= ROFF_PRELUDE
;
428 (void)memcpy(&tree
->cb
, cb
, sizeof(struct roffcb
));
435 roff_engine(struct rofftree
*tree
, char *buf
)
442 roff_err(tree
, buf
, "blank line");
444 } else if ('.' != *buf
)
445 return(textparse(tree
, buf
));
447 return(roffparse(tree
, buf
));
452 textparse(const struct rofftree
*tree
, char *buf
)
455 if ( ! (ROFF_BODY
& tree
->state
)) {
456 roff_err(tree
, buf
, "data not in body");
459 return((*tree
->cb
.roffdata
)(tree
->arg
, 1, buf
));
464 roffargs(const struct rofftree
*tree
,
465 int tok
, char *buf
, char **argv
)
470 assert(tok
>= 0 && tok
< ROFF_MAX
);
476 for (i
= 0; *buf
&& i
< ROFF_MAXARG
; i
++) {
479 while (*buf
&& '\"' != *buf
)
482 roff_err(tree
, argv
[i
], "unclosed "
490 while (*buf
&& ! isspace(*buf
))
496 while (*buf
&& isspace(*buf
))
501 if (ROFF_MAXARG
== i
&& *buf
) {
502 roff_err(tree
, p
, "too many arguments for `%s'", toknames
513 roffscan(int tok
, const int *tokv
)
519 for ( ; ROFF_MAX
!= *tokv
; tokv
++)
528 roffparse(struct rofftree
*tree
, char *buf
)
532 char *argv
[ROFF_MAXARG
];
535 if (0 != *buf
&& 0 != *(buf
+ 1) && 0 != *(buf
+ 2))
536 if (0 == strncmp(buf
, ".\\\"", 3))
539 if (ROFF_MAX
== (tok
= rofffindtok(buf
+ 1))) {
540 roff_err(tree
, buf
+ 1, "bogus line macro");
542 } else if (NULL
== tokens
[tok
].cb
) {
543 roff_err(tree
, buf
+ 1, "unsupported macro `%s'",
548 assert(ROFF___
!= tok
);
549 if ( ! roffargs(tree
, tok
, buf
, argv
))
552 argvp
= (char **)argv
;
555 * Prelude macros break some assumptions, so branch now.
558 if (ROFF_PRELUDE
& tree
->state
) {
559 assert(NULL
== tree
->last
);
560 return((*tokens
[tok
].cb
)(tok
, tree
, argvp
, ROFF_ENTER
));
563 assert(ROFF_BODY
& tree
->state
);
566 * First check that our possible parents and parent's possible
567 * children are satisfied.
570 if (tree
->last
&& ! roffscan
571 (tree
->last
->tok
, tokens
[tok
].parents
)) {
572 roff_err(tree
, *argvp
, "`%s' has invalid parent `%s'",
574 toknames
[tree
->last
->tok
]);
578 if (tree
->last
&& ! roffscan
579 (tok
, tokens
[tree
->last
->tok
].children
)) {
580 roff_err(tree
, *argvp
, "`%s' is invalid child of `%s'",
582 toknames
[tree
->last
->tok
]);
587 * Branch if we're not a layout token.
590 if (ROFF_LAYOUT
!= tokens
[tok
].type
)
591 return((*tokens
[tok
].cb
)(tok
, tree
, argvp
, ROFF_ENTER
));
592 if (0 == tokens
[tok
].ctx
)
593 return((*tokens
[tok
].cb
)(tok
, tree
, argvp
, ROFF_ENTER
));
596 * First consider implicit-end tags, like as follows:
599 * In this, we want to close the scope of the NAME section. If
600 * there's an intermediary implicit-end tag, such as
604 * then it must be closed as well.
607 if (tok
== tokens
[tok
].ctx
) {
609 * First search up to the point where we must close.
610 * If one doesn't exist, then we can open a new scope.
613 for (n
= tree
->last
; n
; n
= n
->parent
) {
614 assert(0 == tokens
[n
->tok
].ctx
||
615 n
->tok
== tokens
[n
->tok
].ctx
);
618 if (ROFF_SHALLOW
& tokens
[tok
].flags
) {
622 if (tokens
[n
->tok
].ctx
== n
->tok
)
624 roff_err(tree
, *argv
, "`%s' breaks `%s' scope",
625 toknames
[tok
], toknames
[n
->tok
]);
630 * Create a new scope, as no previous one exists to
635 return((*tokens
[tok
].cb
)(tok
, tree
, argvp
, ROFF_ENTER
));
638 * Close out all intermediary scoped blocks, then hang
639 * the current scope from our predecessor's parent.
644 if ( ! (*tokens
[t
].cb
)(t
, tree
, NULL
, ROFF_EXIT
))
648 return((*tokens
[tok
].cb
)(tok
, tree
, argvp
, ROFF_ENTER
));
652 * Now consider explicit-end tags, where we want to close back
653 * to a specific tag. Example:
657 * In this, the `El' tag closes out the scope of `Bl'.
660 assert(tok
!= tokens
[tok
].ctx
&& 0 != tokens
[tok
].ctx
);
663 for (n
= tree
->last
; n
; n
= n
->parent
)
664 if (n
->tok
!= tokens
[tok
].ctx
) {
665 if (n
->tok
== tokens
[n
->tok
].ctx
)
667 roff_err(tree
, *argv
, "`%s' breaks `%s' scope",
668 toknames
[tok
], toknames
[n
->tok
]);
675 roff_err(tree
, *argv
, "`%s' has no starting tag `%s'",
677 toknames
[tokens
[tok
].ctx
]);
684 if ( ! (*tokens
[t
].cb
)(t
, tree
, NULL
, ROFF_EXIT
))
686 } while (t
!= tokens
[tok
].ctx
);
693 rofffindarg(const char *name
)
697 /* FIXME: use a table, this is slow but ok for now. */
700 for (i
= 0; i
< ROFF_ARGMAX
; i
++)
702 if (0 == strcmp(name
, tokargnames
[i
]))
710 rofffindtok(const char *buf
)
715 for (i
= 0; *buf
&& ! isspace(*buf
) && i
< 3; i
++, buf
++)
723 /* FIXME: use a table, this is slow but ok for now. */
726 for (i
= 0; i
< ROFF_MAX
; i
++)
728 if (0 == strcmp(toknames
[i
], token
))
736 roffispunct(const char *p
)
778 rofffindcallable(const char *name
)
782 if (ROFF_MAX
== (c
= rofffindtok(name
)))
784 assert(c
>= 0 && c
< ROFF_MAX
);
785 return(ROFF_CALLABLE
& tokens
[c
].flags
? c
: ROFF_MAX
);
789 static struct roffnode
*
790 roffnode_new(int tokid
, struct rofftree
*tree
)
794 if (NULL
== (p
= malloc(sizeof(struct roffnode
))))
798 p
->parent
= tree
->last
;
806 roffargok(int tokid
, int argid
)
810 if (NULL
== (c
= tokens
[tokid
].args
))
813 for ( ; ROFF_ARGMAX
!= *c
; c
++)
822 roffnode_free(struct rofftree
*tree
)
829 tree
->last
= tree
->last
->parent
;
835 roffcall(struct rofftree
*tree
, int tok
, char **argv
)
838 if (NULL
== tokens
[tok
].cb
) {
839 roff_err(tree
, *argv
, "unsupported macro `%s'",
843 if ( ! (*tokens
[tok
].cb
)(tok
, tree
, argv
, ROFF_ENTER
))
850 roffnextopt(const struct rofftree
*tree
, int tok
,
851 char ***in
, char **val
)
860 if (NULL
== (arg
= *argv
))
865 if (ROFF_ARGMAX
== (v
= rofffindarg(arg
+ 1))) {
866 roff_warn(tree
, arg
, "argument-like parameter `%s' to "
867 "`%s'", arg
, toknames
[tok
]);
871 if ( ! roffargok(tok
, v
)) {
872 roff_warn(tree
, arg
, "invalid argument parameter `%s' to "
873 "`%s'", tokargnames
[v
], toknames
[tok
]);
877 if ( ! (ROFF_VALUE
& tokenargs
[v
]))
883 roff_err(tree
, arg
, "empty value of `%s' for `%s'",
884 tokargnames
[v
], toknames
[tok
]);
893 roffpurgepunct(struct rofftree
*tree
, char **argv
)
901 if ( ! roffispunct(argv
[--i
]))
903 while (i
>= 0 && roffispunct(argv
[i
]))
909 if ( ! (*tree
->cb
.roffdata
)(tree
->arg
, 0, argv
[i
++]))
916 roffparseopts(struct rofftree
*tree
, int tok
,
917 char ***args
, int *argc
, char **argv
)
924 while (-1 != (c
= roffnextopt(tree
, tok
, args
, &v
))) {
925 if (ROFF_ARGMAX
== c
)
934 argc
[i
] = ROFF_ARGMAX
;
942 roff_Dd(ROFFCALL_ARGS
)
947 if (ROFF_BODY
& tree
->state
) {
948 assert( ! (ROFF_PRELUDE
& tree
->state
));
949 assert(ROFF_PRELUDE_Dd
& tree
->state
);
950 return(roff_text(tok
, tree
, argv
, type
));
953 assert(ROFF_PRELUDE
& tree
->state
);
954 assert( ! (ROFF_BODY
& tree
->state
));
956 if (ROFF_PRELUDE_Dd
& tree
->state
) {
957 roff_err(tree
, *argv
, "repeated `Dd' in prelude");
959 } else if (ROFF_PRELUDE_Dt
& tree
->state
) {
960 roff_err(tree
, *argv
, "out-of-order `Dd' in prelude");
964 assert(NULL
== tree
->last
);
968 if (0 == strcmp(*argv
, "$Mdocdate: December 2 2008 $")) {
970 if (NULL
== localtime_r(&t
, &tree
->tm
))
971 err(1, "localtime_r");
972 tree
->state
|= ROFF_PRELUDE_Dd
;
976 /* Build this from Mdocdate or raw date. */
981 if (0 != strcmp(*argv
, "$Mdocdate:")) {
983 if (strlcat(buf
, *argv
++, sizeof(buf
))
986 roff_err(tree
, p
, "bad `Dd' date");
989 if (strptime(buf
, "%b%d,%Y", &tree
->tm
)) {
990 tree
->state
|= ROFF_PRELUDE_Dd
;
993 roff_err(tree
, *argv
, "bad `Dd' date");
998 while (*argv
&& **argv
!= '$') {
999 if (strlcat(buf
, *argv
++, sizeof(buf
))
1001 roff_err(tree
, p
, "bad `Dd' Mdocdate");
1004 if (strlcat(buf
, " ", sizeof(buf
))
1006 roff_err(tree
, p
, "bad `Dd' Mdocdate");
1010 if (NULL
== *argv
) {
1011 roff_err(tree
, p
, "bad `Dd' Mdocdate");
1015 if (NULL
== strptime(buf
, "%b %d %Y", &tree
->tm
)) {
1016 roff_err(tree
, *argv
, "bad `Dd' Mdocdate");
1020 tree
->state
|= ROFF_PRELUDE_Dd
;
1027 roff_Dt(ROFFCALL_ARGS
)
1030 if (ROFF_BODY
& tree
->state
) {
1031 assert( ! (ROFF_PRELUDE
& tree
->state
));
1032 assert(ROFF_PRELUDE_Dt
& tree
->state
);
1033 return(roff_text(tok
, tree
, argv
, type
));
1036 assert(ROFF_PRELUDE
& tree
->state
);
1037 assert( ! (ROFF_BODY
& tree
->state
));
1039 if ( ! (ROFF_PRELUDE_Dd
& tree
->state
)) {
1040 roff_err(tree
, *argv
, "out-of-order `Dt' in prelude");
1042 } else if (ROFF_PRELUDE_Dt
& tree
->state
) {
1043 roff_err(tree
, *argv
, "repeated `Dt' in prelude");
1048 if (NULL
== *argv
) {
1049 roff_err(tree
, *argv
, "`Dt' needs document title");
1051 } else if (strlcpy(tree
->title
, *argv
, sizeof(tree
->title
))
1052 >= sizeof(tree
->title
)) {
1053 roff_err(tree
, *argv
, "`Dt' document title too long");
1058 if (NULL
== *argv
) {
1059 roff_err(tree
, *argv
, "`Dt' needs section");
1061 } else if (strlcpy(tree
->section
, *argv
, sizeof(tree
->section
))
1062 >= sizeof(tree
->section
)) {
1063 roff_err(tree
, *argv
, "`Dt' section too long");
1068 if (NULL
== *argv
) {
1069 tree
->volume
[0] = 0;
1070 } else if (strlcpy(tree
->volume
, *argv
, sizeof(tree
->volume
))
1071 >= sizeof(tree
->volume
)) {
1072 roff_err(tree
, *argv
, "`Dt' volume too long");
1076 assert(NULL
== tree
->last
);
1077 tree
->state
|= ROFF_PRELUDE_Dt
;
1085 roff_Sm(ROFFCALL_ARGS
)
1088 char *argvp
[1], *morep
[1], *p
;
1092 argcp
[0] = ROFF_ARGMAX
;
1094 if (NULL
== (morep
[0] = *argv
++)) {
1095 roff_err(tree
, p
, "`Sm' expects an argument");
1097 } else if (0 != strcmp(morep
[0], "on") &&
1098 0 != strcmp(morep
[0], "off")) {
1099 roff_err(tree
, p
, "`Sm' has invalid argument");
1104 roff_warn(tree
, *argv
, "`Sm' shouldn't have arguments");
1106 if ( ! (*tree
->cb
.roffspecial
)(tree
->arg
,
1107 tok
, argcp
, argvp
, morep
))
1111 if ((*tree
->cb
.roffdata
)(tree
->arg
, 1, *argv
++))
1122 roff_Ns(ROFFCALL_ARGS
)
1126 char *argvp
[1], *morep
[1];
1128 first
= (*argv
++ == tree
->cur
);
1130 argcp
[0] = ROFF_ARGMAX
;
1131 argvp
[0] = morep
[0] = NULL
;
1133 if ( ! (*tree
->cb
.roffspecial
)(tree
->arg
,
1134 tok
, argcp
, argvp
, morep
))
1138 if (ROFF_MAX
!= (c
= rofffindcallable(*argv
))) {
1139 if ( ! roffcall(tree
, c
, argv
))
1144 if ( ! roffispunct(*argv
)) {
1145 if ((*tree
->cb
.roffdata
)(tree
->arg
, 1, *argv
++))
1149 for (j
= 0; argv
[j
]; j
++)
1150 if ( ! roffispunct(argv
[j
]))
1154 if ((*tree
->cb
.roffdata
)(tree
->arg
, 0, *argv
++))
1165 return(roffpurgepunct(tree
, argv
));
1171 roff_Os(ROFFCALL_ARGS
)
1175 if (ROFF_BODY
& tree
->state
) {
1176 assert( ! (ROFF_PRELUDE
& tree
->state
));
1177 assert(ROFF_PRELUDE_Os
& tree
->state
);
1178 return(roff_text(tok
, tree
, argv
, type
));
1181 assert(ROFF_PRELUDE
& tree
->state
);
1182 if ( ! (ROFF_PRELUDE_Dt
& tree
->state
) ||
1183 ! (ROFF_PRELUDE_Dd
& tree
->state
)) {
1184 roff_err(tree
, *argv
, "out-of-order `Os' in prelude");
1193 if (strlcat(tree
->os
, *argv
++, sizeof(tree
->os
))
1196 roff_err(tree
, p
, "`Os' value too long");
1200 if (0 == tree
->os
[0])
1201 if (strlcpy(tree
->os
, "LOCAL", sizeof(tree
->os
))
1202 >= sizeof(tree
->os
)) {
1203 roff_err(tree
, p
, "`Os' value too long");
1207 tree
->state
|= ROFF_PRELUDE_Os
;
1208 tree
->state
&= ~ROFF_PRELUDE
;
1209 tree
->state
|= ROFF_BODY
;
1211 assert(NULL
== tree
->last
);
1213 return((*tree
->cb
.roffhead
)(tree
->arg
));
1219 roff_layout(ROFFCALL_ARGS
)
1221 int i
, c
, argcp
[ROFF_MAXARG
];
1222 char *argvp
[ROFF_MAXARG
];
1224 if (ROFF_PRELUDE
& tree
->state
) {
1225 roff_err(tree
, *argv
, "bad `%s' in prelude",
1228 } else if (ROFF_EXIT
== type
) {
1229 roffnode_free(tree
);
1230 return((*tree
->cb
.roffblkout
)(tree
->arg
, tok
));
1233 assert( ! (ROFF_CALLABLE
& tokens
[tok
].flags
));
1237 if ( ! roffparseopts(tree
, tok
, &argv
, argcp
, argvp
))
1239 if (NULL
== roffnode_new(tok
, tree
))
1243 * Layouts have two parts: the layout body and header. The
1244 * layout header is the trailing text of the line macro, while
1245 * the layout body is everything following until termination.
1248 if ( ! (*tree
->cb
.roffblkin
)(tree
->arg
, tok
, argcp
, argvp
))
1252 if ( ! (*tree
->cb
.roffin
)(tree
->arg
, tok
, argcp
, argvp
))
1256 * If there are no parsable parts, then write remaining tokens
1257 * into the layout header and exit.
1260 if ( ! (ROFF_PARSED
& tokens
[tok
].flags
)) {
1263 if ( ! (*tree
->cb
.roffdata
)(tree
->arg
, i
, *argv
++))
1267 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1271 * Parsable elements may be in the header (or be the header, for
1272 * that matter). Follow the regular parsing rules for these.
1277 if (ROFF_MAX
== (c
= rofffindcallable(*argv
))) {
1279 if ( ! (*tree
->cb
.roffdata
)
1280 (tree
->arg
, i
, *argv
++))
1285 if ( ! roffcall(tree
, c
, argv
))
1291 * If there's trailing punctuation in the header, then write it
1292 * out now. Here we mimic the behaviour of a line-dominant text
1297 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1300 * Expensive. Scan to the end of line then work backwards until
1301 * a token isn't punctuation.
1304 if ( ! roffpurgepunct(tree
, argv
))
1307 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1313 roff_text(ROFFCALL_ARGS
)
1315 int i
, j
, first
, c
, argcp
[ROFF_MAXARG
];
1316 char *argvp
[ROFF_MAXARG
];
1318 if (ROFF_PRELUDE
& tree
->state
) {
1319 roff_err(tree
, *argv
, "`%s' disallowed in prelude",
1324 first
= (*argv
== tree
->cur
);
1327 if ( ! roffparseopts(tree
, tok
, &argv
, argcp
, argvp
))
1329 if ( ! (*tree
->cb
.roffin
)(tree
->arg
, tok
, argcp
, argvp
))
1332 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1334 if ( ! (ROFF_PARSED
& tokens
[tok
].flags
)) {
1337 if ( ! (*tree
->cb
.roffdata
)(tree
->arg
, i
, *argv
++))
1341 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1345 * Deal with punctuation. Ugly. Work ahead until we encounter
1346 * terminating punctuation. If we encounter it and all
1347 * subsequent tokens are punctuation, then stop processing (the
1348 * line-dominant macro will print these tokens after closure).
1353 if (ROFF_MAX
!= (c
= rofffindcallable(*argv
))) {
1354 if ( ! (ROFF_LSCOPE
& tokens
[tok
].flags
))
1355 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1358 if ( ! roffcall(tree
, c
, argv
))
1361 if (ROFF_LSCOPE
& tokens
[tok
].flags
)
1362 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1368 if ( ! roffispunct(*argv
)) {
1369 if ( ! (*tree
->cb
.roffdata
)(tree
->arg
, i
, *argv
++))
1376 for (j
= 0; argv
[j
]; j
++)
1377 if ( ! roffispunct(argv
[j
]))
1381 if ( ! (*tree
->cb
.roffdata
)(tree
->arg
, 0, *argv
++))
1386 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1392 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1396 return(roffpurgepunct(tree
, argv
));
1402 roff_noop(ROFFCALL_ARGS
)
1411 roff_depr(ROFFCALL_ARGS
)
1414 roff_err(tree
, *argv
, "`%s' is deprecated", toknames
[tok
]);
1420 roff_warn(const struct rofftree
*tree
, const char *pos
, char *fmt
, ...)
1426 (void)vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
1429 (*tree
->cb
.roffmsg
)(tree
->arg
,
1430 ROFF_WARN
, tree
->cur
, pos
, buf
);
1435 roff_err(const struct rofftree
*tree
, const char *pos
, char *fmt
, ...)
1441 (void)vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
1444 (*tree
->cb
.roffmsg
)(tree
->arg
,
1445 ROFF_ERROR
, tree
->cur
, pos
, buf
);
1450 /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
1453 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1455 * Permission to use, copy, modify, and distribute this software for any
1456 * purpose with or without fee is hereby granted, provided that the
1457 * above copyright notice and this permission notice appear in all
1460 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
1461 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
1462 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
1463 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
1464 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
1465 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1466 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1467 * PERFORMANCE OF THIS SOFTWARE.
1470 strlcat(char *dst
, const char *src
, size_t siz
)
1473 const char *s
= src
;
1477 /* Find the end of dst and adjust bytes left but don't go past
1479 while (n
-- != 0 && *d
!= '\0')
1485 return(dlen
+ strlen(s
));
1486 while (*s
!= '\0') {
1495 return(dlen
+ (s
- src
)); /* count does not include NUL */
1500 strlcpy(char *dst
, const char *src
, size_t siz
)
1503 const char *s
= src
;
1506 /* Copy as many bytes as will fit */
1509 if ((*d
++ = *s
++) == '\0')
1514 /* Not enough room in dst, add NUL and traverse rest of src */
1517 *d
= '\0'; /* NUL-terminate dst */
1522 return(s
- src
- 1); /* count does not include NUL */
1524 #endif /*__linux__*/