[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.4

1.4     ! schwarze    1: /*     $Id: out.c,v 1.3 2009/12/24 02:08:14 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:        dst->pt = hasd;
                    139:
                    140:        return(1);
                    141: }
1.2       schwarze  142:
                    143:
                    144: /*
                    145:  * Correctly writes the time in nroff form, which differs from standard
                    146:  * form in that a space isn't printed in lieu of the extra %e field for
                    147:  * single-digit dates.
                    148:  */
                    149: void
                    150: time2a(time_t t, char *dst, size_t sz)
                    151: {
                    152:        struct tm        tm;
                    153:        char             buf[5];
                    154:        char            *p;
                    155:        size_t           nsz;
                    156:
                    157:        assert(sz > 1);
                    158:        localtime_r(&t, &tm);
                    159:
                    160:        p = dst;
                    161:        nsz = 0;
                    162:
                    163:        dst[0] = '\0';
                    164:
                    165:        if (0 == (nsz = strftime(p, sz, "%B ", &tm)))
                    166:                return;
                    167:
                    168:        p += (int)nsz;
                    169:        sz -= nsz;
                    170:
                    171:        if (0 == strftime(buf, sizeof(buf), "%e, ", &tm))
                    172:                return;
                    173:
                    174:        nsz = strlcat(p, buf + (' ' == buf[0] ? 1 : 0), sz);
                    175:
                    176:        if (nsz >= sz)
                    177:                return;
                    178:
                    179:        p += (int)nsz;
                    180:        sz -= nsz;
                    181:
                    182:        (void)strftime(p, sz, "%Y", &tm);
                    183: }
                    184:
1.3       schwarze  185:
                    186: /*
                    187:  * Returns length of parsed string (the leading "\" should NOT be
                    188:  * included).  This can be zero if the current character is the nil
                    189:  * terminator.  "d" is set to the type of parsed decorator, which may
                    190:  * have an adjoining "word" of size "sz" (e.g., "(ab" -> "ab", 2).
                    191:  */
                    192: int
                    193: a2roffdeco(enum roffdeco *d,
                    194:                const char **word, size_t *sz)
                    195: {
1.4     ! schwarze  196:        int              j, term, lim;
        !           197:        char             set;
1.3       schwarze  198:        const char      *wp, *sp;
                    199:
                    200:        *d = DECO_NONE;
                    201:        wp = *word;
                    202:
1.4     ! schwarze  203:        switch ((set = *wp)) {
1.3       schwarze  204:        case ('\0'):
                    205:                return(0);
                    206:
                    207:        case ('('):
                    208:                if ('\0' == *(++wp))
                    209:                        return(1);
                    210:                if ('\0' == *(wp + 1))
                    211:                        return(2);
                    212:
                    213:                *d = DECO_SPECIAL;
                    214:                *sz = 2;
                    215:                *word = wp;
                    216:                return(3);
                    217:
1.4     ! schwarze  218:        case ('F'):
        !           219:                /* FALLTHROUGH */
        !           220:        case ('f'):
        !           221:                /*
        !           222:                 * FIXME: this needs work and consolidation (it should
        !           223:                 * follow the sequence that special characters do, for
        !           224:                 * one), but isn't a priority at the moment.  Note, for
        !           225:                 * one, that in reality \fB != \FB, although here we let
        !           226:                 * these slip by.
        !           227:                 */
        !           228:                switch (*(++wp)) {
        !           229:                case ('\0'):
        !           230:                        return(1);
        !           231:                case ('3'):
        !           232:                        /* FALLTHROUGH */
        !           233:                case ('B'):
        !           234:                        *d = DECO_BOLD;
        !           235:                        return(2);
        !           236:                case ('2'):
        !           237:                        /* FALLTHROUGH */
        !           238:                case ('I'):
        !           239:                        *d = DECO_ITALIC;
        !           240:                        return(2);
        !           241:                case ('P'):
        !           242:                        *d = DECO_PREVIOUS;
        !           243:                        return(2);
        !           244:                case ('1'):
        !           245:                        /* FALLTHROUGH */
        !           246:                case ('R'):
        !           247:                        *d = DECO_ROMAN;
        !           248:                        return(2);
        !           249:                case ('('):
        !           250:                        if ('\0' == *(++wp))
        !           251:                                return(2);
        !           252:                        if ('\0' == *(wp + 1))
        !           253:                                return(3);
        !           254:
        !           255:                        *d = 'F' == set ? DECO_FFONT : DECO_FONT;
        !           256:                        *sz = 2;
        !           257:                        *word = wp;
        !           258:                        return(4);
        !           259:                case ('['):
        !           260:                        *word = ++wp;
        !           261:                        for (j = 0; *wp && ']' != *wp; wp++, j++)
        !           262:                                /* Loop... */ ;
        !           263:
        !           264:                        if ('\0' == *wp)
        !           265:                                return(j + 2);
        !           266:
        !           267:                        *d = 'F' == set ? DECO_FFONT : DECO_FONT;
        !           268:                        *sz = (size_t)j;
        !           269:                        return(j + 3);
        !           270:                default:
        !           271:                        break;
        !           272:                }
        !           273:
        !           274:                *d = 'F' == set ? DECO_FFONT : DECO_FONT;
        !           275:                *sz = 1;
        !           276:                *word = wp;
        !           277:                return(2);
        !           278:
1.3       schwarze  279:        case ('*'):
                    280:                switch (*(++wp)) {
                    281:                case ('\0'):
                    282:                        return(1);
                    283:
                    284:                case ('('):
                    285:                        if ('\0' == *(++wp))
                    286:                                return(2);
                    287:                        if ('\0' == *(wp + 1))
                    288:                                return(3);
                    289:
                    290:                        *d = DECO_RESERVED;
                    291:                        *sz = 2;
                    292:                        *word = wp;
                    293:                        return(4);
                    294:
                    295:                case ('['):
1.4     ! schwarze  296:                        *word = ++wp;
        !           297:                        for (j = 0; *wp && ']' != *wp; wp++, j++)
        !           298:                                /* Loop... */ ;
        !           299:
        !           300:                        if ('\0' == *wp)
        !           301:                                return(j + 2);
        !           302:
        !           303:                        *d = DECO_RESERVED;
        !           304:                        *sz = (size_t)j;
        !           305:                        return(j + 3);
1.3       schwarze  306:
                    307:                default:
1.4     ! schwarze  308:                        break;
1.3       schwarze  309:                }
1.4     ! schwarze  310:
        !           311:                *d = DECO_RESERVED;
        !           312:                *sz = 1;
        !           313:                *word = wp;
        !           314:                return(2);
1.3       schwarze  315:
                    316:        case ('s'):
                    317:                sp = wp;
                    318:                if ('\0' == *(++wp))
                    319:                        return(1);
                    320:
                    321:                C2LIM(*wp, lim);
                    322:                C2TERM(*wp, term);
                    323:
                    324:                if (term)
                    325:                        wp++;
                    326:
                    327:                *word = wp;
                    328:
                    329:                if (*wp == '+' || *wp == '-')
                    330:                        ++wp;
                    331:
                    332:                switch (*wp) {
                    333:                case ('\''):
                    334:                        /* FALLTHROUGH */
                    335:                case ('['):
                    336:                        /* FALLTHROUGH */
                    337:                case ('('):
                    338:                        if (term)
                    339:                                return((int)(wp - sp));
                    340:
                    341:                        C2LIM(*wp, lim);
                    342:                        C2TERM(*wp, term);
                    343:                        wp++;
                    344:                        break;
                    345:                default:
                    346:                        break;
                    347:                }
                    348:
                    349:                if ( ! isdigit((u_char)*wp))
                    350:                        return((int)(wp - sp));
                    351:
                    352:                for (j = 0; isdigit((u_char)*wp); j++) {
                    353:                        if (lim && j >= lim)
                    354:                                break;
                    355:                        ++wp;
                    356:                }
                    357:
                    358:                if (term && term < 3) {
                    359:                        if (1 == term && *wp != '\'')
                    360:                                return((int)(wp - sp));
                    361:                        if (2 == term && *wp != ']')
                    362:                                return((int)(wp - sp));
                    363:                        ++wp;
                    364:                }
                    365:
                    366:                *d = DECO_SIZE;
                    367:                return((int)(wp - sp));
                    368:
1.4     ! schwarze  369:        case ('['):
        !           370:                *word = ++wp;
        !           371:
        !           372:                for (j = 0; *wp && ']' != *wp; wp++, j++)
        !           373:                        /* Loop... */ ;
1.3       schwarze  374:
1.4     ! schwarze  375:                if ('\0' == *wp)
        !           376:                        return(j + 1);
1.3       schwarze  377:
1.4     ! schwarze  378:                *d = DECO_SPECIAL;
        !           379:                *sz = (size_t)j;
        !           380:                return(j + 2);
1.3       schwarze  381:
                    382:        case ('c'):
                    383:                *d = DECO_NOSPACE;
                    384:                *sz = 1;
                    385:                return(1);
                    386:
                    387:        default:
1.4     ! schwarze  388:                break;
1.3       schwarze  389:        }
                    390:
1.4     ! schwarze  391:        *d = DECO_SPECIAL;
        !           392:        *word = wp;
        !           393:        *sz = 1;
        !           394:        return(1);
1.3       schwarze  395: }