Merge branch 'vendor/GCC44' into gcc442
[dragonfly.git] / usr.bin / mandoc / mdoc_macro.c
1 /*      $Id: mdoc_macro.c,v 1.24 2009/09/21 21:11:37 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <assert.h>
18 #include <ctype.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #include "libmdoc.h"
24
25 #define REWIND_REWIND   (1 << 0)
26 #define REWIND_NOHALT   (1 << 1)
27 #define REWIND_HALT     (1 << 2)
28
29 static  int       obsolete(MACRO_PROT_ARGS);
30 static  int       blk_part_exp(MACRO_PROT_ARGS);
31 static  int       in_line_eoln(MACRO_PROT_ARGS);
32 static  int       in_line_argn(MACRO_PROT_ARGS);
33 static  int       in_line(MACRO_PROT_ARGS);
34 static  int       blk_full(MACRO_PROT_ARGS);
35 static  int       blk_exp_close(MACRO_PROT_ARGS);
36 static  int       blk_part_imp(MACRO_PROT_ARGS);
37
38 static  int       phrase(struct mdoc *, int, int, char *);
39 static  int       rew_dohalt(int, enum mdoc_type,
40                         const struct mdoc_node *);
41 static  int       rew_alt(int);
42 static  int       rew_dobreak(int, const struct mdoc_node *);
43 static  int       rew_elem(struct mdoc *, int);
44 static  int       rew_sub(enum mdoc_type, struct mdoc *,
45                         int, int, int);
46 static  int       rew_last(struct mdoc *,
47                         const struct mdoc_node *);
48 static  int       append_delims(struct mdoc *, int, int *, char *);
49 static  int       lookup(int, const char *);
50 static  int       lookup_raw(const char *);
51 static  int       swarn(struct mdoc *, enum mdoc_type, int, int,
52                         const struct mdoc_node *);
53
54 /* Central table of library: who gets parsed how. */
55
56 const   struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
57         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */
58         { in_line_eoln, MDOC_PROLOGUE }, /* Dd */
59         { in_line_eoln, MDOC_PROLOGUE }, /* Dt */
60         { in_line_eoln, MDOC_PROLOGUE }, /* Os */
61         { blk_full, 0 }, /* Sh */
62         { blk_full, 0 }, /* Ss */
63         { in_line_eoln, 0 }, /* Pp */
64         { blk_part_imp, MDOC_PARSED }, /* D1 */
65         { blk_part_imp, MDOC_PARSED }, /* Dl */
66         { blk_full, MDOC_EXPLICIT }, /* Bd */
67         { blk_exp_close, MDOC_EXPLICIT }, /* Ed */
68         { blk_full, MDOC_EXPLICIT }, /* Bl */
69         { blk_exp_close, MDOC_EXPLICIT }, /* El */
70         { blk_full, MDOC_PARSED }, /* It */
71         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
72         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* An */
73         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
74         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cd */
75         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
76         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
77         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
78         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
79         { in_line_eoln, 0 }, /* Ex */
80         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
81         { in_line_eoln, 0 }, /* Fd */
82         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
83         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
84         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */
85         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
86         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */
87         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
88         { blk_full, 0 }, /* Nd */
89         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
90         { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
91         { obsolete, 0 }, /* Ot */
92         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
93         { in_line_eoln, 0 }, /* Rv */
94         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
95         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
96         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
97         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
98         { in_line_eoln, 0 }, /* %A */
99         { in_line_eoln, 0 }, /* %B */
100         { in_line_eoln, 0 }, /* %D */
101         { in_line_eoln, 0 }, /* %I */
102         { in_line_eoln, 0 }, /* %J */
103         { in_line_eoln, 0 }, /* %N */
104         { in_line_eoln, 0 }, /* %O */
105         { in_line_eoln, 0 }, /* %P */
106         { in_line_eoln, 0 }, /* %R */
107         { in_line_eoln, 0 }, /* %T */
108         { in_line_eoln, 0 }, /* %V */
109         { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
110         { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */
111         { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
112         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */
113         { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
114         { blk_full, MDOC_EXPLICIT }, /* Bf */
115         { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */
116         { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */
117         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */
118         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */
119         { in_line_eoln, 0 }, /* Db */
120         { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
121         { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */
122         { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
123         { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
124         { blk_exp_close, MDOC_EXPLICIT }, /* Ef */
125         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */
126         { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
127         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */
128         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */
129         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* No */
130         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ns */
131         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
132         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */
133         { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
134         { in_line_argn, MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */
135         { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */
136         { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
137         { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
138         { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
139         { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */
140         { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
141         { blk_exp_close, MDOC_EXPLICIT }, /* Re */
142         { blk_full, MDOC_EXPLICIT }, /* Rs */
143         { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
144         { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */
145         { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */
146         { in_line_eoln, 0 }, /* Sm */
147         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */
148         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */
149         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
150         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ux */
151         { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
152         { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
153         { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */
154         { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */
155         { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */
156         { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
157         { blk_full, MDOC_EXPLICIT }, /* Bk */
158         { blk_exp_close, MDOC_EXPLICIT }, /* Ek */
159         { in_line_eoln, 0 }, /* Bt */
160         { in_line_eoln, 0 }, /* Hf */
161         { obsolete, 0 }, /* Fr */
162         { in_line_eoln, 0 }, /* Ud */
163         { in_line_eoln, 0 }, /* Lb */
164         { in_line_eoln, 0 }, /* Lp */
165         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */
166         { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */
167         { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */
168         { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */
169         { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */
170         { in_line_eoln, 0 }, /* %C */
171         { obsolete, 0 }, /* Es */
172         { obsolete, 0 }, /* En */
173         { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
174         { in_line_eoln, 0 }, /* %Q */
175         { in_line_eoln, 0 }, /* br */
176         { in_line_eoln, 0 }, /* sp */
177 };
178
179 const   struct mdoc_macro * const mdoc_macros = __mdoc_macros;
180
181
182 static int
183 swarn(struct mdoc *mdoc, enum mdoc_type type,
184                 int line, int pos, const struct mdoc_node *p)
185 {
186         const char      *n, *t, *tt;
187
188         n = t = "<root>";
189         tt = "block";
190
191         switch (type) {
192         case (MDOC_BODY):
193                 tt = "multi-line";
194                 break;
195         case (MDOC_HEAD):
196                 tt = "line";
197                 break;
198         default:
199                 break;
200         }
201
202         switch (p->type) {
203         case (MDOC_BLOCK):
204                 n = mdoc_macronames[p->tok];
205                 t = "block";
206                 break;
207         case (MDOC_BODY):
208                 n = mdoc_macronames[p->tok];
209                 t = "multi-line";
210                 break;
211         case (MDOC_HEAD):
212                 n = mdoc_macronames[p->tok];
213                 t = "line";
214                 break;
215         default:
216                 break;
217         }
218
219         if ( ! (MDOC_IGN_SCOPE & mdoc->pflags))
220                 return(mdoc_verr(mdoc, line, pos,
221                                 "%s scope breaks %s scope of %s",
222                                 tt, t, n));
223         return(mdoc_vwarn(mdoc, line, pos,
224                                 "%s scope breaks %s scope of %s",
225                                 tt, t, n));
226 }
227
228
229 /*
230  * This is called at the end of parsing.  It must traverse up the tree,
231  * closing out open [implicit] scopes.  Obviously, open explicit scopes
232  * are errors.
233  */
234 int
235 mdoc_macroend(struct mdoc *m)
236 {
237         struct mdoc_node *n;
238
239         /* Scan for open explicit scopes. */
240
241         n = MDOC_VALID & m->last->flags ?  m->last->parent : m->last;
242
243         for ( ; n; n = n->parent) {
244                 if (MDOC_BLOCK != n->type)
245                         continue;
246                 if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
247                         continue;
248                 return(mdoc_nerr(m, n, EOPEN));
249         }
250
251         /* Rewind to the first. */
252
253         return(rew_last(m, m->first));
254 }
255
256
257 /*
258  * Look up a macro from within a subsequent context.
259  */
260 static int
261 lookup(int from, const char *p)
262 {
263         /* FIXME: make -diag lists be un-PARSED. */
264
265         if ( ! (MDOC_PARSED & mdoc_macros[from].flags))
266                 return(MDOC_MAX);
267         return(lookup_raw(p));
268 }
269
270
271 /*
272  * Lookup a macro following the initial line macro.
273  */
274 static int
275 lookup_raw(const char *p)
276 {
277         int              res;
278
279         if (MDOC_MAX == (res = mdoc_hash_find(p)))
280                 return(MDOC_MAX);
281         if (MDOC_CALLABLE & mdoc_macros[res].flags)
282                 return(res);
283         return(MDOC_MAX);
284 }
285
286
287 static int
288 rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
289 {
290
291         assert(to);
292         mdoc->next = MDOC_NEXT_SIBLING;
293
294         /* LINTED */
295         while (mdoc->last != to) {
296                 if ( ! mdoc_valid_post(mdoc))
297                         return(0);
298                 if ( ! mdoc_action_post(mdoc))
299                         return(0);
300                 mdoc->last = mdoc->last->parent;
301                 assert(mdoc->last);
302         }
303
304         if ( ! mdoc_valid_post(mdoc))
305                 return(0);
306         return(mdoc_action_post(mdoc));
307 }
308
309
310 /*
311  * Return the opening macro of a closing one, e.g., `Ec' has `Eo' as its
312  * matching pair.
313  */
314 static int
315 rew_alt(int tok)
316 {
317         switch (tok) {
318         case (MDOC_Ac):
319                 return(MDOC_Ao);
320         case (MDOC_Bc):
321                 return(MDOC_Bo);
322         case (MDOC_Brc):
323                 return(MDOC_Bro);
324         case (MDOC_Dc):
325                 return(MDOC_Do);
326         case (MDOC_Ec):
327                 return(MDOC_Eo);
328         case (MDOC_Ed):
329                 return(MDOC_Bd);
330         case (MDOC_Ef):
331                 return(MDOC_Bf);
332         case (MDOC_Ek):
333                 return(MDOC_Bk);
334         case (MDOC_El):
335                 return(MDOC_Bl);
336         case (MDOC_Fc):
337                 return(MDOC_Fo);
338         case (MDOC_Oc):
339                 return(MDOC_Oo);
340         case (MDOC_Pc):
341                 return(MDOC_Po);
342         case (MDOC_Qc):
343                 return(MDOC_Qo);
344         case (MDOC_Re):
345                 return(MDOC_Rs);
346         case (MDOC_Sc):
347                 return(MDOC_So);
348         case (MDOC_Xc):
349                 return(MDOC_Xo);
350         default:
351                 break;
352         }
353         abort();
354         /* NOTREACHED */
355 }
356
357
358 /*
359  * Rewind rules.  This indicates whether to stop rewinding
360  * (REWIND_HALT) without touching our current scope, stop rewinding and
361  * close our current scope (REWIND_REWIND), or continue (REWIND_NOHALT).
362  * The scope-closing and so on occurs in the various rew_* routines.
363  */
364 static int
365 rew_dohalt(int tok, enum mdoc_type type, const struct mdoc_node *p)
366 {
367
368         if (MDOC_ROOT == p->type)
369                 return(REWIND_HALT);
370         if (MDOC_VALID & p->flags)
371                 return(REWIND_NOHALT);
372
373         switch (tok) {
374         case (MDOC_Aq):
375                 /* FALLTHROUGH */
376         case (MDOC_Bq):
377                 /* FALLTHROUGH */
378         case (MDOC_Brq):
379                 /* FALLTHROUGH */
380         case (MDOC_D1):
381                 /* FALLTHROUGH */
382         case (MDOC_Dl):
383                 /* FALLTHROUGH */
384         case (MDOC_Dq):
385                 /* FALLTHROUGH */
386         case (MDOC_Op):
387                 /* FALLTHROUGH */
388         case (MDOC_Pq):
389                 /* FALLTHROUGH */
390         case (MDOC_Ql):
391                 /* FALLTHROUGH */
392         case (MDOC_Qq):
393                 /* FALLTHROUGH */
394         case (MDOC_Sq):
395                 assert(MDOC_TAIL != type);
396                 if (type == p->type && tok == p->tok)
397                         return(REWIND_REWIND);
398                 break;
399         case (MDOC_It):
400                 assert(MDOC_TAIL != type);
401                 if (type == p->type && tok == p->tok)
402                         return(REWIND_REWIND);
403                 if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
404                         return(REWIND_HALT);
405                 break;
406         case (MDOC_Sh):
407                 if (type == p->type && tok == p->tok)
408                         return(REWIND_REWIND);
409                 break;
410         case (MDOC_Nd):
411                 /* FALLTHROUGH */
412         case (MDOC_Ss):
413                 assert(MDOC_TAIL != type);
414                 if (type == p->type && tok == p->tok)
415                         return(REWIND_REWIND);
416                 if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
417                         return(REWIND_HALT);
418                 break;
419         case (MDOC_Ao):
420                 /* FALLTHROUGH */
421         case (MDOC_Bd):
422                 /* FALLTHROUGH */
423         case (MDOC_Bf):
424                 /* FALLTHROUGH */
425         case (MDOC_Bk):
426                 /* FALLTHROUGH */
427         case (MDOC_Bl):
428                 /* FALLTHROUGH */
429         case (MDOC_Bo):
430                 /* FALLTHROUGH */
431         case (MDOC_Bro):
432                 /* FALLTHROUGH */
433         case (MDOC_Do):
434                 /* FALLTHROUGH */
435         case (MDOC_Eo):
436                 /* FALLTHROUGH */
437         case (MDOC_Fo):
438                 /* FALLTHROUGH */
439         case (MDOC_Oo):
440                 /* FALLTHROUGH */
441         case (MDOC_Po):
442                 /* FALLTHROUGH */
443         case (MDOC_Qo):
444                 /* FALLTHROUGH */
445         case (MDOC_Rs):
446                 /* FALLTHROUGH */
447         case (MDOC_So):
448                 /* FALLTHROUGH */
449         case (MDOC_Xo):
450                 if (type == p->type && tok == p->tok)
451                         return(REWIND_REWIND);
452                 break;
453         /* Multi-line explicit scope close. */
454         case (MDOC_Ac):
455                 /* FALLTHROUGH */
456         case (MDOC_Bc):
457                 /* FALLTHROUGH */
458         case (MDOC_Brc):
459                 /* FALLTHROUGH */
460         case (MDOC_Dc):
461                 /* FALLTHROUGH */
462         case (MDOC_Ec):
463                 /* FALLTHROUGH */
464         case (MDOC_Ed):
465                 /* FALLTHROUGH */
466         case (MDOC_Ek):
467                 /* FALLTHROUGH */
468         case (MDOC_El):
469                 /* FALLTHROUGH */
470         case (MDOC_Fc):
471                 /* FALLTHROUGH */
472         case (MDOC_Ef):
473                 /* FALLTHROUGH */
474         case (MDOC_Oc):
475                 /* FALLTHROUGH */
476         case (MDOC_Pc):
477                 /* FALLTHROUGH */
478         case (MDOC_Qc):
479                 /* FALLTHROUGH */
480         case (MDOC_Re):
481                 /* FALLTHROUGH */
482         case (MDOC_Sc):
483                 /* FALLTHROUGH */
484         case (MDOC_Xc):
485                 if (type == p->type && rew_alt(tok) == p->tok)
486                         return(REWIND_REWIND);
487                 break;
488         default:
489                 abort();
490                 /* NOTREACHED */
491         }
492
493         return(REWIND_NOHALT);
494 }
495
496
497 /*
498  * See if we can break an encountered scope (the rew_dohalt has returned
499  * REWIND_NOHALT).
500  */
501 static int
502 rew_dobreak(int tok, const struct mdoc_node *p)
503 {
504
505         assert(MDOC_ROOT != p->type);
506         if (MDOC_ELEM == p->type)
507                 return(1);
508         if (MDOC_TEXT == p->type)
509                 return(1);
510         if (MDOC_VALID & p->flags)
511                 return(1);
512
513         switch (tok) {
514         case (MDOC_It):
515                 return(MDOC_It == p->tok);
516         case (MDOC_Nd):
517                 return(MDOC_Nd == p->tok);
518         case (MDOC_Ss):
519                 return(MDOC_Ss == p->tok);
520         case (MDOC_Sh):
521                 if (MDOC_Nd == p->tok)
522                         return(1);
523                 if (MDOC_Ss == p->tok)
524                         return(1);
525                 return(MDOC_Sh == p->tok);
526         case (MDOC_El):
527                 if (MDOC_It == p->tok)
528                         return(1);
529                 break;
530         case (MDOC_Oc):
531                 /* XXX - experimental! */
532                 if (MDOC_Op == p->tok)
533                         return(1);
534                 break;
535         default:
536                 break;
537         }
538
539         if (MDOC_EXPLICIT & mdoc_macros[tok].flags)
540                 return(p->tok == rew_alt(tok));
541         else if (MDOC_BLOCK == p->type)
542                 return(1);
543
544         return(tok == p->tok);
545 }
546
547
548 static int
549 rew_elem(struct mdoc *mdoc, int tok)
550 {
551         struct mdoc_node *n;
552
553         n = mdoc->last;
554         if (MDOC_ELEM != n->type)
555                 n = n->parent;
556         assert(MDOC_ELEM == n->type);
557         assert(tok == n->tok);
558
559         return(rew_last(mdoc, n));
560 }
561
562
563 static int
564 rew_sub(enum mdoc_type t, struct mdoc *m,
565                 int tok, int line, int ppos)
566 {
567         struct mdoc_node *n;
568         int               c;
569
570         /* LINTED */
571         for (n = m->last; n; n = n->parent) {
572                 c = rew_dohalt(tok, t, n);
573                 if (REWIND_HALT == c) {
574                         if (MDOC_BLOCK != t)
575                                 return(1);
576                         if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags))
577                                 return(1);
578                         return(mdoc_perr(m, line, ppos, ENOCTX));
579                 }
580                 if (REWIND_REWIND == c)
581                         break;
582                 else if (rew_dobreak(tok, n))
583                         continue;
584                 if ( ! swarn(m, t, line, ppos, n))
585                         return(0);
586         }
587
588         assert(n);
589         return(rew_last(m, n));
590 }
591
592
593 static int
594 append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
595 {
596         int              c, lastarg;
597         char            *p;
598
599         if (0 == buf[*pos])
600                 return(1);
601
602         for (;;) {
603                 lastarg = *pos;
604                 c = mdoc_zargs(mdoc, line, pos, buf, ARGS_NOWARN, &p);
605                 assert(ARGS_PHRASE != c);
606
607                 if (ARGS_ERROR == c)
608                         return(0);
609                 else if (ARGS_EOLN == c)
610                         break;
611                 assert(mdoc_isdelim(p));
612                 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
613                         return(0);
614         }
615
616         return(1);
617 }
618
619
620 /*
621  * Close out block partial/full explicit.
622  */
623 static int
624 blk_exp_close(MACRO_PROT_ARGS)
625 {
626         int              j, c, lastarg, maxargs, flushed;
627         char            *p;
628
629         switch (tok) {
630         case (MDOC_Ec):
631                 maxargs = 1;
632                 break;
633         default:
634                 maxargs = 0;
635                 break;
636         }
637
638         if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
639                 if (buf[*pos])
640                         if ( ! mdoc_pwarn(m, line, ppos, ENOLINE))
641                                 return(0);
642
643                 if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
644                         return(0);
645                 return(rew_sub(MDOC_BLOCK, m, tok, line, ppos));
646         }
647
648         if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
649                 return(0);
650
651         if (maxargs > 0)
652                 if ( ! mdoc_tail_alloc(m, line, ppos, rew_alt(tok)))
653                         return(0);
654
655         for (flushed = j = 0; ; j++) {
656                 lastarg = *pos;
657
658                 if (j == maxargs && ! flushed) {
659                         if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
660                                 return(0);
661                         flushed = 1;
662                 }
663
664                 c = mdoc_args(m, line, pos, buf, tok, &p);
665
666                 if (ARGS_ERROR == c)
667                         return(0);
668                 if (ARGS_PUNCT == c)
669                         break;
670                 if (ARGS_EOLN == c)
671                         break;
672
673                 if (MDOC_MAX != (c = lookup(tok, p))) {
674                         if ( ! flushed) {
675                                 if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
676                                         return(0);
677                                 flushed = 1;
678                         }
679                         if ( ! mdoc_macro(m, c, line, lastarg, pos, buf))
680                                 return(0);
681                         break;
682                 }
683
684                 if ( ! mdoc_word_alloc(m, line, lastarg, p))
685                         return(0);
686         }
687
688         if ( ! flushed && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
689                 return(0);
690
691         if (ppos > 1)
692                 return(1);
693         return(append_delims(m, line, pos, buf));
694 }
695
696
697 static int
698 in_line(MACRO_PROT_ARGS)
699 {
700         int               la, lastpunct, c, w, cnt, d, nc;
701         struct mdoc_arg  *arg;
702         char             *p;
703
704         /*
705          * Whether we allow ignored elements (those without content,
706          * usually because of reserved words) to squeak by.
707          */
708         switch (tok) {
709         case (MDOC_An):
710                 /* FALLTHROUGH */
711         case (MDOC_Ar):
712                 /* FALLTHROUGH */
713         case (MDOC_Fl):
714                 /* FALLTHROUGH */
715         case (MDOC_Lk):
716                 /* FALLTHROUGH */
717         case (MDOC_Nm):
718                 /* FALLTHROUGH */
719         case (MDOC_Pa):
720                 nc = 1;
721                 break;
722         default:
723                 nc = 0;
724                 break;
725         }
726
727         for (arg = NULL;; ) {
728                 la = *pos;
729                 c = mdoc_argv(m, line, tok, &arg, pos, buf);
730
731                 if (ARGV_WORD == c) {
732                         *pos = la;
733                         break;
734                 }
735                 if (ARGV_EOLN == c)
736                         break;
737                 if (ARGV_ARG == c)
738                         continue;
739
740                 mdoc_argv_free(arg);
741                 return(0);
742         }
743
744         for (cnt = 0, lastpunct = 1;; ) {
745                 la = *pos;
746                 w = mdoc_args(m, line, pos, buf, tok, &p);
747
748                 if (ARGS_ERROR == w)
749                         return(0);
750                 if (ARGS_EOLN == w)
751                         break;
752                 if (ARGS_PUNCT == w)
753                         break;
754
755                 /* Quoted words shouldn't be looked-up. */
756
757                 c = ARGS_QWORD == w ? MDOC_MAX : lookup(tok, p);
758
759                 /*
760                  * In this case, we've located a submacro and must
761                  * execute it.  Close out scope, if open.  If no
762                  * elements have been generated, either create one (nc)
763                  * or raise a warning.
764                  */
765
766                 if (MDOC_MAX != c) {
767                         if (0 == lastpunct && ! rew_elem(m, tok))
768                                 return(0);
769                         if (nc && 0 == cnt) {
770                                 if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
771                                         return(0);
772                                 if ( ! rew_last(m, m->last))
773                                         return(0);
774                         } else if ( ! nc && 0 == cnt) {
775                                 mdoc_argv_free(arg);
776                                 if ( ! mdoc_pwarn(m, line, ppos, EIGNE))
777                                         return(0);
778                         }
779                         c = mdoc_macro(m, c, line, la, pos, buf);
780                         if (0 == c)
781                                 return(0);
782                         if (ppos > 1)
783                                 return(1);
784                         return(append_delims(m, line, pos, buf));
785                 }
786
787                 /*
788                  * Non-quote-enclosed punctuation.  Set up our scope, if
789                  * a word; rewind the scope, if a delimiter; then append
790                  * the word.
791                  */
792
793                 d = mdoc_isdelim(p);
794
795                 if (ARGS_QWORD != w && d) {
796                         if (0 == lastpunct && ! rew_elem(m, tok))
797                                 return(0);
798                         lastpunct = 1;
799                 } else if (lastpunct) {
800                         if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
801                                 return(0);
802                         lastpunct = 0;
803                 }
804
805                 if ( ! d)
806                         cnt++;
807                 if ( ! mdoc_word_alloc(m, line, la, p))
808                         return(0);
809         }
810
811         if (0 == lastpunct && ! rew_elem(m, tok))
812                 return(0);
813
814         /*
815          * If no elements have been collected and we're allowed to have
816          * empties (nc), open a scope and close it out.  Otherwise,
817          * raise a warning.
818          *
819          */
820         if (nc && 0 == cnt) {
821                 if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
822                         return(0);
823                 if ( ! rew_last(m, m->last))
824                         return(0);
825         } else if ( ! nc && 0 == cnt) {
826                 mdoc_argv_free(arg);
827                 if ( ! mdoc_pwarn(m, line, ppos, EIGNE))
828                         return(0);
829         }
830
831         if (ppos > 1)
832                 return(1);
833         return(append_delims(m, line, pos, buf));
834 }
835
836
837 static int
838 blk_full(MACRO_PROT_ARGS)
839 {
840         int               c, lastarg, reopen, dohead;
841         struct mdoc_arg  *arg;
842         char             *p;
843
844         /*
845          * Whether to process a block-head section.  If this is
846          * non-zero, then a head will be opened for all line arguments.
847          * If not, then the head will always be empty and only a body
848          * will be opened, which will stay open at the eoln.
849          */
850
851         switch (tok) {
852         case (MDOC_Nd):
853                 dohead = 0;
854                 break;
855         default:
856                 dohead = 1;
857                 break;
858         }
859
860         if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
861                 if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
862                         return(0);
863                 if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
864                         return(0);
865         }
866
867         for (arg = NULL;; ) {
868                 lastarg = *pos;
869                 c = mdoc_argv(m, line, tok, &arg, pos, buf);
870
871                 if (ARGV_WORD == c) {
872                         *pos = lastarg;
873                         break;
874                 }
875
876                 if (ARGV_EOLN == c)
877                         break;
878                 if (ARGV_ARG == c)
879                         continue;
880
881                 mdoc_argv_free(arg);
882                 return(0);
883         }
884
885         if ( ! mdoc_block_alloc(m, line, ppos, tok, arg))
886                 return(0);
887
888         if (0 == buf[*pos]) {
889                 if ( ! mdoc_head_alloc(m, line, ppos, tok))
890                         return(0);
891                 if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
892                         return(0);
893                 if ( ! mdoc_body_alloc(m, line, ppos, tok))
894                         return(0);
895                 return(1);
896         }
897
898         if ( ! mdoc_head_alloc(m, line, ppos, tok))
899                 return(0);
900
901         /* Immediately close out head and enter body, if applicable. */
902
903         if (0 == dohead) {
904                 if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
905                         return(0);
906                 if ( ! mdoc_body_alloc(m, line, ppos, tok))
907                         return(0);
908         }
909
910         for (reopen = 0;; ) {
911                 lastarg = *pos;
912                 c = mdoc_args(m, line, pos, buf, tok, &p);
913
914                 if (ARGS_ERROR == c)
915                         return(0);
916                 if (ARGS_EOLN == c)
917                         break;
918                 if (ARGS_PHRASE == c) {
919                         assert(dohead);
920                         if (reopen && ! mdoc_head_alloc(m, line, ppos, tok))
921                                 return(0);
922                         /*
923                          * Phrases are self-contained macro phrases used
924                          * in the columnar output of a macro. They need
925                          * special handling.
926                          */
927                         if ( ! phrase(m, line, lastarg, buf))
928                                 return(0);
929                         if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
930                                 return(0);
931
932                         reopen = 1;
933                         continue;
934                 }
935
936                 if (MDOC_MAX == (c = lookup(tok, p))) {
937                         if ( ! mdoc_word_alloc(m, line, lastarg, p))
938                                 return(0);
939                         continue;
940                 }
941
942                 if ( ! mdoc_macro(m, c, line, lastarg, pos, buf))
943                         return(0);
944                 break;
945         }
946
947         if (1 == ppos && ! append_delims(m, line, pos, buf))
948                 return(0);
949
950         /* If the body's already open, then just return. */
951         if (0 == dohead)
952                 return(1);
953
954         if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
955                 return(0);
956         if ( ! mdoc_body_alloc(m, line, ppos, tok))
957                 return(0);
958
959         return(1);
960 }
961
962
963 static int
964 blk_part_imp(MACRO_PROT_ARGS)
965 {
966         int               la, c;
967         char             *p;
968         struct mdoc_node *blk, *body, *n;
969
970         /* If applicable, close out prior scopes. */
971
972         if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
973                 return(0);
974         /* Saved for later close-out. */
975         blk = m->last;
976         if ( ! mdoc_head_alloc(m, line, ppos, tok))
977                 return(0);
978         if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
979                 return(0);
980         if ( ! mdoc_body_alloc(m, line, ppos, tok))
981                 return(0);
982         /* Saved for later close-out. */
983         body = m->last;
984
985         /* Body argument processing. */
986
987         for (;;) {
988                 la = *pos;
989                 c = mdoc_args(m, line, pos, buf, tok, &p);
990                 assert(ARGS_PHRASE != c);
991
992                 if (ARGS_ERROR == c)
993                         return(0);
994                 if (ARGS_PUNCT == c)
995                         break;
996                 if (ARGS_EOLN == c)
997                         break;
998
999                 if (MDOC_MAX == (c = lookup(tok, p))) {
1000                         if ( ! mdoc_word_alloc(m, line, la, p))
1001                                 return(0);
1002                         continue;
1003                 }
1004
1005                 if ( ! mdoc_macro(m, c, line, la, pos, buf))
1006                         return(0);
1007                 break;
1008         }
1009
1010         /*
1011          * If we can't rewind to our body, then our scope has already
1012          * been closed by another macro (like `Oc' closing `Op').  This
1013          * is ugly behaviour nodding its head to OpenBSD's overwhelming
1014          * crufty use of `Op' breakage--XXX, deprecate in time.
1015          */
1016         for (n = m->last; n; n = n->parent)
1017                 if (body == n)
1018                         break;
1019         if (NULL == n && ! mdoc_nwarn(m, body, EIMPBRK))
1020                 return(0);
1021         if (n && ! rew_last(m, body))
1022                 return(0);
1023
1024         /* Standard appending of delimiters. */
1025
1026         if (1 == ppos && ! append_delims(m, line, pos, buf))
1027                 return(0);
1028
1029         /* Rewind scope, if applicable. */
1030
1031         if (n && ! rew_last(m, blk))
1032                 return(0);
1033
1034         return(1);
1035 }
1036
1037
1038 static int
1039 blk_part_exp(MACRO_PROT_ARGS)
1040 {
1041         int               la, flushed, j, c, maxargs;
1042         char             *p;
1043
1044         /* Number of head arguments.  Only `Eo' has these, */
1045
1046         switch (tok) {
1047         case (MDOC_Eo):
1048                 maxargs = 1;
1049                 break;
1050         default:
1051                 maxargs = 0;
1052                 break;
1053         }
1054
1055         /* Begin the block scope. */
1056
1057         if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
1058                 return(0);
1059
1060         /*
1061          * If no head arguments, open and then close out a head, noting
1062          * that we've flushed our terms.  `flushed' means that we've
1063          * flushed out the head and the body is open.
1064          */
1065
1066         if (0 == maxargs) {
1067                 if ( ! mdoc_head_alloc(m, line, ppos, tok))
1068                         return(0);
1069                 if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1070                         return(0);
1071                 if ( ! mdoc_body_alloc(m, line, ppos, tok))
1072                         return(0);
1073                 flushed = 1;
1074         } else {
1075                 if ( ! mdoc_head_alloc(m, line, ppos, tok))
1076                         return(0);
1077                 flushed = 0;
1078         }
1079
1080         /* Process the head/head+body line arguments. */
1081
1082         for (j = 0; ; j++) {
1083                 la = *pos;
1084                 if (j == maxargs && ! flushed) {
1085                         if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1086                                 return(0);
1087                         flushed = 1;
1088                         if ( ! mdoc_body_alloc(m, line, ppos, tok))
1089                                 return(0);
1090                 }
1091
1092                 c = mdoc_args(m, line, pos, buf, tok, &p);
1093                 assert(ARGS_PHRASE != c);
1094
1095                 if (ARGS_ERROR == c)
1096                         return(0);
1097                 if (ARGS_PUNCT == c)
1098                         break;
1099                 if (ARGS_EOLN == c)
1100                         break;
1101
1102                 if (MDOC_MAX != (c = lookup(tok, p))) {
1103                         if ( ! flushed) {
1104                                 if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1105                                         return(0);
1106                                 flushed = 1;
1107                                 if ( ! mdoc_body_alloc(m, line, ppos, tok))
1108                                         return(0);
1109                         }
1110                         if ( ! mdoc_macro(m, c, line, la, pos, buf))
1111                                 return(0);
1112                         break;
1113                 }
1114
1115                 if ( ! flushed && mdoc_isdelim(p)) {
1116                         if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1117                                 return(0);
1118                         flushed = 1;
1119                         if ( ! mdoc_body_alloc(m, line, ppos, tok))
1120                                 return(0);
1121                 }
1122
1123                 if ( ! mdoc_word_alloc(m, line, la, p))
1124                         return(0);
1125         }
1126
1127         /* Close the head and open the body, if applicable. */
1128
1129         if ( ! flushed) {
1130                 if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1131                         return(0);
1132                 if ( ! mdoc_body_alloc(m, line, ppos, tok))
1133                         return(0);
1134         }
1135
1136         /* Standard appending of delimiters. */
1137
1138         if (ppos > 1)
1139                 return(1);
1140         return(append_delims(m, line, pos, buf));
1141 }
1142
1143
1144 static int
1145 in_line_argn(MACRO_PROT_ARGS)
1146 {
1147         int               la, flushed, j, c, maxargs;
1148         struct mdoc_arg  *arg;
1149         char             *p;
1150
1151         /* Fixed maximum arguments per macro, if applicable. */
1152
1153         switch (tok) {
1154         case (MDOC_Ap):
1155                 /* FALLTHROUGH */
1156         case (MDOC_No):
1157                 /* FALLTHROUGH */
1158         case (MDOC_Ns):
1159                 /* FALLTHROUGH */
1160         case (MDOC_Ux):
1161                 maxargs = 0;
1162                 break;
1163         default:
1164                 maxargs = 1;
1165                 break;
1166         }
1167
1168         /* Macro argument processing. */
1169
1170         for (arg = NULL;; ) {
1171                 la = *pos;
1172                 c = mdoc_argv(m, line, tok, &arg, pos, buf);
1173
1174                 if (ARGV_WORD == c) {
1175                         *pos = la;
1176                         break;
1177                 }
1178
1179                 if (ARGV_EOLN == c)
1180                         break;
1181                 if (ARGV_ARG == c)
1182                         continue;
1183
1184                 mdoc_argv_free(arg);
1185                 return(0);
1186         }
1187
1188         /* Open the element scope. */
1189
1190         if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
1191                 return(0);
1192
1193         /* Process element arguments. */
1194
1195         for (flushed = j = 0; ; j++) {
1196                 la = *pos;
1197
1198                 if (j == maxargs && ! flushed) {
1199                         if ( ! rew_elem(m, tok))
1200                                 return(0);
1201                         flushed = 1;
1202                 }
1203
1204                 c = mdoc_args(m, line, pos, buf, tok, &p);
1205
1206                 if (ARGS_ERROR == c)
1207                         return(0);
1208                 if (ARGS_PUNCT == c)
1209                         break;
1210                 if (ARGS_EOLN == c)
1211                         break;
1212
1213                 if (MDOC_MAX != (c = lookup(tok, p))) {
1214                         if ( ! flushed && ! rew_elem(m, tok))
1215                                 return(0);
1216                         flushed = 1;
1217                         if ( ! mdoc_macro(m, c, line, la, pos, buf))
1218                                 return(0);
1219                         break;
1220                 }
1221
1222                 if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1223                                 ! flushed && mdoc_isdelim(p)) {
1224                         if ( ! rew_elem(m, tok))
1225                                 return(0);
1226                         flushed = 1;
1227                 }
1228
1229                 if ( ! mdoc_word_alloc(m, line, la, p))
1230                         return(0);
1231         }
1232
1233         /* Close out and append delimiters. */
1234
1235         if ( ! flushed && ! rew_elem(m, tok))
1236                 return(0);
1237
1238         if (ppos > 1)
1239                 return(1);
1240         return(append_delims(m, line, pos, buf));
1241 }
1242
1243
1244 static int
1245 in_line_eoln(MACRO_PROT_ARGS)
1246 {
1247         int               c, w, la;
1248         struct mdoc_arg  *arg;
1249         char             *p;
1250
1251         assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
1252
1253         /* Parse macro arguments. */
1254
1255         for (arg = NULL; ; ) {
1256                 la = *pos;
1257                 c = mdoc_argv(m, line, tok, &arg, pos, buf);
1258
1259                 if (ARGV_WORD == c) {
1260                         *pos = la;
1261                         break;
1262                 }
1263                 if (ARGV_EOLN == c)
1264                         break;
1265                 if (ARGV_ARG == c)
1266                         continue;
1267
1268                 mdoc_argv_free(arg);
1269                 return(0);
1270         }
1271
1272         /* Open element scope. */
1273
1274         if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
1275                 return(0);
1276
1277         /* Parse argument terms. */
1278
1279         for (;;) {
1280                 la = *pos;
1281                 w = mdoc_args(m, line, pos, buf, tok, &p);
1282
1283                 if (ARGS_ERROR == w)
1284                         return(0);
1285                 if (ARGS_EOLN == w)
1286                         break;
1287
1288                 c = ARGS_QWORD == w ? MDOC_MAX : lookup(tok, p);
1289
1290                 if (MDOC_MAX != c) {
1291                         if ( ! rew_elem(m, tok))
1292                                 return(0);
1293                         return(mdoc_macro(m, c, line, la, pos, buf));
1294                 }
1295
1296                 if ( ! mdoc_word_alloc(m, line, la, p))
1297                         return(0);
1298         }
1299
1300         /* Close out (no delimiters). */
1301
1302         return(rew_elem(m, tok));
1303 }
1304
1305
1306 /* ARGSUSED */
1307 static int
1308 obsolete(MACRO_PROT_ARGS)
1309 {
1310
1311         return(mdoc_pwarn(m, line, ppos, EOBS));
1312 }
1313
1314
1315 /*
1316  * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs.
1317  * They're unusual because they're basically free-form text until a
1318  * macro is encountered.
1319  */
1320 static int
1321 phrase(struct mdoc *m, int line, int ppos, char *buf)
1322 {
1323         int               c, w, la, pos;
1324         char             *p;
1325
1326         for (pos = ppos; ; ) {
1327                 la = pos;
1328
1329                 /* Note: no calling context! */
1330                 w = mdoc_zargs(m, line, &pos, buf, 0, &p);
1331
1332                 if (ARGS_ERROR == w)
1333                         return(0);
1334                 if (ARGS_EOLN == w)
1335                         break;
1336
1337                 c = ARGS_QWORD == w ? MDOC_MAX : lookup_raw(p);
1338
1339                 if (MDOC_MAX != c) {
1340                         if ( ! mdoc_macro(m, c, line, la, &pos, buf))
1341                                 return(0);
1342                         return(append_delims(m, line, &pos, buf));
1343                 }
1344
1345                 if ( ! mdoc_word_alloc(m, line, la, p))
1346                         return(0);
1347         }
1348
1349         return(1);
1350 }