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

Annotation of mandoc/term_ps.c, Revision 1.4

1.4     ! kristaps    1: /*     $Id: term_ps.c,v 1.3 2010/06/08 15:06:01 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);
        !           128: }
        !           129:
        !           130:
        !           131: static void
        !           132: ps_putchar(struct termp *p, char c)
        !           133: {
        !           134:        int              pos;
        !           135:
        !           136:        /* See ps_printf(). */
        !           137:
        !           138:        if ( ! (PS_MARGINS & p->engine.ps.psstate)) {
        !           139:                putchar(c);
        !           140:                return;
        !           141:        }
        !           142:
        !           143:        PS_GROWBUF(p, 2);
        !           144:
        !           145:        pos = (int)p->engine.ps.psmargcur++;
        !           146:        p->engine.ps.psmarg[pos] = c;
        !           147:        p->engine.ps.psmarg[pos] = '\0';
1.2       kristaps  148: }
                    149:
                    150:
1.3       kristaps  151: /* ARGSUSED */
1.2       kristaps  152: static void
                    153: ps_end(struct termp *p)
                    154: {
                    155:
1.4     ! kristaps  156:        /*
        !           157:         * At the end of the file, do one last showpage.  This is the
        !           158:         * same behaviour as groff(1) and works for multiple pages as
        !           159:         * well as just one.
        !           160:         */
        !           161:
        !           162:        assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
        !           163:        printf("%s", p->engine.ps.psmarg);
        !           164:        printf("showpage\n");
1.2       kristaps  165:        printf("%s\n", "%%EOF");
                    166: }
                    167:
                    168:
                    169: static void
                    170: ps_begin(struct termp *p)
                    171: {
                    172:
                    173:        /*
                    174:         * Emit the standard PostScript prologue, set our initial page
                    175:         * position, then run pageopen() on the initial page.
                    176:         */
                    177:
                    178:        printf("%s\n", "%!PS");
                    179:        printf("%s\n", "/Courier");
                    180:        printf("%s\n", "10 selectfont");
                    181:
                    182:        p->engine.ps.psstate = 0;
1.4     ! kristaps  183:
        !           184:        if (p->engine.ps.psmarg) {
        !           185:                assert(p->engine.ps.psmargsz);
        !           186:                p->engine.ps.psmarg[0] = '\0';
        !           187:        }
        !           188:
        !           189:        p->engine.ps.psmargcur = 0;
        !           190:
        !           191:        /*
        !           192:         * Now dump the margins into our margin buffer.  If we don't do
        !           193:         * this, we'd break any current state to run the header and
        !           194:         * footer with each and evern new page.
        !           195:         */
        !           196:
        !           197:        p->engine.ps.pscol = PS_CHAR_LEFT;
        !           198:        p->engine.ps.psrow = PS_CHAR_TOPMARG;
        !           199:
        !           200:        p->engine.ps.psstate |= PS_MARGINS;
        !           201:
        !           202:        (*p->headf)(p, p->argf);
        !           203:        (*p->endline)(p);
        !           204:
        !           205:        p->engine.ps.psstate &= ~PS_MARGINS;
        !           206:        assert(0 == p->engine.ps.psstate);
        !           207:
        !           208:        p->engine.ps.pscol = PS_CHAR_LEFT;
        !           209:        p->engine.ps.psrow = PS_CHAR_BOTMARG;
        !           210:        p->engine.ps.psstate |= PS_MARGINS;
        !           211:
        !           212:        (*p->footf)(p, p->argf);
        !           213:        (*p->endline)(p);
        !           214:
        !           215:        p->engine.ps.psstate &= ~PS_MARGINS;
        !           216:        assert(0 == p->engine.ps.psstate);
        !           217:
        !           218:        p->engine.ps.pscol = PS_CHAR_LEFT;
        !           219:        p->engine.ps.psrow = PS_CHAR_TOP;
        !           220:
        !           221:        assert(p->engine.ps.psmarg);
        !           222:        assert('\0' != p->engine.ps.psmarg[0]);
1.2       kristaps  223: }
                    224:
                    225:
                    226: static void
                    227: ps_letter(struct termp *p, char c)
                    228: {
                    229:
                    230:        if ( ! (PS_INLINE & p->engine.ps.psstate)) {
                    231:                /*
                    232:                 * If we're not in a PostScript "word" context, then
                    233:                 * open one now at the current cursor.
                    234:                 */
1.4     ! kristaps  235:                ps_printf(p, "%zu %zu moveto\n(",
1.2       kristaps  236:                                p->engine.ps.pscol,
                    237:                                p->engine.ps.psrow);
                    238:                p->engine.ps.psstate |= PS_INLINE;
                    239:        }
                    240:
                    241:        /*
                    242:         * We need to escape these characters as per the PostScript
                    243:         * specification.  We would also escape non-graphable characters
                    244:         * (like tabs), but none of them would get to this point and
                    245:         * it's superfluous to abort() on them.
                    246:         */
                    247:
                    248:        switch (c) {
                    249:        case ('('):
                    250:                /* FALLTHROUGH */
                    251:        case (')'):
                    252:                /* FALLTHROUGH */
                    253:        case ('\\'):
1.4     ! kristaps  254:                ps_putchar(p, '\\');
1.2       kristaps  255:                break;
                    256:        default:
                    257:                break;
                    258:        }
                    259:
                    260:        /* Write the character and adjust where we are on the page. */
1.4     ! kristaps  261:        ps_putchar(p, c);
1.2       kristaps  262:        p->engine.ps.pscol += PS_CHAR_WIDTH;
                    263: }
                    264:
                    265:
                    266: static void
                    267: ps_advance(struct termp *p, size_t len)
                    268: {
                    269:
                    270:        if (PS_INLINE & p->engine.ps.psstate) {
                    271:                /* Dump out any existing line scope. */
1.4     ! kristaps  272:                ps_printf(p, ") show\n");
1.2       kristaps  273:                p->engine.ps.psstate &= ~PS_INLINE;
                    274:        }
                    275:
                    276:        p->engine.ps.pscol += len ? len * PS_CHAR_WIDTH : 0;
                    277: }
                    278:
                    279:
                    280: static void
                    281: ps_endline(struct termp *p)
                    282: {
                    283:
                    284:        if (PS_INLINE & p->engine.ps.psstate) {
1.4     ! kristaps  285:                ps_printf(p, ") show\n");
1.2       kristaps  286:                p->engine.ps.psstate &= ~PS_INLINE;
                    287:        }
                    288:
                    289:        if (PS_MARGINS & p->engine.ps.psstate)
                    290:                return;
                    291:
                    292:        p->engine.ps.pscol = PS_CHAR_LEFT;
                    293:        if (p->engine.ps.psrow >= PS_CHAR_HEIGHT + PS_CHAR_BOT) {
                    294:                p->engine.ps.psrow -= PS_CHAR_HEIGHT;
                    295:                return;
                    296:        }
                    297:
1.4     ! kristaps  298:        assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
        !           299:        printf("%s", p->engine.ps.psmarg);
1.2       kristaps  300:        printf("showpage\n");
                    301:        p->engine.ps.psrow = PS_CHAR_TOP;
1.1       kristaps  302: }

CVSweb