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

Annotation of mandoc/term_ps.c, Revision 1.6

1.6     ! kristaps    1: /*     $Id: term_ps.c,v 1.5 2010/06/09 08:31:18 kristaps Exp $ */
1.1       kristaps    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: #ifdef HAVE_CONFIG_H
                     18: #include "config.h"
                     19: #endif
                     20:
1.4       kristaps   21: #include <sys/param.h>
                     22:
1.2       kristaps   23: #include <assert.h>
1.4       kristaps   24: #include <stdarg.h>
1.2       kristaps   25: #include <stdio.h>
1.1       kristaps   26: #include <stdlib.h>
1.4       kristaps   27: #include <string.h>
1.1       kristaps   28:
                     29: #include "out.h"
                     30: #include "main.h"
                     31: #include "term.h"
                     32:
1.2       kristaps   33: #define        PS_CHAR_WIDTH     6
                     34: #define        PS_CHAR_HEIGHT    12
                     35: #define        PS_CHAR_TOPMARG  (792 - 24)
                     36: #define        PS_CHAR_TOP      (PS_CHAR_TOPMARG - 36)
                     37: #define        PS_CHAR_LEFT      36
                     38: #define        PS_CHAR_BOTMARG   24
                     39: #define        PS_CHAR_BOT      (PS_CHAR_BOTMARG + 36)
                     40:
1.4       kristaps   41: #define        PS_BUFSLOP        128
                     42: #define        PS_GROWBUF(p, sz) \
                     43:        do if ((p)->engine.ps.psmargcur + (sz) > \
                     44:                        (p)->engine.ps.psmargsz) { \
                     45:                (p)->engine.ps.psmargsz += /* CONSTCOND */ \
                     46:                        MAX(PS_BUFSLOP, (sz)); \
                     47:                (p)->engine.ps.psmarg = realloc \
                     48:                        ((p)->engine.ps.psmarg,  \
                     49:                         (p)->engine.ps.psmargsz); \
                     50:                if (NULL == (p)->engine.ps.psmarg) { \
                     51:                        perror(NULL); \
                     52:                        exit(EXIT_FAILURE); \
                     53:                } \
                     54:        } while (/* CONSTCOND */ 0)
                     55:
1.2       kristaps   56: static void              ps_letter(struct termp *, char);
                     57: static void              ps_begin(struct termp *);
                     58: static void              ps_end(struct termp *);
                     59: static void              ps_advance(struct termp *, size_t);
                     60: static void              ps_endline(struct termp *);
1.4       kristaps   61: static void              ps_printf(struct termp *, const char *, ...);
                     62: static void              ps_putchar(struct termp *, char);
1.2       kristaps   63:
                     64:
