version 1.2, 2010/06/08 15:00:17 |
version 1.4, 2010/06/09 08:07:13 |
|
|
#include "config.h" |
#include "config.h" |
#endif |
#endif |
|
|
|
#include <sys/param.h> |
|
|
#include <assert.h> |
#include <assert.h> |
|
#include <stdarg.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
#include <string.h> |
|
|
#include "out.h" |
#include "out.h" |
#include "main.h" |
#include "main.h" |
|
|
#define PS_CHAR_BOTMARG 24 |
#define PS_CHAR_BOTMARG 24 |
#define PS_CHAR_BOT (PS_CHAR_BOTMARG + 36) |
#define PS_CHAR_BOT (PS_CHAR_BOTMARG + 36) |
|
|
|
#define PS_BUFSLOP 128 |
|
#define PS_GROWBUF(p, sz) \ |
|
do if ((p)->engine.ps.psmargcur + (sz) > \ |
|
(p)->engine.ps.psmargsz) { \ |
|
(p)->engine.ps.psmargsz += /* CONSTCOND */ \ |
|
MAX(PS_BUFSLOP, (sz)); \ |
|
(p)->engine.ps.psmarg = realloc \ |
|
((p)->engine.ps.psmarg, \ |
|
(p)->engine.ps.psmargsz); \ |
|
if (NULL == (p)->engine.ps.psmarg) { \ |
|
perror(NULL); \ |
|
exit(EXIT_FAILURE); \ |
|
} \ |
|
} while (/* CONSTCOND */ 0) |
|
|
static void ps_letter(struct termp *, char); |
static void ps_letter(struct termp *, char); |
static void ps_begin(struct termp *); |
static void ps_begin(struct termp *); |
static void ps_end(struct termp *); |
static void ps_end(struct termp *); |
static void ps_pageopen(struct termp *); |
|
static void ps_advance(struct termp *, size_t); |
static void ps_advance(struct termp *, size_t); |
static void ps_endline(struct termp *); |
static void ps_endline(struct termp *); |
|
static void ps_printf(struct termp *, const char *, ...); |
|
static void ps_putchar(struct termp *, char); |
|
|
|
|
void * |
void * |
|
|
void |
void |
ps_free(void *arg) |
ps_free(void *arg) |
{ |
{ |
|
struct termp *p; |
|
|
term_free((struct termp *)arg); |
p = (struct termp *)arg; |
|
|
|
if (p->engine.ps.psmarg) |
|
free(p->engine.ps.psmarg); |
|
|
|
term_free(p); |
} |
} |
|
|
|
|
static void |
static void |
|
ps_printf(struct termp *p, const char *fmt, ...) |
|
{ |
|
va_list ap; |
|
int pos; |
|
|
|
va_start(ap, fmt); |
|
|
|
/* |
|
* If we're running in regular mode, then pipe directly into |
|
* vprintf(). If we're processing margins, then push the data |
|
* into our growable margin buffer. |
|
*/ |
|
|
|
if ( ! (PS_MARGINS & p->engine.ps.psstate)) { |
|
vprintf(fmt, ap); |
|
va_end(ap); |
|
return; |
|
} |
|
|
|
/* |
|
* XXX: I assume that the in-margin print won't exceed |
|
* PS_BUFSLOP (128 bytes), which is reasonable but still an |
|
* assumption that will cause pukeage if it's not the case. |
|
*/ |
|
|
|
PS_GROWBUF(p, PS_BUFSLOP); |
|
|
|
pos = (int)p->engine.ps.psmargcur; |
|
vsnprintf(&p->engine.ps.psmarg[pos], PS_BUFSLOP, fmt, ap); |
|
p->engine.ps.psmargcur = strlen(p->engine.ps.psmarg); |
|
} |
|
|
|
|
|
static void |
|
ps_putchar(struct termp *p, char c) |
|
{ |
|
int pos; |
|
|
|
/* See ps_printf(). */ |
|
|
|
if ( ! (PS_MARGINS & p->engine.ps.psstate)) { |
|
putchar(c); |
|
return; |
|
} |
|
|
|
PS_GROWBUF(p, 2); |
|
|
|
pos = (int)p->engine.ps.psmargcur++; |
|
p->engine.ps.psmarg[pos] = c; |
|
p->engine.ps.psmarg[pos] = '\0'; |
|
} |
|
|
|
|
|
/* ARGSUSED */ |
|
static void |
ps_end(struct termp *p) |
ps_end(struct termp *p) |
{ |
{ |
|
|
|
/* |
|
* At the end of the file, do one last showpage. This is the |
|
* same behaviour as groff(1) and works for multiple pages as |
|
* well as just one. |
|
*/ |
|
|
|
assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]); |
|
printf("%s", p->engine.ps.psmarg); |
|
printf("showpage\n"); |
printf("%s\n", "%%EOF"); |
printf("%s\n", "%%EOF"); |
} |
} |
|
|
Line 89 ps_begin(struct termp *p) |
|
Line 179 ps_begin(struct termp *p) |
|
printf("%s\n", "/Courier"); |
printf("%s\n", "/Courier"); |
printf("%s\n", "10 selectfont"); |
printf("%s\n", "10 selectfont"); |
|
|
p->engine.ps.pspage = 1; |
|
p->engine.ps.psstate = 0; |
p->engine.ps.psstate = 0; |
ps_pageopen(p); |
|
|
if (p->engine.ps.psmarg) { |
|
assert(p->engine.ps.psmargsz); |
|
p->engine.ps.psmarg[0] = '\0'; |
|
} |
|
|
|
p->engine.ps.psmargcur = 0; |
|
|
|
/* |
|
* Now dump the margins into our margin buffer. If we don't do |
|
* this, we'd break any current state to run the header and |
|
* footer with each and evern new page. |
|
*/ |
|
|
|
p->engine.ps.pscol = PS_CHAR_LEFT; |
|
p->engine.ps.psrow = PS_CHAR_TOPMARG; |
|
|
|
p->engine.ps.psstate |= PS_MARGINS; |
|
|
|
(*p->headf)(p, p->argf); |
|
(*p->endline)(p); |
|
|
|
p->engine.ps.psstate &= ~PS_MARGINS; |
|
assert(0 == p->engine.ps.psstate); |
|
|
|
p->engine.ps.pscol = PS_CHAR_LEFT; |
|
p->engine.ps.psrow = PS_CHAR_BOTMARG; |
|
p->engine.ps.psstate |= PS_MARGINS; |
|
|
|
(*p->footf)(p, p->argf); |
|
(*p->endline)(p); |
|
|
|
p->engine.ps.psstate &= ~PS_MARGINS; |
|
assert(0 == p->engine.ps.psstate); |
|
|
|
p->engine.ps.pscol = PS_CHAR_LEFT; |
|
p->engine.ps.psrow = PS_CHAR_TOP; |
|
|
|
assert(p->engine.ps.psmarg); |
|
assert('\0' != p->engine.ps.psmarg[0]); |
} |
} |
|
|
|
|
Line 104 ps_letter(struct termp *p, char c) |
|
Line 232 ps_letter(struct termp *p, char c) |
|
* If we're not in a PostScript "word" context, then |
* If we're not in a PostScript "word" context, then |
* open one now at the current cursor. |
* open one now at the current cursor. |
*/ |
*/ |
printf("%zu %zu moveto\n", |
ps_printf(p, "%zu %zu moveto\n(", |
p->engine.ps.pscol, |
p->engine.ps.pscol, |
p->engine.ps.psrow); |
p->engine.ps.psrow); |
putchar('('); |
|
p->engine.ps.psstate |= PS_INLINE; |
p->engine.ps.psstate |= PS_INLINE; |
} |
} |
|
|
Line 124 ps_letter(struct termp *p, char c) |
|
Line 251 ps_letter(struct termp *p, char c) |
|
case (')'): |
case (')'): |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
case ('\\'): |
case ('\\'): |
putchar('\\'); |
ps_putchar(p, '\\'); |
break; |
break; |
default: |
default: |
break; |
break; |
} |
} |
|
|
/* Write the character and adjust where we are on the page. */ |
/* Write the character and adjust where we are on the page. */ |
putchar(c); |
ps_putchar(p, c); |
p->engine.ps.pscol += PS_CHAR_WIDTH; |
p->engine.ps.pscol += PS_CHAR_WIDTH; |
} |
} |
|
|
|
|
/* |
|
* Open a page. This is only used for -Tps at the moment. It opens a |
|
* page context, printing the header and the footer. THE OUTPUT BUFFER |
|
* MUST BE EMPTY. If it is not, output will ghost on the next line and |
|
* we'll be all gross and out of state. |
|
*/ |
|
static void |
static void |
ps_pageopen(struct termp *p) |
|
{ |
|
|
|
assert(TERMTYPE_PS == p->type); |
|
assert(0 == p->engine.ps.psstate); |
|
|
|
p->engine.ps.pscol = PS_CHAR_LEFT; |
|
p->engine.ps.psrow = PS_CHAR_TOPMARG; |
|
p->engine.ps.psstate |= PS_MARGINS; |
|
|
|
(*p->headf)(p, p->argf); |
|
(*p->endline)(p); |
|
|
|
p->engine.ps.psstate &= ~PS_MARGINS; |
|
assert(0 == p->engine.ps.psstate); |
|
|
|
p->engine.ps.pscol = PS_CHAR_LEFT; |
|
p->engine.ps.psrow = PS_CHAR_BOTMARG; |
|
p->engine.ps.psstate |= PS_MARGINS; |
|
|
|
(*p->footf)(p, p->argf); |
|
(*p->endline)(p); |
|
|
|
p->engine.ps.psstate &= ~PS_MARGINS; |
|
assert(0 == p->engine.ps.psstate); |
|
|
|
p->engine.ps.pscol = PS_CHAR_LEFT; |
|
p->engine.ps.psrow = PS_CHAR_TOP; |
|
|
|
} |
|
|
|
|
|
static void |
|
ps_advance(struct termp *p, size_t len) |
ps_advance(struct termp *p, size_t len) |
{ |
{ |
|
|
if (PS_INLINE & p->engine.ps.psstate) { |
if (PS_INLINE & p->engine.ps.psstate) { |
/* Dump out any existing line scope. */ |
/* Dump out any existing line scope. */ |
printf(") show\n"); |
ps_printf(p, ") show\n"); |
p->engine.ps.psstate &= ~PS_INLINE; |
p->engine.ps.psstate &= ~PS_INLINE; |
} |
} |
|
|
Line 194 ps_endline(struct termp *p) |
|
Line 282 ps_endline(struct termp *p) |
|
{ |
{ |
|
|
if (PS_INLINE & p->engine.ps.psstate) { |
if (PS_INLINE & p->engine.ps.psstate) { |
printf(") show\n"); |
ps_printf(p, ") show\n"); |
p->engine.ps.psstate &= ~PS_INLINE; |
p->engine.ps.psstate &= ~PS_INLINE; |
} |
} |
|
|
Line 207 ps_endline(struct termp *p) |
|
Line 295 ps_endline(struct termp *p) |
|
return; |
return; |
} |
} |
|
|
/* |
assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]); |
* XXX: can't run pageopen() until we're certain a flushln() has |
printf("%s", p->engine.ps.psmarg); |
* occured, else the buf will reopen in an awkward state on the |
|
* next line. |
|
*/ |
|
printf("showpage\n"); |
printf("showpage\n"); |
p->engine.ps.psrow = PS_CHAR_TOP; |
p->engine.ps.psrow = PS_CHAR_TOP; |
} |
} |