[BACK]Return to out.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mandoc

Annotation of src/usr.bin/mandoc/out.c, Revision 1.5

1.5     ! schwarze    1: /*     $Id: out.c,v 1.4 2010/04/07 23:15:05 schwarze Exp $ */
1.1       schwarze    2: /*
                      3:  * Copyright (c) 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 <sys/types.h>
                     18:
1.2       schwarze   19: #include <assert.h>
1.1       schwarze   20: #include <ctype.h>
                     21: #include <stdio.h>
                     22: #include <stdlib.h>
1.2       schwarze   23: #include <string.h>
                     24: #include <time.h>
1.1       schwarze   25:
                     26: #include "out.h"
                     27:
1.3       schwarze   28: /* See a2roffdeco(). */
                     29: #define        C2LIM(c, l) do { \
                     30:        (l) = 1; \
                     31:        if ('[' == (c) || '\'' == (c)) \
                     32:                (l) = 0; \
                     33:        else if ('(' == (c)) \
                     34:                (l) = 2; } \
                     35:        while (/* CONSTCOND */ 0)
                     36:
                     37: /* See a2roffdeco(). */
                     38: #define        C2TERM(c, t) do { \
                     39:        (t) = 0; \
                     40:        if ('\'' == (c)) \
                     41:                (t) = 1; \
                     42:        else if ('[' == (c)) \
                     43:                (t) = 2; \
                     44:        else if ('(' == (c)) \
                     45:                (t) = 3; } \
                     46:        while (/* CONSTCOND */ 0)
                     47:
1.1       schwarze   48: /*
                     49:  * Convert a `scaling unit' to a consistent form, or fail.  Scaling
                     50:  * units are documented in groff.7, mdoc.7, man.7.
                     51:  */
                     52: int
                     53: a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
                     54: {
                     55:        char             buf[BUFSIZ], hasd;
                     56:        int              i;
                     57:        enum roffscale   unit;
                     58:
                     59:        if ('\0' == *src)
                     60:                return(0);
                     61:
                     62:        i = hasd = 0;
                     63:
                     64:        switch (*src) {
                     65:        case ('+'):
                     66:                src++;
                     67:                break;
                     68:        case ('-'):
                     69:                buf[i++] = *src++;
                     70:                break;
                     71:        default:
                     72:                break;
                     73:        }
                     74:
                     75:        if ('\0' == *src)
                     76:                return(0);
                     77:
                     78:        while (i < BUFSIZ) {
                     79:                if ( ! isdigit((u_char)*src)) {
                     80:                        if ('.' != *src)
                     81:                                break;
                     82:                        else if (hasd)
                     83:                                break;
                     84:                        else
                     85:                                hasd = 1;
                     86:                }
                     87:                buf[i++] = *src++;
                     88:        }
                     89:
                     90:        if (BUFSIZ == i || (*src && *(src + 1)))
                     91:                return(0);
                     92:
                     93:        buf[i] = '\0';
                     94:
                     95:        switch (*src) {
                     96:        case ('c'):
                     97:                unit = SCALE_CM;
                     98:                break;
                     99:        case ('i'):
                    100:                unit = SCALE_IN;
                    101:                break;
                    102:        case ('P'):
                    103:                unit = SCALE_PC;
                    104:                break;
                    105:        case ('p'):
                    106:                unit = SCALE_PT;
                    107:                break;
                    108:        case ('f'):
                    109:                unit = SCALE_FS;
                    110:                break;
                    111:        case ('v'):
                    112:                unit = SCALE_VS;
                    113:                break;
                    114:        case ('m'):
                    115:                unit = SCALE_EM;
                    116:                break;
                    117:        case ('\0'):
                    118:                if (SCALE_MAX == def)
                    119:                        return(0);
                    120:                unit = SCALE_BU;
                    121:                break;
                    122:        case ('u'):
                    123:                unit = SCALE_BU;
                    124:                break;
                    125:        case ('M'):
                    126:                unit = SCALE_MM;
                    127:                break;
                    128:        case ('n'):
                    129:                unit = SCALE_EN;
                    130:                break;
                    131:        default:
                    132:                return(0);
                    133:        }
                    134:
                    135:        if ((dst->scale = atof(buf)) < 0)
                    136:                dst->scale = 0;
                    137:        dst->unit = unit;
                    138:        return(1);
                    139: }
