[BACK]Return to mdoc_man.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Annotation of mandoc/mdoc_man.c, Revision 1.4

1.4     ! kristaps    1: /*     $Id: mdoc_man.c,v 1.3 2011/09/30 00:13:28 schwarze Exp $ */
1.1       schwarze    2: /*
                      3:  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
                      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 <stdio.h>
                     18: #include <string.h>
                     19:
                     20: #include "mandoc.h"
1.4     ! kristaps   21: #include "man.h"
1.1       schwarze   22: #include "mdoc.h"
                     23: #include "main.h"
                     24:
                     25: static int       need_space = 0;
                     26: static int       need_nl = 0;
                     27:
                     28: #define        DECL_ARGS const struct mdoc_meta *m, \
                     29:                  const struct mdoc_node *n
                     30:
                     31: struct manact {
                     32:        int             (*cond)(DECL_ARGS);
                     33:        int             (*pre)(DECL_ARGS);
                     34:        void            (*post)(DECL_ARGS);
1.2       schwarze   35:        const char       *prefix;
                     36:        const char       *suffix;
1.1       schwarze   37: };
                     38:
                     39: static void      print_word(const char *);
                     40: static void      print_node(DECL_ARGS);
                     41:
                     42: static int       cond_head(DECL_ARGS);
                     43: static int       cond_body(DECL_ARGS);
                     44: static int       pre_enc(DECL_ARGS);
                     45: static void      post_enc(DECL_ARGS);
                     46: static void      post_percent(DECL_ARGS);
1.3       schwarze   47: static int       pre_sect(DECL_ARGS);
                     48: static void      post_sect(DECL_ARGS);
1.1       schwarze   49:
1.3       schwarze   50: static int       pre_ap(DECL_ARGS);
                     51: static int       pre_bd(DECL_ARGS);
                     52: static void      post_bd(DECL_ARGS);
                     53: static int       pre_br(DECL_ARGS);
1.1       schwarze   54: static int       pre_dl(DECL_ARGS);
                     55: static void      post_dl(DECL_ARGS);
                     56: static int       pre_it(DECL_ARGS);
                     57: static int       pre_nm(DECL_ARGS);
                     58: static void      post_nm(DECL_ARGS);
                     59: static int       pre_ns(DECL_ARGS);
1.3       schwarze   60: static void      post_pf(DECL_ARGS);
1.1       schwarze   61: static int       pre_pp(DECL_ARGS);
1.3       schwarze   62: static int       pre_sp(DECL_ARGS);
                     63: static void      post_sp(DECL_ARGS);
1.1       schwarze   64: static int       pre_xr(DECL_ARGS);
                     65:
                     66:
1.3       schwarze   67: static const struct manact manacts[MDOC_MAX + 1] = {
                     68:        { NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
                     69:        { NULL, NULL, NULL, NULL, NULL }, /* Dd */
                     70:        { NULL, NULL, NULL, NULL, NULL }, /* Dt */
1.1       schwarze   71:        { NULL, NULL, NULL, NULL, NULL }, /* _Os */
1.3       schwarze   72:        { NULL, pre_sect, post_sect, ".SH", NULL }, /* Sh */
                     73:        { NULL, pre_sect, post_sect, ".SS", NULL }, /* Ss */
