2 /* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
3 Written by Gaius Mulley (gaius@glam.ac.uk).
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
32 #include "stringclass.h"
35 #include "searchpath.h"
40 #include <sys/types.h>
48 #else /* not _POSIX_VERSION */
50 #endif /* not _POSIX_VERSION */
56 extern "C" const char *Version_string;
60 #include "html-strings.h"
62 #define DEFAULT_LINE_LENGTH 7 // inches wide
63 #define DEFAULT_IMAGE_RES 100 // number of pixels per inch resolution
64 #define IMAGE_BOARDER_PIXELS 0
65 #define INLINE_LEADER_CHAR '\\'
67 #define TRANSPARENT "-background white -transparent white"
68 #define MIN_ALPHA_BITS 0
69 #define MAX_ALPHA_BITS 4
71 #define PAGE_TEMPLATE_SHORT "pg"
72 #define PAGE_TEMPLATE_LONG "-page-"
73 #define PS_TEMPLATE_SHORT "ps"
74 #define PS_TEMPLATE_LONG "-ps-"
75 #define REGION_TEMPLATE_SHORT "rg"
76 #define REGION_TEMPLATE_LONG "-regions-"
89 typedef enum {CENTERED, LEFT, RIGHT, INLINE} IMAGE_ALIGNMENT;
91 static int postscriptRes =-1; // postscript resolution, dots per inch
92 static int stdoutfd = 1; // output file descriptor - normally 1 but might move
94 static int copyofstdoutfd =-1; // a copy of stdout, so we can restore stdout when
95 // writing to post-html
96 static char *psFileName = NULL; // name of postscript file
97 static char *psPageName = NULL; // name of file containing postscript current page
98 static char *regionFileName = NULL; // name of file containing all image regions
99 static char *imagePageName = NULL; // name of bitmap image containing current page
100 static char *image_device = "pnmraw";
101 static int image_res = DEFAULT_IMAGE_RES;
102 static int vertical_offset = 0;
103 static char *image_template = NULL; // image template filename
104 static char *macroset_template= NULL; // image template passed to troff by -D
105 static int troff_arg = 0; // troff arg index
106 static char *image_dir = NULL; // user specified image directory
107 static int textAlphaBits = MAX_ALPHA_BITS;
108 static int graphicAlphaBits = MAX_ALPHA_BITS;
109 static char *antiAlias = NULL; // antialias arguments we pass to gs.
110 static int show_progress = FALSE; // should we display page numbers as they are processed?
111 static int currentPageNo = -1; // current image page number
112 #if defined(DEBUGGING)
113 static int debug = FALSE;
114 static char *troffFileName = NULL; // output of pre-html output which is sent to troff -Tps
115 static char *htmlFileName = NULL; // output of pre-html output which is sent to troff -Thtml
118 static char *linebuf = NULL; // for scanning devps/DESC
119 static int linebufsize = 0;
121 const char *const FONT_ENV_VAR = "GROFF_FONT_PATH";
122 static search_path font_path(FONT_ENV_VAR, FONTPATH, 0, 0);
126 * Images are generated via postscript, gs and the pnm utilities.
129 #define IMAGE_DEVICE "-Tps"
134 static int do_file(const char *filename);
137 * sys_fatal - writes a fatal error message.
138 * Taken from src/roff/groff/pipeline.c.
141 void sys_fatal (const char *s)
143 fatal("%1: %2", s, strerror(errno));
147 * get_line - copies a line (w/o newline) from a file to the global line buffer
150 int get_line (FILE *f)
155 linebuf = new char[128];
159 // skip leading whitespace
164 if (c != ' ' && c != '\t') {
173 if (i + 1 >= linebufsize) {
174 char *old_linebuf = linebuf;
175 linebuf = new char[linebufsize * 2];
176 memcpy(linebuf, old_linebuf, linebufsize);
177 a_delete old_linebuf;
191 * get_resolution - returns the postscript resolution from devps/DESC
194 static unsigned int get_resolution (void)
199 f = font_path.open_file("devps/DESC", &pathp);
201 fatal("can't open devps/DESC");
202 while (get_line(f)) {
203 int n = sscanf(linebuf, "res %u", &res);
209 fatal("can't find `res' keyword in devps/DESC");
214 * html_system - a wrapper for system()
217 void html_system(const char *s, int redirect_stdout)
219 // Redirect standard error to the null device. This is more
220 // portable than using "2> /dev/null", since it doesn't require a
222 int save_stderr = dup(2);
223 int save_stdout = dup(1);
224 int fdnull = open(NULL_DEV, O_WRONLY|O_BINARY, 0666);
225 if (save_stderr > 2 && fdnull > 2)
227 if (redirect_stdout && save_stdout > 1 && fdnull > 1)
231 int status = system(s);
232 dup2(save_stderr, 2);
234 dup2(save_stdout, 1);
236 fprintf(stderr, "Calling `%s' failed\n", s);
238 fprintf(stderr, "Calling `%s' returned status %d\n", s, status);
244 * make_message - taken from man printf(3), creates a string via malloc
245 * and places the result of the va args into string.
246 * Finally the new string is returned.
250 make_message (const char *fmt, ...)
252 /* Guess we need no more than 100 bytes. */
257 if ((p = (char *)malloc (size)) == NULL)
260 /* Try to print in the allocated space. */
262 n = vsnprintf (p, size, fmt, ap);
264 /* If that worked, return the string. */
265 if (n > -1 && n < size) {
273 /* Else try again with more space. */
274 if (n > -1) /* glibc 2.1 */
275 size = n+1; /* precisely what is needed */
277 size *= 2; /* twice the old size */
278 if ((np = (char *)realloc (p, size)) == NULL) {
279 free(p); /* realloc failed, free old, p. */
282 p = np; /* use realloc'ed, p */
287 * the class and methods for retaining ascii text
300 * char_block - constructor, sets the, used, and, next, fields to zero.
303 char_block::char_block()
312 int read_file(FILE *fp);
313 int do_html(int argc, char *argv[]);
314 int do_image(int argc, char *argv[]);
315 void write_file_html(void);
316 void write_file_troff(void);
317 void write_upto_newline (char_block **t, int *i, int is_html);
318 int can_see(char_block **t, int *i, char *string);
319 int skip_spaces(char_block **t, int *i);
320 void skip_until_newline(char_block **t, int *i);
327 * char_buffer - constructor
330 char_buffer::char_buffer()
336 * char_buffer - deconstructor, throws aways the whole buffer list.
339 char_buffer::~char_buffer()
341 while (head != NULL) {
342 char_block *temp = head;
349 * read_file - read in a complete file, fp, placing the contents inside char_blocks.
352 int char_buffer::read_file (FILE *fp)
358 tail = new char_block;
361 if (tail->used == char_block::SIZE) {
362 tail->next = new char_block;
366 // at this point we have a tail which is ready for the next SIZE bytes of the file
368 n = fread(tail->buffer, sizeof(char), char_block::SIZE-tail->used, fp);
373 tail->used += n*sizeof(char);
380 * writeNbytes - writes n bytes to stdout.
383 static void writeNbytes (char *s, int l)
389 r = write(stdoutfd, s, l-n);
399 * writeString - writes a string to stdout.
402 static void writeString (char *s)
404 writeNbytes(s, strlen(s));
408 * makeFileName - creates the image filename template
409 * and the macroset image template.
412 static void makeFileName (void)
414 if ((image_dir != NULL) && (strchr(image_dir, '%') != NULL)) {
415 error("cannot use a `%%' within the image directory name");
419 if ((image_template != NULL) && (strchr(image_template, '%') != NULL)) {
420 error("cannot use a `%%' within the image template");
424 if (image_dir == NULL) {
426 } else if ((strlen(image_dir)>0) && (image_dir[strlen(image_dir)-1] != '/')) {
427 image_dir = make_message("%s/", image_dir);
428 if (image_dir == NULL)
429 sys_fatal("make_message");
432 if (image_template == NULL)
433 macroset_template = make_message("%sgrohtml-%d", image_dir, (int)getpid());
435 macroset_template = make_message("%s%s", image_dir, image_template);
437 if (macroset_template == NULL)
438 sys_fatal("make_message");
440 image_template = (char *)malloc(strlen("-%d")+strlen(macroset_template)+1);
441 if (image_template == NULL)
443 strcpy(image_template, macroset_template);
444 strcat(image_template, "-%d");
448 * setupAntiAlias - sets up the antialias string, used when we call gs.
451 static void setupAntiAlias (void)
453 if (textAlphaBits == 0 && graphicAlphaBits == 0)
454 antiAlias = make_message(" ");
455 else if (textAlphaBits == 0)
456 antiAlias = make_message("-dGraphicsAlphaBits=%d ", graphicAlphaBits);
457 else if (graphicAlphaBits == 0)
458 antiAlias = make_message("-dTextAlphaBits=%d ", textAlphaBits);
460 antiAlias = make_message("-dTextAlphaBits=%d -dGraphicsAlphaBits=%d ",
461 textAlphaBits, graphicAlphaBits);
465 * checkImageDir - checks to see whether the image directory is available.
468 static void checkImageDir (void)
470 if ((image_dir != NULL) && (strcmp(image_dir, "") != 0))
471 if (! ((mkdir(image_dir, 0777) == 0) || (errno == EEXIST))) {
472 error("cannot create directory `%1'", image_dir);
478 * write_end_image - ends the image. It writes out the image extents if we are using -Tps.
481 static void write_end_image (int is_html)
484 * if we are producing html then these
485 * emit image name and enable output
487 * we are producing images
488 * in which case these generate image
491 writeString("\\O[4]\\O[2]");
493 writeString("\\O[1]");
495 writeString("\\O[0]");
499 * write_start_image - writes the troff which will:
501 * (i) disable html output for the following image
502 * (ii) reset the max/min x/y registers during postscript
506 static void write_start_image (IMAGE_ALIGNMENT pos, int is_html)
508 writeString("\\O[5");
525 writeString(image_template); writeString(".png]");
527 writeString("\\O[0]\\O[3]");
529 // reset min/max registers
530 writeString("\\O[1]\\O[3]");
534 * write_upto_newline - writes the contents of the buffer until a newline is seen.
535 * It checks for HTML_IMAGE_INLINE_BEGIN and HTML_IMAGE_INLINE_END
536 * and if they are present it processes them.
539 void char_buffer::write_upto_newline (char_block **t, int *i, int is_html)
544 while ((j < (*t)->used) && ((*t)->buffer[j] != '\n') &&
545 ((*t)->buffer[j] != INLINE_LEADER_CHAR)) {
548 if ((j < (*t)->used) && ((*t)->buffer[j] == '\n')) {
551 writeNbytes((*t)->buffer+(*i), j-(*i));
552 if ((*t)->buffer[j] == INLINE_LEADER_CHAR) {
553 if (can_see(t, &j, HTML_IMAGE_INLINE_BEGIN))
554 write_start_image(INLINE, is_html);
555 else if (can_see(t, &j, HTML_IMAGE_INLINE_END))
556 write_end_image(is_html);
558 if (j < (*t)->used) {
561 writeNbytes((*t)->buffer+(*i), j-(*i));
565 if (j == (*t)->used) {
567 if ((*t)->buffer[j-1] == '\n') {
571 write_upto_newline(t, i, is_html);
581 * can_see - returns TRUE if we can see string in t->buffer[i] onwards
584 int char_buffer::can_see (char_block **t, int *i, char *string)
587 int l = strlen(string);
592 while ((k<s->used) && (j<l) && (s->buffer[k] == string[j])) {
600 } else if ((k<s->used) && (s->buffer[k] != string[j])) {
610 * skip_spaces - returns TRUE if we have not run out of data.
611 * It also consumes spaces.
614 int char_buffer::skip_spaces(char_block **t, int *i)
620 while ((k<s->used) && (isspace(s->buffer[k]))) {
635 * skip_until_newline - skips all characters until a newline is seen.
636 * The newline is not consumed.
639 void char_buffer::skip_until_newline (char_block **t, int *i)
644 while ((j < (*t)->used) && ((*t)->buffer[j] != '\n')) {
647 if (j == (*t)->used) {
650 skip_until_newline(t, i);
659 * write_file_troff - writes the buffer to stdout (troff).
662 void char_buffer::write_file_troff (void)
669 write_upto_newline(&t, &i, FALSE);
672 if (close(stdoutfd) < 0)
675 // now we grab fd=1 so that the next pipe cannot use fd=1
677 if (dup(2) != stdoutfd) {
678 sys_fatal("dup failed to use fd=1");
684 * the image class remembers the position of all images in the postscript file
685 * and assigns names for each image.
699 imageItem (int x1, int y1, int x2, int y2, int page, int res, int max_width, char *name);
704 * imageItem - constructor
707 imageItem::imageItem (int x1, int y1, int x2, int y2, int page, int res, int max_width, char *name)
721 * imageItem - deconstructor
724 imageItem::~imageItem ()
729 * imageList - class containing a list of imageItems.
740 void add(int x1, int y1, int x2, int y2, int page, int res, int maxx, char *name);
741 void createImages (void);
742 int createPage (int pageno);
743 void createImage (imageItem *i);
744 int getMaxX (int pageno);
748 * imageList - constructor.
751 imageList::imageList ()
752 : head(0), tail(0), count(0)
757 * imageList - deconstructor.
760 imageList::~imageList ()
762 while (head != NULL) {
770 * createPage - creates one image of, page pageno, from the postscript file.
773 int imageList::createPage (int pageno)
777 if (currentPageNo == pageno)
780 if (currentPageNo >= 1) {
782 * we need to unlink the files which change each time a new page is processed.
783 * The final unlink is done by xtmpfile when pre-grohtml exits.
785 unlink(imagePageName);
790 fprintf(stderr, "[%d] ", pageno);
794 #if defined(DEBUGGING)
796 fprintf(stderr, "creating page %d\n", pageno);
799 s = make_message("psselect -q -p%d %s %s\n",
800 pageno, psFileName, psPageName);
803 sys_fatal("make_message");
804 #if defined(DEBUGGING)
806 fwrite(s, sizeof(char), strlen(s), stderr);
812 s = make_message("echo showpage | "
813 "gs%s -q -dBATCH -dSAFER "
814 "-dDEVICEHEIGHTPOINTS=792 "
815 "-dDEVICEWIDTHPOINTS=%d -dFIXEDMEDIA=true "
816 "-sDEVICE=%s -r%d %s "
817 "-sOutputFile=%s %s -\n",
819 (getMaxX(pageno) * image_res) / postscriptRes,
826 sys_fatal("make_message");
827 #if defined(DEBUGGING)
829 fwrite(s, sizeof(char), strlen(s), stderr);
835 currentPageNo = pageno;
840 * min - returns the minimum of two numbers.
843 int min (int x, int y)
853 * max - returns the maximum of two numbers.
856 int max (int x, int y)
866 * getMaxX - returns the largest right hand position for any image on, pageno
869 int imageList::getMaxX (int pageno)
872 int x = postscriptRes * DEFAULT_LINE_LENGTH;
875 if (h->pageNo == pageno)
883 * createImage - generates a minimal png file from the set of page images.
886 void imageList::createImage (imageItem *i)
890 int x1 = max(min(i->X1, i->X2)*image_res/postscriptRes-1*IMAGE_BOARDER_PIXELS, 0);
891 int y1 = max((image_res*vertical_offset/72)+min(i->Y1, i->Y2)*image_res/postscriptRes-IMAGE_BOARDER_PIXELS, 0);
892 int x2 = max(i->X1, i->X2)*image_res/postscriptRes+1*IMAGE_BOARDER_PIXELS;
893 int y2 = (image_res*vertical_offset/72)+(max(i->Y1, i->Y2)*image_res/postscriptRes)+1+IMAGE_BOARDER_PIXELS;
894 if (createPage(i->pageNo) == 0) {
895 s = make_message("pnmcut%s %d %d %d %d < %s | pnmcrop -quiet | pnmtopng%s %s > %s \n",
897 x1, y1, x2-x1+1, y2-y1+1,
903 sys_fatal("make_message");
905 #if defined(DEBUGGING)
914 fprintf(stderr, "failed to generate image of page %d\n", i->pageNo);
917 #if defined(DEBUGGING)
920 fprintf(stderr, "ignoring image as x1 coord is -1\n");
928 * add - an image description to the imageList.
931 void imageList::add (int x1, int y1, int x2, int y2, int page, int res, int maxx, char *name)
933 imageItem *i = new imageItem(x1, y1, x2, y2, page, res, maxx, name);
945 * createImages - foreach image descriptor on the imageList, create the actual image.
948 void imageList::createImages (void)
958 static imageList listOfImages; // list of images defined by the region file.
961 * write_file_html - writes the buffer to stdout (troff).
962 * It writes out the file replacing template image names with
963 * actual image names.
966 void char_buffer::write_file_html (void)
973 write_upto_newline(&t, &i, TRUE);
976 if (close(stdoutfd) < 0)
979 // now we grab fd=1 so that the next pipe cannot use fd=1
981 if (dup(2) != stdoutfd) {
982 sys_fatal("dup failed to use fd=1");
988 * generateImages - parses the region file and generates images
989 * from the postscript file. The region file
990 * contains the x1,y1 x2,y2 extents of each
994 static void generateImages (char *regionFileName)
996 pushBackBuffer *f=new pushBackBuffer(regionFileName);
998 while (f->putPB(f->getPB()) != eof) {
999 if (f->isString("grohtml-info:page")) {
1000 int page = f->readInt();
1001 int x1 = f->readInt();
1002 int y1 = f->readInt();
1003 int x2 = f->readInt();
1004 int y2 = f->readInt();
1005 int maxx = f->readInt();
1006 char *name = f->readString();
1007 int res = postscriptRes;
1008 listOfImages.add(x1, y1, x2, y2, page, res, maxx, name);
1009 while ((f->putPB(f->getPB()) != '\n') &&
1010 (f->putPB(f->getPB()) != eof)) {
1013 if (f->putPB(f->getPB()) == '\n') {
1018 * write any error messages out to the user
1020 fputc(f->getPB(), stderr);
1024 listOfImages.createImages();
1025 if (show_progress) {
1026 fprintf(stderr, "done\n");
1033 * replaceFd - replace a file descriptor, was, with, willbe.
1036 static void replaceFd (int was, int willbe)
1040 if (was != willbe) {
1044 dupres = dup(willbe);
1045 if (dupres != was) {
1047 fprintf(stderr, "trying to replace fd=%d with %d dup used %d\n", was, willbe, dupres);
1049 fprintf(stderr, "likely that stdout should be opened before %d\n", was);
1053 if (close(willbe) < 0) {
1060 * waitForChild - waits for child, pid, to exit.
1063 static void waitForChild (PID_T pid)
1068 waitpd = WAIT(&status, pid, _WAIT_CHILD);
1074 * alterDeviceTo - if toImage is set then the arg list is altered to include
1075 * IMAGE_DEVICE and we invoke groff rather than troff.
1077 * set -Thtml and groff
1080 static void alterDeviceTo (int argc, char *argv[], int toImage)
1086 if (strcmp(argv[i], "-Thtml") == 0) {
1087 argv[i] = IMAGE_DEVICE;
1091 argv[troff_arg] = "groff"; /* rather than troff */
1094 if (strcmp(argv[i], IMAGE_DEVICE) == 0) {
1099 argv[troff_arg] = "groff"; /* use groff -Z */
1104 * addZ - appends -Z onto the command list for groff.
1107 char **addZ (int argc, char *argv[])
1109 char **new_argv = (char **)malloc((argc+2)*sizeof(char *));
1112 if (new_argv == NULL)
1113 sys_fatal("malloc");
1116 new_argv[i] = argv[i];
1121 new_argv[i+1] = argv[i];
1125 new_argv[argc] = NULL;
1130 * addRegDef - appends a defined register or string onto the command list for troff.
1133 char **addRegDef (int argc, char *argv[], const char *numReg)
1135 char **new_argv = (char **)malloc((argc+2)*sizeof(char *));
1138 if (new_argv == NULL)
1139 sys_fatal("malloc");
1142 new_argv[i] = argv[i];
1145 new_argv[argc] = strdup(numReg);
1147 new_argv[argc] = NULL;
1152 * dump_args - display the argument list.
1155 void dump_args (int argc, char *argv[])
1157 fprintf(stderr, " %d arguments:", argc);
1158 for (int i=0; i<argc; i++)
1159 fprintf(stderr, " %s", argv[i]);
1160 fprintf(stderr, "\n");
1164 * do_html - sets the troff number htmlflip and
1165 * writes out the buffer to troff -Thtml
1168 int char_buffer::do_html(int argc, char *argv[])
1174 alterDeviceTo(argc, argv, 0);
1175 argv += troff_arg; // skip all arguments up to groff
1177 argv = addZ(argc, argv);
1180 s = "-dwww-image-template=";
1181 s += macroset_template; // do not combine these statements otherwise they will not work
1182 s += '\0'; // the trailing '\0' is ignored
1183 argv = addRegDef(argc, argv, s.contents());
1195 replaceFd(0, pdes[0]);
1196 // close end we are not using
1197 if (close(pdes[1])<0)
1199 replaceFd(1, copyofstdoutfd); // and restore stdout
1201 execvp(argv[0], argv);
1202 error("couldn't exec %1: %2", argv[0], strerror(errno), (char *)0);
1203 fflush(stderr); /* just in case error() doesn't */
1208 #if defined(DEBUGGING)
1210 * slight security risk so only enabled if compiled with defined(DEBUGGING)
1213 replaceFd(1, creat(htmlFileName, S_IWUSR|S_IRUSR));
1217 replaceFd(1, pdes[1]);
1218 // close end we are not using
1219 if (close(pdes[0])<0)
1229 * do_image - writes out the buffer to troff -Tps
1232 int char_buffer::do_image(int argc, char *argv[])
1238 alterDeviceTo(argc, argv, 1);
1239 argv += troff_arg; // skip all arguments up to troff/groff
1241 argv = addRegDef(argc, argv, "-rps4html=1");
1244 s = "-dwww-image-template=";
1245 s += macroset_template;
1247 argv = addRegDef(argc, argv, s.contents());
1250 // override local settings and produce a page size letter postscript file
1251 argv = addRegDef(argc, argv, "-P-pletter");
1261 int psFd = creat(psFileName, S_IWUSR|S_IRUSR);
1262 int regionFd = creat(regionFileName, S_IWUSR|S_IRUSR);
1265 replaceFd(0, pdes[0]);
1266 replaceFd(2, regionFd);
1268 // close end we are not using
1269 if (close(pdes[1])<0)
1272 execvp(argv[0], argv);
1273 error("couldn't exec %1: %2", argv[0], strerror(errno), (char *)0);
1274 fflush(stderr); /* just in case error() doesn't */
1279 #if defined(DEBUGGING)
1281 * slight security risk so only enabled if compiled with defined(DEBUGGING)
1284 replaceFd(1, creat(troffFileName, S_IWUSR|S_IRUSR));
1288 replaceFd(1, pdes[1]);
1295 static char_buffer inputFile;
1299 * usage - emit usage arguments.
1302 void usage(FILE *stream)
1304 fprintf(stream, "usage: %s troffname [-Iimage_name] [-Dimage_directory] [-P-o vertical_image_offset] [-P-i image_resolution] [troff flags] [files]\n", program_name);
1305 fprintf(stream, " vertical_image_offset (default %d/72 of an inch)\n", vertical_offset);
1306 fprintf(stream, " image_resolution (default %d) pixels per inch\n", image_res);
1307 fprintf(stream, " image_name is the name of the stem for all images (default is grohtml-<pid>)\n");
1308 fprintf(stream, " place all png files into image_directory\n");
1312 * scanArguments - scans for all arguments including -P-i, -P-o, -P-D and -P-I. It returns
1313 * the argument index of the first non option.
1316 int scanArguments (int argc, char **argv)
1318 const char *command_prefix = getenv("GROFF_COMMAND_PREFIX");
1319 if (!command_prefix)
1320 command_prefix = PROG_PREFIX;
1321 char *troff_name = new char[strlen(command_prefix) + strlen("troff") + 1];
1322 strcpy(troff_name, command_prefix);
1323 strcat(troff_name, "troff");
1325 static const struct option long_options[] = {
1326 { "help", no_argument, 0, CHAR_MAX + 1 },
1327 { "version", no_argument, 0, 'v' },
1330 while ((c = getopt_long(argc, argv, "+a:g:o:i:I:D:F:vbdhlrnp", long_options, NULL))
1334 printf("GNU pre-grohtml (groff) version %s\n", Version_string);
1337 textAlphaBits = min(max(MIN_ALPHA_BITS, atoi(optarg)), MAX_ALPHA_BITS);
1338 if (textAlphaBits == 3) {
1339 error("cannot use 3 bits of antialiasing information");
1344 graphicAlphaBits = min(max(MIN_ALPHA_BITS, atoi(optarg)), MAX_ALPHA_BITS);
1345 if (graphicAlphaBits == 3) {
1346 error("cannot use 3 bits of antialiasing information");
1351 // handled by post-grohtml (set background color to white)
1357 image_template = optarg;
1360 image_res = atoi(optarg);
1363 font_path.command_line_dir(optarg);
1366 vertical_offset = atoi(optarg);
1369 show_progress = TRUE;
1372 #if defined(DEBUGGING)
1377 // handled by post-grohtml
1379 case CHAR_MAX + 1: // --help
1393 if (strcmp(argv[i], troff_name) == 0)
1395 else if (argv[i][0] != '-')
1399 a_delete troff_name;
1405 * makeTempFiles - name the temporary files
1408 static int makeTempFiles (void)
1410 #if defined(DEBUGGING)
1411 psFileName = "/tmp/prehtml-ps";
1412 regionFileName = "/tmp/prehtml-region";
1413 imagePageName = "/tmp/prehtml-page";
1414 psPageName = "/tmp/prehtml-psn";
1415 troffFileName = "/tmp/prehtml-troff";
1416 htmlFileName = "/tmp/prehtml-html";
1420 /* psPageName contains a single page of postscript */
1421 f = xtmpfile(&psPageName,
1422 PS_TEMPLATE_LONG, PS_TEMPLATE_SHORT,
1425 sys_fatal("xtmpfile");
1430 /* imagePageName contains a bitmap image of the single postscript page */
1431 f = xtmpfile(&imagePageName,
1432 PAGE_TEMPLATE_LONG, PAGE_TEMPLATE_SHORT,
1435 sys_fatal("xtmpfile");
1440 /* psFileName contains a postscript file of the complete document */
1441 f = xtmpfile(&psFileName,
1442 PS_TEMPLATE_LONG, PS_TEMPLATE_SHORT,
1445 sys_fatal("xtmpfile");
1450 /* regionFileName contains a list of the images and their boxed coordinates */
1451 f = xtmpfile(®ionFileName,
1452 REGION_TEMPLATE_LONG, REGION_TEMPLATE_SHORT,
1455 sys_fatal("xtmpfile");
1464 int main(int argc, char **argv)
1466 program_name = argv[0];
1471 postscriptRes = get_resolution();
1472 i = scanArguments(argc, argv);
1477 if (argv[i][0] != '-') {
1478 /* found source file */
1479 ok = do_file(argv[i]);
1488 copyofstdoutfd=dup(stdoutfd);
1493 if (makeTempFiles())
1495 ok = inputFile.do_image(argc, argv);
1497 generateImages(regionFileName);
1498 ok = inputFile.do_html(argc, argv);
1503 static int do_file(const char *filename)
1507 current_filename = filename;
1508 if (strcmp(filename, "-") == 0) {
1511 fp = fopen(filename, "r");
1513 error("can't open `%1': %2", filename, strerror(errno));
1518 if (inputFile.read_file(fp)) {
1523 current_filename = NULL;