1.2       schwarze  140:
                    141:
                    142: /*
                    143:  * Correctly writes the time in nroff form, which differs from standard
                    144:  * form in that a space isn't printed in lieu of the extra %e field for
                    145:  * single-digit dates.
                    146:  */
                    147: void
                    148: time2a(time_t t, char *dst, size_t sz)
                    149: {
                    150:        struct tm        tm;
                    151:        char             buf[5];
                    152:        char            *p;
                    153:        size_t           nsz;
                    154:
                    155:        assert(sz > 1);
                    156:        localtime_r(&t, &tm);
                    157:
                    158:        p = dst;
                    159:        nsz = 0;
                    160:
                    161:        dst[0] = '\0';
                    162:
                    163:        if (0 == (nsz = strftime(p, sz, "%B ", &tm)))
                    164:                return;
                    165:
                    166:        p += (int)nsz;
                    167:        sz -= nsz;
                    168:
                    169:        if (0 == strftime(buf, sizeof(buf), "%e, ", &tm))
                    170:                return;
                    171:
                    172:        nsz = strlcat(p, buf + (' ' == buf[0] ? 1 : 0), sz);
                    173:
                    174:        if (nsz >= sz)
                    175:                return;
                    176:
                    177:        p += (int)nsz;
                    178:        sz -= nsz;
                    179:
                    180:        (void)strftime(p, sz, "%Y", &tm);
                    181: }
                    182:
