Sync-to-go: src/pre-html..
[s-roff.git] / src / pre-html / pre-html.cpp
blobdac698bb80500804be5c10b128897eb425dc7787
1 /*@
2 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 2000 - 2004, 2007, 2008
5 * Free Software Foundation, Inc.
6 * Written by Gaius Mulley (gaius@glam.ac.uk).
8 * This is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2, or (at your option) any later
11 * version.
13 * This is distributed in the hope that it will be useful, but WITHOUT ANY
14 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with groff; see the file COPYING. If not, write to the Free Software
20 * Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
22 #define PREHTMLC
24 #include "config.h"
25 #include "html-config.h"
27 #include <sys/types.h>
29 #ifdef _POSIX_VERSION
30 # include <sys/wait.h>
31 # define PID_T pid_t
32 #else
33 # define PID_T int
34 #endif
36 #include <assert.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <signal.h>
40 #include <stdarg.h>
41 #include <stdlib.h>
43 #include "defs.h"
44 #include "device.h"
45 #include "errarg.h"
46 #include "error.h"
47 #include "file_case.h"
48 #include "font.h"
49 #include "lib.h"
50 #include "nonposix.h"
51 #include "paper.h"
52 #include "posix.h"
53 #include "searchpath.h"
54 #include "stringclass.h"
56 #include "html-strings.h"
57 #include "pushback.h"
58 #include "pre-html.h"
60 #if 0
61 # define DEBUGGING
62 #endif
64 /* Establish some definitions to facilitate discrimination between
65 differing runtime environments. */
67 #undef MAY_FORK_CHILD_PROCESS
68 #undef MAY_SPAWN_ASYNCHRONOUS_CHILD
70 #if defined(__MSDOS__) || defined(_WIN32)
72 // Most MS-DOS and Win32 environments will be missing the `fork' capability
73 // (some like Cygwin have it, but it is best avoided).
75 # define MAY_FORK_CHILD_PROCESS 0
77 // On these systems, we use `spawn...', instead of `fork' ... `exec...'.
78 # include <process.h> // for `spawn...'
79 # include <fcntl.h> // for attributes of pipes
81 # if defined(__CYGWIN__) || defined(_UWIN) || defined(_WIN32)
83 // These Win32 implementations allow parent and `spawn...'ed child to
84 // multitask asynchronously.
86 # define MAY_SPAWN_ASYNCHRONOUS_CHILD 1
88 # else
90 // Others may adopt MS-DOS behaviour where parent must sleep,
91 // from `spawn...' until child terminates.
93 # define MAY_SPAWN_ASYNCHRONOUS_CHILD 0
95 # endif /* not defined __CYGWIN__, _UWIN, or _WIN32 */
97 # if defined(DEBUGGING) && !defined(DEBUG_FILE_DIR)
98 /* When we are building a DEBUGGING version we need to tell pre-grohtml
99 where to put intermediate files (the DEBUGGING version will preserve
100 these on exit).
102 On a UNIX host, we might simply use `/tmp', but MS-DOS and Win32 will
103 probably not have this on all disk drives, so default to using
104 `c:/temp' instead. (Note that user may choose to override this by
105 supplying a definition such as
107 -DDEBUG_FILE_DIR=d:/path/to/debug/files FIXME what more special to come?
109 in the CPPFLAGS to `make'.) */
111 # define DEBUG_FILE_DIR c:/temp
112 # endif
114 #else /* not __MSDOS__ or _WIN32 */
116 // For non-Microsoft environments assume UNIX conventions,
117 // so `fork' is required and child processes are asynchronous.
118 # define MAY_FORK_CHILD_PROCESS 1
119 # define MAY_SPAWN_ASYNCHRONOUS_CHILD 1
121 # if defined(DEBUGGING) && !defined(DEBUG_FILE_DIR)
122 /* For a DEBUGGING version, on the UNIX host, we can also usually rely
123 on being able to use `/tmp' for temporary file storage. (Note that,
124 as in the __MSDOS__ or _WIN32 case above, the user may override this
125 by defining
127 -DDEBUG_FILE_DIR=/path/to/debug/files
129 in the CPPFLAGS.) */
131 # define DEBUG_FILE_DIR /tmp
132 # endif
134 #endif /* not __MSDOS__ or _WIN32 */
136 #ifdef DEBUGGING
137 // For a DEBUGGING version, we need some additional macros,
138 // to direct the captured debug mode output to appropriately named files
139 // in the specified DEBUG_FILE_DIR.
141 # define DEBUG_TEXT(text) #text
142 # define DEBUG_NAME(text) DEBUG_TEXT(text)
143 # define DEBUG_FILE(name) DEBUG_NAME(DEBUG_FILE_DIR) "/" name
144 #endif
146 #define INLINE_LEADER_CHAR '\\'
148 // Don't use colour names here! Otherwise there is a dependency on
149 // a file called `rgb.txt' which maps names to colours.
150 #define TRANSPARENT "-background rgb:f/f/f -transparent rgb:f/f/f"
151 #define MIN_ALPHA_BITS 0
152 #define MAX_ALPHA_BITS 4
154 #define PAGE_TEMPLATE_SHORT "pg"
155 #define PAGE_TEMPLATE_LONG "-page-"
156 #define PS_TEMPLATE_SHORT "ps"
157 #define PS_TEMPLATE_LONG "-ps-"
158 #define REGION_TEMPLATE_SHORT "rg"
159 #define REGION_TEMPLATE_LONG "-regions-"
161 typedef enum {
162 CENTERED, LEFT, RIGHT, INLINE
163 } IMAGE_ALIGNMENT;
165 typedef enum {xhtml, html4} html_dialect;
167 static int postscriptRes = -1; // postscript resolution,
168 // dots per inch
169 static int stdoutfd = 1; // output file descriptor -
170 // normally 1 but might move
171 // -1 means closed
172 static char *psFileName = NULL; // name of postscript file
173 static char *psPageName = NULL; // name of file containing
174 // postscript current page
175 static char *regionFileName = NULL; // name of file containing all
176 // image regions
177 static char *imagePageName = NULL; // name of bitmap image containing
178 // current page
179 static const char *image_device = "pnmraw";
180 static int image_res = DEFAULT_IMAGE_RES;
181 static int vertical_offset = 0;
182 static char *image_template = NULL; // image template filename
183 static char *macroset_template= NULL; // image template passed to troff
184 // by -D
185 static int troff_arg = 0; // troff arg index
186 static char *image_dir = NULL; // user specified image directory
187 static int textAlphaBits = MAX_ALPHA_BITS;
188 static int graphicAlphaBits = MAX_ALPHA_BITS;
189 static char *antiAlias = NULL; // antialias arguments we pass to gs
190 static int show_progress = false; // should we display page numbers as
191 // they are processed?
192 static int currentPageNo = -1; // current image page number
193 #if defined(DEBUGGING)
194 static int debug = false;
195 static char *troffFileName = NULL; // output of pre-html output which
196 // is sent to troff -Tps
197 static char *htmlFileName = NULL; // output of pre-html output which
198 // is sent to troff -Thtml
199 #endif
200 static int eqn_flag = false; // must we preprocess via eqn?
202 static char *linebuf = NULL; // for scanning dev-ps/DESC
203 static int linebufsize = 0;
204 static const char *image_gen = NULL; // the `gs' program
206 const char *const FONT_ENV_VAR = U_ROFF_FONT_PATH;
207 static search_path font_path(FONT_ENV_VAR, FONTPATH, 0, 0);
208 static html_dialect dialect = html4;
210 static int do_file(const char *filename);
213 * sys_fatal - Write a fatal error message.
216 void sys_fatal(const char *s)
218 fatal("%1: %2", s, strerror(errno));
222 * get_line - Copy a line (w/o newline) from a file to the
223 * global line buffer.
226 int get_line(file_case *fcp)
228 if (fcp == NULL)
229 return 0;
230 if (linebuf == 0) {
231 linebuf = new char[128];
232 linebufsize = 128;
234 int i = 0;
235 // skip leading whitespace
236 for (;;) {
237 int c = fcp->get_c();
238 if (c == EOF)
239 return 0;
240 if (c != ' ' && c != '\t') {
241 fcp->unget_c(c);
242 break;
245 for (;;) {
246 int c = fcp->get_c();
247 if (c == EOF)
248 break;
249 if (i + 1 >= linebufsize) {
250 char *old_linebuf = linebuf;
251 linebuf = new char[linebufsize * 2];
252 memcpy(linebuf, old_linebuf, linebufsize);
253 a_delete old_linebuf;
254 linebufsize *= 2;
256 linebuf[i++] = c;
257 if (c == '\n') {
258 i--;
259 break;
262 linebuf[i] = '\0';
263 return 1;
267 * get_resolution - Return the postscript resolution from dev-ps/DESC. FIXME
270 static unsigned int get_resolution(void)
272 unsigned int res;
273 file_case *fcp;
274 if ((fcp = font_path.open_file("dev-ps/DESC", fcp->fc_const_path)) == NULL)
275 fatal("can't open dev-ps/DESC");
276 while (get_line(fcp)) {
277 int n = sscanf(linebuf, "res %u", &res);
278 if (n >= 1)
279 goto jleave;
281 fatal("can't find `res' keyword in dev-ps/DESC");
282 jleave:
283 delete fcp;
284 return res;
288 * html_system - A wrapper for system().
291 void html_system(const char *s, int redirect_stdout)
293 #if defined(DEBUGGING)
294 if (debug) {
295 fprintf(stderr, "executing: ");
296 fwrite(s, sizeof(char), strlen(s), stderr);
297 fflush(stderr);
299 #endif
301 // Redirect standard error to the null device. This is more
302 // portable than using "2> /dev/null", since it doesn't require a
303 // Unixy shell.
304 int save_stderr = dup(2);
305 int save_stdout = dup(1);
306 int fdnull = open(NULL_DEV, O_WRONLY|O_BINARY, 0666);
307 if (save_stderr > 2 && fdnull > 2)
308 dup2(fdnull, 2);
309 if (redirect_stdout && save_stdout > 1 && fdnull > 1)
310 dup2(fdnull, 1);
311 if (fdnull >= 0)
312 close(fdnull);
313 int status = system(s);
314 dup2(save_stderr, 2);
315 if (redirect_stdout)
316 dup2(save_stdout, 1);
317 if (status == -1)
318 fprintf(stderr, "Calling `%s' failed\n", s);
319 else if (status)
320 fprintf(stderr, "Calling `%s' returned status %d\n", s, status);
321 close(save_stderr);
322 close(save_stdout);
327 * make_message - Create a string via malloc and place the result of the
328 * va args into string. Finally the new string is returned.
329 * Taken from man page of printf(3).
332 char *make_message(const char *fmt, ...)
334 /* Guess we need no more than 100 bytes. */
335 int n, size = 100;
336 char *p;
337 char *np;
338 va_list ap;
339 if ((p = (char *)malloc(size)) == NULL)
340 return NULL;
341 while (1) {
342 /* Try to print in the allocated space. */
343 va_start(ap, fmt);
344 n = vsnprintf(p, size, fmt, ap);
345 va_end(ap);
346 /* If that worked, return the string. */
347 if (n > -1 && n < size - 1) { /* glibc 2.1 and pre-ANSI C 99 */
348 if (size > n + 1) {
349 np = strsave(p);
350 free(p);
351 return np;
353 return p;
355 /* Else try again with more space. */
356 else /* glibc 2.0 */
357 size *= 2; /* twice the old size */
358 if ((np = (char *)realloc(p, size)) == NULL) {
359 free(p); /* realloc failed, free old, p. */
360 return NULL;
362 p = np; /* use realloc'ed, p */
367 * the class and methods for retaining ascii text
370 class char_block
372 public:
373 enum { SIZE = 256 };
374 char buffer[SIZE];
375 int used;
376 char_block *next;
378 char_block();
382 * char_block - Constructor. Set the, used, and, next, fields to zero.
385 char_block::char_block()
386 : used(0), next(0)
388 for (int i = 0; i < SIZE; i++)
389 buffer[i] = 0;
392 class char_buffer
394 char_block *head;
395 char_block *tail;
397 int run_output_filter(int device_format_selector, int argc, char *argv[]);
399 public:
400 char_buffer();
401 ~char_buffer();
402 int read_file(file_case *fcp);
403 int do_html(int argc, char *argv[]);
404 int do_image(int argc, char *argv[]);
405 void emit_troff_output(int device_format_selector);
406 void write_upto_newline(char_block **t, int *i, int is_html);
407 int can_see(char_block **t, int *i, const char *string);
408 int skip_spaces(char_block **t, int *i);
409 void skip_until_newline(char_block **t, int *i);
413 * char_buffer - Constructor.
416 char_buffer::char_buffer()
417 : head(0), tail(0)
422 * char_buffer - Destructor. Throw away the whole buffer list.
425 char_buffer::~char_buffer()
427 while (head != NULL) {
428 char_block *temp = head;
429 head = head->next;
430 delete temp;
435 * read_file - Read in a complete file, fp, placing the contents inside
436 * char_blocks.
439 int char_buffer::read_file(file_case *fcp)
441 int n;
442 while (!fcp->is_eof()) {
443 if (tail == NULL) {
444 tail = new char_block;
445 head = tail;
447 else {
448 if (tail->used == char_block::SIZE) {
449 tail->next = new char_block;
450 tail = tail->next;
453 // at this point we have a tail which is ready for the next SIZE
454 // bytes of the file
455 n = fcp->get_buf(tail->buffer, char_block::SIZE - tail->used);
456 if (n != 0)
457 tail->used += n * sizeof(char);
458 else {
459 n = fcp->is_eof();
460 goto jleave;
463 n = 1;
464 jleave:
465 return n;
469 * writeNbytes - Write n bytes to stdout.
472 static void writeNbytes(const char *s, int l)
474 int n = 0;
475 int r;
477 while (n < l) {
478 r = write(stdoutfd, s, l - n);
479 if (r < 0)
480 sys_fatal("write");
481 n += r;
482 s += r;
487 * writeString - Write a string to stdout.
490 static void writeString(const char *s)
492 writeNbytes(s, strlen(s));
496 * makeFileName - Create the image filename template
497 * and the macroset image template.
500 static void makeFileName(void)
502 if ((image_dir != NULL) && (strchr(image_dir, '%') != NULL)) {
503 error("cannot use a `%%' within the image directory name");
504 exit(1);
507 if ((image_template != NULL) && (strchr(image_template, '%') != NULL)) {
508 error("cannot use a `%%' within the image template");
509 exit(1);
512 if (image_dir == NULL)
513 image_dir = (char *)"";
514 else if (strlen(image_dir) > 0
515 && image_dir[strlen(image_dir) - 1] != '/') {
516 image_dir = make_message("%s/", image_dir);
517 if (image_dir == NULL)
518 sys_fatal("make_message");
521 if (image_template == NULL)
522 macroset_template = make_message("%s" L_D_HTML "-%d", image_dir,
523 (int)getpid());
524 else
525 macroset_template = make_message("%s%s", image_dir, image_template);
527 if (macroset_template == NULL)
528 sys_fatal("make_message");
530 image_template =
531 (char *)malloc(strlen("-%d") + strlen(macroset_template) + 1);
532 if (image_template == NULL)
533 sys_fatal("malloc");
534 strcpy(image_template, macroset_template);
535 strcat(image_template, "-%d");
539 * setupAntiAlias - Set up the antialias string, used when we call gs.
542 static void setupAntiAlias(void)
544 if (textAlphaBits == 0 && graphicAlphaBits == 0)
545 antiAlias = make_message(" ");
546 else if (textAlphaBits == 0)
547 antiAlias = make_message("-dGraphicsAlphaBits=%d ", graphicAlphaBits);
548 else if (graphicAlphaBits == 0)
549 antiAlias = make_message("-dTextAlphaBits=%d ", textAlphaBits);
550 else
551 antiAlias = make_message("-dTextAlphaBits=%d -dGraphicsAlphaBits=%d ",
552 textAlphaBits, graphicAlphaBits);
556 * checkImageDir - Check whether the image directory is available.
559 static void checkImageDir(void)
561 if (image_dir != NULL && strcmp(image_dir, "") != 0)
562 if (!(mkdir(image_dir, 0777) == 0 || errno == EEXIST)) {
563 error("cannot create directory `%1'", image_dir);
564 exit(1);
569 * write_end_image - End the image. Write out the image extents if we
570 * are using -Tps.
573 static void write_end_image(int is_html)
576 * if we are producing html then these
577 * emit image name and enable output
578 * else
579 * we are producing images
580 * in which case these generate image
581 * boundaries
583 writeString("\\O[4]\\O[2]");
584 if (is_html)
585 writeString("\\O[1]");
586 else
587 writeString("\\O[0]");
591 * write_start_image - Write troff code which will:
593 * (i) disable html output for the following image
594 * (ii) reset the max/min x/y registers during postscript
595 * rendering.
598 static void write_start_image(IMAGE_ALIGNMENT pos, int is_html)
600 writeString("\\O[5");
601 switch (pos) {
602 case INLINE:
603 writeString("i");
604 break;
605 case LEFT:
606 writeString("l");
607 break;
608 case RIGHT:
609 writeString("r");
610 break;
611 case CENTERED:
612 default:
613 writeString("c");
614 break;
616 writeString(image_template);
617 writeString(".png]");
618 if (is_html)
619 writeString("\\O[0]\\O[3]");
620 else
621 // reset min/max registers
622 writeString("\\O[1]\\O[3]");
626 * write_upto_newline - Write the contents of the buffer until a newline
627 * is seen. Check for HTML_IMAGE_INLINE_BEGIN and
628 * HTML_IMAGE_INLINE_END; process them if they are
629 * present.
632 void char_buffer::write_upto_newline(char_block **t, int *i, int is_html)
634 int j = *i;
636 if (*t) {
637 while (j < (*t)->used
638 && (*t)->buffer[j] != '\n'
639 && (*t)->buffer[j] != INLINE_LEADER_CHAR)
640 j++;
641 if (j < (*t)->used
642 && (*t)->buffer[j] == '\n')
643 j++;
644 writeNbytes((*t)->buffer + (*i), j - (*i));
645 if ((*t)->buffer[j] == INLINE_LEADER_CHAR) {
646 if (can_see(t, &j, HTML_IMAGE_INLINE_BEGIN))
647 write_start_image(INLINE, is_html);
648 else if (can_see(t, &j, HTML_IMAGE_INLINE_END))
649 write_end_image(is_html);
650 else {
651 if (j < (*t)->used) {
652 *i = j;
653 j++;
654 writeNbytes((*t)->buffer + (*i), j - (*i));
658 if (j == (*t)->used) {
659 *i = 0;
660 *t = (*t)->next;
661 if (*t && (*t)->buffer[j - 1] != '\n')
662 write_upto_newline(t, i, is_html);
664 else
665 // newline was seen
666 *i = j;
671 * can_see - Return true if we can see string in t->buffer[i] onwards.
674 int char_buffer::can_see(char_block **t, int *i, const char *str)
676 int j = 0;
677 int l = strlen(str);
678 int k = *i;
679 char_block *s = *t;
681 while (s) {
682 while (k < s->used && j < l && s->buffer[k] == str[j]) {
683 j++;
684 k++;
686 if (j == l) {
687 *i = k;
688 *t = s;
689 return true;
691 else if (k < s->used && s->buffer[k] != str[j])
692 return( false );
693 s = s->next;
694 k = 0;
696 return false;
700 * skip_spaces - Return true if we have not run out of data.
701 * Consume spaces also.
704 int char_buffer::skip_spaces(char_block **t, int *i)
706 char_block *s = *t;
707 int k = *i;
709 while (s) {
710 while (k < s->used && isspace(s->buffer[k]))
711 k++;
712 if (k == s->used) {
713 k = 0;
714 s = s->next;
716 else {
717 *i = k;
718 return true;
721 return false;
725 * skip_until_newline - Skip all characters until a newline is seen.
726 * The newline is not consumed.
729 void char_buffer::skip_until_newline(char_block **t, int *i)
731 int j = *i;
733 if (*t) {
734 while (j < (*t)->used && (*t)->buffer[j] != '\n')
735 j++;
736 if (j == (*t)->used) {
737 *i = 0;
738 *t = (*t)->next;
739 skip_until_newline(t, i);
741 else
742 // newline was seen
743 *i = j;
747 #define DEVICE_FORMAT(filter) (filter == HTML_OUTPUT_FILTER)
748 #define HTML_OUTPUT_FILTER 0
749 #define IMAGE_OUTPUT_FILTER 1
750 #define OUTPUT_STREAM(name) creat((name), S_IWUSR | S_IRUSR)
751 #define PS_OUTPUT_STREAM OUTPUT_STREAM(psFileName)
752 #define REGION_OUTPUT_STREAM OUTPUT_STREAM(regionFileName)
755 * emit_troff_output - Write formatted buffer content to the troff
756 * post-processor data pipeline.
759 void char_buffer::emit_troff_output(int device_format_selector)
761 // Handle output for BOTH html and image device formats
762 // if `device_format_selector' is passed as
764 // HTML_FORMAT(HTML_OUTPUT_FILTER)
765 // Buffer data is written to the output stream
766 // with template image names translated to actual image names.
768 // HTML_FORMAT(IMAGE_OUTPUT_FILTER)
769 // Buffer data is written to the output stream
770 // with no translation, for image file creation in the post-processor.
772 int idx = 0;
773 char_block *element = head;
775 while (element != NULL)
776 write_upto_newline(&element, &idx, device_format_selector);
778 #if 0
779 if (close(stdoutfd) < 0)
780 sys_fatal ("close");
782 // now we grab fd=1 so that the next pipe cannot use fd=1
783 if (stdoutfd == 1) {
784 if (dup(2) != stdoutfd)
785 sys_fatal ("dup failed to use fd=1");
787 #endif /* 0 */
791 * The image class remembers the position of all images in the
792 * postscript file and assigns names for each image.
795 class imageItem
797 public:
798 imageItem *next;
799 int X1;
800 int Y1;
801 int X2;
802 int Y2;
803 char *imageName;
804 int resolution;
805 int maxx;
806 int pageNo;
808 imageItem(int x1, int y1, int x2, int y2,
809 int page, int res, int max_width, char *name);
810 ~imageItem();
814 * imageItem - Constructor.
817 imageItem::imageItem(int x1, int y1, int x2, int y2,
818 int page, int res, int max_width, char *name)
820 X1 = x1;
821 Y1 = y1;
822 X2 = x2;
823 Y2 = y2;
824 pageNo = page;
825 resolution = res;
826 maxx = max_width;
827 imageName = name;
828 next = NULL;
832 * imageItem - Destructor.
835 imageItem::~imageItem()
837 if (imageName)
838 free(imageName);
842 * imageList - A class containing a list of imageItems.
845 class imageList
847 imageItem *head;
848 imageItem *tail;
849 int count;
851 public:
852 imageList();
853 ~imageList();
854 void add(int x1, int y1, int x2, int y2,
855 int page, int res, int maxx, char *name);
856 void createImages(void);
857 int createPage(int pageno);
858 void createImage(imageItem *i);
859 int getMaxX(int pageno);
863 * imageList - Constructor.
866 imageList::imageList()
867 : head(0), tail(0), count(0)
872 * imageList - Destructor.
875 imageList::~imageList()
877 while (head != NULL) {
878 imageItem *i = head;
879 head = head->next;
880 delete i;
885 * createPage - Create one image of, page pageno, from the postscript file.
888 int imageList::createPage(int pageno)
890 char *s;
892 if (currentPageNo == pageno)
893 return 0;
895 if (currentPageNo >= 1) {
897 * We need to unlink the files which change each time a new page is
898 * processed. The final unlink is done by xtmpfile when pre-grohtml
899 * exits.
901 unlink(imagePageName);
902 unlink(psPageName);
905 if (show_progress) {
906 fprintf(stderr, "[%d] ", pageno);
907 fflush(stderr);
910 #if defined(DEBUGGING)
911 if (debug)
912 fprintf(stderr, "creating page %d\n", pageno);
913 #endif
915 s = make_message("psselect -q -p%d %s %s\n",
916 pageno, psFileName, psPageName);
918 if (s == NULL)
919 sys_fatal("make_message");
920 html_system(s, 1);
922 s = make_message("echo showpage | "
923 "%s%s -q -dBATCH -dSAFER "
924 "-dDEVICEHEIGHTPOINTS=792 "
925 "-dDEVICEWIDTHPOINTS=%d -dFIXEDMEDIA=true "
926 "-sDEVICE=%s -r%d %s "
927 "-sOutputFile=%s %s -\n",
928 image_gen,
929 EXE_EXT,
930 (getMaxX(pageno) * image_res) / postscriptRes,
931 image_device,
932 image_res,
933 antiAlias,
934 imagePageName,
935 psPageName);
936 if (s == NULL)
937 sys_fatal("make_message");
938 html_system(s, 1);
939 free(s);
940 currentPageNo = pageno;
941 return 0;
945 * min - Return the minimum of two numbers.
948 int min(int x, int y)
950 if (x < y)
951 return x;
952 else
953 return y;
957 * max - Return the maximum of two numbers.
960 int max(int x, int y)
962 if (x > y)
963 return x;
964 else
965 return y;
969 * getMaxX - Return the largest right-hand position for any image
970 * on, pageno.
973 int imageList::getMaxX(int pageno)
975 imageItem *h = head;
976 int x = postscriptRes * DEFAULT_LINE_LENGTH;
978 while (h != NULL) {
979 if (h->pageNo == pageno)
980 x = max(h->X2, x);
981 h = h->next;
983 return x;
987 * createImage - Generate a minimal png file from the set of page images.
990 void imageList::createImage(imageItem *i)
992 if (i->X1 != -1) {
993 char *s;
994 int x1 = max(min(i->X1, i->X2) * image_res / postscriptRes
995 - IMAGE_BOARDER_PIXELS,
997 int y1 = max(image_res * vertical_offset / 72
998 + min(i->Y1, i->Y2) * image_res / postscriptRes
999 - IMAGE_BOARDER_PIXELS,
1001 int x2 = max(i->X1, i->X2) * image_res / postscriptRes
1002 + IMAGE_BOARDER_PIXELS;
1003 int y2 = image_res * vertical_offset / 72
1004 + max(i->Y1, i->Y2) * image_res / postscriptRes
1005 + 1 + IMAGE_BOARDER_PIXELS;
1006 if (createPage(i->pageNo) == 0) {
1007 s = make_message("pnmcut%s %d %d %d %d < %s "
1008 "| pnmcrop -quiet | pnmtopng%s %s > %s\n",
1009 EXE_EXT,
1010 x1, y1, x2 - x1 + 1, y2 - y1 + 1,
1011 imagePageName,
1012 EXE_EXT,
1013 TRANSPARENT,
1014 i->imageName);
1015 if (s == NULL)
1016 sys_fatal("make_message");
1018 html_system(s, 0);
1019 free(s);
1021 else {
1022 fprintf(stderr, "failed to generate image of page %d\n", i->pageNo);
1023 fflush(stderr);
1025 #if defined(DEBUGGING)
1027 else {
1028 if (debug) {
1029 fprintf(stderr, "ignoring image as x1 coord is -1\n");
1030 fflush(stderr);
1032 #endif
1037 * add - Add an image description to the imageList.
1040 void imageList::add(int x1, int y1, int x2, int y2,
1041 int page, int res, int maxx, char *name)
1043 imageItem *i = new imageItem(x1, y1, x2, y2, page, res, maxx, name);
1045 if (head == NULL) {
1046 head = i;
1047 tail = i;
1049 else {
1050 tail->next = i;
1051 tail = i;
1056 * createImages - For each image descriptor on the imageList,
1057 * create the actual image.
1060 void imageList::createImages(void)
1062 imageItem *h = head;
1064 while (h != NULL) {
1065 createImage(h);
1066 h = h->next;
1070 static imageList listOfImages; // List of images defined by the region file.
1073 * generateImages - Parse the region file and generate images
1074 * from the postscript file. The region file
1075 * contains the x1,y1--x2,y2 extents of each
1076 * image.
1079 static void generateImages(char *region_file_name)
1081 pushBackBuffer *f=new pushBackBuffer(region_file_name);
1083 while (f->putPB(f->getPB()) != eof) {
1084 if (f->isString(L_D_HTML "-info:page")) {
1085 int page = f->readInt();
1086 int x1 = f->readInt();
1087 int y1 = f->readInt();
1088 int x2 = f->readInt();
1089 int y2 = f->readInt();
1090 int maxx = f->readInt();
1091 char *name = f->readString();
1092 int res = postscriptRes;
1093 listOfImages.add(x1, y1, x2, y2, page, res, maxx, name);
1094 while (f->putPB(f->getPB()) != '\n'
1095 && f->putPB(f->getPB()) != eof)
1096 (void)f->getPB();
1097 if (f->putPB(f->getPB()) == '\n')
1098 (void)f->getPB();
1100 else {
1101 /* Write any error messages out to the user. */
1102 fputc(f->getPB(), stderr);
1106 listOfImages.createImages();
1107 if (show_progress) {
1108 fprintf(stderr, "done\n");
1109 fflush(stderr);
1111 delete f;
1115 * set_redirection - Set up I/O Redirection for handle, was, to refer to
1116 * stream on handle, willbe.
1119 static void set_redirection(int was, int willbe)
1121 // Nothing to do if `was' and `willbe' already have same handle.
1122 if (was != willbe) {
1123 // Otherwise attempt the specified redirection.
1124 if (dup2 (willbe, was) < 0) {
1125 // Redirection failed, so issue diagnostic and bail out.
1126 fprintf(stderr, "failed to replace fd=%d with %d\n", was, willbe);
1127 if (willbe == STDOUT_FILENO)
1128 fprintf(stderr,
1129 "likely that stdout should be opened before %d\n", was);
1130 sys_fatal("dup2");
1133 // When redirection has been successfully completed assume redundant
1134 // handle `willbe' is no longer required, so close it.
1135 if (close(willbe) < 0)
1136 // Issue diagnostic if `close' fails.
1137 sys_fatal("close");
1142 * save_and_redirect - Get duplicate handle for stream, was, then
1143 * redirect, was, to refer to, willbe.
1146 static int save_and_redirect(int was, int willbe)
1148 if (was == willbe)
1149 // No redirection specified so don't do anything but silently bailing out.
1150 return (was);
1152 // Proceeding with redirection so first save and verify our duplicate
1153 // handle for `was'.
1154 int saved = dup(was);
1155 if (saved < 0) {
1156 fprintf(stderr, "unable to get duplicate handle for %d\n", was);
1157 sys_fatal("dup");
1160 // Duplicate handle safely established so complete redirection.
1161 set_redirection(was, willbe);
1163 // Finally return the saved duplicate descriptor for the
1164 // original `was' stream.
1165 return saved;
1169 * alterDeviceTo - If, toImage, is set
1170 * the argument list is altered to include
1171 * IMAGE_DEVICE and we invoke groff rather than troff.
1172 * Else
1173 * set -Thtml and groff.
1176 static void alterDeviceTo(int argc, char *argv[], int toImage)
1178 int i = 0;
1180 if (toImage) {
1181 while (i < argc) {
1182 if ((strcmp(argv[i], "-Thtml") == 0) ||
1183 (strcmp(argv[i], "-Txhtml") == 0))
1184 argv[i] = (char *)IMAGE_DEVICE;
1185 i++;
1187 } else {
1188 while (i < argc) {
1189 if (strcmp(argv[i], IMAGE_DEVICE) == 0)
1190 argv[i] = UNCONST((dialect == xhtml) ? "-Txhtml" : "-Thtml");
1191 i++;
1194 argv[troff_arg] = UNCONST(L_ROFF); // use groff -Z
1198 * addArg - Append newarg onto the command list for groff.
1201 char **addArg(int argc, char *argv[], char *newarg)
1203 char **new_argv = (char **)malloc((argc + 2) * sizeof(char *));
1204 int i = 0;
1206 if (new_argv == NULL)
1207 sys_fatal("malloc");
1209 if (argc > 0) {
1210 new_argv[i] = argv[i];
1211 i++;
1213 new_argv[i] = newarg;
1214 while (i < argc) {
1215 new_argv[i + 1] = argv[i];
1216 i++;
1218 argc++;
1219 new_argv[argc] = NULL;
1220 return new_argv;
1224 * addRegDef - Append a defined register or string onto the command
1225 * list for troff.
1228 char **addRegDef(int argc, char *argv[], const char *numReg)
1230 char **new_argv = (char **)malloc((argc + 2) * sizeof(char *));
1231 int i = 0;
1233 if (new_argv == NULL)
1234 sys_fatal("malloc");
1236 while (i < argc) {
1237 new_argv[i] = argv[i];
1238 i++;
1240 new_argv[argc] = strsave(numReg);
1241 argc++;
1242 new_argv[argc] = NULL;
1243 return new_argv;
1247 * dump_args - Display the argument list.
1250 void dump_args(int argc, char *argv[])
1252 fprintf(stderr, " %d arguments:", argc);
1253 for (int i = 0; i < argc; i++)
1254 fprintf(stderr, " %s", argv[i]);
1255 fprintf(stderr, "\n");
1259 * print_args - print arguments as if they were issued on the command line.
1261 #ifdef DEBUGGING
1262 void print_args(int argc, char *argv[])
1264 if (debug) {
1265 fprintf(stderr, "executing: ");
1266 for (int i = 0; i < argc; i++)
1267 fprintf(stderr, "%s ", argv[i]);
1268 fprintf(stderr, "\n");
1271 #else
1272 void print_args(int, char **)
1275 #endif
1277 int char_buffer::run_output_filter(int filter, int argc, char **argv)
1279 int pipedes[2];
1280 PID_T child_pid;
1281 int status;
1283 print_args(argc, argv);
1284 if (pipe(pipedes) < 0)
1285 sys_fatal("pipe");
1287 #if MAY_FORK_CHILD_PROCESS
1288 // This is the UNIX process model. To invoke our post-processor,
1289 // we must `fork' the current process.
1291 if ((child_pid = fork()) < 0)
1292 sys_fatal("fork");
1294 else if (child_pid == 0) {
1295 // This is the child process fork. We redirect its `stdin' stream
1296 // to read data emerging from our pipe. There is no point in saving,
1297 // since we won't be able to restore later!
1299 set_redirection(STDIN_FILENO, pipedes[0]);
1301 // The parent process will be writing this data, so we should release
1302 // the child's writeable handle on the pipe, since we have no use for it.
1304 if (close(pipedes[1]) < 0)
1305 sys_fatal("close");
1307 // The IMAGE_OUTPUT_FILTER needs special output redirection...
1309 if (filter == IMAGE_OUTPUT_FILTER) {
1310 // with BOTH `stdout' AND `stderr' diverted to files.
1312 set_redirection(STDOUT_FILENO, PS_OUTPUT_STREAM);
1313 set_redirection(STDERR_FILENO, REGION_OUTPUT_STREAM);
1316 // Now we are ready to launch the output filter.
1318 execvp(argv[0], argv);
1320 // If we get to here then the `exec...' request for the output filter
1321 // failed. Diagnose it and bail out.
1323 error("couldn't exec %1: %2", argv[0], strerror(errno), ((char *)0));
1324 fflush(stderr); // just in case error() didn't
1325 exit(1);
1328 else {
1329 // This is the parent process fork. We will be writing data to the
1330 // filter pipeline, and the child will be reading it. We have no further
1331 // use for our read handle on the pipe, and should close it.
1333 if (close(pipedes[0]) < 0)
1334 sys_fatal("close");
1336 // Now we redirect the `stdout' stream to the inlet end of the pipe,
1337 // and push out the appropiately formatted data to the filter.
1339 pipedes[1] = save_and_redirect(STDOUT_FILENO, pipedes[1]);
1340 emit_troff_output(DEVICE_FORMAT(filter));
1342 // After emitting all the data we close our connection to the inlet
1343 // end of the pipe so the child process will detect end of data.
1345 set_redirection(STDOUT_FILENO, pipedes[1]);
1347 // Finally, we must wait for the child process to complete.
1349 if (WAIT(&status, child_pid, _WAIT_CHILD) != child_pid)
1350 sys_fatal("wait");
1353 #elif MAY_SPAWN_ASYNCHRONOUS_CHILD
1355 // We do not have `fork', (or we prefer not to use it),
1356 // but asynchronous processes are allowed, passing data through pipes.
1357 // This should be ok for most Win32 systems and is preferred to `fork'
1358 // for starting child processes under Cygwin.
1360 // Before we start the post-processor we bind its inherited `stdin'
1361 // stream to the readable end of our pipe, saving our own `stdin' stream
1362 // in `pipedes[0]'.
1364 pipedes[0] = save_and_redirect(STDIN_FILENO, pipedes[0]);
1366 // for the Win32 model,
1367 // we need special provision for saving BOTH `stdout' and `stderr'.
1369 int saved_stdout = dup(STDOUT_FILENO);
1370 int saved_stderr = STDERR_FILENO;
1372 // The IMAGE_OUTPUT_FILTER needs special output redirection...
1374 if (filter == IMAGE_OUTPUT_FILTER) {
1375 // with BOTH `stdout' AND `stderr' diverted to files while saving a
1376 // duplicate handle for `stderr'.
1378 set_redirection(STDOUT_FILENO, PS_OUTPUT_STREAM);
1379 saved_stderr = save_and_redirect(STDERR_FILENO, REGION_OUTPUT_STREAM);
1382 // We then use an asynchronous spawn request to start the post-processor.
1384 if ((child_pid = spawnvp(_P_NOWAIT, argv[0], argv)) < 0) {
1385 // Should the spawn request fail we issue a diagnostic and bail out.
1387 error("cannot spawn %1: %2", argv[0], strerror(errno), ((char *)0));
1388 exit(1);
1391 // Once the post-processor has been started we revert our `stdin'
1392 // to its original saved source, which also closes the readable handle
1393 // for the pipe.
1395 set_redirection(STDIN_FILENO, pipedes[0]);
1397 // if we redirected `stderr', for use by the image post-processor,
1398 // then we also need to reinstate its original assignment.
1400 if (filter == IMAGE_OUTPUT_FILTER)
1401 set_redirection(STDERR_FILENO, saved_stderr);
1403 // Now we redirect the `stdout' stream to the inlet end of the pipe,
1404 // and push out the appropiately formatted data to the filter.
1406 set_redirection(STDOUT_FILENO, pipedes[1]);
1407 emit_troff_output(DEVICE_FORMAT(filter));
1409 // After emitting all the data we close our connection to the inlet
1410 // end of the pipe so the child process will detect end of data.
1412 set_redirection(STDOUT_FILENO, saved_stdout);
1414 // And finally, we must wait for the child process to complete.
1416 if (WAIT(&status, child_pid, _WAIT_CHILD) != child_pid)
1417 sys_fatal("wait");
1419 #else /* can't do asynchronous pipes! */
1421 // TODO: code to support an MS-DOS style process model
1422 // should go here
1424 #endif /* MAY_FORK_CHILD_PROCESS or MAY_SPAWN_ASYNCHRONOUS_CHILD */
1426 return 0;
1430 * do_html - Set the troff number htmlflip and
1431 * write out the buffer to troff -Thtml.
1434 int char_buffer::do_html(int argc, char *argv[])
1436 string s;
1438 alterDeviceTo(argc, argv, 0);
1439 argv += troff_arg; // skip all arguments up to groff
1440 argc -= troff_arg;
1441 argv = addArg(argc, argv, (char *)"-Z");
1442 argc++;
1444 s = (char *)"-dwww-image-template=";
1445 s += macroset_template; // do not combine these statements,
1446 // otherwise they will not work
1447 s += '\0'; // the trailing `\0' is ignored
1448 argv = addRegDef(argc, argv, s.contents());
1449 argc++;
1451 if (dialect == xhtml) {
1452 argv = addRegDef(argc, argv, "-rxhtml=1");
1453 argc++;
1454 if (eqn_flag) {
1455 argv = addRegDef(argc, argv, "-e");
1456 argc++;
1460 #if defined(DEBUGGING)
1461 # define HTML_DEBUG_STREAM OUTPUT_STREAM(htmlFileName)
1462 // slight security risk so only enabled if compiled with defined(DEBUGGING)
1463 if (debug) {
1464 int saved_stdout = save_and_redirect(STDOUT_FILENO, HTML_DEBUG_STREAM);
1465 emit_troff_output(DEVICE_FORMAT(HTML_OUTPUT_FILTER));
1466 set_redirection(STDOUT_FILENO, saved_stdout);
1468 #endif
1470 return run_output_filter(HTML_OUTPUT_FILTER, argc, argv);
1474 * do_image - Write out the buffer to troff -Tps.
1477 int char_buffer::do_image(int argc, char *argv[])
1479 string s;
1481 alterDeviceTo(argc, argv, 1);
1482 argv += troff_arg; // skip all arguments up to troff/groff
1483 argc -= troff_arg;
1484 argv = addRegDef(argc, argv, "-rps4html=1");
1485 argc++;
1487 s = "-dwww-image-template=";
1488 s += macroset_template;
1489 s += '\0';
1490 argv = addRegDef(argc, argv, s.contents());
1491 argc++;
1493 // override local settings and produce a page size letter postscript file
1494 argv = addRegDef(argc, argv, "-P-pletter");
1495 argc++;
1497 if (dialect == xhtml) {
1498 if (eqn_flag) {
1499 argv = addRegDef(argc, argv, "-rxhtml=1");
1500 argc++;
1502 argv = addRegDef(argc, argv, "-e");
1503 argc++;
1506 #if defined(DEBUGGING)
1507 # define IMAGE_DEBUG_STREAM OUTPUT_STREAM(troffFileName)
1508 // slight security risk so only enabled if compiled with defined(DEBUGGING)
1509 if (debug) {
1510 int saved_stdout = save_and_redirect(STDOUT_FILENO, IMAGE_DEBUG_STREAM);
1511 emit_troff_output(DEVICE_FORMAT(IMAGE_OUTPUT_FILTER));
1512 set_redirection(STDOUT_FILENO, saved_stdout);
1514 #endif
1516 return run_output_filter(IMAGE_OUTPUT_FILTER, argc, argv);
1519 static char_buffer inputFile;
1522 * usage - Emit usage arguments.
1525 static void usage(FILE *stream)
1527 fprintf(stream,
1528 "\n"
1529 "This program is not intended to be called stand-alone;\n"
1530 "it is part of the " L_ROFF " pipeline to produce HTML output.\n"
1531 "\n"
1532 "If there is ever the need to call it manually (e.g., for\n"
1533 "debugging purposes), add command line option `-V' while calling\n"
1534 "the `" L_ROFF "' program to see which arguments are passed to it.\n"
1535 "\n");
1539 * scanArguments - Scan for all arguments including -P-i, -P-o, -P-D,
1540 * and -P-I. Return the argument index of the first
1541 * non-option.
1544 static int scanArguments(int argc, char **argv)
1546 const char *command_prefix = getenv(U_ROFF_COMMAND_PREFIX);
1547 if (!command_prefix)
1548 command_prefix = PROG_PREFIX;
1549 char *troff_name = new char[strlen(command_prefix) + strlen("troff") + 1];
1550 strcpy(troff_name, command_prefix);
1551 strcat(troff_name, "troff");
1552 int c, i;
1553 static const struct option long_options[] = {
1554 { "help", no_argument, 0, CHAR_MAX + 1 },
1555 { "version", no_argument, 0, 'v' },
1556 { NULL, 0, 0, 0 }
1558 while ((c = getopt_long(argc, argv, "+a:bdD:eF:g:hi:I:j:lno:prs:S:vVx:y",
1559 long_options, NULL))
1560 != EOF)
1561 switch(c) {
1562 case 'a':
1563 textAlphaBits = min(max(MIN_ALPHA_BITS, atoi(optarg)),
1564 MAX_ALPHA_BITS);
1565 if (textAlphaBits == 3) {
1566 error("cannot use 3 bits of antialiasing information");
1567 exit(1);
1569 break;
1570 case 'b':
1571 // handled by post-grohtml (set background color to white)
1572 break;
1573 case 'd':
1574 #ifdef DEBUGGING
1575 debug = true;
1576 #endif
1577 break;
1578 case 'D':
1579 image_dir = optarg;
1580 break;
1581 case 'e':
1582 eqn_flag = true;
1583 break;
1584 case 'F':
1585 font_path.command_line_dir(optarg);
1586 break;
1587 case 'g':
1588 graphicAlphaBits = min(max(MIN_ALPHA_BITS, atoi(optarg)),
1589 MAX_ALPHA_BITS);
1590 if (graphicAlphaBits == 3) {
1591 error("cannot use 3 bits of antialiasing information");
1592 exit(1);
1594 break;
1595 case 'h':
1596 // handled by post-grohtml
1597 break;
1598 case 'i':
1599 image_res = atoi(optarg);
1600 break;
1601 case 'I':
1602 image_template = optarg;
1603 break;
1604 case 'j':
1605 // handled by post-grohtml (set job name for multiple file output)
1606 break;
1607 case 'l':
1608 // handled by post-grohtml (no automatic section links)
1609 break;
1610 case 'n':
1611 // handled by post-grohtml (generate simple heading anchors)
1612 break;
1613 case 'o':
1614 vertical_offset = atoi(optarg);
1615 break;
1616 case 'p':
1617 show_progress = true;
1618 break;
1619 case 'r':
1620 // handled by post-grohtml (no header and footer lines)
1621 break;
1622 case 's':
1623 // handled by post-grohtml (use font size n as the html base font size)
1624 break;
1625 case 'S':
1626 // handled by post-grohtml (set file split level)
1627 break;
1628 case 'v':
1629 puts(L_D_PREHTML " (" T_ROFF ") v" VERSION);
1630 exit(0);
1631 case 'V':
1632 // handled by post-grohtml (create validator button)
1633 break;
1634 case 'x':
1635 // html dialect
1636 if (strcmp(optarg, "x") == 0)
1637 dialect = xhtml;
1638 else if (strcmp(optarg, "4") == 0)
1639 dialect = html4;
1640 else
1641 printf("unsupported html dialect %s (defaulting to html4)\n", optarg);
1642 break;
1643 case 'y':
1644 // handled by post-grohtml (create groff signature)
1645 break;
1646 case CHAR_MAX + 1: // --help
1647 usage(stdout);
1648 exit(0);
1649 break;
1650 case '?':
1651 usage(stderr);
1652 exit(1);
1653 break;
1654 default:
1655 break;
1658 i = optind;
1659 while (i < argc) {
1660 if (strcmp(argv[i], troff_name) == 0)
1661 troff_arg = i;
1662 else if (argv[i][0] != '-')
1663 return i;
1664 i++;
1666 a_delete troff_name;
1668 return argc;
1672 * makeTempFiles - Name the temporary files.
1675 static int makeTempFiles(void)
1677 #if defined(DEBUGGING)
1678 psFileName = DEBUG_FILE("prehtml-ps");
1679 regionFileName = DEBUG_FILE("prehtml-region");
1680 imagePageName = DEBUG_FILE("prehtml-page");
1681 psPageName = DEBUG_FILE("prehtml-psn");
1682 troffFileName = DEBUG_FILE("prehtml-troff");
1683 htmlFileName = DEBUG_FILE("prehtml-html");
1684 #else /* not DEBUGGING */
1685 FILE *f;
1687 /* psPageName contains a single page of postscript */
1688 f = xtmpfile(&psPageName,
1689 PS_TEMPLATE_LONG, PS_TEMPLATE_SHORT,
1690 true);
1691 if (f == NULL) {
1692 sys_fatal("xtmpfile");
1693 return -1;
1695 fclose(f);
1697 /* imagePageName contains a bitmap image of the single postscript page */
1698 f = xtmpfile(&imagePageName,
1699 PAGE_TEMPLATE_LONG, PAGE_TEMPLATE_SHORT,
1700 true);
1701 if (f == NULL) {
1702 sys_fatal("xtmpfile");
1703 return -1;
1705 fclose(f);
1707 /* psFileName contains a postscript file of the complete document */
1708 f = xtmpfile(&psFileName,
1709 PS_TEMPLATE_LONG, PS_TEMPLATE_SHORT,
1710 true);
1711 if (f == NULL) {
1712 sys_fatal("xtmpfile");
1713 return -1;
1715 fclose(f);
1717 /* regionFileName contains a list of the images and their boxed coordinates */
1718 f = xtmpfile(&regionFileName,
1719 REGION_TEMPLATE_LONG, REGION_TEMPLATE_SHORT,
1720 true);
1721 if (f == NULL) {
1722 sys_fatal("xtmpfile");
1723 return -1;
1725 fclose(f);
1727 #endif /* not DEBUGGING */
1728 return 0;
1731 int main(int argc, char **argv)
1733 program_name = argv[0];
1734 int i;
1735 int found = 0;
1736 int ok = 1;
1738 #ifdef CAPTURE_MODE
1739 FILE *dump;
1740 fprintf(stderr, "%s: invoked with %d arguments ...\n", argv[0], argc);
1741 for (i = 0; i < argc; i++)
1742 fprintf(stderr, "%2d: %s\n", i, argv[i]);
1743 if ((dump = fopen(DEBUG_FILE("pre-html-data"), "wb")) != NULL) {
1744 while((i = fgetc(stdin)) >= 0)
1745 fputc(i, dump);
1746 fclose(dump);
1748 exit(1);
1749 #endif /* CAPTURE_MODE */
1750 device = "html";
1751 if (!font::load_desc())
1752 fatal("cannot find dev-html/DESC exiting");
1753 image_gen = font::image_generator;
1754 if (image_gen == NULL || (strcmp(image_gen, "") == 0))
1755 fatal("dev-html/DESC must set the image_generator field, exiting");
1756 postscriptRes = get_resolution();
1757 i = scanArguments(argc, argv);
1758 setupAntiAlias();
1759 checkImageDir();
1760 makeFileName();
1761 while (i < argc) {
1762 if (argv[i][0] != '-') {
1763 /* found source file */
1764 ok = do_file(argv[i]);
1765 if (!ok)
1766 return 0;
1767 found = 1;
1769 i++;
1772 if (!found)
1773 do_file("-");
1774 if (makeTempFiles())
1775 return 1;
1776 ok = inputFile.do_image(argc, argv);
1777 if (ok == 0) {
1778 generateImages(regionFileName);
1779 ok = inputFile.do_html(argc, argv);
1781 return ok;
1784 static int do_file(const char *filename)
1786 file_case *fcp;
1788 current_filename = filename;
1789 fcp = file_case::muxer(filename);
1790 if (fcp == NULL) {
1791 assert(strcmp(filename, "-"));
1792 error("can't open `%1': %2", filename, strerror(errno));
1793 return 0;
1796 if (inputFile.read_file(fcp)) {
1797 // XXX
1800 delete fcp;
1801 current_filename = NULL;
1802 return 1;
1805 // s-it2-mode