1.1       kristaps   65: void *
                     66: ps_alloc(void)
                     67: {
                     68:        struct termp    *p;
                     69:
                     70:        if (NULL == (p = term_alloc(TERMENC_ASCII)))
                     71:                return(NULL);
                     72:
                     73:        p->type = TERMTYPE_PS;
1.2       kristaps   74:        p->letter = ps_letter;
                     75:        p->begin = ps_begin;
                     76:        p->end = ps_end;
                     77:        p->advance = ps_advance;
                     78:        p->endline = ps_endline;
1.1       kristaps   79:        return(p);
                     80: }
                     81:
                     82:
                     83: void
                     84: ps_free(void *arg)
                     85: {
1.4       kristaps   86:        struct termp    *p;
                     87:
                     88:        p = (struct termp *)arg;
                     89:
                     90:        if (p->engine.ps.psmarg)
                     91:                free(p->engine.ps.psmarg);
                     92:
                     93:        term_free(p);
                     94: }
                     95:
                     96:
                     97: static void
                     98: ps_printf(struct termp *p, const char *fmt, ...)
                     99: {
                    100:        va_list          ap;
                    101:        int              pos;
                    102:
                    103:        va_start(ap, fmt);
                    104:
                    105:        /*
                    106:         * If we're running in regular mode, then pipe directly into
                    107:         * vprintf().  If we're processing margins, then push the data
                    108:         * into our growable margin buffer.
                    109:         */
1.1       kristaps  110:
1.4       kristaps  111:        if ( ! (PS_MARGINS & p->engine.ps.psstate)) {
                    112:                vprintf(fmt, ap);
                    113:                va_end(ap);
                    114:                return;
                    115:        }
                    116:
                    117:        /*
                    118:         * XXX: I assume that the in-margin print won't exceed
                    119:         * PS_BUFSLOP (128 bytes), which is reasonable but still an
                    120:         * assumption that will cause pukeage if it's not the case.
                    121:         */
                    122:
                    123:        PS_GROWBUF(p, PS_BUFSLOP);
                    124:
                    125:        pos = (int)p->engine.ps.psmargcur;
                    126:        vsnprintf(&p->engine.ps.psmarg[pos], PS_BUFSLOP, fmt, ap);
                    127:        p->engine.ps.psmargcur = strlen(p->engine.ps.psmarg);
1.5       kristaps  128:
                    129:        va_end(ap);
1.4       kristaps  130: }
                    131:
                    132:
                    133: static void
                    134: ps_putchar(struct termp *p, char c)
                    135: {
                    136:        int              pos;
                    137:
                    138:        /* See ps_printf(). */
                    139:
                    140:        if ( ! (PS_MARGINS & p->engine.ps.psstate)) {
                    141:                putchar(c);
                    142:                return;
                    143:        }
                    144:
                    145:        PS_GROWBUF(p, 2);
                    146:
                    147:        pos = (int)p->engine.ps.psmargcur++;
1.5       kristaps  148:        p->engine.ps.psmarg[pos++] = c;
1.4       kristaps  149:        p->engine.ps.psmarg[pos] = '\0';
1.2       kristaps  150: }
                    151:
                    152:
