2 * neatpost troff postscript postprocessor
4 * Copyright (C) 2013-2014 Ali Gholami Rudi <ali at rudi dot ir>
6 * This program is released under the Modified BSD license.
14 static int ps_pagewidth
= 2159; /* page width (tenths of a millimetre) */
15 static int ps_pageheight
= 2794;/* page height (tenths of a millimetre) */
16 static int ps_linewidth
= 40; /* drawing line thickness in thousandths of an em */
17 static int o_pages
; /* output pages */
24 static void back(int c
)
29 static int utf8len(int c
)
46 static int nextutf8(char *s
)
54 for (i
= 1; i
< l
; i
++)
61 static void nextskip(void)
70 static int nextnum(void)
84 if (c
< 0 || !isdigit(c
))
91 static int iseol(void)
101 /* skip until the end of line */
102 static void nexteol(void)
107 } while (c
>= 0 && c
!= '\n');
110 static void nextword(char *s
)
115 while (c
>= 0 && !isspace(c
)) {
125 static void readln(char *s
)
129 while (c
> 0 && c
!= '\n') {
138 static void postline(void)
148 static void postspline(void)
160 draws(h1
, v1
, h2
, v2
);
167 static void postdraw(void)
172 switch (tolower(c
)) {
191 drawa(h1
, v1
, h2
, v2
);
200 drawend(c
== 'p' || c
== 'P', c
== 'E' || c
== 'C' || c
== 'P');
204 static void postps(void)
210 if (!strcmp("PS", cmd
) || !strcmp("ps", cmd
))
212 if (!strcmp("rotate", cmd
))
213 outrotate(atoi(arg
));
214 if (!strcmp("eps", cmd
))
216 if (!strcmp("BeginObject", cmd
))
218 if (!strcmp("EndObject", cmd
))
222 static char postdir
[PATHLEN
] = TROFFFDIR
; /* output device directory */
223 static char postdev
[PATHLEN
] = "utf"; /* output device name */
225 static void postx(void)
235 dev_mnt(pos
, font
, font
);
239 if (dev_open(postdir
, postdev
)) {
240 fprintf(stderr
, "neatpost: cannot open device %s\n", postdev
);
243 ps_header(ps_pagewidth
, ps_pageheight
, ps_linewidth
);
257 static void postcmd(int c
)
261 outrel((c
- '0') * 10 + next() - '0', 0);
280 outrel(nextnum(), 0);
283 outrel(0, nextnum());
291 outcolor(clr_get(cs
));
323 fprintf(stderr
, "neatpost: unknown command %c\n", c
);
328 static void post(void)
331 while ((c
= next()) >= 0)
338 static struct paper
{
342 {"letter", 2159, 2794},
343 {"legal", 2159, 3556},
344 {"ledger", 4318, 2794},
345 {"tabloid", 2794, 4318},
348 static void setpagesize(char *s
)
351 /* predefined paper sizes */
352 for (i
= 0; i
< LEN(papers
); i
++) {
353 if (!strcmp(papers
[i
].name
, s
)) {
354 ps_pagewidth
= papers
[i
].w
;
355 ps_pageheight
= papers
[i
].h
;
359 /* custom paper size in mm, like 2100x2970 for a4 */
360 if (isdigit(s
[0]) && strchr(s
, 'x')) {
361 ps_pagewidth
= atoi(s
);
362 ps_pageheight
= atoi(strchr(s
, 'x') + 1);
365 /* ISO paper sizes */
366 if (!strchr("abcABC", s
[0]) || !isdigit(s
[1]))
368 if (tolower(s
[0]) == 'a') {
372 if (tolower(s
[0]) == 'b') {
376 if (tolower(s
[0]) == 'c') {
381 ps_pagewidth
= ((n
& 1) ? d2
: d1
) >> ((n
+ 1) >> 1);
382 ps_pageheight
= ((n
& 1) ? d1
: d2
) >> (n
>> 1);
383 ps_pagewidth
-= ps_pagewidth
% 10;
384 ps_pageheight
-= ps_pageheight
% 10;
387 static void errdie(char *msg
)
389 fprintf(stderr
, msg
);
393 void *mextend(void *old
, long oldsz
, long newsz
, int memsz
)
395 void *new = xmalloc(newsz
* memsz
);
396 memcpy(new, old
, oldsz
* memsz
);
397 memset(new + oldsz
* memsz
, 0, (newsz
- oldsz
) * memsz
);
402 void *xmalloc(long len
)
404 void *m
= malloc(len
);
406 errdie("neatroff: malloc() failed\n");
411 "Usage: neatpost [options] <input >output\n"
413 " -F dir \tset font directory (" TROFFFDIR
")\n"
414 " -p size \tset paper size (letter); e.g., a4, 2100x2970\n"
415 " -w lwid \tdrawing line thickness in thousandths of an em (40)\n";
417 int main(int argc
, char *argv
[])
420 for (i
= 1; i
< argc
; i
++) {
421 if (argv
[i
][0] == '-' && argv
[i
][1] == 'F') {
422 strcpy(postdir
, argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
423 } else if (argv
[i
][0] == '-' && argv
[i
][1] == 'p') {
424 setpagesize(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
425 } else if (argv
[i
][0] == '-' && argv
[i
][1] == 'w') {
426 ps_linewidth
= atoi(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
433 ps_trailer(o_pages
, o_fonts
);