1.3       schwarze  183:
                    184: /*
                    185:  * Returns length of parsed string (the leading "\" should NOT be
                    186:  * included).  This can be zero if the current character is the nil
                    187:  * terminator.  "d" is set to the type of parsed decorator, which may
                    188:  * have an adjoining "word" of size "sz" (e.g., "(ab" -> "ab", 2).
                    189:  */
                    190: int
                    191: a2roffdeco(enum roffdeco *d,
                    192:                const char **word, size_t *sz)
                    193: {
1.4       schwarze  194:        int              j, term, lim;
                    195:        char             set;
1.3       schwarze  196:        const char      *wp, *sp;
                    197:
                    198:        *d = DECO_NONE;
                    199:        wp = *word;
                    200:
1.4       schwarze  201:        switch ((set = *wp)) {
1.3       schwarze  202:        case ('\0'):
                    203:                return(0);
                    204:
                    205:        case ('('):
                    206:                if ('\0' == *(++wp))
                    207:                        return(1);
                    208:                if ('\0' == *(wp + 1))
                    209:                        return(2);
                    210:
                    211:                *d = DECO_SPECIAL;
                    212:                *sz = 2;
                    213:                *word = wp;
                    214:                return(3);
                    215:
1.4       schwarze  216:        case ('F'):
                    217:                /* FALLTHROUGH */
                    218:        case ('f'):
                    219:                /*
                    220:                 * FIXME: this needs work and consolidation (it should
                    221:                 * follow the sequence that special characters do, for
                    222:                 * one), but isn't a priority at the moment.  Note, for
                    223:                 * one, that in reality \fB != \FB, although here we let
                    224:                 * these slip by.
                    225:                 */
                    226:                switch (*(++wp)) {
                    227:                case ('\0'):
                    228:                        return(1);
                    229:                case ('3'):
                    230:                        /* FALLTHROUGH */
                    231:                case ('B'):
                    232:                        *d = DECO_BOLD;
                    233:                        return(2);
                    234:                case ('2'):
                    235:                        /* FALLTHROUGH */
                    236:                case ('I'):
                    237:                        *d = DECO_ITALIC;
                    238:                        return(2);
                    239:                case ('P'):
                    240:                        *d = DECO_PREVIOUS;
                    241:                        return(2);
                    242:                case ('1'):
                    243:                        /* FALLTHROUGH */
                    244:                case ('R'):
                    245:                        *d = DECO_ROMAN;
                    246:                        return(2);
                    247:                case ('('):
                    248:                        if ('\0' == *(++wp))
                    249:                                return(2);
                    250:                        if ('\0' == *(wp + 1))
                    251:                                return(3);
                    252:
                    253:                        *d = 'F' == set ? DECO_FFONT : DECO_FONT;
                    254:                        *sz = 2;
                    255:                        *word = wp;
                    256:                        return(4);
                    257:                case ('['):
                    258:                        *word = ++wp;
                    259:                        for (j = 0; *wp && ']' != *wp; wp++, j++)
                    260:                                /* Loop... */ ;
                    261:
                    262:                        if ('\0' == *wp)
                    263:                                return(j + 2);
                    264:
                    265:                        *d = 'F' == set ? DECO_FFONT : DECO_FONT;
                    266:                        *sz = (size_t)j;
                    267:                        return(j + 3);
                    268:                default:
                    269:                        break;
                    270:                }
                    271:
                    272:                *d = 'F' == set ? DECO_FFONT : DECO_FONT;
                    273:                *sz = 1;
                    274:                *word = wp;
                    275:                return(2);
                    276:
1.3       schwarze  277:        case ('*'):
                    278:                switch (*(++wp)) {
                    279:                case ('\0'):
                    280:                        return(1);
                    281:
                    282:                case ('('):
                    283:                        if ('\0' == *(++wp))
                    284:                                return(2);
                    285:                        if ('\0' == *(wp + 1))
                    286:                                return(3);
                    287:
                    288:                        *d = DECO_RESERVED;
                    289:                        *sz = 2;
                    290:                        *word = wp;
                    291:                        return(4);
                    292:
                    293:                case ('['):
1.4       schwarze  294:                        *word = ++wp;
                    295:                        for (j = 0; *wp && ']' != *wp; wp++, j++)
                    296:                                /* Loop... */ ;
                    297:
                    298:                        if ('\0' == *wp)
                    299:                                return(j + 2);
                    300:
                    301:                        *d = DECO_RESERVED;
                    302:                        *sz = (size_t)j;
                    303:                        return(j + 3);
1.3       schwarze  304:
                    305:                default:
1.4       schwarze  306:                        break;
1.3       schwarze  307:                }
1.4       schwarze  308:
                    309:                *d = DECO_RESERVED;
                    310:                *sz = 1;
                    311:                *word = wp;
                    312:                return(2);
1.3       schwarze  313:
                    314:        case ('s'):
                    315:                sp = wp;
                    316:                if ('\0' == *(++wp))
                    317:                        return(1);
                    318:
                    319:                C2LIM(*wp, lim);
                    320:                C2TERM(*wp, term);
                    321:
                    322:                if (term)
                    323:                        wp++;
                    324:
                    325:                *word = wp;
                    326:
                    327:                if (*wp == '+' || *wp == '-')
                    328:                        ++wp;
                    329:
                    330:                switch (*wp) {
                    331:                case ('\''):
                    332:                        /* FALLTHROUGH */
                    333:                case ('['):
                    334:                        /* FALLTHROUGH */
                    335:                case ('('):
                    336:                        if (term)
                    337:                                return((int)(wp - sp));
                    338:
                    339:                        C2LIM(*wp, lim);
                    340:                        C2TERM(*wp, term);
                    341:                        wp++;
                    342:                        break;
                    343:                default:
                    344:                        break;
                    345:                }
                    346:
                    347:                if ( ! isdigit((u_char)*wp))
                    348:                        return((int)(wp - sp));
                    349:
                    350:                for (j = 0; isdigit((u_char)*wp); j++) {
                    351:                        if (lim && j >= lim)
                    352:                                break;
                    353:                        ++wp;
                    354:                }
                    355:
                    356:                if (term && term < 3) {
                    357:                        if (1 == term && *wp != '\'')
                    358:                                return((int)(wp - sp));
                    359:                        if (2 == term && *wp != ']')
                    360:                                return((int)(wp - sp));
                    361:                        ++wp;
                    362:                }
                    363:
                    364:                *d = DECO_SIZE;
                    365:                return((int)(wp - sp));
                    366:
1.4       schwarze  367:        case ('['):
                    368:                *word = ++wp;
                    369:
                    370:                for (j = 0; *wp && ']' != *wp; wp++, j++)
                    371:                        /* Loop... */ ;
1.3       schwarze  372:
1.4       schwarze  373:                if ('\0' == *wp)
                    374:                        return(j + 1);
1.3       schwarze  375:
1.4       schwarze  376:                *d = DECO_SPECIAL;
                    377:                *sz = (size_t)j;
                    378:                return(j + 2);
1.3       schwarze  379:
                    380:        case ('c'):
                    381:                *d = DECO_NOSPACE;
                    382:                *sz = 1;
                    383:                return(1);
                    384:
                    385:        default:
1.4       schwarze  386:                break;
1.3       schwarze  387:        }
                    388:
1.4       schwarze  389:        *d = DECO_SPECIAL;
                    390:        *word = wp;
                    391:        *sz = 1;
                    392:        return(1);
1.3       schwarze  393: }