1.1       schwarze   74:        { NULL, pre_pp, NULL, NULL, NULL }, /* Pp */
1.3       schwarze   75:        { cond_body, pre_dl, post_dl, NULL, NULL }, /* D1 */
1.1       schwarze   76:        { cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */
1.3       schwarze   77:        { cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */
                     78:        { NULL, NULL, NULL, NULL, NULL }, /* Ed */
                     79:        { NULL, NULL, NULL, NULL, NULL }, /* Bl */
                     80:        { NULL, NULL, NULL, NULL, NULL }, /* El */
1.1       schwarze   81:        { NULL, pre_it, NULL, NULL, NULL }, /* _It */
                     82:        { NULL, NULL, NULL, NULL, NULL }, /* _Ad */
                     83:        { NULL, NULL, NULL, NULL, NULL }, /* _An */
                     84:        { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ar */
                     85:        { NULL, NULL, NULL, NULL, NULL }, /* _Cd */
                     86:        { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cm */
                     87:        { NULL, NULL, NULL, NULL, NULL }, /* _Dv */
                     88:        { NULL, NULL, NULL, NULL, NULL }, /* _Er */
                     89:        { NULL, NULL, NULL, NULL, NULL }, /* _Ev */
                     90:        { NULL, pre_enc, post_enc, "The \\fB",
                     91:            "\\fP\nutility exits 0 on success, and >0 if an error occurs."
                     92:            }, /* Ex */
                     93:        { NULL, NULL, NULL, NULL, NULL }, /* _Fa */
                     94:        { NULL, NULL, NULL, NULL, NULL }, /* _Fd */
                     95:        { NULL, pre_enc, post_enc, "\\fB-", "\\fP" }, /* Fl */
                     96:        { NULL, NULL, NULL, NULL, NULL }, /* _Fn */
                     97:        { NULL, NULL, NULL, NULL, NULL }, /* _Ft */
1.3       schwarze   98:        { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ic */
1.1       schwarze   99:        { NULL, NULL, NULL, NULL, NULL }, /* _In */
                    100:        { NULL, NULL, NULL, NULL, NULL }, /* _Li */
                    101:        { cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
                    102:        { NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
                    103:        { cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
                    104:        { NULL, NULL, NULL, NULL, NULL }, /* _Ot */
                    105:        { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* _Pa */
                    106:        { NULL, NULL, NULL, NULL, NULL }, /* _Rv */
                    107:        { NULL, NULL, NULL, NULL, NULL }, /* _St */
                    108:        { NULL, NULL, NULL, NULL, NULL }, /* _Va */
                    109:        { NULL, NULL, NULL, NULL, NULL }, /* _Vt */
                    110:        { NULL, pre_xr, NULL, NULL, NULL }, /* _Xr */
                    111:        { NULL, NULL, post_percent, NULL, NULL }, /* _%A */
                    112:        { NULL, NULL, NULL, NULL, NULL }, /* _%B */
                    113:        { NULL, NULL, post_percent, NULL, NULL }, /* _%D */
                    114:        { NULL, NULL, NULL, NULL, NULL }, /* _%I */
                    115:        { NULL, pre_enc, post_percent, "\\fI", "\\fP" }, /* %J */
                    116:        { NULL, NULL, NULL, NULL, NULL }, /* _%N */
                    117:        { NULL, NULL, NULL, NULL, NULL }, /* _%O */
                    118:        { NULL, NULL, NULL, NULL, NULL }, /* _%P */
                    119:        { NULL, NULL, NULL, NULL, NULL }, /* _%R */
                    120:        { NULL, pre_enc, post_percent, "\"", "\"" }, /* %T */
                    121:        { NULL, NULL, NULL, NULL, NULL }, /* _%V */
                    122:        { NULL, NULL, NULL, NULL, NULL }, /* _Ac */
                    123:        { NULL, NULL, NULL, NULL, NULL }, /* _Ao */
                    124:        { cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */
                    125:        { NULL, NULL, NULL, NULL, NULL }, /* _At */
1.3       schwarze  126:        { NULL, NULL, NULL, NULL, NULL }, /* Bc */
1.1       schwarze  127:        { NULL, NULL, NULL, NULL, NULL }, /* _Bf */
1.3       schwarze  128:        { cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */
                    129:        { cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
1.1       schwarze  130:        { NULL, NULL, NULL, NULL, NULL }, /* _Bsx */
                    131:        { NULL, NULL, NULL, NULL, NULL }, /* _Bx */
                    132:        { NULL, NULL, NULL, NULL, NULL }, /* _Db */
                    133:        { NULL, NULL, NULL, NULL, NULL }, /* _Dc */
                    134:        { NULL, NULL, NULL, NULL, NULL }, /* _Do */
                    135:        { cond_body, pre_enc, post_enc, "``", "''" }, /* Dq */
                    136:        { NULL, NULL, NULL, NULL, NULL }, /* _Ec */
                    137:        { NULL, NULL, NULL, NULL, NULL }, /* _Ef */
1.3       schwarze  138:        { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Em */
1.1       schwarze  139:        { NULL, NULL, NULL, NULL, NULL }, /* _Eo */
                    140:        { NULL, NULL, NULL, NULL, NULL }, /* _Fx */
                    141:        { NULL, NULL, NULL, NULL, NULL }, /* _Ms */
                    142:        { NULL, NULL, NULL, NULL, NULL }, /* _No */
                    143:        { NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
                    144:        { NULL, NULL, NULL, NULL, NULL }, /* _Nx */
                    145:        { NULL, NULL, NULL, NULL, NULL }, /* _Ox */
1.3       schwarze  146:        { NULL, NULL, NULL, NULL, NULL }, /* Pc */
                    147:        { NULL, NULL, post_pf, NULL, NULL }, /* Pf */
                    148:        { cond_body, pre_enc, post_enc, "(", ")" }, /* Po */
                    149:        { cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */
1.1       schwarze  150:        { NULL, NULL, NULL, NULL, NULL }, /* _Qc */
                    151:        { cond_body, pre_enc, post_enc, "`", "'" }, /* Ql */
                    152:        { NULL, NULL, NULL, NULL, NULL }, /* _Qo */
                    153:        { NULL, NULL, NULL, NULL, NULL }, /* _Qq */
                    154:        { NULL, NULL, NULL, NULL, NULL }, /* _Re */
                    155:        { cond_body, pre_pp, NULL, NULL, NULL }, /* Rs */
                    156:        { NULL, NULL, NULL, NULL, NULL }, /* _Sc */
                    157:        { NULL, NULL, NULL, NULL, NULL }, /* _So */
                    158:        { cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */
                    159:        { NULL, NULL, NULL, NULL, NULL }, /* _Sm */
1.3       schwarze  160:        { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Sx */
                    161:        { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Sy */
1.1       schwarze  162:        { NULL, NULL, NULL, NULL, NULL }, /* _Tn */
                    163:        { NULL, NULL, NULL, NULL, NULL }, /* _Ux */
                    164:        { NULL, NULL, NULL, NULL, NULL }, /* _Xc */
                    165:        { NULL, NULL, NULL, NULL, NULL }, /* _Xo */
                    166:        { NULL, NULL, NULL, NULL, NULL }, /* _Fo */
                    167:        { NULL, NULL, NULL, NULL, NULL }, /* _Fc */
1.3       schwarze  168:        { cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */
1.1       schwarze  169:        { NULL, NULL, NULL, NULL, NULL }, /* _Oc */
                    170:        { NULL, NULL, NULL, NULL, NULL }, /* _Bk */
                    171:        { NULL, NULL, NULL, NULL, NULL }, /* _Ek */
                    172:        { NULL, NULL, NULL, NULL, NULL }, /* _Bt */
                    173:        { NULL, NULL, NULL, NULL, NULL }, /* _Hf */
                    174:        { NULL, NULL, NULL, NULL, NULL }, /* _Fr */
                    175:        { NULL, NULL, NULL, NULL, NULL }, /* _Ud */
                    176:        { NULL, NULL, NULL, NULL, NULL }, /* _Lb */
1.3       schwarze  177:        { NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
1.1       schwarze  178:        { NULL, NULL, NULL, NULL, NULL }, /* _Lk */
                    179:        { NULL, NULL, NULL, NULL, NULL }, /* _Mt */
                    180:        { NULL, NULL, NULL, NULL, NULL }, /* _Brq */
                    181:        { NULL, NULL, NULL, NULL, NULL }, /* _Bro */
                    182:        { NULL, NULL, NULL, NULL, NULL }, /* _Brc */
                    183:        { NULL, NULL, NULL, NULL, NULL }, /* _%C */
                    184:        { NULL, NULL, NULL, NULL, NULL }, /* _Es */
                    185:        { NULL, NULL, NULL, NULL, NULL }, /* _En */
                    186:        { NULL, NULL, NULL, NULL, NULL }, /* _Dx */
                    187:        { NULL, NULL, NULL, NULL, NULL }, /* _%Q */
1.3       schwarze  188:        { NULL, pre_br, NULL, NULL, NULL }, /* br */
                    189:        { NULL, pre_sp, post_sp, NULL, NULL }, /* sp */
1.1       schwarze  190:        { NULL, NULL, NULL, NULL, NULL }, /* _%U */
                    191:        { NULL, NULL, NULL, NULL, NULL }, /* _Ta */
1.3       schwarze  192:        { NULL, NULL, NULL, NULL, NULL }, /* ROOT */
1.1       schwarze  193: };
                    194:
                    195:
                    196: static void
                    197: print_word(const char *s)
                    198: {
                    199:        if (need_nl) {
                    200:                putchar('\n');
                    201:                need_space = 0;
                    202:                need_nl = 0;
                    203:        } else if (need_space &&
                    204:            (NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]))
                    205:                putchar(' ');
                    206:        need_space = ('(' != s[0] && '[' != s[0]) || '\0' != s[1];
                    207:        for ( ; *s; s++) {
                    208:                switch (*s) {
                    209:                case (ASCII_NBRSP):
                    210:                        printf("\\~");
                    211:                        break;
                    212:                case (ASCII_HYPH):
                    213:                        putchar('-');
                    214:                        break;
                    215:                default:
                    216:                        putchar(*s);
                    217:                        break;
                    218:                }
                    219:        }
1.4     ! kristaps  220: }
        !           221:
        !           222: void
        !           223: man_man(void *arg, const struct man *man)
        !           224: {
        !           225:
        !           226:        fputs(mparse_getkeep(man_mparse(man)), stdout);
1.1       schwarze  227: }
                    228:
                    229: void
                    230: man_mdoc(void *arg, const struct mdoc *mdoc)
                    231: {
                    232:        const struct mdoc_meta *m;
                    233:        const struct mdoc_node *n;
                    234:
                    235:        m = mdoc_meta(mdoc);
                    236:        n = mdoc_node(mdoc);
                    237:
1.3       schwarze  238:        printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
                    239:            m->title, m->msec, m->date, m->os, m->vol);
1.1       schwarze  240:        need_nl = 1;
                    241:        need_space = 0;
                    242:
                    243:        print_node(m, n);
1.3       schwarze  244:        putchar('\n');
1.1       schwarze  245: }
                    246:
                    247: static void
                    248: print_node(DECL_ARGS)
                    249: {
                    250:        const struct mdoc_node  *prev, *sub;
                    251:        const struct manact     *act = NULL;
                    252:        int                      cond, do_sub;
                    253:
                    254:        prev = n->prev ? n->prev : n->parent;
                    255:        if (prev && prev->line < n->line)
                    256:                need_nl = 1;
                    257:
                    258:        cond = 0;
                    259:        do_sub = 1;
                    260:        if (MDOC_TEXT == n->type) {
1.3       schwarze  261:                if (need_nl && ('.' == *n->string || '\'' == *n->string)) {
                    262:                        print_word("\\&");
                    263:                        need_space = 0;
                    264:                }
1.1       schwarze  265:                print_word(n->string);
                    266:        } else {
                    267:                act = manacts + n->tok;
                    268:                cond = NULL == act->cond || (*act->cond)(m, n);
                    269:                if (cond && act->pre)
                    270:                        do_sub = (*act->pre)(m, n);
                    271:        }
                    272:
                    273:        if (do_sub)
                    274:                for (sub = n->child; sub; sub = sub->next)
                    275:                        print_node(m, sub);
                    276:
                    277:        if (cond && act->post)
                    278:                (*act->post)(m, n);
                    279: }
                    280:
                    281: static int
                    282: cond_head(DECL_ARGS)
                    283: {
                    284:        return(MDOC_HEAD == n->type);
                    285: }
                    286:
                    287: static int
                    288: cond_body(DECL_ARGS)
                    289: {
                    290:        return(MDOC_BODY == n->type);
                    291: }
                    292:
                    293: static int
                    294: pre_enc(DECL_ARGS)
                    295: {
                    296:        const char *prefix;
                    297:
                    298:        prefix = manacts[n->tok].prefix;
                    299:        if (NULL == prefix)
                    300:                return(1);
                    301:        print_word(prefix);
                    302:        need_space = 0;
                    303:        return(1);
                    304: }
                    305:
                    306: static void
                    307: post_enc(DECL_ARGS)
                    308: {
                    309:        const char *suffix;
                    310:
                    311:        suffix = manacts[n->tok].suffix;
                    312:        if (NULL == suffix)
                    313:                return;
                    314:        need_space = 0;
                    315:        print_word(suffix);
                    316: }
                    317:
                    318: static void
                    319: post_percent(DECL_ARGS)
                    320: {
                    321:
                    322:        post_enc(m, n);
                    323:        if (n->next)
                    324:                print_word(",");
                    325:        else {
                    326:                print_word(".");
                    327:                need_nl = 1;
                    328:        }
                    329: }
                    330:
                    331: static int
1.3       schwarze  332: pre_sect(DECL_ARGS)
                    333: {
                    334:
                    335:        if (MDOC_HEAD != n->type)
                    336:                return(1);
                    337:        need_nl = 1;
                    338:        print_word(manacts[n->tok].prefix);
                    339:        print_word("\"");
                    340:        need_space = 0;
                    341:        return(1);
                    342: }
                    343:
                    344: static void
                    345: post_sect(DECL_ARGS)
                    346: {
                    347:
                    348:        if (MDOC_HEAD != n->type)
                    349:                return;
                    350:        need_space = 0;
                    351:        print_word("\"");
                    352:        need_nl = 1;
                    353: }
                    354:
                    355: static int
                    356: pre_ap(DECL_ARGS)
                    357: {
                    358:
                    359:        need_space = 0;
                    360:        print_word("'");
                    361:        need_space = 0;
                    362:        return(0);
                    363: }
                    364:
                    365: static int
                    366: pre_bd(DECL_ARGS)
                    367: {
                    368:
                    369:        if (DISP_unfilled == n->norm->Bd.type ||
                    370:            DISP_literal  == n->norm->Bd.type) {
                    371:                need_nl = 1;
                    372:                print_word(".nf");
                    373:        }
                    374:        need_nl = 1;
                    375:        return(1);
                    376: }
                    377:
                    378: static void
                    379: post_bd(DECL_ARGS)
                    380: {
                    381:
                    382:        if (DISP_unfilled == n->norm->Bd.type ||
                    383:            DISP_literal  == n->norm->Bd.type) {
                    384:                need_nl = 1;
                    385:                print_word(".fi");
                    386:        }
                    387:        need_nl = 1;
                    388: }
                    389:
                    390: static int
                    391: pre_br(DECL_ARGS)
                    392: {
                    393:
                    394:        need_nl = 1;
                    395:        print_word(".br");
                    396:        need_nl = 1;
                    397:        return(0);
                    398: }
                    399:
                    400: static int
1.1       schwarze  401: pre_dl(DECL_ARGS)
                    402: {
                    403:
                    404:        need_nl = 1;
                    405:        print_word(".RS 6n");
                    406:        need_nl = 1;
                    407:        return(1);
                    408: }
                    409:
                    410: static void
                    411: post_dl(DECL_ARGS)
                    412: {
                    413:
                    414:        need_nl = 1;
                    415:        print_word(".RE");
                    416:        need_nl = 1;
                    417: }
                    418:
                    419: static int
                    420: pre_it(DECL_ARGS)
                    421: {
                    422:        const struct mdoc_node *bln;
                    423:
                    424:        if (MDOC_HEAD == n->type) {
                    425:                need_nl = 1;
                    426:                print_word(".TP");
                    427:                bln = n->parent->parent->prev;
1.3       schwarze  428:                switch (bln->norm->Bl.type) {
                    429:                case (LIST_bullet):
                    430:                        print_word("4n");
                    431:                        need_nl = 1;
                    432:                        print_word("\\fBo\\fP");
                    433:                        break;
                    434:                default:
                    435:                        if (bln->norm->Bl.width)
                    436:                                print_word(bln->norm->Bl.width);
                    437:                        break;
                    438:                }
1.1       schwarze  439:                need_nl = 1;
                    440:        }
                    441:        return(1);
                    442: }
                    443:
                    444: static int
                    445: pre_nm(DECL_ARGS)
                    446: {
                    447:
                    448:        if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
                    449:                return(1);
                    450:        print_word("\\fB");
                    451:        need_space = 0;
                    452:        if (NULL == n->child)
                    453:                print_word(m->name);
                    454:        return(1);
                    455: }
                    456:
                    457: static void
                    458: post_nm(DECL_ARGS)
                    459: {
                    460:
                    461:        if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
                    462:                return;
                    463:        need_space = 0;
                    464:        print_word("\\fP");
                    465: }
                    466:
                    467: static int
                    468: pre_ns(DECL_ARGS)
                    469: {
                    470:
                    471:        need_space = 0;
                    472:        return(0);
                    473: }
                    474:
1.3       schwarze  475: static void
                    476: post_pf(DECL_ARGS)
                    477: {
                    478:
                    479:        need_space = 0;
                    480: }
                    481:
1.1       schwarze  482: static int
                    483: pre_pp(DECL_ARGS)
                    484: {
                    485:
                    486:        need_nl = 1;
                    487:        if (MDOC_It == n->parent->tok)
                    488:                print_word(".sp");
                    489:        else
                    490:                print_word(".PP");
                    491:        need_nl = 1;
                    492:        return(1);
                    493: }
                    494:
                    495: static int
1.3       schwarze  496: pre_sp(DECL_ARGS)
1.1       schwarze  497: {
                    498:
                    499:        need_nl = 1;
1.3       schwarze  500:        print_word(".sp");
1.1       schwarze  501:        return(1);
                    502: }
                    503:
                    504: static void
1.3       schwarze  505: post_sp(DECL_ARGS)
1.1       schwarze  506: {
                    507:
                    508:        need_nl = 1;
                    509: }
                    510:
                    511: static int
                    512: pre_xr(DECL_ARGS)
                    513: {
                    514:
                    515:        n = n->child;
                    516:        if (NULL == n)
                    517:                return(0);
                    518:        print_node(m, n);
                    519:        n = n->next;
                    520:        if (NULL == n)
                    521:                return(0);
                    522:        need_space = 0;
                    523:        print_word("(");
                    524:        print_node(m, n);
                    525:        print_word(")");
                    526:        return(0);
                    527: }

CVSweb