1.3       kristaps  153: /* ARGSUSED */
1.2       kristaps  154: static void
                    155: ps_end(struct termp *p)
                    156: {
                    157:
1.4       kristaps  158:        /*
                    159:         * At the end of the file, do one last showpage.  This is the
                    160:         * same behaviour as groff(1) and works for multiple pages as
                    161:         * well as just one.
                    162:         */
                    163:
                    164:        assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
                    165:        printf("%s", p->engine.ps.psmarg);
                    166:        printf("showpage\n");
1.2       kristaps  167:        printf("%s\n", "%%EOF");
                    168: }
                    169:
                    170:
                    171: static void
                    172: ps_begin(struct termp *p)
                    173: {
                    174:
                    175:        /*
                    176:         * Emit the standard PostScript prologue, set our initial page
                    177:         * position, then run pageopen() on the initial page.
                    178:         */
                    179:
                    180:        printf("%s\n", "%!PS");
                    181:        printf("%s\n", "/Courier");
                    182:        printf("%s\n", "10 selectfont");
                    183:
                    184:        p->engine.ps.psstate = 0;
1.4       kristaps  185:
                    186:        if (p->engine.ps.psmarg) {
                    187:                assert(p->engine.ps.psmargsz);
                    188:                p->engine.ps.psmarg[0] = '\0';
                    189:        }
                    190:
                    191:        p->engine.ps.psmargcur = 0;
                    192:
                    193:        /*
                    194:         * Now dump the margins into our margin buffer.  If we don't do
                    195:         * this, we'd break any current state to run the header and
                    196:         * footer with each and evern new page.
                    197:         */
                    198:
                    199:        p->engine.ps.pscol = PS_CHAR_LEFT;
                    200:        p->engine.ps.psrow = PS_CHAR_TOPMARG;
                    201:
                    202:        p->engine.ps.psstate |= PS_MARGINS;
                    203:
                    204:        (*p->headf)(p, p->argf);
                    205:        (*p->endline)(p);
                    206:
                    207:        p->engine.ps.psstate &= ~PS_MARGINS;
                    208:        assert(0 == p->engine.ps.psstate);
                    209:
                    210:        p->engine.ps.pscol = PS_CHAR_LEFT;
                    211:        p->engine.ps.psrow = PS_CHAR_BOTMARG;
                    212:        p->engine.ps.psstate |= PS_MARGINS;
                    213:
                    214:        (*p->footf)(p, p->argf);
                    215:        (*p->endline)(p);
                    216:
                    217:        p->engine.ps.psstate &= ~PS_MARGINS;
                    218:        assert(0 == p->engine.ps.psstate);
                    219:
                    220:        p->engine.ps.pscol = PS_CHAR_LEFT;
                    221:        p->engine.ps.psrow = PS_CHAR_TOP;
                    222:
                    223:        assert(p->engine.ps.psmarg);
                    224:        assert('\0' != p->engine.ps.psmarg[0]);
1.2       kristaps  225: }
                    226:
                    227:
                    228: static void
                    229: ps_letter(struct termp *p, char c)
                    230: {
                    231:
                    232:        if ( ! (PS_INLINE & p->engine.ps.psstate)) {
                    233:                /*
                    234:                 * If we're not in a PostScript "word" context, then
                    235:                 * open one now at the current cursor.
                    236:                 */
1.4       kristaps  237:                ps_printf(p, "%zu %zu moveto\n(",
1.2       kristaps  238:                                p->engine.ps.pscol,
                    239:                                p->engine.ps.psrow);
                    240:                p->engine.ps.psstate |= PS_INLINE;
                    241:        }
                    242:
                    243:        /*
                    244:         * We need to escape these characters as per the PostScript
                    245:         * specification.  We would also escape non-graphable characters
                    246:         * (like tabs), but none of them would get to this point and
                    247:         * it's superfluous to abort() on them.
                    248:         */
                    249:
                    250:        switch (c) {
                    251:        case ('('):
                    252:                /* FALLTHROUGH */
                    253:        case (')'):
                    254:                /* FALLTHROUGH */
                    255:        case ('\\'):
1.4       kristaps  256:                ps_putchar(p, '\\');
1.2       kristaps  257:                break;
                    258:        default:
                    259:                break;
                    260:        }
                    261:
                    262:        /* Write the character and adjust where we are on the page. */
1.4       kristaps  263:        ps_putchar(p, c);
1.2       kristaps  264:        p->engine.ps.pscol += PS_CHAR_WIDTH;
                    265: }
                    266:
                    267:
                    268: static void
                    269: ps_advance(struct termp *p, size_t len)
                    270: {
1.6     ! kristaps  271:        size_t           i;
1.2       kristaps  272:
                    273:        if (PS_INLINE & p->engine.ps.psstate) {
1.6     ! kristaps  274:                for (i = 0; i < len; i++)
        !           275:                        ps_letter(p, ' ');
        !           276:                return;
1.2       kristaps  277:        }
                    278:
                    279:        p->engine.ps.pscol += len ? len * PS_CHAR_WIDTH : 0;
                    280: }
                    281:
                    282:
                    283: static void
                    284: ps_endline(struct termp *p)
                    285: {
                    286:
                    287:        if (PS_INLINE & p->engine.ps.psstate) {
1.4       kristaps  288:                ps_printf(p, ") show\n");
1.2       kristaps  289:                p->engine.ps.psstate &= ~PS_INLINE;
                    290:        }
                    291:
                    292:        if (PS_MARGINS & p->engine.ps.psstate)
                    293:                return;
                    294:
                    295:        p->engine.ps.pscol = PS_CHAR_LEFT;
                    296:        if (p->engine.ps.psrow >= PS_CHAR_HEIGHT + PS_CHAR_BOT) {
                    297:                p->engine.ps.psrow -= PS_CHAR_HEIGHT;
                    298:                return;
                    299:        }
                    300:
1.4       kristaps  301:        assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
                    302:        printf("%s", p->engine.ps.psmarg);
1.2       kristaps  303:        printf("showpage\n");
                    304:        p->engine.ps.psrow = PS_CHAR_TOP;
1.1       kristaps  305: }

CVSweb