]> git.cameronkatri.com Git - mandoc.git/blob - roff.c
Two minor tweaks regarding the fallback from -u/-d to default mode:
[mandoc.git] / roff.c
1 /* $Id: roff.c,v 1.206 2014/04/08 01:37:27 schwarze Exp $ */
2 /*
3 * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <assert.h>
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "mandoc.h"
29 #include "mandoc_aux.h"
30 #include "libroff.h"
31 #include "libmandoc.h"
32
33 /* Maximum number of nested if-else conditionals. */
34 #define RSTACK_MAX 128
35
36 /* Maximum number of string expansions per line, to break infinite loops. */
37 #define EXPAND_LIMIT 1000
38
39 enum rofft {
40 ROFF_ad,
41 ROFF_am,
42 ROFF_ami,
43 ROFF_am1,
44 ROFF_as,
45 ROFF_cc,
46 ROFF_ce,
47 ROFF_de,
48 ROFF_dei,
49 ROFF_de1,
50 ROFF_ds,
51 ROFF_el,
52 ROFF_fam,
53 ROFF_hw,
54 ROFF_hy,
55 ROFF_ie,
56 ROFF_if,
57 ROFF_ig,
58 ROFF_it,
59 ROFF_ne,
60 ROFF_nh,
61 ROFF_nr,
62 ROFF_ns,
63 ROFF_ps,
64 ROFF_rm,
65 ROFF_rr,
66 ROFF_so,
67 ROFF_ta,
68 ROFF_tr,
69 ROFF_Dd,
70 ROFF_TH,
71 ROFF_TS,
72 ROFF_TE,
73 ROFF_T_,
74 ROFF_EQ,
75 ROFF_EN,
76 ROFF_cblock,
77 ROFF_USERDEF,
78 ROFF_MAX
79 };
80
81 /*
82 * An incredibly-simple string buffer.
83 */
84 struct roffstr {
85 char *p; /* nil-terminated buffer */
86 size_t sz; /* saved strlen(p) */
87 };
88
89 /*
90 * A key-value roffstr pair as part of a singly-linked list.
91 */
92 struct roffkv {
93 struct roffstr key;
94 struct roffstr val;
95 struct roffkv *next; /* next in list */
96 };
97
98 /*
99 * A single number register as part of a singly-linked list.
100 */
101 struct roffreg {
102 struct roffstr key;
103 int val;
104 struct roffreg *next;
105 };
106
107 struct roff {
108 struct mparse *parse; /* parse point */
109 int options; /* parse options */
110 struct roffnode *last; /* leaf of stack */
111 int rstack[RSTACK_MAX]; /* stack of !`ie' rules */
112 char control; /* control character */
113 int rstackpos; /* position in rstack */
114 struct roffreg *regtab; /* number registers */
115 struct roffkv *strtab; /* user-defined strings & macros */
116 struct roffkv *xmbtab; /* multi-byte trans table (`tr') */
117 struct roffstr *xtab; /* single-byte trans table (`tr') */
118 const char *current_string; /* value of last called user macro */
119 struct tbl_node *first_tbl; /* first table parsed */
120 struct tbl_node *last_tbl; /* last table parsed */
121 struct tbl_node *tbl; /* current table being parsed */
122 struct eqn_node *last_eqn; /* last equation parsed */
123 struct eqn_node *first_eqn; /* first equation parsed */
124 struct eqn_node *eqn; /* current equation being parsed */
125 };
126
127 struct roffnode {
128 enum rofft tok; /* type of node */
129 struct roffnode *parent; /* up one in stack */
130 int line; /* parse line */
131 int col; /* parse col */
132 char *name; /* node name, e.g. macro name */
133 char *end; /* end-rules: custom token */
134 int endspan; /* end-rules: next-line or infty */
135 int rule; /* current evaluation rule */
136 };
137
138 #define ROFF_ARGS struct roff *r, /* parse ctx */ \
139 enum rofft tok, /* tok of macro */ \
140 char **bufp, /* input buffer */ \
141 size_t *szp, /* size of input buffer */ \
142 int ln, /* parse line */ \
143 int ppos, /* original pos in buffer */ \
144 int pos, /* current pos in buffer */ \
145 int *offs /* reset offset of buffer data */
146
147 typedef enum rofferr (*roffproc)(ROFF_ARGS);
148
149 struct roffmac {
150 const char *name; /* macro name */
151 roffproc proc; /* process new macro */
152 roffproc text; /* process as child text of macro */
153 roffproc sub; /* process as child of macro */
154 int flags;
155 #define ROFFMAC_STRUCT (1 << 0) /* always interpret */
156 struct roffmac *next;
157 };
158
159 struct predef {
160 const char *name; /* predefined input name */
161 const char *str; /* replacement symbol */
162 };
163
164 #define PREDEF(__name, __str) \
165 { (__name), (__str) },
166
167 static enum rofft roffhash_find(const char *, size_t);
168 static void roffhash_init(void);
169 static void roffnode_cleanscope(struct roff *);
170 static void roffnode_pop(struct roff *);
171 static void roffnode_push(struct roff *, enum rofft,
172 const char *, int, int);
173 static enum rofferr roff_block(ROFF_ARGS);
174 static enum rofferr roff_block_text(ROFF_ARGS);
175 static enum rofferr roff_block_sub(ROFF_ARGS);
176 static enum rofferr roff_cblock(ROFF_ARGS);
177 static enum rofferr roff_cc(ROFF_ARGS);
178 static void roff_ccond(struct roff *, int, int);
179 static enum rofferr roff_cond(ROFF_ARGS);
180 static enum rofferr roff_cond_text(ROFF_ARGS);
181 static enum rofferr roff_cond_sub(ROFF_ARGS);
182 static enum rofferr roff_ds(ROFF_ARGS);
183 static int roff_evalcond(const char *, int *);
184 static int roff_evalnum(const char *, int *, int *, int);
185 static int roff_evalpar(const char *, int *, int *);
186 static int roff_evalstrcond(const char *, int *);
187 static void roff_free1(struct roff *);
188 static void roff_freereg(struct roffreg *);
189 static void roff_freestr(struct roffkv *);
190 static char *roff_getname(struct roff *, char **, int, int);
191 static int roff_getnum(const char *, int *, int *);
192 static int roff_getop(const char *, int *, char *);
193 static int roff_getregn(const struct roff *,
194 const char *, size_t);
195 static int roff_getregro(const char *name);
196 static const char *roff_getstrn(const struct roff *,
197 const char *, size_t);
198 static enum rofferr roff_it(ROFF_ARGS);
199 static enum rofferr roff_line_ignore(ROFF_ARGS);
200 static enum rofferr roff_nr(ROFF_ARGS);
201 static void roff_openeqn(struct roff *, const char *,
202 int, int, const char *);
203 static enum rofft roff_parse(struct roff *, const char *, int *);
204 static enum rofferr roff_parsetext(char **, size_t *, int, int *);
205 static enum rofferr roff_res(struct roff *,
206 char **, size_t *, int, int);
207 static enum rofferr roff_rm(ROFF_ARGS);
208 static enum rofferr roff_rr(ROFF_ARGS);
209 static void roff_setstr(struct roff *,
210 const char *, const char *, int);
211 static void roff_setstrn(struct roffkv **, const char *,
212 size_t, const char *, size_t, int);
213 static enum rofferr roff_so(ROFF_ARGS);
214 static enum rofferr roff_tr(ROFF_ARGS);
215 static enum rofferr roff_Dd(ROFF_ARGS);
216 static enum rofferr roff_TH(ROFF_ARGS);
217 static enum rofferr roff_TE(ROFF_ARGS);
218 static enum rofferr roff_TS(ROFF_ARGS);
219 static enum rofferr roff_EQ(ROFF_ARGS);
220 static enum rofferr roff_EN(ROFF_ARGS);
221 static enum rofferr roff_T_(ROFF_ARGS);
222 static enum rofferr roff_userdef(ROFF_ARGS);
223
224 /* See roffhash_find() */
225
226 #define ASCII_HI 126
227 #define ASCII_LO 33
228 #define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
229
230 static struct roffmac *hash[HASHWIDTH];
231
232 static struct roffmac roffs[ROFF_MAX] = {
233 { "ad", roff_line_ignore, NULL, NULL, 0, NULL },
234 { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
235 { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
236 { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
237 { "as", roff_ds, NULL, NULL, 0, NULL },
238 { "cc", roff_cc, NULL, NULL, 0, NULL },
239 { "ce", roff_line_ignore, NULL, NULL, 0, NULL },
240 { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
241 { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
242 { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
243 { "ds", roff_ds, NULL, NULL, 0, NULL },
244 { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
245 { "fam", roff_line_ignore, NULL, NULL, 0, NULL },
246 { "hw", roff_line_ignore, NULL, NULL, 0, NULL },
247 { "hy", roff_line_ignore, NULL, NULL, 0, NULL },
248 { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
249 { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
250 { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
251 { "it", roff_it, NULL, NULL, 0, NULL },
252 { "ne", roff_line_ignore, NULL, NULL, 0, NULL },
253 { "nh", roff_line_ignore, NULL, NULL, 0, NULL },
254 { "nr", roff_nr, NULL, NULL, 0, NULL },
255 { "ns", roff_line_ignore, NULL, NULL, 0, NULL },
256 { "ps", roff_line_ignore, NULL, NULL, 0, NULL },
257 { "rm", roff_rm, NULL, NULL, 0, NULL },
258 { "rr", roff_rr, NULL, NULL, 0, NULL },
259 { "so", roff_so, NULL, NULL, 0, NULL },
260 { "ta", roff_line_ignore, NULL, NULL, 0, NULL },
261 { "tr", roff_tr, NULL, NULL, 0, NULL },
262 { "Dd", roff_Dd, NULL, NULL, 0, NULL },
263 { "TH", roff_TH, NULL, NULL, 0, NULL },
264 { "TS", roff_TS, NULL, NULL, 0, NULL },
265 { "TE", roff_TE, NULL, NULL, 0, NULL },
266 { "T&", roff_T_, NULL, NULL, 0, NULL },
267 { "EQ", roff_EQ, NULL, NULL, 0, NULL },
268 { "EN", roff_EN, NULL, NULL, 0, NULL },
269 { ".", roff_cblock, NULL, NULL, 0, NULL },
270 { NULL, roff_userdef, NULL, NULL, 0, NULL },
271 };
272
273 /* not currently implemented: Ds em Eq LP Me PP pp Or Rd Sf SH */
274 const char *const __mdoc_reserved[] = {
275 "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
276 "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
277 "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
278 "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
279 "Dt", "Dv", "Dx", "D1",
280 "Ec", "Ed", "Ef", "Ek", "El", "Em",
281 "En", "Eo", "Er", "Es", "Ev", "Ex",
282 "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
283 "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp",
284 "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
285 "Oc", "Oo", "Op", "Os", "Ot", "Ox",
286 "Pa", "Pc", "Pf", "Po", "Pp", "Pq",
287 "Qc", "Ql", "Qo", "Qq", "Re", "Rs", "Rv",
288 "Sc", "Sh", "Sm", "So", "Sq",
289 "Ss", "St", "Sx", "Sy",
290 "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
291 "%A", "%B", "%C", "%D", "%I", "%J", "%N", "%O",
292 "%P", "%Q", "%R", "%T", "%U", "%V",
293 NULL
294 };
295
296 /* not currently implemented: BT DE DS ME MT PT SY TQ YS */
297 const char *const __man_reserved[] = {
298 "AT", "B", "BI", "BR", "DT",
299 "EE", "EN", "EQ", "EX", "HP", "I", "IB", "IP", "IR",
300 "LP", "OP", "P", "PD", "PP",
301 "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS",
302 "TE", "TH", "TP", "TS", "T&", "UC", "UE", "UR",
303 NULL
304 };
305
306 /* Array of injected predefined strings. */
307 #define PREDEFS_MAX 38
308 static const struct predef predefs[PREDEFS_MAX] = {
309 #include "predefs.in"
310 };
311
312 /* See roffhash_find() */
313 #define ROFF_HASH(p) (p[0] - ASCII_LO)
314
315 static int roffit_lines; /* number of lines to delay */
316 static char *roffit_macro; /* nil-terminated macro line */
317
318 static void
319 roffhash_init(void)
320 {
321 struct roffmac *n;
322 int buc, i;
323
324 for (i = 0; i < (int)ROFF_USERDEF; i++) {
325 assert(roffs[i].name[0] >= ASCII_LO);
326 assert(roffs[i].name[0] <= ASCII_HI);
327
328 buc = ROFF_HASH(roffs[i].name);
329
330 if (NULL != (n = hash[buc])) {
331 for ( ; n->next; n = n->next)
332 /* Do nothing. */ ;
333 n->next = &roffs[i];
334 } else
335 hash[buc] = &roffs[i];
336 }
337 }
338
339 /*
340 * Look up a roff token by its name. Returns ROFF_MAX if no macro by
341 * the nil-terminated string name could be found.
342 */
343 static enum rofft
344 roffhash_find(const char *p, size_t s)
345 {
346 int buc;
347 struct roffmac *n;
348
349 /*
350 * libroff has an extremely simple hashtable, for the time
351 * being, which simply keys on the first character, which must
352 * be printable, then walks a chain. It works well enough until
353 * optimised.
354 */
355
356 if (p[0] < ASCII_LO || p[0] > ASCII_HI)
357 return(ROFF_MAX);
358
359 buc = ROFF_HASH(p);
360
361 if (NULL == (n = hash[buc]))
362 return(ROFF_MAX);
363 for ( ; n; n = n->next)
364 if (0 == strncmp(n->name, p, s) && '\0' == n->name[(int)s])
365 return((enum rofft)(n - roffs));
366
367 return(ROFF_MAX);
368 }
369
370
371 /*
372 * Pop the current node off of the stack of roff instructions currently
373 * pending.
374 */
375 static void
376 roffnode_pop(struct roff *r)
377 {
378 struct roffnode *p;
379
380 assert(r->last);
381 p = r->last;
382
383 r->last = r->last->parent;
384 free(p->name);
385 free(p->end);
386 free(p);
387 }
388
389
390 /*
391 * Push a roff node onto the instruction stack. This must later be
392 * removed with roffnode_pop().
393 */
394 static void
395 roffnode_push(struct roff *r, enum rofft tok, const char *name,
396 int line, int col)
397 {
398 struct roffnode *p;
399
400 p = mandoc_calloc(1, sizeof(struct roffnode));
401 p->tok = tok;
402 if (name)
403 p->name = mandoc_strdup(name);
404 p->parent = r->last;
405 p->line = line;
406 p->col = col;
407 p->rule = p->parent ? p->parent->rule : 0;
408
409 r->last = p;
410 }
411
412
413 static void
414 roff_free1(struct roff *r)
415 {
416 struct tbl_node *tbl;
417 struct eqn_node *e;
418 int i;
419
420 while (NULL != (tbl = r->first_tbl)) {
421 r->first_tbl = tbl->next;
422 tbl_free(tbl);
423 }
424
425 r->first_tbl = r->last_tbl = r->tbl = NULL;
426
427 while (NULL != (e = r->first_eqn)) {
428 r->first_eqn = e->next;
429 eqn_free(e);
430 }
431
432 r->first_eqn = r->last_eqn = r->eqn = NULL;
433
434 while (r->last)
435 roffnode_pop(r);
436
437 roff_freestr(r->strtab);
438 roff_freestr(r->xmbtab);
439
440 r->strtab = r->xmbtab = NULL;
441
442 roff_freereg(r->regtab);
443
444 r->regtab = NULL;
445
446 if (r->xtab)
447 for (i = 0; i < 128; i++)
448 free(r->xtab[i].p);
449
450 free(r->xtab);
451 r->xtab = NULL;
452 }
453
454 void
455 roff_reset(struct roff *r)
456 {
457
458 roff_free1(r);
459 r->control = 0;
460 }
461
462
463 void
464 roff_free(struct roff *r)
465 {
466
467 roff_free1(r);
468 free(r);
469 }
470
471
472 struct roff *
473 roff_alloc(struct mparse *parse, int options)
474 {
475 struct roff *r;
476
477 r = mandoc_calloc(1, sizeof(struct roff));
478 r->parse = parse;
479 r->options = options;
480 r->rstackpos = -1;
481
482 roffhash_init();
483
484 return(r);
485 }
486
487 /*
488 * In the current line, expand escape sequences that tend to get
489 * used in numerical expressions and conditional requests.
490 * Also check the syntax of the remaining escape sequences.
491 */
492 static enum rofferr
493 roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
494 {
495 char ubuf[12]; /* buffer to print the number */
496 const char *start; /* start of the string to process */
497 const char *stesc; /* start of an escape sequence ('\\') */
498 const char *stnam; /* start of the name, after "[(*" */
499 const char *cp; /* end of the name, e.g. before ']' */
500 const char *res; /* the string to be substituted */
501 char *nbuf; /* new buffer to copy bufp to */
502 size_t maxl; /* expected length of the escape name */
503 size_t naml; /* actual length of the escape name */
504 size_t ressz; /* size of the replacement string */
505 int expand_count; /* to avoid infinite loops */
506 int npos; /* position in numeric expression */
507 int irc; /* return code from roff_evalnum() */
508 char term; /* character terminating the escape */
509
510 expand_count = 0;
511 start = *bufp + pos;
512 stesc = strchr(start, '\0') - 1;
513 while (stesc-- > start) {
514
515 /* Search backwards for the next backslash. */
516
517 if ('\\' != *stesc)
518 continue;
519
520 /* If it is escaped, skip it. */
521
522 for (cp = stesc - 1; cp >= start; cp--)
523 if ('\\' != *cp)
524 break;
525
526 if (0 == (stesc - cp) % 2) {
527 stesc = cp;
528 continue;
529 }
530
531 /* Decide whether to expand or to check only. */
532
533 term = '\0';
534 cp = stesc + 1;
535 switch (*cp) {
536 case ('*'):
537 res = NULL;
538 break;
539 case ('B'):
540 /* FALLTHROUGH */
541 case ('w'):
542 term = cp[1];
543 /* FALLTHROUGH */
544 case ('n'):
545 res = ubuf;
546 break;
547 default:
548 if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL))
549 mandoc_msg(MANDOCERR_BADESCAPE, r->parse,
550 ln, (int)(stesc - *bufp), NULL);
551 continue;
552 }
553
554 if (EXPAND_LIMIT < ++expand_count) {
555 mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
556 ln, (int)(stesc - *bufp), NULL);
557 return(ROFF_IGN);
558 }
559
560 /*
561 * The third character decides the length
562 * of the name of the string or register.
563 * Save a pointer to the name.
564 */
565
566 if ('\0' == term) {
567 switch (*++cp) {
568 case ('\0'):
569 maxl = 0;
570 break;
571 case ('('):
572 cp++;
573 maxl = 2;
574 break;
575 case ('['):
576 cp++;
577 term = ']';
578 maxl = 0;
579 break;
580 default:
581 maxl = 1;
582 break;
583 }
584 } else {
585 cp += 2;
586 maxl = 0;
587 }
588 stnam = cp;
589
590 /* Advance to the end of the name. */
591
592 for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
593 if ('\0' == *cp) {
594 mandoc_msg
595 (MANDOCERR_BADESCAPE,
596 r->parse, ln,
597 (int)(stesc - *bufp), NULL);
598 break;
599 }
600 if (0 == maxl && *cp == term) {
601 cp++;
602 break;
603 }
604 }
605
606 /*
607 * Retrieve the replacement string; if it is
608 * undefined, resume searching for escapes.
609 */
610
611 switch (stesc[1]) {
612 case ('*'):
613 res = roff_getstrn(r, stnam, naml);
614 break;
615 case ('B'):
616 npos = 0;
617 irc = roff_evalnum(stnam, &npos, NULL, 0);
618 ubuf[0] = irc && stnam + npos + 1 == cp
619 ? '1' : '0';
620 ubuf[1] = '\0';
621 break;
622 case ('n'):
623 snprintf(ubuf, sizeof(ubuf), "%d",
624 roff_getregn(r, stnam, naml));
625 break;
626 case ('w'):
627 snprintf(ubuf, sizeof(ubuf), "%d",
628 24 * (int)naml);
629 break;
630 }
631
632 if (NULL == res) {
633 mandoc_msg
634 (MANDOCERR_BADESCAPE, r->parse,
635 ln, (int)(stesc - *bufp), NULL);
636 res = "";
637 }
638 ressz = strlen(res);
639
640 /* Replace the escape sequence by the string. */
641
642 *szp += ressz + 1;
643 nbuf = mandoc_malloc(*szp);
644
645 strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
646 strlcat(nbuf, res, *szp);
647 strlcat(nbuf, cp, *szp);
648
649 /* Prepare for the next replacement. */
650
651 start = nbuf + pos;
652 stesc = nbuf + (stesc - *bufp) + ressz;
653 free(*bufp);
654 *bufp = nbuf;
655 }
656 return(ROFF_CONT);
657 }
658
659 /*
660 * Process text streams:
661 * Convert all breakable hyphens into ASCII_HYPH.
662 * Decrement and spring input line trap.
663 */
664 static enum rofferr
665 roff_parsetext(char **bufp, size_t *szp, int pos, int *offs)
666 {
667 size_t sz;
668 const char *start;
669 char *p;
670 int isz;
671 enum mandoc_esc esc;
672
673 start = p = *bufp + pos;
674
675 while ('\0' != *p) {
676 sz = strcspn(p, "-\\");
677 p += sz;
678
679 if ('\0' == *p)
680 break;
681
682 if ('\\' == *p) {
683 /* Skip over escapes. */
684 p++;
685 esc = mandoc_escape((const char **)&p, NULL, NULL);
686 if (ESCAPE_ERROR == esc)
687 break;
688 continue;
689 } else if (p == start) {
690 p++;
691 continue;
692 }
693
694 if (isalpha((unsigned char)p[-1]) &&
695 isalpha((unsigned char)p[1]))
696 *p = ASCII_HYPH;
697 p++;
698 }
699
700 /* Spring the input line trap. */
701 if (1 == roffit_lines) {
702 isz = mandoc_asprintf(&p, "%s\n.%s", *bufp, roffit_macro);
703 free(*bufp);
704 *bufp = p;
705 *szp = isz + 1;
706 *offs = 0;
707 free(roffit_macro);
708 roffit_lines = 0;
709 return(ROFF_REPARSE);
710 } else if (1 < roffit_lines)
711 --roffit_lines;
712 return(ROFF_CONT);
713 }
714
715 enum rofferr
716 roff_parseln(struct roff *r, int ln, char **bufp,
717 size_t *szp, int pos, int *offs)
718 {
719 enum rofft t;
720 enum rofferr e;
721 int ppos, ctl;
722
723 /*
724 * Run the reserved-word filter only if we have some reserved
725 * words to fill in.
726 */
727
728 e = roff_res(r, bufp, szp, ln, pos);
729 if (ROFF_IGN == e)
730 return(e);
731 assert(ROFF_CONT == e);
732
733 ppos = pos;
734 ctl = roff_getcontrol(r, *bufp, &pos);
735
736 /*
737 * First, if a scope is open and we're not a macro, pass the
738 * text through the macro's filter. If a scope isn't open and
739 * we're not a macro, just let it through.
740 * Finally, if there's an equation scope open, divert it into it
741 * no matter our state.
742 */
743
744 if (r->last && ! ctl) {
745 t = r->last->tok;
746 assert(roffs[t].text);
747 e = (*roffs[t].text)
748 (r, t, bufp, szp, ln, pos, pos, offs);
749 assert(ROFF_IGN == e || ROFF_CONT == e);
750 if (ROFF_CONT != e)
751 return(e);
752 }
753 if (r->eqn)
754 return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
755 if ( ! ctl) {
756 if (r->tbl)
757 return(tbl_read(r->tbl, ln, *bufp, pos));
758 return(roff_parsetext(bufp, szp, pos, offs));
759 }
760
761 /*
762 * If a scope is open, go to the child handler for that macro,
763 * as it may want to preprocess before doing anything with it.
764 * Don't do so if an equation is open.
765 */
766
767 if (r->last) {
768 t = r->last->tok;
769 assert(roffs[t].sub);
770 return((*roffs[t].sub)
771 (r, t, bufp, szp,
772 ln, ppos, pos, offs));
773 }
774
775 /*
776 * Lastly, as we've no scope open, try to look up and execute
777 * the new macro. If no macro is found, simply return and let
778 * the compilers handle it.
779 */
780
781 if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos)))
782 return(ROFF_CONT);
783
784 assert(roffs[t].proc);
785 return((*roffs[t].proc)
786 (r, t, bufp, szp,
787 ln, ppos, pos, offs));
788 }
789
790
791 void
792 roff_endparse(struct roff *r)
793 {
794
795 if (r->last)
796 mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
797 r->last->line, r->last->col, NULL);
798
799 if (r->eqn) {
800 mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
801 r->eqn->eqn.ln, r->eqn->eqn.pos, NULL);
802 eqn_end(&r->eqn);
803 }
804
805 if (r->tbl) {
806 mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
807 r->tbl->line, r->tbl->pos, NULL);
808 tbl_end(&r->tbl);
809 }
810 }
811
812 /*
813 * Parse a roff node's type from the input buffer. This must be in the
814 * form of ".foo xxx" in the usual way.
815 */
816 static enum rofft
817 roff_parse(struct roff *r, const char *buf, int *pos)
818 {
819 const char *mac;
820 size_t maclen;
821 enum rofft t;
822
823 if ('\0' == buf[*pos] || '"' == buf[*pos] ||
824 '\t' == buf[*pos] || ' ' == buf[*pos])
825 return(ROFF_MAX);
826
827 /* We stop the macro parse at an escape, tab, space, or nil. */
828
829 mac = buf + *pos;
830 maclen = strcspn(mac, " \\\t\0");
831
832 t = (r->current_string = roff_getstrn(r, mac, maclen))
833 ? ROFF_USERDEF : roffhash_find(mac, maclen);
834
835 *pos += (int)maclen;
836
837 while (buf[*pos] && ' ' == buf[*pos])
838 (*pos)++;
839
840 return(t);
841 }
842
843 /* ARGSUSED */
844 static enum rofferr
845 roff_cblock(ROFF_ARGS)
846 {
847
848 /*
849 * A block-close `..' should only be invoked as a child of an
850 * ignore macro, otherwise raise a warning and just ignore it.
851 */
852
853 if (NULL == r->last) {
854 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
855 return(ROFF_IGN);
856 }
857
858 switch (r->last->tok) {
859 case (ROFF_am):
860 /* FALLTHROUGH */
861 case (ROFF_ami):
862 /* FALLTHROUGH */
863 case (ROFF_am1):
864 /* FALLTHROUGH */
865 case (ROFF_de):
866 /* ROFF_de1 is remapped to ROFF_de in roff_block(). */
867 /* FALLTHROUGH */
868 case (ROFF_dei):
869 /* FALLTHROUGH */
870 case (ROFF_ig):
871 break;
872 default:
873 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
874 return(ROFF_IGN);
875 }
876
877 if ((*bufp)[pos])
878 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
879
880 roffnode_pop(r);
881 roffnode_cleanscope(r);
882 return(ROFF_IGN);
883
884 }
885
886
887 static void
888 roffnode_cleanscope(struct roff *r)
889 {
890
891 while (r->last) {
892 if (--r->last->endspan != 0)
893 break;
894 roffnode_pop(r);
895 }
896 }
897
898
899 static void
900 roff_ccond(struct roff *r, int ln, int ppos)
901 {
902
903 if (NULL == r->last) {
904 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
905 return;
906 }
907
908 switch (r->last->tok) {
909 case (ROFF_el):
910 /* FALLTHROUGH */
911 case (ROFF_ie):
912 /* FALLTHROUGH */
913 case (ROFF_if):
914 break;
915 default:
916 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
917 return;
918 }
919
920 if (r->last->endspan > -1) {
921 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
922 return;
923 }
924
925 roffnode_pop(r);
926 roffnode_cleanscope(r);
927 return;
928 }
929
930
931 /* ARGSUSED */
932 static enum rofferr
933 roff_block(ROFF_ARGS)
934 {
935 int sv;
936 size_t sz;
937 char *name;
938
939 name = NULL;
940
941 if (ROFF_ig != tok) {
942 if ('\0' == (*bufp)[pos]) {
943 mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
944 return(ROFF_IGN);
945 }
946
947 /*
948 * Re-write `de1', since we don't really care about
949 * groff's strange compatibility mode, into `de'.
950 */
951
952 if (ROFF_de1 == tok)
953 tok = ROFF_de;
954 if (ROFF_de == tok)
955 name = *bufp + pos;
956 else
957 mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos,
958 roffs[tok].name);
959
960 while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
961 pos++;
962
963 while (isspace((unsigned char)(*bufp)[pos]))
964 (*bufp)[pos++] = '\0';
965 }
966
967 roffnode_push(r, tok, name, ln, ppos);
968
969 /*
970 * At the beginning of a `de' macro, clear the existing string
971 * with the same name, if there is one. New content will be
972 * appended from roff_block_text() in multiline mode.
973 */
974
975 if (ROFF_de == tok)
976 roff_setstr(r, name, "", 0);
977
978 if ('\0' == (*bufp)[pos])
979 return(ROFF_IGN);
980
981 /* If present, process the custom end-of-line marker. */
982
983 sv = pos;
984 while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
985 pos++;
986
987 /*
988 * Note: groff does NOT like escape characters in the input.
989 * Instead of detecting this, we're just going to let it fly and
990 * to hell with it.
991 */
992
993 assert(pos > sv);
994 sz = (size_t)(pos - sv);
995
996 if (1 == sz && '.' == (*bufp)[sv])
997 return(ROFF_IGN);
998
999 r->last->end = mandoc_malloc(sz + 1);
1000
1001 memcpy(r->last->end, *bufp + sv, sz);
1002 r->last->end[(int)sz] = '\0';
1003
1004 if ((*bufp)[pos])
1005 mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
1006
1007 return(ROFF_IGN);
1008 }
1009
1010
1011 /* ARGSUSED */
1012 static enum rofferr
1013 roff_block_sub(ROFF_ARGS)
1014 {
1015 enum rofft t;
1016 int i, j;
1017
1018 /*
1019 * First check whether a custom macro exists at this level. If
1020 * it does, then check against it. This is some of groff's
1021 * stranger behaviours. If we encountered a custom end-scope
1022 * tag and that tag also happens to be a "real" macro, then we
1023 * need to try interpreting it again as a real macro. If it's
1024 * not, then return ignore. Else continue.
1025 */
1026
1027 if (r->last->end) {
1028 for (i = pos, j = 0; r->last->end[j]; j++, i++)
1029 if ((*bufp)[i] != r->last->end[j])
1030 break;
1031
1032 if ('\0' == r->last->end[j] &&
1033 ('\0' == (*bufp)[i] ||
1034 ' ' == (*bufp)[i] ||
1035 '\t' == (*bufp)[i])) {
1036 roffnode_pop(r);
1037 roffnode_cleanscope(r);
1038
1039 while (' ' == (*bufp)[i] || '\t' == (*bufp)[i])
1040 i++;
1041
1042 pos = i;
1043 if (ROFF_MAX != roff_parse(r, *bufp, &pos))
1044 return(ROFF_RERUN);
1045 return(ROFF_IGN);
1046 }
1047 }
1048
1049 /*
1050 * If we have no custom end-query or lookup failed, then try
1051 * pulling it out of the hashtable.
1052 */
1053
1054 t = roff_parse(r, *bufp, &pos);
1055
1056 /*
1057 * Macros other than block-end are only significant
1058 * in `de' blocks; elsewhere, simply throw them away.
1059 */
1060 if (ROFF_cblock != t) {
1061 if (ROFF_de == tok)
1062 roff_setstr(r, r->last->name, *bufp + ppos, 2);
1063 return(ROFF_IGN);
1064 }
1065
1066 assert(roffs[t].proc);
1067 return((*roffs[t].proc)(r, t, bufp, szp,
1068 ln, ppos, pos, offs));
1069 }
1070
1071
1072 /* ARGSUSED */
1073 static enum rofferr
1074 roff_block_text(ROFF_ARGS)
1075 {
1076
1077 if (ROFF_de == tok)
1078 roff_setstr(r, r->last->name, *bufp + pos, 2);
1079
1080 return(ROFF_IGN);
1081 }
1082
1083
1084 /* ARGSUSED */
1085 static enum rofferr
1086 roff_cond_sub(ROFF_ARGS)
1087 {
1088 enum rofft t;
1089 char *ep;
1090 int rr;
1091
1092 rr = r->last->rule;
1093 roffnode_cleanscope(r);
1094 t = roff_parse(r, *bufp, &pos);
1095
1096 /*
1097 * Fully handle known macros when they are structurally
1098 * required or when the conditional evaluated to true.
1099 */
1100
1101 if ((ROFF_MAX != t) &&
1102 (rr || ROFFMAC_STRUCT & roffs[t].flags)) {
1103 assert(roffs[t].proc);
1104 return((*roffs[t].proc)(r, t, bufp, szp,
1105 ln, ppos, pos, offs));
1106 }
1107
1108 /*
1109 * If `\}' occurs on a macro line without a preceding macro,
1110 * drop the line completely.
1111 */
1112
1113 ep = *bufp + pos;
1114 if ('\\' == ep[0] && '}' == ep[1])
1115 rr = 0;
1116
1117 /* Always check for the closing delimiter `\}'. */
1118
1119 while (NULL != (ep = strchr(ep, '\\'))) {
1120 if ('}' == *(++ep)) {
1121 *ep = '&';
1122 roff_ccond(r, ln, ep - *bufp - 1);
1123 }
1124 ++ep;
1125 }
1126 return(rr ? ROFF_CONT : ROFF_IGN);
1127 }
1128
1129 /* ARGSUSED */
1130 static enum rofferr
1131 roff_cond_text(ROFF_ARGS)
1132 {
1133 char *ep;
1134 int rr;
1135
1136 rr = r->last->rule;
1137 roffnode_cleanscope(r);
1138
1139 ep = *bufp + pos;
1140 while (NULL != (ep = strchr(ep, '\\'))) {
1141 if ('}' == *(++ep)) {
1142 *ep = '&';
1143 roff_ccond(r, ln, ep - *bufp - 1);
1144 }
1145 ++ep;
1146 }
1147 return(rr ? ROFF_CONT : ROFF_IGN);
1148 }
1149
1150 /*
1151 * Parse a single signed integer number. Stop at the first non-digit.
1152 * If there is at least one digit, return success and advance the
1153 * parse point, else return failure and let the parse point unchanged.
1154 * Ignore overflows, treat them just like the C language.
1155 */
1156 static int
1157 roff_getnum(const char *v, int *pos, int *res)
1158 {
1159 int myres, n, p;
1160
1161 if (NULL == res)
1162 res = &myres;
1163
1164 p = *pos;
1165 n = v[p] == '-';
1166 if (n)
1167 p++;
1168
1169 for (*res = 0; isdigit((unsigned char)v[p]); p++)
1170 *res = 10 * *res + v[p] - '0';
1171 if (p == *pos + n)
1172 return 0;
1173
1174 if (n)
1175 *res = -*res;
1176
1177 *pos = p;
1178 return 1;
1179 }
1180
1181 /*
1182 * Evaluate a string comparison condition.
1183 * The first character is the delimiter.
1184 * Succeed if the string up to its second occurrence
1185 * matches the string up to its third occurence.
1186 * Advance the cursor after the third occurrence
1187 * or lacking that, to the end of the line.
1188 */
1189 static int
1190 roff_evalstrcond(const char *v, int *pos)
1191 {
1192 const char *s1, *s2, *s3;
1193 int match;
1194
1195 match = 0;
1196 s1 = v + *pos; /* initial delimiter */
1197 s2 = s1 + 1; /* for scanning the first string */
1198 s3 = strchr(s2, *s1); /* for scanning the second string */
1199
1200 if (NULL == s3) /* found no middle delimiter */
1201 goto out;
1202
1203 while ('\0' != *++s3) {
1204 if (*s2 != *s3) { /* mismatch */
1205 s3 = strchr(s3, *s1);
1206 break;
1207 }
1208 if (*s3 == *s1) { /* found the final delimiter */
1209 match = 1;
1210 break;
1211 }
1212 s2++;
1213 }
1214
1215 out:
1216 if (NULL == s3)
1217 s3 = strchr(s2, '\0');
1218 else
1219 s3++;
1220 *pos = s3 - v;
1221 return(match);
1222 }
1223
1224 /*
1225 * Evaluate an optionally negated single character, numerical,
1226 * or string condition.
1227 */
1228 static int
1229 roff_evalcond(const char *v, int *pos)
1230 {
1231 int wanttrue, number;
1232
1233 if ('!' == v[*pos]) {
1234 wanttrue = 0;
1235 (*pos)++;
1236 } else
1237 wanttrue = 1;
1238
1239 switch (v[*pos]) {
1240 case ('n'):
1241 /* FALLTHROUGH */
1242 case ('o'):
1243 (*pos)++;
1244 return(wanttrue);
1245 case ('c'):
1246 /* FALLTHROUGH */
1247 case ('d'):
1248 /* FALLTHROUGH */
1249 case ('e'):
1250 /* FALLTHROUGH */
1251 case ('r'):
1252 /* FALLTHROUGH */
1253 case ('t'):
1254 (*pos)++;
1255 return(!wanttrue);
1256 default:
1257 break;
1258 }
1259
1260 if (roff_evalnum(v, pos, &number, 0))
1261 return((number > 0) == wanttrue);
1262 else
1263 return(roff_evalstrcond(v, pos) == wanttrue);
1264 }
1265
1266 /* ARGSUSED */
1267 static enum rofferr
1268 roff_line_ignore(ROFF_ARGS)
1269 {
1270
1271 return(ROFF_IGN);
1272 }
1273
1274 /* ARGSUSED */
1275 static enum rofferr
1276 roff_cond(ROFF_ARGS)
1277 {
1278
1279 roffnode_push(r, tok, NULL, ln, ppos);
1280
1281 /*
1282 * An `.el' has no conditional body: it will consume the value
1283 * of the current rstack entry set in prior `ie' calls or
1284 * defaults to DENY.
1285 *
1286 * If we're not an `el', however, then evaluate the conditional.
1287 */
1288
1289 r->last->rule = ROFF_el == tok ?
1290 (r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) :
1291 roff_evalcond(*bufp, &pos);
1292
1293 /*
1294 * An if-else will put the NEGATION of the current evaluated
1295 * conditional into the stack of rules.
1296 */
1297
1298 if (ROFF_ie == tok) {
1299 if (r->rstackpos == RSTACK_MAX - 1) {
1300 mandoc_msg(MANDOCERR_MEM,
1301 r->parse, ln, ppos, NULL);
1302 return(ROFF_ERR);
1303 }
1304 r->rstack[++r->rstackpos] = !r->last->rule;
1305 }
1306
1307 /* If the parent has false as its rule, then so do we. */
1308
1309 if (r->last->parent && !r->last->parent->rule)
1310 r->last->rule = 0;
1311
1312 /*
1313 * Determine scope.
1314 * If there is nothing on the line after the conditional,
1315 * not even whitespace, use next-line scope.
1316 */
1317
1318 if ('\0' == (*bufp)[pos]) {
1319 r->last->endspan = 2;
1320 goto out;
1321 }
1322
1323 while (' ' == (*bufp)[pos])
1324 pos++;
1325
1326 /* An opening brace requests multiline scope. */
1327
1328 if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
1329 r->last->endspan = -1;
1330 pos += 2;
1331 goto out;
1332 }
1333
1334 /*
1335 * Anything else following the conditional causes
1336 * single-line scope. Warn if the scope contains
1337 * nothing but trailing whitespace.
1338 */
1339
1340 if ('\0' == (*bufp)[pos])
1341 mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
1342
1343 r->last->endspan = 1;
1344
1345 out:
1346 *offs = pos;
1347 return(ROFF_RERUN);
1348 }
1349
1350
1351 /* ARGSUSED */
1352 static enum rofferr
1353 roff_ds(ROFF_ARGS)
1354 {
1355 char *name, *string;
1356
1357 /*
1358 * A symbol is named by the first word following the macro
1359 * invocation up to a space. Its value is anything after the
1360 * name's trailing whitespace and optional double-quote. Thus,
1361 *
1362 * [.ds foo "bar " ]
1363 *
1364 * will have `bar " ' as its value.
1365 */
1366
1367 string = *bufp + pos;
1368 name = roff_getname(r, &string, ln, pos);
1369 if ('\0' == *name)
1370 return(ROFF_IGN);
1371
1372 /* Read past initial double-quote. */
1373 if ('"' == *string)
1374 string++;
1375
1376 /* The rest is the value. */
1377 roff_setstr(r, name, string, ROFF_as == tok);
1378 return(ROFF_IGN);
1379 }
1380
1381 /*
1382 * Parse a single operator, one or two characters long.
1383 * If the operator is recognized, return success and advance the
1384 * parse point, else return failure and let the parse point unchanged.
1385 */
1386 static int
1387 roff_getop(const char *v, int *pos, char *res)
1388 {
1389
1390 *res = v[*pos];
1391
1392 switch (*res) {
1393 case ('+'):
1394 /* FALLTHROUGH */
1395 case ('-'):
1396 /* FALLTHROUGH */
1397 case ('*'):
1398 /* FALLTHROUGH */
1399 case ('/'):
1400 /* FALLTHROUGH */
1401 case ('%'):
1402 /* FALLTHROUGH */
1403 case ('&'):
1404 /* FALLTHROUGH */
1405 case (':'):
1406 break;
1407 case '<':
1408 switch (v[*pos + 1]) {
1409 case ('='):
1410 *res = 'l';
1411 (*pos)++;
1412 break;
1413 case ('>'):
1414 *res = '!';
1415 (*pos)++;
1416 break;
1417 case ('?'):
1418 *res = 'i';
1419 (*pos)++;
1420 break;
1421 default:
1422 break;
1423 }
1424 break;
1425 case '>':
1426 switch (v[*pos + 1]) {
1427 case ('='):
1428 *res = 'g';
1429 (*pos)++;
1430 break;
1431 case ('?'):
1432 *res = 'a';
1433 (*pos)++;
1434 break;
1435 default:
1436 break;
1437 }
1438 break;
1439 case '=':
1440 if ('=' == v[*pos + 1])
1441 (*pos)++;
1442 break;
1443 default:
1444 return(0);
1445 }
1446 (*pos)++;
1447
1448 return(*res);
1449 }
1450
1451 /*
1452 * Evaluate either a parenthesized numeric expression
1453 * or a single signed integer number.
1454 */
1455 static int
1456 roff_evalpar(const char *v, int *pos, int *res)
1457 {
1458
1459 if ('(' != v[*pos])
1460 return(roff_getnum(v, pos, res));
1461
1462 (*pos)++;
1463 if ( ! roff_evalnum(v, pos, res, 1))
1464 return(0);
1465
1466 /*
1467 * Omission of the closing parenthesis
1468 * is an error in validation mode,
1469 * but ignored in evaluation mode.
1470 */
1471
1472 if (')' == v[*pos])
1473 (*pos)++;
1474 else if (NULL == res)
1475 return(0);
1476
1477 return(1);
1478 }
1479
1480 /*
1481 * Evaluate a complete numeric expression.
1482 * Proceed left to right, there is no concept of precedence.
1483 */
1484 static int
1485 roff_evalnum(const char *v, int *pos, int *res, int skipwhite)
1486 {
1487 int mypos, operand2;
1488 char operator;
1489
1490 if (NULL == pos) {
1491 mypos = 0;
1492 pos = &mypos;
1493 }
1494
1495 if (skipwhite)
1496 while (isspace((unsigned char)v[*pos]))
1497 (*pos)++;
1498
1499 if ( ! roff_evalpar(v, pos, res))
1500 return(0);
1501
1502 while (1) {
1503 if (skipwhite)
1504 while (isspace((unsigned char)v[*pos]))
1505 (*pos)++;
1506
1507 if ( ! roff_getop(v, pos, &operator))
1508 break;
1509
1510 if (skipwhite)
1511 while (isspace((unsigned char)v[*pos]))
1512 (*pos)++;
1513
1514 if ( ! roff_evalpar(v, pos, &operand2))
1515 return(0);
1516
1517 if (skipwhite)
1518 while (isspace((unsigned char)v[*pos]))
1519 (*pos)++;
1520
1521 if (NULL == res)
1522 continue;
1523
1524 switch (operator) {
1525 case ('+'):
1526 *res += operand2;
1527 break;
1528 case ('-'):
1529 *res -= operand2;
1530 break;
1531 case ('*'):
1532 *res *= operand2;
1533 break;
1534 case ('/'):
1535 *res /= operand2;
1536 break;
1537 case ('%'):
1538 *res %= operand2;
1539 break;
1540 case ('<'):
1541 *res = *res < operand2;
1542 break;
1543 case ('>'):
1544 *res = *res > operand2;
1545 break;
1546 case ('l'):
1547 *res = *res <= operand2;
1548 break;
1549 case ('g'):
1550 *res = *res >= operand2;
1551 break;
1552 case ('='):
1553 *res = *res == operand2;
1554 break;
1555 case ('!'):
1556 *res = *res != operand2;
1557 break;
1558 case ('&'):
1559 *res = *res && operand2;
1560 break;
1561 case (':'):
1562 *res = *res || operand2;
1563 break;
1564 case ('i'):
1565 if (operand2 < *res)
1566 *res = operand2;
1567 break;
1568 case ('a'):
1569 if (operand2 > *res)
1570 *res = operand2;
1571 break;
1572 default:
1573 abort();
1574 }
1575 }
1576 return(1);
1577 }
1578
1579 void
1580 roff_setreg(struct roff *r, const char *name, int val, char sign)
1581 {
1582 struct roffreg *reg;
1583
1584 /* Search for an existing register with the same name. */
1585 reg = r->regtab;
1586
1587 while (reg && strcmp(name, reg->key.p))
1588 reg = reg->next;
1589
1590 if (NULL == reg) {
1591 /* Create a new register. */
1592 reg = mandoc_malloc(sizeof(struct roffreg));
1593 reg->key.p = mandoc_strdup(name);
1594 reg->key.sz = strlen(name);
1595 reg->val = 0;
1596 reg->next = r->regtab;
1597 r->regtab = reg;
1598 }
1599
1600 if ('+' == sign)
1601 reg->val += val;
1602 else if ('-' == sign)
1603 reg->val -= val;
1604 else
1605 reg->val = val;
1606 }
1607
1608 /*
1609 * Handle some predefined read-only number registers.
1610 * For now, return -1 if the requested register is not predefined;
1611 * in case a predefined read-only register having the value -1
1612 * were to turn up, another special value would have to be chosen.
1613 */
1614 static int
1615 roff_getregro(const char *name)
1616 {
1617
1618 switch (*name) {
1619 case ('A'): /* ASCII approximation mode is always off. */
1620 return(0);
1621 case ('g'): /* Groff compatibility mode is always on. */
1622 return(1);
1623 case ('H'): /* Fixed horizontal resolution. */
1624 return (24);
1625 case ('j'): /* Always adjust left margin only. */
1626 return(0);
1627 case ('T'): /* Some output device is always defined. */
1628 return(1);
1629 case ('V'): /* Fixed vertical resolution. */
1630 return (40);
1631 default:
1632 return (-1);
1633 }
1634 }
1635
1636 int
1637 roff_getreg(const struct roff *r, const char *name)
1638 {
1639 struct roffreg *reg;
1640 int val;
1641
1642 if ('.' == name[0] && '\0' != name[1] && '\0' == name[2]) {
1643 val = roff_getregro(name + 1);
1644 if (-1 != val)
1645 return (val);
1646 }
1647
1648 for (reg = r->regtab; reg; reg = reg->next)
1649 if (0 == strcmp(name, reg->key.p))
1650 return(reg->val);
1651
1652 return(0);
1653 }
1654
1655 static int
1656 roff_getregn(const struct roff *r, const char *name, size_t len)
1657 {
1658 struct roffreg *reg;
1659 int val;
1660
1661 if ('.' == name[0] && 2 == len) {
1662 val = roff_getregro(name + 1);
1663 if (-1 != val)
1664 return (val);
1665 }
1666
1667 for (reg = r->regtab; reg; reg = reg->next)
1668 if (len == reg->key.sz &&
1669 0 == strncmp(name, reg->key.p, len))
1670 return(reg->val);
1671
1672 return(0);
1673 }
1674
1675 static void
1676 roff_freereg(struct roffreg *reg)
1677 {
1678 struct roffreg *old_reg;
1679
1680 while (NULL != reg) {
1681 free(reg->key.p);
1682 old_reg = reg;
1683 reg = reg->next;
1684 free(old_reg);
1685 }
1686 }
1687
1688 static enum rofferr
1689 roff_nr(ROFF_ARGS)
1690 {
1691 const char *key;
1692 char *val;
1693 int iv;
1694 char sign;
1695
1696 val = *bufp + pos;
1697 key = roff_getname(r, &val, ln, pos);
1698
1699 sign = *val;
1700 if ('+' == sign || '-' == sign)
1701 val++;
1702
1703 if (roff_evalnum(val, NULL, &iv, 0))
1704 roff_setreg(r, key, iv, sign);
1705
1706 return(ROFF_IGN);
1707 }
1708
1709 static enum rofferr
1710 roff_rr(ROFF_ARGS)
1711 {
1712 struct roffreg *reg, **prev;
1713 const char *name;
1714 char *cp;
1715
1716 cp = *bufp + pos;
1717 name = roff_getname(r, &cp, ln, pos);
1718
1719 prev = &r->regtab;
1720 while (1) {
1721 reg = *prev;
1722 if (NULL == reg || !strcmp(name, reg->key.p))
1723 break;
1724 prev = &reg->next;
1725 }
1726 if (NULL != reg) {
1727 *prev = reg->next;
1728 free(reg->key.p);
1729 free(reg);
1730 }
1731 return(ROFF_IGN);
1732 }
1733
1734 /* ARGSUSED */
1735 static enum rofferr
1736 roff_rm(ROFF_ARGS)
1737 {
1738 const char *name;
1739 char *cp;
1740
1741 cp = *bufp + pos;
1742 while ('\0' != *cp) {
1743 name = roff_getname(r, &cp, ln, (int)(cp - *bufp));
1744 if ('\0' != *name)
1745 roff_setstr(r, name, NULL, 0);
1746 }
1747 return(ROFF_IGN);
1748 }
1749
1750 /* ARGSUSED */
1751 static enum rofferr
1752 roff_it(ROFF_ARGS)
1753 {
1754 char *cp;
1755 size_t len;
1756 int iv;
1757
1758 /* Parse the number of lines. */
1759 cp = *bufp + pos;
1760 len = strcspn(cp, " \t");
1761 cp[len] = '\0';
1762 if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
1763 mandoc_msg(MANDOCERR_NUMERIC, r->parse,
1764 ln, ppos, *bufp + 1);
1765 return(ROFF_IGN);
1766 }
1767 cp += len + 1;
1768
1769 /* Arm the input line trap. */
1770 roffit_lines = iv;
1771 roffit_macro = mandoc_strdup(cp);
1772 return(ROFF_IGN);
1773 }
1774
1775 /* ARGSUSED */
1776 static enum rofferr
1777 roff_Dd(ROFF_ARGS)
1778 {
1779 const char *const *cp;
1780
1781 if (0 == ((MPARSE_MDOC | MPARSE_QUICK) & r->options))
1782 for (cp = __mdoc_reserved; *cp; cp++)
1783 roff_setstr(r, *cp, NULL, 0);
1784
1785 return(ROFF_CONT);
1786 }
1787
1788 /* ARGSUSED */
1789 static enum rofferr
1790 roff_TH(ROFF_ARGS)
1791 {
1792 const char *const *cp;
1793
1794 if (0 == (MPARSE_QUICK & r->options))
1795 for (cp = __man_reserved; *cp; cp++)
1796 roff_setstr(r, *cp, NULL, 0);
1797
1798 return(ROFF_CONT);
1799 }
1800
1801 /* ARGSUSED */
1802 static enum rofferr
1803 roff_TE(ROFF_ARGS)
1804 {
1805
1806 if (NULL == r->tbl)
1807 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1808 else
1809 tbl_end(&r->tbl);
1810
1811 return(ROFF_IGN);
1812 }
1813
1814 /* ARGSUSED */
1815 static enum rofferr
1816 roff_T_(ROFF_ARGS)
1817 {
1818
1819 if (NULL == r->tbl)
1820 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1821 else
1822 tbl_restart(ppos, ln, r->tbl);
1823
1824 return(ROFF_IGN);
1825 }
1826
1827 #if 0
1828 static int
1829 roff_closeeqn(struct roff *r)
1830 {
1831
1832 return(r->eqn && ROFF_EQN == eqn_end(&r->eqn) ? 1 : 0);
1833 }
1834 #endif
1835
1836 static void
1837 roff_openeqn(struct roff *r, const char *name, int line,
1838 int offs, const char *buf)
1839 {
1840 struct eqn_node *e;
1841 int poff;
1842
1843 assert(NULL == r->eqn);
1844 e = eqn_alloc(name, offs, line, r->parse);
1845
1846 if (r->last_eqn)
1847 r->last_eqn->next = e;
1848 else
1849 r->first_eqn = r->last_eqn = e;
1850
1851 r->eqn = r->last_eqn = e;
1852
1853 if (buf) {
1854 poff = 0;
1855 eqn_read(&r->eqn, line, buf, offs, &poff);
1856 }
1857 }
1858
1859 /* ARGSUSED */
1860 static enum rofferr
1861 roff_EQ(ROFF_ARGS)
1862 {
1863
1864 roff_openeqn(r, *bufp + pos, ln, ppos, NULL);
1865 return(ROFF_IGN);
1866 }
1867
1868 /* ARGSUSED */
1869 static enum rofferr
1870 roff_EN(ROFF_ARGS)
1871 {
1872
1873 mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1874 return(ROFF_IGN);
1875 }
1876
1877 /* ARGSUSED */
1878 static enum rofferr
1879 roff_TS(ROFF_ARGS)
1880 {
1881 struct tbl_node *tbl;
1882
1883 if (r->tbl) {
1884 mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
1885 tbl_end(&r->tbl);
1886 }
1887
1888 tbl = tbl_alloc(ppos, ln, r->parse);
1889
1890 if (r->last_tbl)
1891 r->last_tbl->next = tbl;
1892 else
1893 r->first_tbl = r->last_tbl = tbl;
1894
1895 r->tbl = r->last_tbl = tbl;
1896 return(ROFF_IGN);
1897 }
1898
1899 /* ARGSUSED */
1900 static enum rofferr
1901 roff_cc(ROFF_ARGS)
1902 {
1903 const char *p;
1904
1905 p = *bufp + pos;
1906
1907 if ('\0' == *p || '.' == (r->control = *p++))
1908 r->control = 0;
1909
1910 if ('\0' != *p)
1911 mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
1912
1913 return(ROFF_IGN);
1914 }
1915
1916 /* ARGSUSED */
1917 static enum rofferr
1918 roff_tr(ROFF_ARGS)
1919 {
1920 const char *p, *first, *second;
1921 size_t fsz, ssz;
1922 enum mandoc_esc esc;
1923
1924 p = *bufp + pos;
1925
1926 if ('\0' == *p) {
1927 mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
1928 return(ROFF_IGN);
1929 }
1930
1931 while ('\0' != *p) {
1932 fsz = ssz = 1;
1933
1934 first = p++;
1935 if ('\\' == *first) {
1936 esc = mandoc_escape(&p, NULL, NULL);
1937 if (ESCAPE_ERROR == esc) {
1938 mandoc_msg
1939 (MANDOCERR_BADESCAPE, r->parse,
1940 ln, (int)(p - *bufp), NULL);
1941 return(ROFF_IGN);
1942 }
1943 fsz = (size_t)(p - first);
1944 }
1945
1946 second = p++;
1947 if ('\\' == *second) {
1948 esc = mandoc_escape(&p, NULL, NULL);
1949 if (ESCAPE_ERROR == esc) {
1950 mandoc_msg
1951 (MANDOCERR_BADESCAPE, r->parse,
1952 ln, (int)(p - *bufp), NULL);
1953 return(ROFF_IGN);
1954 }
1955 ssz = (size_t)(p - second);
1956 } else if ('\0' == *second) {
1957 mandoc_msg(MANDOCERR_ARGCOUNT, r->parse,
1958 ln, (int)(p - *bufp), NULL);
1959 second = " ";
1960 p--;
1961 }
1962
1963 if (fsz > 1) {
1964 roff_setstrn(&r->xmbtab, first,
1965 fsz, second, ssz, 0);
1966 continue;
1967 }
1968
1969 if (NULL == r->xtab)
1970 r->xtab = mandoc_calloc
1971 (128, sizeof(struct roffstr));
1972
1973 free(r->xtab[(int)*first].p);
1974 r->xtab[(int)*first].p = mandoc_strndup(second, ssz);
1975 r->xtab[(int)*first].sz = ssz;
1976 }
1977
1978 return(ROFF_IGN);
1979 }
1980
1981 /* ARGSUSED */
1982 static enum rofferr
1983 roff_so(ROFF_ARGS)
1984 {
1985 char *name;
1986
1987 mandoc_msg(MANDOCERR_SO, r->parse, ln, ppos, NULL);
1988
1989 /*
1990 * Handle `so'. Be EXTREMELY careful, as we shouldn't be
1991 * opening anything that's not in our cwd or anything beneath
1992 * it. Thus, explicitly disallow traversing up the file-system
1993 * or using absolute paths.
1994 */
1995
1996 name = *bufp + pos;
1997 if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) {
1998 mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL);
1999 return(ROFF_ERR);
2000 }
2001
2002 *offs = pos;
2003 return(ROFF_SO);
2004 }
2005
2006 /* ARGSUSED */
2007 static enum rofferr
2008 roff_userdef(ROFF_ARGS)
2009 {
2010 const char *arg[9];
2011 char *cp, *n1, *n2;
2012 int i;
2013
2014 /*
2015 * Collect pointers to macro argument strings
2016 * and NUL-terminate them.
2017 */
2018 cp = *bufp + pos;
2019 for (i = 0; i < 9; i++)
2020 arg[i] = '\0' == *cp ? "" :
2021 mandoc_getarg(r->parse, &cp, ln, &pos);
2022
2023 /*
2024 * Expand macro arguments.
2025 */
2026 *szp = 0;
2027 n1 = cp = mandoc_strdup(r->current_string);
2028 while (NULL != (cp = strstr(cp, "\\$"))) {
2029 i = cp[2] - '1';
2030 if (0 > i || 8 < i) {
2031 /* Not an argument invocation. */
2032 cp += 2;
2033 continue;
2034 }
2035
2036 *szp = strlen(n1) - 3 + strlen(arg[i]) + 1;
2037 n2 = mandoc_malloc(*szp);
2038
2039 strlcpy(n2, n1, (size_t)(cp - n1 + 1));
2040 strlcat(n2, arg[i], *szp);
2041 strlcat(n2, cp + 3, *szp);
2042
2043 cp = n2 + (cp - n1);
2044 free(n1);
2045 n1 = n2;
2046 }
2047
2048 /*
2049 * Replace the macro invocation
2050 * by the expanded macro.
2051 */
2052 free(*bufp);
2053 *bufp = n1;
2054 if (0 == *szp)
2055 *szp = strlen(*bufp) + 1;
2056
2057 return(*szp > 1 && '\n' == (*bufp)[(int)*szp - 2] ?
2058 ROFF_REPARSE : ROFF_APPEND);
2059 }
2060
2061 static char *
2062 roff_getname(struct roff *r, char **cpp, int ln, int pos)
2063 {
2064 char *name, *cp;
2065
2066 name = *cpp;
2067 if ('\0' == *name)
2068 return(name);
2069
2070 /* Read until end of name. */
2071 for (cp = name; '\0' != *cp && ' ' != *cp; cp++) {
2072 if ('\\' != *cp)
2073 continue;
2074 cp++;
2075 if ('\\' == *cp)
2076 continue;
2077 mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL);
2078 *cp = '\0';
2079 name = cp;
2080 }
2081
2082 /* Nil-terminate name. */
2083 if ('\0' != *cp)
2084 *(cp++) = '\0';
2085
2086 /* Read past spaces. */
2087 while (' ' == *cp)
2088 cp++;
2089
2090 *cpp = cp;
2091 return(name);
2092 }
2093
2094 /*
2095 * Store *string into the user-defined string called *name.
2096 * To clear an existing entry, call with (*r, *name, NULL, 0).
2097 * append == 0: replace mode
2098 * append == 1: single-line append mode
2099 * append == 2: multiline append mode, append '\n' after each call
2100 */
2101 static void
2102 roff_setstr(struct roff *r, const char *name, const char *string,
2103 int append)
2104 {
2105
2106 roff_setstrn(&r->strtab, name, strlen(name), string,
2107 string ? strlen(string) : 0, append);
2108 }
2109
2110 static void
2111 roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
2112 const char *string, size_t stringsz, int append)
2113 {
2114 struct roffkv *n;
2115 char *c;
2116 int i;
2117 size_t oldch, newch;
2118
2119 /* Search for an existing string with the same name. */
2120 n = *r;
2121
2122 while (n && strcmp(name, n->key.p))
2123 n = n->next;
2124
2125 if (NULL == n) {
2126 /* Create a new string table entry. */
2127 n = mandoc_malloc(sizeof(struct roffkv));
2128 n->key.p = mandoc_strndup(name, namesz);
2129 n->key.sz = namesz;
2130 n->val.p = NULL;
2131 n->val.sz = 0;
2132 n->next = *r;
2133 *r = n;
2134 } else if (0 == append) {
2135 free(n->val.p);
2136 n->val.p = NULL;
2137 n->val.sz = 0;
2138 }
2139
2140 if (NULL == string)
2141 return;
2142
2143 /*
2144 * One additional byte for the '\n' in multiline mode,
2145 * and one for the terminating '\0'.
2146 */
2147 newch = stringsz + (1 < append ? 2u : 1u);
2148
2149 if (NULL == n->val.p) {
2150 n->val.p = mandoc_malloc(newch);
2151 *n->val.p = '\0';
2152 oldch = 0;
2153 } else {
2154 oldch = n->val.sz;
2155 n->val.p = mandoc_realloc(n->val.p, oldch + newch);
2156 }
2157
2158 /* Skip existing content in the destination buffer. */
2159 c = n->val.p + (int)oldch;
2160
2161 /* Append new content to the destination buffer. */
2162 i = 0;
2163 while (i < (int)stringsz) {
2164 /*
2165 * Rudimentary roff copy mode:
2166 * Handle escaped backslashes.
2167 */
2168 if ('\\' == string[i] && '\\' == string[i + 1])
2169 i++;
2170 *c++ = string[i++];
2171 }
2172
2173 /* Append terminating bytes. */
2174 if (1 < append)
2175 *c++ = '\n';
2176
2177 *c = '\0';
2178 n->val.sz = (int)(c - n->val.p);
2179 }
2180
2181 static const char *
2182 roff_getstrn(const struct roff *r, const char *name, size_t len)
2183 {
2184 const struct roffkv *n;
2185 int i;
2186
2187 for (n = r->strtab; n; n = n->next)
2188 if (0 == strncmp(name, n->key.p, len) &&
2189 '\0' == n->key.p[(int)len])
2190 return(n->val.p);
2191
2192 for (i = 0; i < PREDEFS_MAX; i++)
2193 if (0 == strncmp(name, predefs[i].name, len) &&
2194 '\0' == predefs[i].name[(int)len])
2195 return(predefs[i].str);
2196
2197 return(NULL);
2198 }
2199
2200 static void
2201 roff_freestr(struct roffkv *r)
2202 {
2203 struct roffkv *n, *nn;
2204
2205 for (n = r; n; n = nn) {
2206 free(n->key.p);
2207 free(n->val.p);
2208 nn = n->next;
2209 free(n);
2210 }
2211 }
2212
2213 const struct tbl_span *
2214 roff_span(const struct roff *r)
2215 {
2216
2217 return(r->tbl ? tbl_span(r->tbl) : NULL);
2218 }
2219
2220 const struct eqn *
2221 roff_eqn(const struct roff *r)
2222 {
2223
2224 return(r->last_eqn ? &r->last_eqn->eqn : NULL);
2225 }
2226
2227 /*
2228 * Duplicate an input string, making the appropriate character
2229 * conversations (as stipulated by `tr') along the way.
2230 * Returns a heap-allocated string with all the replacements made.
2231 */
2232 char *
2233 roff_strdup(const struct roff *r, const char *p)
2234 {
2235 const struct roffkv *cp;
2236 char *res;
2237 const char *pp;
2238 size_t ssz, sz;
2239 enum mandoc_esc esc;
2240
2241 if (NULL == r->xmbtab && NULL == r->xtab)
2242 return(mandoc_strdup(p));
2243 else if ('\0' == *p)
2244 return(mandoc_strdup(""));
2245
2246 /*
2247 * Step through each character looking for term matches
2248 * (remember that a `tr' can be invoked with an escape, which is
2249 * a glyph but the escape is multi-character).
2250 * We only do this if the character hash has been initialised
2251 * and the string is >0 length.
2252 */
2253
2254 res = NULL;
2255 ssz = 0;
2256
2257 while ('\0' != *p) {
2258 if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) {
2259 sz = r->xtab[(int)*p].sz;
2260 res = mandoc_realloc(res, ssz + sz + 1);
2261 memcpy(res + ssz, r->xtab[(int)*p].p, sz);
2262 ssz += sz;
2263 p++;
2264 continue;
2265 } else if ('\\' != *p) {
2266 res = mandoc_realloc(res, ssz + 2);
2267 res[ssz++] = *p++;
2268 continue;
2269 }
2270
2271 /* Search for term matches. */
2272 for (cp = r->xmbtab; cp; cp = cp->next)
2273 if (0 == strncmp(p, cp->key.p, cp->key.sz))
2274 break;
2275
2276 if (NULL != cp) {
2277 /*
2278 * A match has been found.
2279 * Append the match to the array and move
2280 * forward by its keysize.
2281 */
2282 res = mandoc_realloc
2283 (res, ssz + cp->val.sz + 1);
2284 memcpy(res + ssz, cp->val.p, cp->val.sz);
2285 ssz += cp->val.sz;
2286 p += (int)cp->key.sz;
2287 continue;
2288 }
2289
2290 /*
2291 * Handle escapes carefully: we need to copy
2292 * over just the escape itself, or else we might
2293 * do replacements within the escape itself.
2294 * Make sure to pass along the bogus string.
2295 */
2296 pp = p++;
2297 esc = mandoc_escape(&p, NULL, NULL);
2298 if (ESCAPE_ERROR == esc) {
2299 sz = strlen(pp);
2300 res = mandoc_realloc(res, ssz + sz + 1);
2301 memcpy(res + ssz, pp, sz);
2302 break;
2303 }
2304 /*
2305 * We bail out on bad escapes.
2306 * No need to warn: we already did so when
2307 * roff_res() was called.
2308 */
2309 sz = (int)(p - pp);
2310 res = mandoc_realloc(res, ssz + sz + 1);
2311 memcpy(res + ssz, pp, sz);
2312 ssz += sz;
2313 }
2314
2315 res[(int)ssz] = '\0';
2316 return(res);
2317 }
2318
2319 /*
2320 * Find out whether a line is a macro line or not.
2321 * If it is, adjust the current position and return one; if it isn't,
2322 * return zero and don't change the current position.
2323 * If the control character has been set with `.cc', then let that grain
2324 * precedence.
2325 * This is slighly contrary to groff, where using the non-breaking
2326 * control character when `cc' has been invoked will cause the
2327 * non-breaking macro contents to be printed verbatim.
2328 */
2329 int
2330 roff_getcontrol(const struct roff *r, const char *cp, int *ppos)
2331 {
2332 int pos;
2333
2334 pos = *ppos;
2335
2336 if (0 != r->control && cp[pos] == r->control)
2337 pos++;
2338 else if (0 != r->control)
2339 return(0);
2340 else if ('\\' == cp[pos] && '.' == cp[pos + 1])
2341 pos += 2;
2342 else if ('.' == cp[pos] || '\'' == cp[pos])
2343 pos++;
2344 else
2345 return(0);
2346
2347 while (' ' == cp[pos] || '\t' == cp[pos])
2348 pos++;
2349
2350 *ppos = pos;
2351 return(1);
2352 }