2 /* Copyright (C) 2000 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. */
33 #include "stringclass.h"
37 #include <sys/types.h>
45 #else /* not _POSIX_VERSION */
47 #endif /* not _POSIX_VERSION */
49 extern char *strerror();
52 #include "pushbackbuffer.h"
54 #define POSTSCRIPTRES 72000 // maybe there is a better way to find this? --fixme--
55 #define DEFAULT_IMAGE_RES 80
56 #define IMAGE_BOARDER_PIXELS 10
58 // #define TRANSPARENT "-background \"#FFF\" -transparent \"#FFF\""
59 #define TRANSPARENT ""
73 static int stdoutfd
=1; // output file descriptor - normally 1 but might move
75 static char *psFileName
=0; // name of postscript file
76 static char *regionFileName
=0; // name of file containing all image regions
77 static char *image_device
= "pnmraw";
78 static int image_res
= DEFAULT_IMAGE_RES
;
82 * Images are generated via postscript, gs and the pnm utilities.
85 #define IMAGEDEVICE "-Tps"
88 static int do_file(const char *filename
);
91 * sys_fatal - writes a fatal error message. Taken from src/roff/groff/pipeline.c
94 void sys_fatal (const char *s
)
96 fprintf(stderr
, "%s: %s: %s", program_name
, s
, strerror(errno
));
100 * the class and methods for retaining ascii text
112 char_block::char_block()
121 int read_file(FILE *fp
);
122 int do_html(int argc
, char *argv
[]);
123 int do_image(int argc
, char *argv
[]);
124 void write_file_html(void);
125 void write_file_troff(void);
126 void write_upto_newline (char_block
**t
, int *i
);
127 int can_see(char_block
**t
, int *i
, char *string
);
133 char_buffer::char_buffer()
138 char_buffer::~char_buffer()
141 char_block
*temp
= head
;
147 int char_buffer::read_file (FILE *fp
)
150 unsigned int old_used
;
155 tail
= new char_block
;
158 if (tail
->used
== char_block::SIZE
) {
159 tail
->next
= new char_block
;
163 // at this point we have a tail which is ready for the next SIZE bytes of the file
165 n
= fread(tail
->buffer
, sizeof(char), char_block::SIZE
-tail
->used
, fp
);
170 tail
->used
+= n
*sizeof(char);
177 * writeNbytes - writes n bytes to stdout.
180 static void writeNbytes (char *s
, int l
)
186 r
= write(stdoutfd
, s
, l
-n
);
196 * writeString - writes a string to stdout.
199 static void writeString (char *s
)
201 writeNbytes(s
, strlen(s
));
205 * write_upto_newline - writes the contents of the buffer until a newline is seen.
208 void char_buffer::write_upto_newline (char_block
**t
, int *i
)
213 while ((j
< (*t
)->used
) && ((*t
)->buffer
[j
] != '\n')) {
216 if ((j
< (*t
)->used
) && ((*t
)->buffer
[j
] == '\n')) {
219 writeNbytes((*t
)->buffer
+(*i
), j
-(*i
));
220 if (j
== (*t
)->used
) {
223 write_upto_newline(t
, i
);
232 * can_see - returns TRUE if we can see string in t->buffer[i] onwards
235 int char_buffer::can_see(char_block
**t
, int *i
, char *string
)
238 int l
= strlen(string
);
243 while ((k
<s
->used
) && (j
<l
) && (s
->buffer
[k
] == string
[j
])) {
251 } else if ((k
<s
->used
) && (s
->buffer
[k
] != string
[j
])) {
261 * write_file_troff - writes the buffer to stdout (troff).
262 * It prepends the number register set to 0.
265 void char_buffer::write_file_troff (void)
270 writeString(".nr html2enable 0\n");
271 writeString(".nr htmlflip 0\n");
274 writeNbytes(t
->buffer
, t
->used
);
276 } while ((t
!= head
) && (t
!= 0));
278 if (close(stdoutfd
) < 0)
281 // now we grab fd=1 so that the next pipe cannot use fd=1
283 if (dup(2) != stdoutfd
) {
284 sys_fatal("dup failed to use fd=1");
290 * the image class remembers the position of all images in the postscript file
291 * and assigns names for each image.
304 imageItem (int x1
, int y1
, int x2
, int y2
, int page
, int res
, char *name
);
309 * imageItem - constructor
312 imageItem::imageItem (int x1
, int y1
, int x2
, int y2
, int page
, int res
, char *name
)
325 * imageItem - deconstructor
328 imageItem::~imageItem ()
333 * imageList - class containing a list of imageItems.
344 void add(int x1
, int y1
, int x2
, int y2
, int page
, int res
);
349 * imageList - constructor.
352 imageList::imageList ()
353 : head(0), tail(0), count(0)
358 * imageList - deconstructor.
361 imageList::~imageList ()
371 * createImage - generates a png file from the information held in, i, and
372 * the postscript file.
375 static void createImage (imageItem
*i
)
381 "echo showpage | gs -q -dFirstPage=%d -dLastPage=%d -dSAFER -sDEVICE=%s -r%d -sOutputFile=- %s - 2> /dev/null | pnmcut %d %d %d %d | pnmtopng %s > %s.png \n",
382 i
->pageNo
, i
->pageNo
,
386 i
->X1
*image_res
/POSTSCRIPTRES
-IMAGE_BOARDER_PIXELS
,
387 i
->Y1
*image_res
/POSTSCRIPTRES
-IMAGE_BOARDER_PIXELS
,
388 (i
->X2
-i
->X1
)*image_res
/POSTSCRIPTRES
+2*IMAGE_BOARDER_PIXELS
,
389 (i
->Y2
-i
->Y1
)*image_res
/POSTSCRIPTRES
+2*IMAGE_BOARDER_PIXELS
,
392 // fprintf(stderr, buffer);
395 fprintf(stderr
, "ignoring image as x1 coord is -1\n");
401 * add - an image description to the imageList.
404 void imageList::add (int x1
, int y1
, int x2
, int y2
, int page
, int res
)
406 char *name
= (char *)malloc(50);
415 sprintf(name
, "grohtml-%d", count
);
417 imageItem
*i
= new imageItem(x1
, y1
, x2
, y2
, page
, res
, name
);
430 * get - returns the name for image number, i.
433 char *imageList::get(int i
)
442 return( t
->imageName
);
450 static imageList listOfImages
; // list of images defined by the region file.
453 * write_file_html - writes the buffer to stdout (troff).
454 * It prepends the number register set to 1 and writes
455 * out the file replacing template image names with
456 * actual image names.
459 void char_buffer::write_file_html (void)
466 writeString(".nr html2enable 1\n");
467 writeString(".nr htmlflip 1\n");
471 if (can_see(&t
, &i
, ".if '\\*(.T'html2' .IMAGE <pre-html-image>\n")) {
473 name
= listOfImages
.get(imageNo
);
475 writeString(".if '\\*(.T'html2' .IMAGE \"");
477 writeString(".png\"\n");
480 write_upto_newline(&t
, &i
);
484 if (close(stdoutfd
) < 0)
487 // now we grab fd=1 so that the next pipe cannot use fd=1
489 if (dup(2) != stdoutfd
) {
490 sys_fatal("dup failed to use fd=1");
496 * generateImages - parses the region file and generates images
497 * from the postscript file. The region file
498 * contains the x1,y1 x2,y2 extents of each
502 static void generateImages (char *regionFileName
)
504 pushBackBuffer
*f
=new pushBackBuffer(regionFileName
);
507 if (f
->putPB('\n') == '\n') {
509 while (f
->putPB(f
->getPB()) != eof
) {
510 if (f
->isString("\ngrohtml-info:page")) {
511 int page
= f
->readInt();
512 int x1
= f
->readInt();
513 int y1
= f
->readInt();
514 int x2
= f
->readInt();
515 int y2
= f
->readInt();
516 int res
= POSTSCRIPTRES
; // --fixme-- prefer (f->readInt()) providing that troff can discover the value
517 listOfImages
.add(x1
, y1
, x2
, y2
, page
, res
);
524 * replaceFd - replace a file descriptor, was, with, willbe.
527 static void replaceFd (int was
, int willbe
)
535 dupres
= dup(willbe
);
538 fprintf(stderr
, "trying to replace fd=%d with %d dup used %d\n", was
, willbe
, dupres
);
540 fprintf(stderr
, "likely that stdout should be opened before %d\n", was
);
544 if (close(willbe
) < 0) {
551 * waitForChild - waits for child, pid, to exit.
554 static void waitForChild (PID_T pid
)
559 waitpd
= wait(&status
);
565 * alterDeviceTo - if toImage is set then the arg list is altered to include
566 * IMAGEDEVICE and we invoke groff rather than troff.
568 * set -Thtml2 and troff
571 static void alterDeviceTo (int argc
, char *argv
[], int toImage
)
577 if (strcmp(argv
[i
], "-Thtml2") == 0) {
578 argv
[i
] = IMAGEDEVICE
;
582 argv
[1] = "groff"; /* rather than troff */
585 if (strcmp(argv
[i
], IMAGEDEVICE
) == 0) {
590 argv
[1] = "troff"; /* use troff */
595 * do_html - sets the troff number htmlflip and
596 * writes out the buffer to troff -Thtml
599 int char_buffer::do_html(int argc
, char *argv
[])
607 alterDeviceTo(argc
, argv
, 0);
608 argv
++; // skip pre-grohtml argv[0]
615 replaceFd(0, pdes
[0]);
616 // close end we are not using
617 if (close(pdes
[1])<0)
620 execvp(argv
[0], argv
);
621 error("couldn't exec %1: %2", argv
[0], strerror(errno
), (char *)0);
622 fflush(stderr
); /* just in case error() doesn't */
627 replaceFd(1, pdes
[1]);
628 // close end we are not using
629 if (close(pdes
[0])<0)
639 * do_image - sets the troff number htmlflip and
640 * writes out the buffer to troff -Tps
643 int char_buffer::do_image(int argc
, char *argv
[])
651 alterDeviceTo(argc
, argv
, 1);
652 argv
++; // skip pre-grohtml argv[0]
658 #if defined(DEBUGGING)
659 int psFd
= creat(psFileName
, S_IWUSR
|S_IRUSR
);
660 int regionFd
= creat(regionFileName
, S_IWUSR
|S_IRUSR
);
662 int psFd
= mkstemp(psFileName
);
663 int regionFd
= mkstemp(regionFileName
);
667 replaceFd(0, pdes
[0]);
668 replaceFd(2, regionFd
);
670 // close end we are not using
671 if (close(pdes
[1])<0)
674 execvp(argv
[0], argv
);
675 error("couldn't exec %1: %2", argv
[0], strerror(errno
), (char *)0);
676 fflush(stderr
); /* just in case error() doesn't */
681 replaceFd(1, pdes
[1]);
688 static char_buffer inputFile
;
692 * usage - emit usage arguments and exit.
697 fprintf(stderr
, "usage: %s troffname [ troff flags ] [ files ]\n", program_name
);
702 * makeTempFiles - name the temporary files
705 static void makeTempFiles (void)
707 #if defined(DEBUGGING)
708 psFileName
= "/tmp/prehtml-ps";
709 regionFileName
= "/tmp/prehtml-region";
711 psFileName
= xtmptemplate("-ps-");
712 regionFileName
= xtmptemplate("-regions-");
716 int main(int argc
, char **argv
)
718 program_name
= argv
[0];
719 int i
; // skip over troff name
723 for (i
= 2; i
< argc
; i
++) {
724 if (argv
[i
][0] == '-') {
725 if (argv
[i
][1] == 'v') {
726 extern const char *Version_string
;
727 printf("GNU pre-grohtml (groff) version %s\n", Version_string
);
731 ok
= do_file(argv
[i
]);
743 ok
= inputFile
.do_image(argc
, argv
);
745 generateImages(regionFileName
);
746 ok
= inputFile
.do_html(argc
, argv
);
751 static int do_file(const char *filename
)
755 current_filename
= filename
;
756 if (strcmp(filename
, "-") == 0) {
759 fp
= fopen(filename
, "r");
761 error("can't open `%1': %2", filename
, strerror(errno
));
766 if (inputFile
.read_file(fp
)) {
771 current_filename
= 0;