1 /*
2  * Main entry for HTMLDOC, a HTML document processing program.
3  *
4  * Copyright 2011-2020 by Michael R Sweet.
5  * Copyright 1997-2010 by Easy Software Products.  All rights reserved.
6  *
7  * This program is free software.  Distribution and use rights are outlined in
8  * the file "COPYING".
9  */
10 
11 /*
12  * Include necessary headers.
13  */
14 
15 #define _HTMLDOC_CXX_
16 #include "htmldoc.h"
17 #include "markdown.h"
18 #include "http.h"
19 #include <ctype.h>
20 #include <fcntl.h>
21 
22 #ifdef HAVE_LOCALE_H
23 #  include <locale.h>
24 #endif // HAVE_LOCALE_H
25 
26 #ifdef WIN32
27 #  include <direct.h>
28 #  include <io.h>
29 #else
30 #  include <signal.h>
31 #  include <unistd.h>
32 #  include <sys/time.h>
33 #endif // WIN32
34 
35 #ifdef __APPLE__
36 #  include <libproc.h>
37 #endif // __APPLE__
38 
39 #ifdef __EMX__
40 extern "C" {
41 const char *__XOS2RedirRoot(const char *);
42 }
43 #endif
44 
45 
46 /*
47  * Local types...
48  */
49 
50 typedef int (*exportfunc_t)(tree_t *, tree_t *);
51 
52 
53 /*
54  * Local functions...
55  */
56 
57 static int	compare_strings(const char *s, const char *t, int tmin);
58 static double	get_seconds(void);
59 static int	load_book(const char *filename, tree_t **document,
60 		          exportfunc_t *exportfunc, int set_nolocal = 0);
61 static void	parse_options(const char *line, exportfunc_t *exportfunc);
62 static const char *prefs_getrc(void);
63 static int	read_file(const char *filename, tree_t **document,
64 		          const char *path);
65 static void	set_permissions(const char *p);
66 #ifndef WIN32
67 extern "C" {
68 static void	term_handler(int signum);
69 }
70 #endif // !WIN32
71 static void	usage(const char *arg = NULL);
72 
73 
74 /*
75  * 'main()' - Main entry for HTMLDOC.
76  */
77 
78 int
main(int argc,char * argv[])79 main(int  argc,				/* I - Number of command-line arguments */
80      char *argv[])			/* I - Command-line arguments */
81 {
82   int		i, j;			/* Looping vars */
83   tree_t	*document,		/* Master HTML document */
84 		*file,			/* HTML document file */
85 		*toc;			/* Table of contents */
86   exportfunc_t	exportfunc;		/* Export function */
87   const char	*extension;		/* Extension of output filename */
88   double	fontsize,		/* Base font size */
89 		fontspacing;		/* Base font spacing */
90   int		num_files;		/* Number of files provided on the command-line */
91   double	start_time,		/* Start time */
92 		load_time,		/* Load time */
93 		end_time;		/* End time */
94   const char	*debug;			/* HTMLDOC_DEBUG environment variable */
95 
96 
97   start_time = get_seconds();
98 
99 #ifdef __APPLE__
100  /*
101   * OSX passes an extra command-line option when run from the Finder.
102   * If the first command-line argument is "-psn..." then skip it...
103   */
104 
105   if (argc > 1 && strncmp(argv[1], "-psn", 4) == 0)
106   {
107     argv ++;
108     argc --;
109   }
110 #endif // __APPLE__
111 
112  /*
113   * Localize as needed...
114   */
115 
116 #ifdef HAVE_LOCALE_H
117   setlocale(LC_TIME, "");
118 #endif // HAVE_LOCALE_H
119 
120  /*
121   * Catch CTRL-C and term signals...
122   */
123 
124 #ifdef WIN32
125 #else
126   signal(SIGTERM, term_handler);
127 #endif // WIN32
128 
129  /*
130   * Set the location of data and help files...
131   */
132 
133   prefs_set_paths();
134 
135  /*
136   * Check if we are being executed as a CGI program...
137   *
138   * Note: We can't short-circuit this test to include a check for
139   * PATH_INFO since that could lead to a remote execution hole.
140   * Instead, we'll display an error message later if we can't find
141   * a PATH_INFO variable and advise the administrator on how to
142   * correct the problem...
143   */
144 
145   if (!getenv("HTMLDOC_NOCGI") && getenv("GATEWAY_INTERFACE") &&
146       getenv("SERVER_NAME") && getenv("SERVER_SOFTWARE"))
147   {
148     const char	*path_translated;	// PATH_TRANSLATED env var
149     char	bookfile[1024];		// Book filename
150 
151 
152     // CGI mode implies the following options:
153     //
154     // --no-localfiles
155     // --webpage
156     // -t pdf
157     // -f -
158     //
159     // Additional args cannot be provided on the command-line, however
160     // we load directory-specific options from the ".book" file in the
161     // current web server directory...
162 
163     CGIMode       = 1;
164     TocLevels     = 0;
165     TitlePage     = 0;
166     OutputPath[0] = '\0';
167     OutputType    = OUTPUT_WEBPAGES;
168     document      = NULL;
169     exportfunc    = (exportfunc_t)pspdf_export;
170     PSLevel       = 0;
171     PDFVersion    = 14;
172     PDFPageMode   = PDF_DOCUMENT;
173     PDFFirstPage  = PDF_PAGE_1;
174 
175     file_cookies(getenv("HTTP_COOKIE"));
176     file_referer(getenv("HTTP_REFERER"));
177 
178     progress_error(HD_ERROR_NONE, "INFO: HTMLDOC " SVERSION " starting in CGI mode.");
179 #ifdef WIN32
180     progress_error(HD_ERROR_NONE, "INFO: TEMP is \"%s\"", getenv("TEMP"));
181 #else
182     progress_error(HD_ERROR_NONE, "INFO: TMPDIR is \"%s\"", getenv("TMPDIR"));
183 #endif // WIN32
184 
185     argc = 1;
186 
187     // Look for a book file in the following order:
188     //
189     // $PATH_TRANSLATED.book
190     // `dirname $PATH_TRANSLATED`/.book
191     // .book
192     //
193     // If we find one, use it...
194     if ((path_translated = getenv("PATH_TRANSLATED")) != NULL)
195     {
196       // Try $PATH_TRANSLATED.book...
197       snprintf(bookfile, sizeof(bookfile), "%s.book", path_translated);
198       if (access(bookfile, 0))
199       {
200         // Not found, try `dirname $PATH_TRANSLATED`/.book
201         snprintf(bookfile, sizeof(bookfile), "%s/.book",
202 	         file_directory(path_translated));
203         if (access(bookfile, 0))
204 	  strlcpy(bookfile, ".book", sizeof(bookfile));
205       }
206     }
207     else
208       strlcpy(bookfile, ".book", sizeof(bookfile));
209 
210     if (!access(bookfile, 0))
211       load_book(bookfile, &document, &exportfunc, 1);
212     else
213       file_nolocal();
214   }
215   else
216   {
217    /*
218     * Default to producing HTML files.
219     */
220 
221     document   = NULL;
222     exportfunc = (exportfunc_t)html_export;
223 
224    /*
225     * Load preferences...
226     */
227 
228     prefs_load();
229   }
230 
231  /*
232   * Parse command-line options...
233   */
234 
235   fontsize    = 11.0f;
236   fontspacing = 1.2f;
237   num_files   = 0;
238   Errors      = 0;
239 
240   for (i = 1; i < argc; i ++)
241   {
242 #ifdef DEBUG
243     printf("argv[%d] = \"%s\"\n", i, argv[i]);
244 #endif // DEBUG
245 
246     if (compare_strings(argv[i], "--batch", 4) == 0)
247     {
248       i ++;
249       if (i < argc)
250       {
251         num_files ++;
252         load_book(argv[i], &document, &exportfunc);
253       }
254       else
255         usage(argv[i - 1]);
256     }
257     else if (compare_strings(argv[i], "--bodycolor", 7) == 0)
258     {
259       i ++;
260       if (i < argc)
261         strlcpy((char *)BodyColor, argv[i], sizeof(BodyColor));
262       else
263         usage(argv[i - 1]);
264     }
265     else if (compare_strings(argv[i], "--bodyfont", 7) == 0 ||
266              compare_strings(argv[i], "--textfont", 7) == 0)
267     {
268       i ++;
269       if (i < argc)
270       {
271         if (!strcasecmp(argv[i], "monospace"))
272 	  _htmlBodyFont = TYPE_MONOSPACE;
273         else if (!strcasecmp(argv[i], "serif"))
274 	  _htmlBodyFont = TYPE_SERIF;
275         else if (!strcasecmp(argv[i], "sans-serif") ||
276 	         !strcasecmp(argv[i], "sans"))
277 	  _htmlBodyFont = TYPE_SANS_SERIF;
278         else if (!strcasecmp(argv[i], "courier"))
279 	  _htmlBodyFont = TYPE_COURIER;
280         else if (!strcasecmp(argv[i], "times"))
281 	  _htmlBodyFont = TYPE_TIMES;
282         else if (!strcasecmp(argv[i], "helvetica") ||
283 	         !strcasecmp(argv[i], "arial"))
284 	  _htmlBodyFont = TYPE_HELVETICA;
285       }
286       else
287         usage(argv[i - 1]);
288     }
289     else if (compare_strings(argv[i], "--bodyimage", 7) == 0)
290     {
291       i ++;
292       if (i < argc)
293         strlcpy((char *)BodyImage, argv[i], sizeof(BodyImage));
294       else
295         usage(argv[i - 1]);
296     }
297     else if (compare_strings(argv[i], "--book", 5) == 0)
298       OutputType = OUTPUT_BOOK;
299     else if (compare_strings(argv[i], "--bottom", 5) == 0)
300     {
301       i ++;
302       if (i < argc)
303         PageBottom = get_measurement(argv[i]);
304       else
305         usage(argv[i - 1]);
306     }
307     else if (compare_strings(argv[i], "--browserwidth", 4) == 0)
308     {
309       i ++;
310       if (i < argc)
311       {
312         _htmlBrowserWidth = atof(argv[i]);
313 
314 	if (_htmlBrowserWidth < 1.0f)
315 	{
316 	  progress_error(HD_ERROR_INTERNAL_ERROR, "Bad browser width \"%s\"!",
317 	                 argv[i]);
318 	  usage();
319 	}
320       }
321       else
322         usage(argv[i - 1]);
323     }
324     else if (compare_strings(argv[i], "--charset", 4) == 0)
325     {
326       i ++;
327       if (i < argc)
328         htmlSetCharSet(argv[i]);
329       else
330         usage(argv[i - 1]);
331     }
332     else if (compare_strings(argv[i], "--color", 5) == 0)
333     {
334       OutputColor    = 1;
335       _htmlGrayscale = 0;
336     }
337     else if (compare_strings(argv[i], "--compression", 5) == 0 ||
338              strncmp(argv[i], "--compression=", 14) == 0)
339     {
340       if (strlen(argv[i]) > 14 && PDFVersion >= 12)
341         Compression = atoi(argv[i] + 14);
342       else if (PDFVersion >= 12)
343         Compression = 1;
344     }
345     else if (compare_strings(argv[i], "--continuous", 5) == 0)
346     {
347       TocLevels    = 0;
348       TitlePage    = 0;
349       OutputType   = OUTPUT_CONTINUOUS;
350       PDFPageMode  = PDF_DOCUMENT;
351       PDFFirstPage = PDF_PAGE_1;
352     }
353     else if (compare_strings(argv[i], "--cookies", 5) == 0)
354     {
355       i ++;
356       if (i < argc)
357         file_cookies(argv[i]);
358       else
359         usage(argv[i - 1]);
360     }
361     else if (compare_strings(argv[i], "--datadir", 4) == 0)
362     {
363       i ++;
364       if (i < argc)
365         _htmlData = argv[i];
366       else
367         usage(argv[i - 1]);
368     }
369 #if defined(HAVE_LIBFLTK) && !WIN32
370     else if (compare_strings(argv[i], "-display", 3) == 0 ||
371              compare_strings(argv[i], "--display", 4) == 0)
372     {
373       // The X standard requires support for the -display option, but
374       // we also support the GNU standard --display...
375       i ++;
376       if (i < argc)
377         Fl::display(argv[i]);
378       else
379         usage(argv[i - 1]);
380     }
381 #endif // HAVE_LIBFLTK && !WIN32
382     else if (compare_strings(argv[i], "--duplex", 4) == 0)
383       PageDuplex = 1;
384     else if (compare_strings(argv[i], "--effectduration", 4) == 0)
385     {
386       i ++;
387       if (i < argc)
388       {
389         PDFEffectDuration = atof(argv[i]);
390 
391 	if (PDFEffectDuration < 0.0f)
392 	{
393 	  progress_error(HD_ERROR_INTERNAL_ERROR, "Bad effect duration \"%s\"!",
394 	                 argv[i]);
395 	  usage();
396 	}
397       }
398       else
399         usage(argv[i - 1]);
400     }
401     else if (compare_strings(argv[i], "--embedfonts", 4) == 0)
402       EmbedFonts = 1;
403     else if (compare_strings(argv[i], "--encryption", 4) == 0)
404       Encryption = 1;
405     else if (compare_strings(argv[i], "--firstpage", 4) == 0)
406     {
407       i ++;
408       if (i >= argc)
409         usage(argv[i - 1]);
410 
411       for (j = 0; j < (int)(sizeof(PDFPages) / sizeof(PDFPages[0])); j ++)
412         if (strcasecmp(argv[i], PDFPages[j]) == 0)
413 	{
414 	  PDFFirstPage = j;
415 	  break;
416 	}
417     }
418     else if (compare_strings(argv[i], "--fontsize", 8) == 0)
419     {
420       i ++;
421       if (i < argc)
422       {
423         fontsize = atof(argv[i]);
424 
425 	if (fontsize < 4.0f)
426 	  fontsize = 4.0f;
427 	else if (fontsize > 24.0f)
428 	  fontsize = 24.0f;
429 
430         htmlSetBaseSize(fontsize, fontspacing);
431       }
432       else
433         usage(argv[i - 1]);
434     }
435     else if (compare_strings(argv[i], "--fontspacing", 8) == 0)
436     {
437       i ++;
438       if (i < argc)
439       {
440         fontspacing = atof(argv[i]);
441 
442 	if (fontspacing < 1.0f)
443 	  fontspacing = 1.0f;
444 	else if (fontspacing > 3.0f)
445 	  fontspacing = 3.0f;
446 
447         htmlSetBaseSize(fontsize, fontspacing);
448       }
449       else
450         usage(argv[i - 1]);
451     }
452     else if (compare_strings(argv[i], "--footer", 5) == 0)
453     {
454       i ++;
455       if (i < argc)
456         get_format(argv[i], Footer);
457       else
458         usage(argv[i - 1]);
459     }
460     else if (compare_strings(argv[i], "--format", 5) == 0 ||
461              strcmp(argv[i], "-t") == 0)
462     {
463       i ++;
464       if (i < argc)
465       {
466         if (strcasecmp(argv[i], "epub") == 0)
467 	  exportfunc = (exportfunc_t)epub_export;
468         else if (strcasecmp(argv[i], "html") == 0)
469           exportfunc = (exportfunc_t)html_export;
470         else if (strcasecmp(argv[i], "htmlsep") == 0)
471           exportfunc = (exportfunc_t)htmlsep_export;
472         else if (strcasecmp(argv[i], "pdf14") == 0 ||
473 	         strcasecmp(argv[i], "pdf") == 0)
474 	{
475           exportfunc = (exportfunc_t)pspdf_export;
476 	  PSLevel    = 0;
477 	  PDFVersion = 14;
478 	}
479         else if (strcasecmp(argv[i], "pdf13") == 0)
480 	{
481           exportfunc = (exportfunc_t)pspdf_export;
482 	  PSLevel    = 0;
483 	  PDFVersion = 13;
484 	}
485         else if (strcasecmp(argv[i], "pdf12") == 0)
486 	{
487           exportfunc = (exportfunc_t)pspdf_export;
488 	  PSLevel    = 0;
489 	  PDFVersion = 12;
490 	}
491         else if (strcasecmp(argv[i], "pdf11") == 0)
492 	{
493           exportfunc  = (exportfunc_t)pspdf_export;
494 	  PSLevel     = 0;
495 	  PDFVersion  = 11;
496 	  Compression = 0;
497 	}
498         else if (strcasecmp(argv[i], "ps1") == 0)
499         {
500 	  exportfunc = (exportfunc_t)pspdf_export;
501 	  PSLevel    = 1;
502 	}
503         else if (strcasecmp(argv[i], "ps2") == 0 ||
504                  strcasecmp(argv[i], "ps") == 0)
505         {
506 	  exportfunc = (exportfunc_t)pspdf_export;
507 	  PSLevel    = 2;
508 	}
509         else if (strcasecmp(argv[i], "ps3") == 0)
510         {
511 	  exportfunc = (exportfunc_t)pspdf_export;
512 	  PSLevel    = 3;
513 	}
514 	else
515 	  usage(argv[i - 1]);
516       }
517       else
518         usage(argv[i - 1]);
519     }
520     else if (compare_strings(argv[i], "--grayscale", 3) == 0)
521     {
522       OutputColor    = 0;
523       _htmlGrayscale = 1;
524     }
525     else if (!strcmp(argv[i], "--header"))
526     {
527       i ++;
528       if (i < argc)
529         get_format(argv[i], Header);
530       else
531         usage(argv[i - 1]);
532     }
533     else if (!strcmp(argv[i], "--header1"))
534     {
535       i ++;
536       if (i < argc)
537         get_format(argv[i], Header1);
538       else
539         usage(argv[i - 1]);
540     }
541     else if (!compare_strings(argv[i], "--headfootfont", 11))
542     {
543       i ++;
544       if (i < argc)
545       {
546         if (!strcasecmp(argv[i], "courier"))
547 	{
548 	  HeadFootType  = TYPE_COURIER;
549 	  HeadFootStyle = STYLE_NORMAL;
550 	}
551         else if (!strcasecmp(argv[i], "courier-bold"))
552 	{
553 	  HeadFootType  = TYPE_COURIER;
554 	  HeadFootStyle = STYLE_BOLD;
555 	}
556         else if (!strcasecmp(argv[i], "courier-oblique"))
557 	{
558 	  HeadFootType  = TYPE_COURIER;
559 	  HeadFootStyle = STYLE_ITALIC;
560 	}
561         else if (!strcasecmp(argv[i], "courier-boldoblique"))
562 	{
563 	  HeadFootType  = TYPE_COURIER;
564 	  HeadFootStyle = STYLE_BOLD_ITALIC;
565 	}
566         else if (!strcasecmp(argv[i], "times") ||
567 	         !strcasecmp(argv[i], "times-roman"))
568 	{
569 	  HeadFootType  = TYPE_TIMES;
570 	  HeadFootStyle = STYLE_NORMAL;
571 	}
572         else if (!strcasecmp(argv[i], "times-bold"))
573 	{
574 	  HeadFootType  = TYPE_TIMES;
575 	  HeadFootStyle = STYLE_BOLD;
576 	}
577         else if (!strcasecmp(argv[i], "times-italic"))
578 	{
579 	  HeadFootType  = TYPE_TIMES;
580 	  HeadFootStyle = STYLE_ITALIC;
581 	}
582         else if (!strcasecmp(argv[i], "times-bolditalic"))
583 	{
584 	  HeadFootType  = TYPE_TIMES;
585 	  HeadFootStyle = STYLE_BOLD_ITALIC;
586 	}
587         else if (!strcasecmp(argv[i], "helvetica"))
588 	{
589 	  HeadFootType  = TYPE_HELVETICA;
590 	  HeadFootStyle = STYLE_NORMAL;
591 	}
592         else if (!strcasecmp(argv[i], "helvetica-bold"))
593 	{
594 	  HeadFootType  = TYPE_HELVETICA;
595 	  HeadFootStyle = STYLE_BOLD;
596 	}
597         else if (!strcasecmp(argv[i], "helvetica-oblique"))
598 	{
599 	  HeadFootType  = TYPE_HELVETICA;
600 	  HeadFootStyle = STYLE_ITALIC;
601 	}
602         else if (!strcasecmp(argv[i], "helvetica-boldoblique"))
603 	{
604 	  HeadFootType  = TYPE_HELVETICA;
605 	  HeadFootStyle = STYLE_BOLD_ITALIC;
606 	}
607         else if (!strcasecmp(argv[i], "monospace"))
608 	{
609 	  HeadFootType  = TYPE_MONOSPACE;
610 	  HeadFootStyle = STYLE_NORMAL;
611 	}
612         else if (!strcasecmp(argv[i], "monospace-bold"))
613 	{
614 	  HeadFootType  = TYPE_MONOSPACE;
615 	  HeadFootStyle = STYLE_BOLD;
616 	}
617         else if (!strcasecmp(argv[i], "monospace-oblique"))
618 	{
619 	  HeadFootType  = TYPE_MONOSPACE;
620 	  HeadFootStyle = STYLE_ITALIC;
621 	}
622         else if (!strcasecmp(argv[i], "monospace-boldoblique"))
623 	{
624 	  HeadFootType  = TYPE_MONOSPACE;
625 	  HeadFootStyle = STYLE_BOLD_ITALIC;
626 	}
627         else if (!strcasecmp(argv[i], "serif") ||
628 	         !strcasecmp(argv[i], "serif-roman"))
629 	{
630 	  HeadFootType  = TYPE_SERIF;
631 	  HeadFootStyle = STYLE_NORMAL;
632 	}
633         else if (!strcasecmp(argv[i], "serif-bold"))
634 	{
635 	  HeadFootType  = TYPE_SERIF;
636 	  HeadFootStyle = STYLE_BOLD;
637 	}
638         else if (!strcasecmp(argv[i], "serif-italic"))
639 	{
640 	  HeadFootType  = TYPE_SERIF;
641 	  HeadFootStyle = STYLE_ITALIC;
642 	}
643         else if (!strcasecmp(argv[i], "serif-bolditalic"))
644 	{
645 	  HeadFootType  = TYPE_SERIF;
646 	  HeadFootStyle = STYLE_BOLD_ITALIC;
647 	}
648         else if (!strcasecmp(argv[i], "sans-serif") ||
649 	         !strcasecmp(argv[i], "sans"))
650 	{
651 	  HeadFootType  = TYPE_SANS_SERIF;
652 	  HeadFootStyle = STYLE_NORMAL;
653 	}
654         else if (!strcasecmp(argv[i], "sans-serif-bold") ||
655 	         !strcasecmp(argv[i], "sans-bold"))
656 	{
657 	  HeadFootType  = TYPE_SANS_SERIF;
658 	  HeadFootStyle = STYLE_BOLD;
659 	}
660         else if (!strcasecmp(argv[i], "sans-serif-oblique") ||
661 	         !strcasecmp(argv[i], "sans-oblique"))
662 	{
663 	  HeadFootType  = TYPE_SANS_SERIF;
664 	  HeadFootStyle = STYLE_ITALIC;
665 	}
666         else if (!strcasecmp(argv[i], "sans-serif-boldoblique") ||
667 	         !strcasecmp(argv[i], "sans-boldoblique"))
668 	{
669 	  HeadFootType  = TYPE_SANS_SERIF;
670 	  HeadFootStyle = STYLE_BOLD_ITALIC;
671 	}
672       }
673       else
674         usage(argv[i - 1]);
675     }
676     else if (compare_strings(argv[i], "--headfootsize", 11) == 0)
677     {
678       i ++;
679       if (i < argc)
680       {
681         HeadFootSize = atof(argv[i]);
682 
683 	if (HeadFootSize < 6.0f)
684 	  HeadFootSize = 6.0f;
685 	else if (HeadFootSize > 24.0f)
686 	  HeadFootSize = 24.0f;
687       }
688       else
689         usage(argv[i - 1]);
690     }
691     else if (!compare_strings(argv[i], "--headingfont", 7))
692     {
693       i ++;
694       if (i < argc)
695       {
696         if (!strcasecmp(argv[i], "courier"))
697 	  _htmlHeadingFont = TYPE_COURIER;
698         else if (!strcasecmp(argv[i], "times"))
699 	  _htmlHeadingFont = TYPE_TIMES;
700         else if (!strcasecmp(argv[i], "helvetica") ||
701 	         !strcasecmp(argv[i], "arial"))
702 	  _htmlHeadingFont = TYPE_HELVETICA;
703         else if (!strcasecmp(argv[i], "monospace"))
704 	  _htmlHeadingFont = TYPE_MONOSPACE;
705         else if (!strcasecmp(argv[i], "serif"))
706 	  _htmlHeadingFont = TYPE_SERIF;
707         else if (!strcasecmp(argv[i], "sans-serif") ||
708 	         !strcasecmp(argv[i], "sans"))
709 	  _htmlHeadingFont = TYPE_SANS_SERIF;
710       }
711       else
712         usage(argv[i - 1]);
713     }
714     else if (compare_strings(argv[i], "--help", 6) == 0)
715       usage(argv[i - 1]);
716 #ifdef HAVE_LIBFLTK
717     else if (compare_strings(argv[i], "--helpdir", 7) == 0)
718     {
719       i ++;
720       if (i < argc)
721         GUI::help_dir = argv[i];
722       else
723         usage(argv[i - 1]);
724     }
725 #endif // HAVE_LIBFLTK
726     else if (strncmp(argv[i], "--hfimage", 9) == 0)
727     {
728       int	hfimgnum;		// Image number
729       char	*hfptr;			// Pointer into option
730 
731 
732       if (strlen(argv[i]) > 9)
733       {
734         hfimgnum = strtol(argv[i] + 9, &hfptr, 10);
735 
736 	if (hfimgnum < 0 || hfimgnum >= MAX_HF_IMAGES || *hfptr)
737 	  usage(argv[i]);
738       }
739       else
740         hfimgnum = 0;
741 
742       i ++;
743 
744       if (i >= argc)
745         usage(argv[i - 1]);
746 
747       strlcpy(HFImage[hfimgnum], argv[i], sizeof(HFImage[0]));
748     }
749     else if (compare_strings(argv[i], "--jpeg", 3) == 0 ||
750              strncmp(argv[i], "--jpeg=", 7) == 0)
751     {
752       if (strlen(argv[i]) > 7)
753         OutputJPEG = atoi(argv[i] + 7);
754       else
755         OutputJPEG = 90;
756     }
757     else if (compare_strings(argv[i], "--landscape", 4) == 0)
758       Landscape = 1;
759     else if (compare_strings(argv[i], "--left", 5) == 0)
760     {
761       i ++;
762       if (i < argc)
763         PageLeft = get_measurement(argv[i]);
764       else
765         usage(argv[i - 1]);
766     }
767     else if (compare_strings(argv[i], "--letterhead", 5) == 0)
768     {
769       i ++;
770       if (i < argc)
771         strlcpy(Letterhead, argv[i], sizeof(Letterhead));
772       else
773         usage(argv[i - 1]);
774     }
775     else if (compare_strings(argv[i], "--linkcolor", 7) == 0)
776     {
777       i ++;
778       if (i < argc)
779         strlcpy(LinkColor, argv[i], sizeof(LinkColor));
780       else
781         usage(argv[i - 1]);
782     }
783     else if (strcmp(argv[i], "--links") == 0)
784       Links = 1;
785     else if (compare_strings(argv[i], "--linkstyle", 8) == 0)
786     {
787       i ++;
788       if (i < argc)
789       {
790         if (strcmp(argv[i], "plain") == 0)
791 	  LinkStyle = 0;
792         else if (strcmp(argv[i], "underline") == 0)
793 	  LinkStyle = 1;
794 	else
795 	  usage(argv[i - 1]);
796       }
797       else
798         usage(argv[i - 1]);
799     }
800     else if (compare_strings(argv[i], "--logoimage", 5) == 0)
801     {
802       i ++;
803       if (i < argc)
804         strlcpy(LogoImage, argv[i], sizeof(LogoImage));
805       else
806         usage(argv[i - 1]);
807     }
808     else if (compare_strings(argv[i], "--no-compression", 6) == 0)
809       Compression = 0;
810     else if (compare_strings(argv[i], "--no-duplex", 4) == 0)
811       PageDuplex = 0;
812     else if (compare_strings(argv[i], "--no-embedfonts", 7) == 0)
813       EmbedFonts = 0;
814     else if (compare_strings(argv[i], "--no-encryption", 7) == 0)
815       Encryption = 0;
816     else if (compare_strings(argv[i], "--no-jpeg", 6) == 0)
817       OutputJPEG = 0;
818     else if (compare_strings(argv[i], "--no-links", 7) == 0)
819       Links = 0;
820     else if (compare_strings(argv[i], "--no-localfiles", 7) == 0)
821       file_nolocal();
822     else if (compare_strings(argv[i], "--no-numbered", 6) == 0)
823       TocNumbers = 0;
824     else if (compare_strings(argv[i], "--no-overflow", 6) == 0)
825       OverflowErrors = 0;
826     else if (compare_strings(argv[i], "--no-pscommands", 6) == 0)
827       PSCommands = 0;
828     else if (compare_strings(argv[i], "--no-strict", 6) == 0)
829       StrictHTML = 0;
830     else if (compare_strings(argv[i], "--no-title", 7) == 0)
831       TitlePage = 0;
832     else if (compare_strings(argv[i], "--no-toc", 7) == 0)
833       TocLevels = 0;
834     else if (compare_strings(argv[i], "--no-truetype", 7) == 0)
835     {
836       fputs("htmldoc: Warning, --no-truetype option superseded by --no-embedfonts!\n", stderr);
837       EmbedFonts = 0;
838     }
839     else if (compare_strings(argv[i], "--no-xrxcomments", 6) == 0)
840       XRXComments = 0;
841     else if (compare_strings(argv[i], "--numbered", 5) == 0)
842       TocNumbers = 1;
843     else if (compare_strings(argv[i], "--nup", 5) == 0)
844     {
845       i ++;
846       if (i >= argc)
847         usage(argv[i - 1]);
848 
849       NumberUp = atoi(argv[i]);
850 
851       if (NumberUp != 1 && NumberUp != 2 && NumberUp != 4 &&
852           NumberUp != 6 && NumberUp != 9 && NumberUp != 16)
853 	usage(argv[i - 1]);
854     }
855     else if (compare_strings(argv[i], "--outdir", 6) == 0 ||
856              strcmp(argv[i], "-d") == 0)
857     {
858       i ++;
859       if (i < argc)
860       {
861         strlcpy(OutputPath, argv[i], sizeof(OutputPath));
862         OutputFiles = 1;
863       }
864       else
865         usage(argv[i - 1]);
866     }
867     else if (compare_strings(argv[i], "--outfile", 6) == 0 ||
868              strcmp(argv[i], "-f") == 0)
869     {
870       i ++;
871       if (i < argc)
872       {
873         strlcpy(OutputPath, argv[i], sizeof(OutputPath));
874         OutputFiles = 0;
875 
876         if ((extension = file_extension(argv[i])) != NULL)
877         {
878           if (strcasecmp(extension, "epub") == 0)
879             exportfunc = (exportfunc_t)epub_export;
880 	  else if (strcasecmp(extension, "html") == 0)
881             exportfunc = (exportfunc_t)html_export;
882           else if (strcasecmp(extension, "pdf") == 0)
883 	  {
884             exportfunc = (exportfunc_t)pspdf_export;
885 	    PSLevel    = 0;
886           }
887           else if (strcasecmp(extension, "ps") == 0)
888           {
889 	    exportfunc = (exportfunc_t)pspdf_export;
890 
891 	    if (PSLevel == 0)
892 	      PSLevel = 2;
893 	  }
894         }
895       }
896       else
897         usage(argv[i - 1]);
898     }
899     else if (compare_strings(argv[i], "--overflow", 4) == 0)
900       OverflowErrors = 1;
901     else if (compare_strings(argv[i], "--owner-password", 4) == 0)
902     {
903       i ++;
904       if (i < argc)
905         strlcpy(OwnerPassword, argv[i], sizeof(OwnerPassword));
906       else
907         usage(argv[i - 1]);
908     }
909     else if (compare_strings(argv[i], "--pageduration", 7) == 0)
910     {
911       i ++;
912       if (i < argc)
913       {
914         PDFPageDuration = atof(argv[i]);
915 
916 	if (PDFPageDuration < 1.0f)
917 	{
918 	  progress_error(HD_ERROR_INTERNAL_ERROR, "Bad page duration \"%s\"!",
919 	                 argv[i]);
920 	  usage();
921 	}
922       }
923       else
924         usage(argv[i - 1]);
925     }
926     else if (compare_strings(argv[i], "--pageeffect", 7) == 0)
927     {
928       i ++;
929       if (i >= argc)
930         usage(argv[i - 1]);
931 
932       for (j = 0; j < (int)(sizeof(PDFEffects) / sizeof(PDFEffects[0])); j ++)
933         if (strcasecmp(argv[i], PDFEffects[j]) == 0)
934 	{
935 	  PDFEffect = j;
936 	  break;
937 	}
938     }
939     else if (compare_strings(argv[i], "--pagelayout", 7) == 0)
940     {
941       i ++;
942       if (i >= argc)
943         usage(argv[i - 1]);
944 
945       for (j = 0; j < (int)(sizeof(PDFLayouts) / sizeof(PDFLayouts[0])); j ++)
946         if (strcasecmp(argv[i], PDFLayouts[j]) == 0)
947 	{
948 	  PDFPageLayout = j;
949 	  break;
950 	}
951     }
952     else if (compare_strings(argv[i], "--pagemode", 7) == 0)
953     {
954       i ++;
955       if (i >= argc)
956         usage(argv[i - 1]);
957 
958       for (j = 0; j < (int)(sizeof(PDFModes) / sizeof(PDFModes[0])); j ++)
959         if (strcasecmp(argv[i], PDFModes[j]) == 0)
960 	{
961 	  PDFPageMode = j;
962 	  break;
963 	}
964     }
965     else if (compare_strings(argv[i], "--path", 5) == 0)
966     {
967       i ++;
968       if (i < argc)
969         strlcpy(Path, argv[i], sizeof(Path));
970       else
971         usage(argv[i - 1]);
972     }
973     else if (compare_strings(argv[i], "--permissions", 4) == 0)
974     {
975       i ++;
976       if (i >= argc)
977         usage(argv[i - 1]);
978 
979       set_permissions(argv[i]);
980     }
981     else if (compare_strings(argv[i], "--portrait", 4) == 0)
982       Landscape = 0;
983     else if (compare_strings(argv[i], "--proxy", 4) == 0)
984     {
985       i ++;
986       if (i < argc)
987       {
988         strlcpy(Proxy, argv[i], sizeof(Proxy));
989 	file_proxy(Proxy);
990       }
991       else
992         usage(argv[i - 1]);
993     }
994     else if (compare_strings(argv[i], "--pscommands", 3) == 0)
995       PSCommands = 1;
996     else if (compare_strings(argv[i], "--quiet", 3) == 0)
997       Verbosity = -1;
998     else if (!compare_strings(argv[i], "--referer", 4))
999     {
1000       i ++;
1001       if (i < argc)
1002         file_referer(argv[i]);
1003       else
1004         usage(argv[i - 1]);
1005     }
1006     else if (compare_strings(argv[i], "--right", 4) == 0)
1007     {
1008       i ++;
1009       if (i < argc)
1010         PageRight = get_measurement(argv[i]);
1011       else
1012         usage(argv[i - 1]);
1013     }
1014     else if (compare_strings(argv[i], "--size", 4) == 0)
1015     {
1016       i ++;
1017       if (i < argc)
1018         set_page_size(argv[i]);
1019       else
1020         usage(argv[i - 1]);
1021     }
1022     else if (compare_strings(argv[i], "--strict", 4) == 0)
1023       StrictHTML = 1;
1024     else if (compare_strings(argv[i], "--textcolor", 7) == 0)
1025     {
1026       i ++;
1027       if (i < argc)
1028         htmlSetTextColor((uchar *)argv[i]);
1029       else
1030         usage(argv[i - 1]);
1031     }
1032     else if (compare_strings(argv[i], "--title", 7) == 0)
1033       TitlePage = 1;
1034     else if (compare_strings(argv[i], "--titlefile", 8) == 0 ||
1035              compare_strings(argv[i], "--titleimage", 8) == 0)
1036     {
1037       i ++;
1038       if (i < argc)
1039         strlcpy(TitleImage, argv[i], sizeof(TitleImage));
1040       else
1041         usage(argv[i - 1]);
1042 
1043       TitlePage = 1;
1044     }
1045     else if (compare_strings(argv[i], "--tocfooter", 6) == 0)
1046     {
1047       i ++;
1048       if (i < argc)
1049         get_format(argv[i], TocFooter);
1050       else
1051         usage(argv[i - 1]);
1052     }
1053     else if (compare_strings(argv[i], "--tocheader", 6) == 0)
1054     {
1055       i ++;
1056       if (i < argc)
1057         get_format(argv[i], TocHeader);
1058       else
1059         usage(argv[i - 1]);
1060     }
1061     else if (compare_strings(argv[i], "--toclevels", 6) == 0)
1062     {
1063       i ++;
1064       if (i < argc)
1065         TocLevels = atoi(argv[i]);
1066       else
1067         usage(argv[i - 1]);
1068     }
1069     else if (compare_strings(argv[i], "--toctitle", 6) == 0)
1070     {
1071       i ++;
1072       if (i < argc)
1073         strlcpy(TocTitle, argv[i], sizeof(TocTitle));
1074       else
1075         usage(argv[i - 1]);
1076     }
1077     else if (compare_strings(argv[i], "--top", 5) == 0)
1078     {
1079       i ++;
1080       if (i < argc)
1081         PageTop = get_measurement(argv[i]);
1082       else
1083         usage(argv[i - 1]);
1084     }
1085     else if (compare_strings(argv[i], "--user-password", 4) == 0)
1086     {
1087       i ++;
1088       if (i < argc)
1089         strlcpy(UserPassword, argv[i], sizeof(UserPassword));
1090       else
1091         usage(argv[i - 1]);
1092     }
1093     else if (compare_strings(argv[i], "--truetype", 4) == 0)
1094     {
1095       fputs("htmldoc: Warning, --truetype option superseded by --embedfonts!\n", stderr);
1096 
1097       EmbedFonts = 1;
1098     }
1099     else if (compare_strings(argv[i], "--verbose", 6) == 0 ||
1100              strcmp(argv[i], "-v") == 0)
1101     {
1102       Verbosity ++;
1103     }
1104     else if (compare_strings(argv[i], "--version", 6) == 0)
1105     {
1106       puts(SVERSION);
1107       return (0);
1108     }
1109     else if (compare_strings(argv[i], "--webpage", 3) == 0)
1110     {
1111       TocLevels    = 0;
1112       TitlePage    = 0;
1113       OutputType   = OUTPUT_WEBPAGES;
1114       PDFPageMode  = PDF_DOCUMENT;
1115       PDFFirstPage = PDF_PAGE_1;
1116     }
1117     else if (compare_strings(argv[i], "--xrxcomments", 3) == 0)
1118       XRXComments = 1;
1119     else if (strcmp(argv[i], "-") == 0)
1120     {
1121      /*
1122       * Read from stdin...
1123       */
1124 
1125       num_files ++;
1126 
1127       _htmlPPI = 72.0f * _htmlBrowserWidth / (PageWidth - PageLeft - PageRight);
1128 
1129       file = htmlAddTree(NULL, MARKUP_FILE, NULL);
1130       htmlSetVariable(file, (uchar *)"_HD_FILENAME", (uchar *)"");
1131       htmlSetVariable(file, (uchar *)"_HD_BASE", (uchar *)".");
1132 
1133 #ifdef WIN32
1134       // Make sure stdin is in binary mode.
1135       // (I hate Microsoft... I hate Microsoft... Everybody join in!)
1136       setmode(0, O_BINARY);
1137 #elif defined(__EMX__)
1138       // OS/2 has a setmode for FILE's...
1139       fflush(stdin);
1140       _fsetmode(stdin, "b");
1141 #endif // WIN32 || __EMX__
1142 
1143       _htmlCurrentFile = "(stdin)";
1144       htmlReadFile(file, stdin, ".");
1145 
1146       if (document == NULL)
1147         document = file;
1148       else
1149       {
1150         while (document->next != NULL)
1151           document = document->next;
1152 
1153         document->next = file;
1154         file->prev     = document;
1155       }
1156     }
1157     else if (argv[i][0] == '-')
1158       usage(argv[i]);
1159 #ifdef HAVE_LIBFLTK
1160     else if (strlen(argv[i]) > 5 &&
1161              strcmp(argv[i] + strlen(argv[i]) - 5, ".book") == 0)
1162     {
1163      /*
1164       * GUI mode...
1165       */
1166 
1167       if (BookGUI == NULL)
1168         BookGUI = new GUI(argv[i]);
1169       else
1170         BookGUI->loadBook(argv[i]);
1171     }
1172 #endif /* HAVE_LIBFLTK */
1173     else
1174     {
1175       num_files ++;
1176 
1177       read_file(argv[i], &document, Path);
1178     }
1179   }
1180 
1181   if (CGIMode)
1182   {
1183     char	url[1024];		// URL
1184     const char	*https,			// HTTPS env var, if any
1185 		*path_info,		// Path info, if any
1186 		*query,			// Query string, if any
1187 		*server_name,		// Server name
1188 		*server_port;		// Server port
1189 
1190 
1191     https       = getenv("HTTPS");
1192     path_info   = getenv("PATH_INFO");
1193     query       = getenv("QUERY_STRING");
1194     server_name = getenv("SERVER_NAME");
1195     server_port = getenv("SERVER_PORT");
1196 
1197     if (server_port && path_info && *path_info)
1198     {
1199       // Read the referenced file from the local server...
1200       if (https && strcmp(https, "off"))
1201 	httpAssembleURI(HTTP_URI_CODING_ALL, url, sizeof(url), "https",
1202 	                NULL, server_name, atoi(server_port), path_info);
1203       else
1204 	httpAssembleURI(HTTP_URI_CODING_ALL, url, sizeof(url), "http",
1205 	                NULL, server_name, atoi(server_port), path_info);
1206 
1207       if (query && *query && *query != '-')
1208       {
1209 	// Include query string on end of URL, which is already URI encoded...
1210         strlcat(url, "?", sizeof(url));
1211 	strlcat(url, query, sizeof(url));
1212       }
1213 
1214       progress_error(HD_ERROR_NONE, "INFO: HTMLDOC converting \"%s\".", url);
1215 
1216       num_files ++;
1217 
1218       read_file(url, &document, Path);
1219     }
1220     else
1221       progress_error(HD_ERROR_FILE_NOT_FOUND,
1222                      "PATH_INFO is not set in the environment!");
1223   }
1224 
1225  /*
1226   * Display the GUI if necessary...
1227   */
1228 
1229 #ifdef HAVE_LIBFLTK
1230   if (num_files == 0 && BookGUI == NULL)
1231     BookGUI = new GUI();
1232 
1233   if (BookGUI != NULL)
1234   {
1235     Fl_File_Icon::load_system_icons();
1236 
1237     BookGUI->show();
1238 
1239     i = Fl::run();
1240 
1241     delete BookGUI;
1242 
1243     return (i);
1244   }
1245 #endif /* HAVE_LIBFLTK */
1246 
1247  /*
1248   * We *must* have a document to process...
1249   */
1250 
1251   if (num_files == 0 || document == NULL)
1252     usage("No HTML files!");
1253 
1254  /*
1255   * Find the first one in the list...
1256   */
1257 
1258   while (document && document->prev != NULL)
1259     document = document->prev;
1260 
1261   // Fix links...
1262   htmlFixLinks(document, document);
1263 
1264   load_time = get_seconds();
1265 
1266   // Show debug info...
1267   htmlDebugStats("Document Tree", document);
1268 
1269  /*
1270   * Build a table of contents for the documents if necessary...
1271   */
1272 
1273   if (OutputType == OUTPUT_BOOK && TocLevels > 0)
1274   {
1275     toc = toc_build(document);
1276   }
1277   else
1278   {
1279     if (TocNumbers)
1280       htmlDeleteTree(toc_build(document));
1281 
1282     toc = NULL;
1283   }
1284 
1285   htmlDebugStats("Table of Contents Tree", toc);
1286 
1287  /*
1288   * Generate the output file(s).
1289   */
1290 
1291   (*exportfunc)(document, toc);
1292 
1293   end_time = get_seconds();
1294 
1295  /*
1296   * Report running time statistics as needed...
1297   */
1298 
1299   if ((debug = getenv("HTMLDOC_DEBUG")) != NULL &&
1300       (strstr(debug, "all") != NULL || strstr(debug, "timing") != NULL))
1301     progress_error(HD_ERROR_NONE, "TIMING: %.3f %.3f %.3f",
1302                    load_time - start_time, end_time - load_time,
1303 		   end_time - start_time);
1304 
1305  /*
1306   * Cleanup...
1307   */
1308 
1309   htmlDeleteTree(document);
1310   htmlDeleteTree(toc);
1311 
1312   file_cleanup();
1313   image_flush_cache();
1314 
1315   return (Errors);
1316 }
1317 
1318 
1319 /*
1320  * 'prefs_getrc()' - Get the rc file for preferences...
1321  */
1322 
1323 static const char *
prefs_getrc(void)1324 prefs_getrc(void)
1325 {
1326 #ifdef WIN32
1327   HKEY		key;		// Registry key
1328   DWORD		size;		// Size of string
1329   char		home[1024];	// Home (profile) directory
1330 #else
1331   const char	*home;		// Home directory
1332 #endif // WIN32
1333   static char	htmldocrc[1024];// HTMLDOC RC file
1334 
1335 
1336   // Find the home directory...
1337 #ifdef WIN32
1338   // Open the registry...
1339   if (RegOpenKeyEx(HKEY_CURRENT_USER,
1340                    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0,
1341 		   KEY_READ, &key))
1342   {
1343     // Use the install directory...
1344     strlcpy(home, _htmlData, sizeof(home));
1345   }
1346   else
1347   {
1348     // Grab the current user's AppData directory...
1349     size = sizeof(home);
1350     if (RegQueryValueEx(key, "AppData", NULL, NULL, (unsigned char *)home, &size))
1351       strlcpy(home, _htmlData, sizeof(home));
1352 
1353     RegCloseKey(key);
1354   }
1355 #else
1356   if ((home = getenv("HOME")) == NULL)
1357     home = _htmlData;
1358 #endif // WIN32
1359 
1360   // Format the rc filename and return...
1361   snprintf(htmldocrc, sizeof(htmldocrc), "%s/.htmldocrc", home);
1362 
1363   return (htmldocrc);
1364 }
1365 
1366 
1367 /*
1368  * 'prefs_load()' - Load HTMLDOC preferences...
1369  */
1370 
1371 void
prefs_load(void)1372 prefs_load(void)
1373 {
1374   int	pos;			// Header/footer position
1375   char	line[2048];		// Line from RC file
1376   FILE	*fp;			// File pointer
1377 
1378 
1379   //
1380   // Read the preferences file...
1381   //
1382 
1383   if ((fp = fopen(prefs_getrc(), "r")) != NULL)
1384   {
1385     while (fgets(line, sizeof(line), fp) != NULL)
1386     {
1387       if (line[strlen(line) - 1] == '\n')
1388         line[strlen(line) - 1] = '\0';
1389 
1390       if (strncasecmp(line, "TEXTCOLOR=", 10) == 0)
1391 	htmlSetTextColor((uchar *)(line + 10));
1392       else if (strncasecmp(line, "BODYCOLOR=", 10) == 0)
1393 	strlcpy(BodyColor, line + 10, sizeof(BodyColor));
1394       else if (strncasecmp(line, "BODYIMAGE=", 10) == 0)
1395 	strlcpy(BodyImage, line + 10, sizeof(BodyImage));
1396       else if (strncasecmp(line, "LINKCOLOR=", 10) == 0)
1397         strlcpy(LinkColor, line + 10, sizeof(LinkColor));
1398       else if (strncasecmp(line, "LINKSTYLE=", 10) == 0)
1399 	LinkStyle = atoi(line + 10);
1400       else if (strncasecmp(line, "BROWSERWIDTH=", 13) == 0)
1401 	_htmlBrowserWidth = atof(line + 13);
1402       else if (strncasecmp(line, "PAGEWIDTH=", 10) == 0)
1403 	PageWidth = atoi(line + 10);
1404       else if (strncasecmp(line, "PAGELENGTH=", 11) == 0)
1405 	PageLength = atoi(line + 11);
1406       else if (strncasecmp(line, "PAGELEFT=", 9) == 0)
1407 	PageLeft = atoi(line + 9);
1408       else if (strncasecmp(line, "PAGERIGHT=", 10) == 0)
1409 	PageRight = atoi(line + 10);
1410       else if (strncasecmp(line, "PAGETOP=", 8) == 0)
1411 	PageTop = atoi(line + 8);
1412       else if (strncasecmp(line, "PAGEBOTTOM=", 11) == 0)
1413 	PageBottom = atoi(line + 11);
1414       else if (strncasecmp(line, "PAGEDUPLEX=", 11) == 0)
1415 	PageDuplex = atoi(line + 11);
1416       else if (strncasecmp(line, "LANDSCAPE=", 10) == 0)
1417 	Landscape = atoi(line + 10);
1418       else if (strncasecmp(line, "COMPRESSION=", 12) == 0)
1419 	Compression = atoi(line + 12);
1420       else if (strncasecmp(line, "OUTPUTCOLOR=", 12) == 0)
1421       {
1422 	OutputColor    = atoi(line + 12);
1423 	_htmlGrayscale = !OutputColor;
1424       }
1425       else if (strncasecmp(line, "TOCNUMBERS=", 11) == 0)
1426 	TocNumbers = atoi(line + 11);
1427       else if (strncasecmp(line, "TOCLEVELS=", 10) == 0)
1428 	TocLevels = atoi(line + 10);
1429       else if (strncasecmp(line, "JPEG=", 5) == 0)
1430 	OutputJPEG = atoi(line + 1);
1431       else if (strncasecmp(line, "PAGEHEADER=", 11) == 0)
1432 	get_format(line + 11, Header);
1433       else if (strncasecmp(line, "PAGEFOOTER=", 11) == 0)
1434 	get_format(line + 11, Footer);
1435       else if (strncasecmp(line, "NUMBERUP=", 9) == 0)
1436         NumberUp = atoi(line + 9);
1437       else if (strncasecmp(line, "TOCHEADER=", 10) == 0)
1438 	get_format(line + 10, TocHeader);
1439       else if (strncasecmp(line, "TOCFOOTER=", 10) == 0)
1440 	get_format(line + 10, TocFooter);
1441       else if (strncasecmp(line, "TOCTITLE=", 9) == 0)
1442 	strlcpy(TocTitle, line + 9, sizeof(TocTitle));
1443       else if (strncasecmp(line, "BODYFONT=", 9) == 0)
1444 	_htmlBodyFont = (typeface_t)atoi(line + 9);
1445       else if (strncasecmp(line, "HEADINGFONT=", 12) == 0)
1446 	_htmlHeadingFont = (typeface_t)atoi(line + 12);
1447       else if (strncasecmp(line, "FONTSIZE=", 9) == 0)
1448 	htmlSetBaseSize(atof(line + 9),
1449 	                _htmlSpacings[SIZE_P] / _htmlSizes[SIZE_P]);
1450       else if (strncasecmp(line, "FONTSPACING=", 12) == 0)
1451 	htmlSetBaseSize(_htmlSizes[SIZE_P], atof(line + 12));
1452       else if (strncasecmp(line, "HEADFOOTTYPE=", 13) == 0)
1453 	HeadFootType = (typeface_t)atoi(line + 13);
1454       else if (strncasecmp(line, "HEADFOOTSTYLE=", 14) == 0)
1455         HeadFootStyle = (style_t)atoi(line + 14);
1456       else if (strncasecmp(line, "HEADFOOTSIZE=", 13) == 0)
1457 	HeadFootSize = atof(line + 13);
1458       else if (strncasecmp(line, "PDFVERSION=", 11) == 0)
1459       {
1460         if (strchr(line + 11, '.') != NULL)
1461 	  PDFVersion = (int)(atof(line + 11) * 10.0 + 0.5);
1462 	else
1463 	  PDFVersion = atoi(line + 11);
1464       }
1465       else if (strncasecmp(line, "PSLEVEL=", 8) == 0)
1466 	PSLevel = atoi(line + 8);
1467       else if (strncasecmp(line, "PSCOMMANDS=", 11) == 0)
1468 	PSCommands = atoi(line + 11);
1469       else if (strncasecmp(line, "XRXCOMMENTS=", 12) == 0)
1470 	XRXComments = atoi(line + 12);
1471       else if (strncasecmp(line, "CHARSET=", 8) == 0)
1472 	htmlSetCharSet(line + 8);
1473       else if (strncasecmp(line, "PAGEMODE=", 9) == 0)
1474 	PDFPageMode = atoi(line + 9);
1475       else if (strncasecmp(line, "PAGELAYOUT=", 11) == 0)
1476 	PDFPageLayout = atoi(line + 11);
1477       else if (strncasecmp(line, "FIRSTPAGE=", 10) == 0)
1478 	PDFFirstPage = atoi(line + 10);
1479       else if (strncasecmp(line, "PAGEEFFECT=", 11) == 0)
1480 	PDFEffect = atoi(line + 11);
1481       else if (strncasecmp(line, "PAGEDURATION=", 14) == 0)
1482 	PDFPageDuration = atof(line + 14);
1483       else if (strncasecmp(line, "EFFECTDURATION=", 16) == 0)
1484 	PDFEffectDuration = atof(line + 16);
1485       else if (strncasecmp(line, "ENCRYPTION=", 11) == 0)
1486 	Encryption = atoi(line + 11);
1487       else if (strncasecmp(line, "PERMISSIONS=", 12) == 0)
1488 	Permissions = atoi(line + 12);
1489       else if (strncasecmp(line, "OWNERPASSWORD=", 14) == 0)
1490 	strlcpy(OwnerPassword, line + 14, sizeof(OwnerPassword));
1491       else if (strncasecmp(line, "USERPASSWORD=", 13) == 0)
1492         strlcpy(UserPassword, line + 13, sizeof(UserPassword));
1493       else if (strncasecmp(line, "LINKS=", 6) == 0)
1494         Links = atoi(line + 6);
1495       else if (strncasecmp(line, "TRUETYPE=", 9) == 0)
1496         EmbedFonts = atoi(line + 9);
1497       else if (strncasecmp(line, "EMBEDFONTS=", 11) == 0)
1498         EmbedFonts = atoi(line + 11);
1499       else if (strncasecmp(line, "PATH=", 5) == 0)
1500 	strlcpy(Path, line + 5, sizeof(Path));
1501       else if (strncasecmp(line, "PROXY=", 6) == 0)
1502 	strlcpy(Proxy, line + 6, sizeof(Proxy));
1503       else if (strncasecmp(line, "STRICTHTML=", 11) == 0)
1504         StrictHTML = atoi(line + 11);
1505 
1506 #  ifdef HAVE_LIBFLTK
1507       else if (strncasecmp(line, "EDITOR=", 7) == 0)
1508         strlcpy(HTMLEditor, line + 7, sizeof(HTMLEditor));
1509       else if (strncasecmp(line, "TOOLTIPS=", 9) == 0)
1510         Tooltips = atoi(line + 9);
1511 #  endif // HAVE_LIBFLTK
1512     }
1513 
1514     fclose(fp);
1515   }
1516 
1517   // Check header/footer formats...
1518   for (pos = 0; pos < 3; pos ++)
1519     if (Header[pos])
1520       break;
1521 
1522   if (pos == 3)
1523     get_format(".t.", Header);
1524 
1525   for (pos = 0; pos < 3; pos ++)
1526     if (Footer[pos])
1527       break;
1528 
1529   if (pos == 3)
1530     get_format("h.1", Footer);
1531 
1532   for (pos = 0; pos < 3; pos ++)
1533     if (TocHeader[pos])
1534       break;
1535 
1536   if (pos == 3)
1537     get_format(".t.", TocHeader);
1538 
1539   for (pos = 0; pos < 3; pos ++)
1540     if (TocFooter[pos])
1541       break;
1542 
1543   if (pos == 3)
1544     get_format("..i", TocFooter);
1545 }
1546 
1547 
1548 /*
1549  * 'prefs_save()' - Save HTMLDOC preferences...
1550  */
1551 
1552 void
prefs_save(void)1553 prefs_save(void)
1554 {
1555   FILE	*fp;			// File pointer
1556 
1557 
1558   if ((fp = fopen(prefs_getrc(), "w")) != NULL)
1559   {
1560     fputs("#HTMLDOCRC " SVERSION "\n", fp);
1561 
1562     fprintf(fp, "TEXTCOLOR=%s\n", _htmlTextColor);
1563     fprintf(fp, "BODYCOLOR=%s\n", BodyColor);
1564     fprintf(fp, "BODYIMAGE=%s\n", BodyImage);
1565     fprintf(fp, "LINKCOLOR=%s\n", LinkColor);
1566     fprintf(fp, "LINKSTYLE=%d\n", LinkStyle);
1567     fprintf(fp, "BROWSERWIDTH=%.0f\n", _htmlBrowserWidth);
1568     fprintf(fp, "PAGEWIDTH=%d\n", PageWidth);
1569     fprintf(fp, "PAGELENGTH=%d\n", PageLength);
1570     fprintf(fp, "PAGELEFT=%d\n", PageLeft);
1571     fprintf(fp, "PAGERIGHT=%d\n", PageRight);
1572     fprintf(fp, "PAGETOP=%d\n", PageTop);
1573     fprintf(fp, "PAGEBOTTOM=%d\n", PageBottom);
1574     fprintf(fp, "PAGEDUPLEX=%d\n", PageDuplex);
1575     fprintf(fp, "LANDSCAPE=%d\n", Landscape);
1576     fprintf(fp, "COMPRESSION=%d\n", Compression);
1577     fprintf(fp, "OUTPUTCOLOR=%d\n", OutputColor);
1578     fprintf(fp, "TOCNUMBERS=%d\n", TocNumbers);
1579     fprintf(fp, "TOCLEVELS=%d\n", TocLevels);
1580     fprintf(fp, "JPEG=%d\n", OutputJPEG);
1581     fprintf(fp, "PAGEHEADER=%s\n", get_fmt(Header));
1582     fprintf(fp, "PAGEFOOTER=%s\n", get_fmt(Footer));
1583     fprintf(fp, "NUMBERUP=%d\n", NumberUp);
1584     fprintf(fp, "TOCHEADER=%s\n", get_fmt(TocHeader));
1585     fprintf(fp, "TOCFOOTER=%s\n", get_fmt(TocFooter));
1586     fprintf(fp, "TOCTITLE=%s\n", TocTitle);
1587     fprintf(fp, "BODYFONT=%d\n", _htmlBodyFont);
1588     fprintf(fp, "HEADINGFONT=%d\n", _htmlHeadingFont);
1589     fprintf(fp, "FONTSIZE=%.2f\n", _htmlSizes[SIZE_P]);
1590     fprintf(fp, "FONTSPACING=%.2f\n",
1591             _htmlSpacings[SIZE_P] / _htmlSizes[SIZE_P]);
1592     fprintf(fp, "HEADFOOTTYPE=%d\n", HeadFootType);
1593     fprintf(fp, "HEADFOOTSTYLE=%d\n", HeadFootStyle);
1594     fprintf(fp, "HEADFOOTSIZE=%.2f\n", HeadFootSize);
1595     fprintf(fp, "PDFVERSION=%d\n", PDFVersion);
1596     fprintf(fp, "PSLEVEL=%d\n", PSLevel);
1597     fprintf(fp, "PSCOMMANDS=%d\n", PSCommands);
1598     fprintf(fp, "XRXCOMMENTS=%d\n", XRXComments);
1599     fprintf(fp, "CHARSET=%s\n", _htmlCharSet);
1600     fprintf(fp, "PAGEMODE=%d\n", PDFPageMode);
1601     fprintf(fp, "PAGELAYOUT=%d\n", PDFPageLayout);
1602     fprintf(fp, "FIRSTPAGE=%d\n", PDFFirstPage);
1603     fprintf(fp, "PAGEEFFECT=%d\n", PDFEffect);
1604     fprintf(fp, "PAGEDURATION=%.0f\n", PDFPageDuration);
1605     fprintf(fp, "EFFECTDURATION=%.1f\n", PDFEffectDuration);
1606     fprintf(fp, "ENCRYPTION=%d\n", Encryption);
1607     fprintf(fp, "PERMISSIONS=%d\n", Permissions);
1608     fprintf(fp, "OWNERPASSWORD=%s\n", OwnerPassword);
1609     fprintf(fp, "USERPASSWORD=%s\n", UserPassword);
1610     fprintf(fp, "LINKS=%d\n", Links);
1611     fprintf(fp, "EMBEDFONTS=%d\n", EmbedFonts);
1612     fprintf(fp, "PATH=%s\n", Path);
1613     fprintf(fp, "PROXY=%s\n", Proxy);
1614     fprintf(fp, "STRICTHTML=%d\n", StrictHTML);
1615 
1616 #ifdef HAVE_LIBFLTK
1617     fprintf(fp, "EDITOR=%s\n", HTMLEditor);
1618     fprintf(fp, "TOOLTIPS=%d\n", Tooltips);
1619 #endif // HAVE_LIBFLTK
1620 
1621     fclose(fp);
1622   }
1623 }
1624 
1625 
1626 /*
1627  * 'prefs_set_paths()' - Set HTMLDOC data/help paths...
1628  */
1629 
1630 void
prefs_set_paths(void)1631 prefs_set_paths(void)
1632 {
1633   //
1634   // Get the installed directories...
1635   //
1636 
1637 #ifdef WIN32			//// Do registry magic...
1638   HKEY		key;		// Registry key
1639   DWORD		size;		// Size of string
1640   static char	data[1024];	// Data directory
1641   static char	doc[1024];	// Documentation directory
1642   static char	path[4096];	// PATH environment variable
1643 
1644   // Open the registry...
1645   if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\HTMLDOC", 0, KEY_READ, &key))
1646   {
1647     // Grab the installed directories...
1648     size = sizeof(data);
1649     if (!RegQueryValueEx(key, "data", NULL, NULL, (unsigned char *)data, &size))
1650       _htmlData = data;
1651     else
1652       progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to read \"data\" value from registry!");
1653 
1654 #  ifdef HAVE_LIBFLTK
1655     size = sizeof(doc);
1656     if (!RegQueryValueEx(key, "doc", NULL, NULL, (unsigned char *)doc, &size))
1657       GUI::help_dir = doc;
1658 #  endif // HAVE_LIBFLTK
1659 
1660     RegCloseKey(key);
1661   }
1662   else
1663     progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to read HTMLDOC installation from registry!");
1664 
1665   // See if the HTMLDOC program folder is in the system execution path...
1666   if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1667                     "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
1668                     0, KEY_READ | KEY_WRITE, &key))
1669   {
1670     // Grab the current path...
1671     size = sizeof(path);
1672     if (!RegQueryValueEx(key, "Path", NULL, NULL, (unsigned char *)path, &size))
1673       if (strstr(path, _htmlData) == NULL)
1674       {
1675         // The data directory is not in the path, so add it...
1676         strlcat(path, ";", sizeof(path));
1677         strlcat(path, _htmlData, sizeof(path));
1678         RegSetValueEx(key, "Path", 0, REG_EXPAND_SZ, (unsigned char *)path, strlen(path) + 1);
1679       }
1680   }
1681 
1682 #elif defined(__EMX__) && defined(HAVE_LIBFLTK)
1683   // If being installed within XFree86 OS/2 Environment
1684   // we can use those values which are overwritten by
1685   // the according environment variables.
1686   _htmlData = strdup(__XOS2RedirRoot("/XFree86/lib/X11/htmldoc"));
1687   GUI::help_dir = strdup(__XOS2RedirRoot("/XFree86/lib/X11/htmldoc/doc"));
1688 
1689 #elif defined(__APPLE__) && defined(HAVE_LIBFLTK)
1690   char          path[PROC_PIDPATHINFO_MAXSIZE + 1];
1691                                 	// Process path
1692   int           pathlen;                // Length of path string
1693   static char	resources[1024];	// Resources directory
1694 
1695   if ((pathlen = proc_pidpath(getpid(), path, sizeof(path) - 1)) >= 0)
1696   {
1697     char        *ptr;           // Pointer into path
1698 
1699     path[pathlen] = '\0';
1700 //    printf("proc_pidpath returned \"%s\"\n", path);
1701 
1702     if ((ptr = strstr(path, "/Contents/MacOS")) != NULL)
1703     {
1704       *ptr = '\0';
1705 //      printf("Bundle path is \"%s\"\n", path);
1706 
1707       snprintf(resources, sizeof(resources), "%s/Contents/Resources", path);
1708       _htmlData     = resources;
1709       GUI::help_dir = resources;
1710     }
1711   }
1712 //  else
1713 //    perror("proc_pidpath failed");
1714 
1715 #elif defined(__linux)
1716   const char    *snap;                  // SNAP environment variable
1717 
1718   // Support HTMLDOC as a snap package...
1719   if ((snap = getenv("SNAP")) != NULL)
1720   {
1721     static char datadir[1024];          // Data directory
1722 
1723     snprintf(datadir, sizeof(datadir), "%s/share/htmldoc", snap);
1724     _htmlData = datadir;
1725 
1726 #  ifdef HAVE_LIBFLTK
1727     static char docdir[1024];           // Documentation directory
1728 
1729     snprintf(docdir, sizeof(docdir), "%s/share/doc/htmldoc", snap);
1730     GUI::help_dir = docdir;
1731 #  endif // HAVE_LIBFLTK
1732   }
1733 #endif // WIN32
1734 
1735   //
1736   // See if the installed directories have been overridden by
1737   // environment variables...
1738   //
1739 
1740   if (getenv("HTMLDOC_DATA") != NULL)
1741     _htmlData = getenv("HTMLDOC_DATA");
1742 
1743 #ifdef HAVE_LIBFLTK
1744   if (getenv("HTMLDOC_HELP") != NULL)
1745     GUI::help_dir = getenv("HTMLDOC_HELP");
1746 #endif // HAVE_LIBFLTK
1747 }
1748 
1749 
1750 /*
1751  * 'compare_strings()' - Compare two command-line strings.
1752  */
1753 
1754 static int				/* O - -1 or 1 = no match, 0 = match */
compare_strings(const char * s,const char * t,int tmin)1755 compare_strings(const char *s,		/* I - Command-line string */
1756                 const char *t,		/* I - Option string */
1757                 int        tmin)	/* I - Minimum number of unique chars in option */
1758 {
1759   size_t	slen;			/* Length of command-line string */
1760 
1761 
1762   slen = strlen(s);
1763   if (slen < (size_t)tmin)
1764     return (-1);
1765   else
1766     return (strncmp(s, t, slen));
1767 }
1768 
1769 
1770 /*
1771  * 'get_seconds()' - Get the current fractional time in seconds.
1772  */
1773 
1774 static double				/* O - Number of seconds */
get_seconds(void)1775 get_seconds(void)
1776 {
1777 #ifdef WIN32
1778   return (GetTickCount() * 0.001);
1779 #else
1780   struct timeval	curtime;	/* Current time */
1781 
1782   gettimeofday(&curtime, NULL);
1783 
1784   return (curtime.tv_sec + curtime.tv_usec * 0.000001);
1785 #endif /* WIN32 */
1786 }
1787 
1788 
1789 //
1790 // 'load_book()' - Load a book file...
1791 //
1792 
1793 static int				// O  - 1 = success, 0 = failure
load_book(const char * filename,tree_t ** document,exportfunc_t * exportfunc,int set_nolocal)1794 load_book(const char   *filename,	// I  - Book file
1795           tree_t       **document,	// IO - Document tree
1796           exportfunc_t *exportfunc,	// O  - Export function
1797           int          set_nolocal)	// I  - Set file_nolocal() after lookup?
1798 {
1799   FILE		*fp;			// File to read from
1800   char		line[10240];		// Line from file
1801   const char 	*dir;			// Directory
1802   const char	*local;			// Local filename
1803   char		path[2048];		// Current path
1804 
1805 
1806   // See if the filename contains a path...
1807   dir = file_directory(filename);
1808 
1809   if (dir != NULL)
1810     snprintf(path, sizeof(path), "%s;%s", dir, Path);
1811   else
1812     strlcpy(path, Path, sizeof(path));
1813 
1814   // Open the file...
1815   local = file_find(Path, filename);
1816 
1817   if (set_nolocal)
1818     file_nolocal();
1819 
1820   if (!local)
1821     return (0);
1822 
1823   if ((fp = fopen(local, "rb")) == NULL)
1824   {
1825     progress_error(HD_ERROR_READ_ERROR, "Unable to open book file \"%s\": %s",
1826                    local, strerror(errno));
1827     return (0);
1828   }
1829 
1830   // Get the header...
1831   file_gets(line, sizeof(line), fp);
1832   if (strncmp(line, "#HTMLDOC", 8) != 0)
1833   {
1834     fclose(fp);
1835     progress_error(HD_ERROR_BAD_FORMAT,
1836                    "Bad or missing #HTMLDOC header in \"%s\".", filename);
1837     return (0);
1838   }
1839 
1840   // Read the second line from the book file; for older book files, this will
1841   // be the file count; for new files this will be the options...
1842   do
1843   {
1844     file_gets(line, sizeof(line), fp);
1845 
1846     if (line[0] == '-')
1847     {
1848       parse_options(line, exportfunc);
1849 
1850       if (dir != NULL)
1851 	snprintf(path, sizeof(path), "%s;%s", dir, Path);
1852       else
1853 	strlcpy(path, Path, sizeof(path));
1854     }
1855   }
1856   while (!line[0]);			// Skip blank lines
1857 
1858   // Get input files/options...
1859   while (file_gets(line, sizeof(line), fp) != NULL)
1860   {
1861     if (!line[0])
1862       continue;				// Skip blank lines
1863     else if (line[0] == '-')
1864     {
1865       parse_options(line, exportfunc);
1866 
1867       if (dir != NULL)
1868 	snprintf(path, sizeof(path), "%s;%s", dir, Path);
1869       else
1870 	strlcpy(path, Path, sizeof(path));
1871     }
1872     else if (line[0] == '\\')
1873       read_file(line + 1, document, path);
1874     else
1875       read_file(line, document, path);
1876   }
1877 
1878   // Close the book file and return...
1879   fclose(fp);
1880 
1881   return (1);
1882 }
1883 
1884 
1885 //
1886 // 'parse_options()' - Parse options from a book file...
1887 //
1888 
1889 static void
parse_options(const char * line,exportfunc_t * exportfunc)1890 parse_options(const char   *line,	// I - Options from book file
1891               exportfunc_t *exportfunc)	// O - Export function
1892 {
1893   int		i;			// Looping var
1894   const char	*lineptr;		// Pointer into line
1895   char		temp[1024],		// Option name
1896 		temp2[1024],		// Option value
1897 		*tempptr;		// Pointer into option
1898   double	fontsize,		// Size of body text
1899 		fontspacing;		// Spacing between lines
1900 
1901 
1902   // Parse the input line...
1903   for (lineptr = line; *lineptr != '\0';)
1904   {
1905     while (*lineptr == ' ')
1906       lineptr ++;
1907 
1908     for (tempptr = temp; *lineptr != '\0' && *lineptr != ' '; lineptr ++)
1909       if (tempptr < (temp + sizeof(temp) - 1))
1910         *tempptr++ = *lineptr;
1911 
1912     *tempptr = '\0';
1913 
1914     while (*lineptr == ' ')
1915       lineptr ++;
1916 
1917     if (strcmp(temp, "--duplex") == 0)
1918     {
1919       PageDuplex = 1;
1920       continue;
1921     }
1922     else if (strcmp(temp, "--landscape") == 0)
1923     {
1924       Landscape = 1;
1925       continue;
1926     }
1927     else if (strcmp(temp, "--portrait") == 0)
1928     {
1929       Landscape = 0;
1930       continue;
1931     }
1932     else if (strncmp(temp, "--jpeg", 6) == 0)
1933     {
1934       if (strlen(temp) > 7)
1935         OutputJPEG = atoi(temp + 7);
1936       else
1937         OutputJPEG = 90;
1938       continue;
1939     }
1940     else if (strcmp(temp, "--grayscale") == 0)
1941     {
1942       OutputColor = 0;
1943       continue;
1944     }
1945     else if (strcmp(temp, "--color") == 0)
1946     {
1947       OutputColor = 1;
1948       continue;
1949     }
1950     else if (strcmp(temp, "--links") == 0)
1951     {
1952       Links = 1;
1953       continue;
1954     }
1955     else if (strcmp(temp, "--no-links") == 0)
1956     {
1957       Links = 0;
1958       continue;
1959     }
1960     else if (strcmp(temp, "--embedfonts") == 0 ||
1961              strcmp(temp, "--truetype") == 0)
1962     {
1963       EmbedFonts = 1;
1964       continue;
1965     }
1966     else if (strcmp(temp, "--no-embedfonts") == 0 ||
1967              strcmp(temp, "--no-truetype") == 0)
1968     {
1969       EmbedFonts = 0;
1970       continue;
1971     }
1972     else if (strcmp(temp, "--pscommands") == 0)
1973     {
1974       PSCommands = 1;
1975       continue;
1976     }
1977     else if (strcmp(temp, "--no-pscommands") == 0)
1978     {
1979       PSCommands = 0;
1980       continue;
1981     }
1982     else if (strcmp(temp, "--xrxcomments") == 0)
1983     {
1984       XRXComments = 1;
1985       continue;
1986     }
1987     else if (strcmp(temp, "--no-xrxcomments") == 0)
1988     {
1989       XRXComments = 0;
1990       continue;
1991     }
1992     else if (strncmp(temp, "--compression", 13) == 0)
1993     {
1994       if (strlen(temp) > 14)
1995         Compression = atoi(temp + 14);
1996       else
1997         Compression = 1;
1998       continue;
1999     }
2000     else if (strcmp(temp, "--no-compression") == 0)
2001     {
2002       Compression = 0;
2003       continue;
2004     }
2005     else if (strcmp(temp, "--no-jpeg") == 0)
2006     {
2007       OutputJPEG = 0;
2008       continue;
2009     }
2010     else if (strcmp(temp, "--numbered") == 0)
2011     {
2012       TocNumbers = 1;
2013       continue;
2014     }
2015     else if (strcmp(temp, "--no-numbered") == 0)
2016     {
2017       TocNumbers = 0;
2018       continue;
2019     }
2020     else if (strcmp(temp, "--no-toc") == 0)
2021     {
2022       TocLevels = 0;
2023       continue;
2024     }
2025     else if (strcmp(temp, "--title") == 0)
2026     {
2027       TitlePage = 1;
2028       continue;
2029     }
2030     else if (strcmp(temp, "--no-title") == 0)
2031     {
2032       TitlePage = 0;
2033       continue;
2034     }
2035     else if (strcmp(temp, "--book") == 0)
2036     {
2037       OutputType = OUTPUT_BOOK;
2038       continue;
2039     }
2040     else if (strcmp(temp, "--continuous") == 0)
2041     {
2042       OutputType = OUTPUT_CONTINUOUS;
2043       continue;
2044     }
2045     else if (strcmp(temp, "--webpage") == 0)
2046     {
2047       OutputType = OUTPUT_WEBPAGES;
2048       continue;
2049     }
2050     else if (strcmp(temp, "--encryption") == 0)
2051     {
2052       Encryption = 1;
2053       continue;
2054     }
2055     else if (strcmp(temp, "--no-encryption") == 0)
2056     {
2057       Encryption = 0;
2058       continue;
2059     }
2060     else if (strcmp(temp, "--strict") == 0)
2061       StrictHTML = 1;
2062     else if (strcmp(temp, "--no-strict") == 0)
2063       StrictHTML = 0;
2064     else if (strcmp(temp, "--overflow") == 0)
2065       OverflowErrors = 1;
2066     else if (strcmp(temp, "--no-overflow") == 0)
2067       OverflowErrors = 0;
2068 
2069     if (*lineptr == '\"')
2070     {
2071       lineptr ++;
2072 
2073       for (tempptr = temp2; *lineptr != '\0' && *lineptr != '\"'; lineptr ++)
2074         if (tempptr < (temp2 + sizeof(temp2) - 1))
2075 	  *tempptr++ = *lineptr;
2076 
2077       if (*lineptr == '\"')
2078         lineptr ++;
2079     }
2080     else
2081     {
2082       for (tempptr = temp2; *lineptr != '\0' && *lineptr != ' '; lineptr ++)
2083         if (tempptr < (temp2 + sizeof(temp2) - 1))
2084 	  *tempptr++ = *lineptr;
2085     }
2086 
2087     *tempptr = '\0';
2088 
2089     if (strcmp(temp, "-t") == 0 && !CGIMode)
2090     {
2091       if (strcmp(temp2, "epub") == 0)
2092         *exportfunc = (exportfunc_t)epub_export;
2093       else if (strcmp(temp2, "html") == 0)
2094         *exportfunc = (exportfunc_t)html_export;
2095       else if (strcmp(temp2, "htmlsep") == 0)
2096         *exportfunc = (exportfunc_t)htmlsep_export;
2097       else if (strcmp(temp2, "pdf11") == 0)
2098       {
2099         *exportfunc = (exportfunc_t)pspdf_export;
2100 	PSLevel     = 0;
2101 	PDFVersion  = 11;
2102       }
2103       else if (strcmp(temp2, "pdf12") == 0)
2104       {
2105         *exportfunc = (exportfunc_t)pspdf_export;
2106 	PSLevel     = 0;
2107 	PDFVersion  = 12;
2108       }
2109       else if (strcmp(temp2, "pdf13") == 0)
2110       {
2111         *exportfunc = (exportfunc_t)pspdf_export;
2112 	PSLevel     = 0;
2113 	PDFVersion  = 13;
2114       }
2115       else if (strcmp(temp2, "pdf") == 0 ||
2116                strcmp(temp2, "pdf14") == 0)
2117       {
2118         *exportfunc = (exportfunc_t)pspdf_export;
2119 	PSLevel     = 0;
2120 	PDFVersion  = 14;
2121       }
2122       else if (strcmp(temp2, "ps1") == 0)
2123       {
2124         *exportfunc = (exportfunc_t)pspdf_export;
2125 	PSLevel     = 1;
2126       }
2127       else if (strcmp(temp2, "ps") == 0 ||
2128                strcmp(temp2, "ps2") == 0)
2129       {
2130         *exportfunc = (exportfunc_t)pspdf_export;
2131 	PSLevel     = 2;
2132       }
2133       else if (strcmp(temp2, "ps3") == 0)
2134       {
2135         *exportfunc = (exportfunc_t)pspdf_export;
2136 	PSLevel     = 3;
2137       }
2138     }
2139     else if (strcmp(temp, "--letterhead") == 0)
2140       strlcpy(Letterhead, temp2, sizeof(Letterhead));
2141     else if (strcmp(temp, "--logo") == 0 ||
2142              strcmp(temp, "--logoimage") == 0)
2143       strlcpy(LogoImage, temp2, sizeof(LogoImage));
2144     else if (strcmp(temp, "--titlefile") == 0 ||
2145              strcmp(temp, "--titleimage") == 0)
2146     {
2147       TitlePage = 1;
2148       strlcpy(TitleImage, temp2, sizeof(TitleImage));
2149     }
2150     else if (strcmp(temp, "-f") == 0 && !CGIMode)
2151     {
2152       OutputFiles = 0;
2153       strlcpy(OutputPath, temp2, sizeof(OutputPath));
2154     }
2155     else if (strcmp(temp, "-d") == 0 && !CGIMode)
2156     {
2157       OutputFiles = 1;
2158       strlcpy(OutputPath, temp2, sizeof(OutputPath));
2159     }
2160     else if (strcmp(temp, "--browserwidth") == 0)
2161       _htmlBrowserWidth = atof(temp2);
2162     else if (strcmp(temp, "--nup") == 0)
2163       NumberUp = atoi(temp2);
2164     else if (strcmp(temp, "--size") == 0)
2165       set_page_size(temp2);
2166     else if (strcmp(temp, "--left") == 0)
2167       PageLeft = get_measurement(temp2);
2168     else if (strcmp(temp, "--right") == 0)
2169       PageRight = get_measurement(temp2);
2170     else if (strcmp(temp, "--top") == 0)
2171       PageTop = get_measurement(temp2);
2172     else if (strcmp(temp, "--bottom") == 0)
2173       PageBottom = get_measurement(temp2);
2174     else if (strcmp(temp, "--header") == 0)
2175       get_format(temp2, Header);
2176     else if (strcmp(temp, "--header1") == 0)
2177       get_format(temp2, Header1);
2178     else if (strcmp(temp, "--footer") == 0)
2179       get_format(temp2, Footer);
2180     else if (strcmp(temp, "--bodycolor") == 0)
2181       strlcpy(BodyColor, temp2, sizeof(BodyColor));
2182     else if (strcmp(temp, "--bodyimage") == 0)
2183       strlcpy(BodyImage, temp2, sizeof(BodyImage));
2184     else if (strcmp(temp, "--textcolor") == 0)
2185       htmlSetTextColor((uchar *)temp2);
2186     else if (strcmp(temp, "--linkcolor") == 0)
2187       strlcpy(LinkColor, temp2, sizeof(LinkColor));
2188     else if (strcmp(temp, "--linkstyle") == 0)
2189     {
2190       if (strcmp(temp2, "plain") == 0)
2191         LinkStyle = 0;
2192       else
2193         LinkStyle = 1;
2194     }
2195     else if (strcmp(temp, "--toclevels") == 0)
2196       TocLevels = atoi(temp2);
2197     else if (strcmp(temp, "--tocheader") == 0)
2198       get_format(temp2, TocHeader);
2199     else if (strcmp(temp, "--tocfooter") == 0)
2200       get_format(temp2, TocFooter);
2201     else if (strcmp(temp, "--toctitle") == 0)
2202       strlcpy(TocTitle, temp2, sizeof(TocTitle));
2203     else if (strcmp(temp, "--fontsize") == 0)
2204     {
2205       fontsize    = atof(temp2);
2206       fontspacing = _htmlSpacings[SIZE_P] / _htmlSizes[SIZE_P];
2207 
2208       if (fontsize < 4.0f)
2209         fontsize = 4.0f;
2210       else if (fontsize > 24.0f)
2211         fontsize = 24.0f;
2212 
2213       htmlSetBaseSize(fontsize, fontspacing);
2214     }
2215     else if (strcmp(temp, "--fontspacing") == 0)
2216     {
2217       fontsize    = _htmlSizes[SIZE_P];
2218       fontspacing = atof(temp2);
2219 
2220       if (fontspacing < 1.0f)
2221         fontspacing = 1.0f;
2222       else if (fontspacing > 3.0f)
2223         fontspacing = 3.0f;
2224 
2225       htmlSetBaseSize(fontsize, fontspacing);
2226     }
2227     else if (!strcmp(temp, "--headingfont"))
2228     {
2229       if (!strcasecmp(temp2, "courier"))
2230 	_htmlHeadingFont = TYPE_COURIER;
2231       else if (!strcasecmp(temp2, "times"))
2232 	_htmlHeadingFont = TYPE_TIMES;
2233       else if (!strcasecmp(temp2, "helvetica") ||
2234 	       !strcasecmp(temp2, "arial"))
2235 	_htmlHeadingFont = TYPE_HELVETICA;
2236       else if (!strcasecmp(temp2, "monospace"))
2237 	_htmlHeadingFont = TYPE_MONOSPACE;
2238       else if (!strcasecmp(temp2, "serif"))
2239 	_htmlHeadingFont = TYPE_SERIF;
2240       else if (!strcasecmp(temp2, "sans"))
2241 	_htmlHeadingFont = TYPE_SANS_SERIF;
2242     }
2243     else if (!strcmp(temp, "--bodyfont"))
2244     {
2245       if (!strcasecmp(temp2, "monospace"))
2246 	_htmlBodyFont = TYPE_MONOSPACE;
2247       else if (!strcasecmp(temp2, "serif"))
2248 	_htmlBodyFont = TYPE_SERIF;
2249       else if (!strcasecmp(temp2, "sans"))
2250 	_htmlBodyFont = TYPE_SANS_SERIF;
2251       else if (!strcasecmp(temp2, "courier"))
2252 	_htmlBodyFont = TYPE_COURIER;
2253       else if (!strcasecmp(temp2, "times"))
2254 	_htmlBodyFont = TYPE_TIMES;
2255       else if (!strcasecmp(temp2, "helvetica") ||
2256 	       !strcasecmp(temp2, "arial"))
2257 	_htmlBodyFont = TYPE_HELVETICA;
2258     }
2259     else if (strcmp(temp, "--headfootsize") == 0)
2260       HeadFootSize = atof(temp2);
2261     else if (!strcmp(temp, "--headfootfont"))
2262     {
2263       if (!strcasecmp(temp2, "courier"))
2264       {
2265 	HeadFootType  = TYPE_COURIER;
2266 	HeadFootStyle = STYLE_NORMAL;
2267       }
2268       else if (!strcasecmp(temp2, "courier-bold"))
2269       {
2270 	HeadFootType  = TYPE_COURIER;
2271 	HeadFootStyle = STYLE_BOLD;
2272       }
2273       else if (!strcasecmp(temp2, "courier-oblique"))
2274       {
2275 	HeadFootType  = TYPE_COURIER;
2276 	HeadFootStyle = STYLE_ITALIC;
2277       }
2278       else if (!strcasecmp(temp2, "courier-boldoblique"))
2279       {
2280 	HeadFootType  = TYPE_COURIER;
2281 	HeadFootStyle = STYLE_BOLD_ITALIC;
2282       }
2283       else if (!strcasecmp(temp2, "times") ||
2284 	       !strcasecmp(temp2, "times-roman"))
2285       {
2286 	HeadFootType  = TYPE_TIMES;
2287 	HeadFootStyle = STYLE_NORMAL;
2288       }
2289       else if (!strcasecmp(temp2, "times-bold"))
2290       {
2291 	HeadFootType  = TYPE_TIMES;
2292 	HeadFootStyle = STYLE_BOLD;
2293       }
2294       else if (!strcasecmp(temp2, "times-italic"))
2295       {
2296 	HeadFootType  = TYPE_TIMES;
2297 	HeadFootStyle = STYLE_ITALIC;
2298       }
2299       else if (!strcasecmp(temp2, "times-bolditalic"))
2300       {
2301 	HeadFootType  = TYPE_TIMES;
2302 	HeadFootStyle = STYLE_BOLD_ITALIC;
2303       }
2304       else if (!strcasecmp(temp2, "helvetica"))
2305       {
2306 	HeadFootType  = TYPE_HELVETICA;
2307 	HeadFootStyle = STYLE_NORMAL;
2308       }
2309       else if (!strcasecmp(temp2, "helvetica-bold"))
2310       {
2311 	HeadFootType  = TYPE_HELVETICA;
2312 	HeadFootStyle = STYLE_BOLD;
2313       }
2314       else if (!strcasecmp(temp2, "helvetica-oblique"))
2315       {
2316 	HeadFootType  = TYPE_HELVETICA;
2317 	HeadFootStyle = STYLE_ITALIC;
2318       }
2319       else if (!strcasecmp(temp2, "helvetica-boldoblique"))
2320       {
2321 	HeadFootType  = TYPE_HELVETICA;
2322 	HeadFootStyle = STYLE_BOLD_ITALIC;
2323       }
2324       else if (!strcasecmp(temp2, "monospace"))
2325       {
2326 	HeadFootType  = TYPE_MONOSPACE;
2327 	HeadFootStyle = STYLE_NORMAL;
2328       }
2329       else if (!strcasecmp(temp2, "monospace-bold"))
2330       {
2331 	HeadFootType  = TYPE_MONOSPACE;
2332 	HeadFootStyle = STYLE_BOLD;
2333       }
2334       else if (!strcasecmp(temp2, "monospace-oblique"))
2335       {
2336 	HeadFootType  = TYPE_MONOSPACE;
2337 	HeadFootStyle = STYLE_ITALIC;
2338       }
2339       else if (!strcasecmp(temp2, "monospace-boldoblique"))
2340       {
2341 	HeadFootType  = TYPE_MONOSPACE;
2342 	HeadFootStyle = STYLE_BOLD_ITALIC;
2343       }
2344       else if (!strcasecmp(temp2, "serif") ||
2345 	       !strcasecmp(temp2, "serif-roman"))
2346       {
2347 	HeadFootType  = TYPE_SERIF;
2348 	HeadFootStyle = STYLE_NORMAL;
2349       }
2350       else if (!strcasecmp(temp2, "serif-bold"))
2351       {
2352 	HeadFootType  = TYPE_SERIF;
2353 	HeadFootStyle = STYLE_BOLD;
2354       }
2355       else if (!strcasecmp(temp2, "serif-italic"))
2356       {
2357 	HeadFootType  = TYPE_SERIF;
2358 	HeadFootStyle = STYLE_ITALIC;
2359       }
2360       else if (!strcasecmp(temp2, "serif-bolditalic"))
2361       {
2362 	HeadFootType  = TYPE_SERIF;
2363 	HeadFootStyle = STYLE_BOLD_ITALIC;
2364       }
2365       else if (!strcasecmp(temp2, "sans"))
2366       {
2367 	HeadFootType  = TYPE_SANS_SERIF;
2368 	HeadFootStyle = STYLE_NORMAL;
2369       }
2370       else if (!strcasecmp(temp2, "sans-bold"))
2371       {
2372 	HeadFootType  = TYPE_SANS_SERIF;
2373 	HeadFootStyle = STYLE_BOLD;
2374       }
2375       else if (!strcasecmp(temp2, "sans-oblique"))
2376       {
2377 	HeadFootType  = TYPE_SANS_SERIF;
2378 	HeadFootStyle = STYLE_ITALIC;
2379       }
2380       else if (!strcasecmp(temp2, "sans-boldoblique"))
2381       {
2382 	HeadFootType  = TYPE_SANS_SERIF;
2383 	HeadFootStyle = STYLE_BOLD_ITALIC;
2384       }
2385     }
2386     else if (strcmp(temp, "--charset") == 0)
2387       htmlSetCharSet(temp2);
2388     else if (strcmp(temp, "--pagemode") == 0)
2389     {
2390       for (i = 0; i < (int)(sizeof(PDFModes) / sizeof(PDFModes[0])); i ++)
2391         if (strcasecmp(temp2, PDFModes[i]) == 0)
2392 	{
2393 	  PDFPageMode = i;
2394 	  break;
2395 	}
2396     }
2397     else if (strcmp(temp, "--pagelayout") == 0)
2398     {
2399       for (i = 0; i < (int)(sizeof(PDFLayouts) / sizeof(PDFLayouts[0])); i ++)
2400         if (strcasecmp(temp2, PDFLayouts[i]) == 0)
2401 	{
2402 	  PDFPageLayout = i;
2403 	  break;
2404 	}
2405     }
2406     else if (strcmp(temp, "--firstpage") == 0)
2407     {
2408       for (i = 0; i < (int)(sizeof(PDFPages) / sizeof(PDFPages[0])); i ++)
2409         if (strcasecmp(temp2, PDFPages[i]) == 0)
2410 	{
2411 	  PDFFirstPage = i;
2412 	  break;
2413 	}
2414     }
2415     else if (strcmp(temp, "--pageeffect") == 0)
2416     {
2417       for (i = 0; i < (int)(sizeof(PDFEffects) / sizeof(PDFEffects[0])); i ++)
2418         if (strcasecmp(temp2, PDFEffects[i]) == 0)
2419 	{
2420 	  PDFEffect = i;
2421 	  break;
2422 	}
2423     }
2424     else if (strcmp(temp, "--pageduration") == 0)
2425       PDFPageDuration = atof(temp2);
2426     else if (strcmp(temp, "--effectduration") == 0)
2427       PDFEffectDuration = atof(temp2);
2428     else if (strcmp(temp, "--permissions") == 0)
2429       set_permissions(temp2);
2430     else if (strcmp(temp, "--user-password") == 0)
2431       strlcpy(UserPassword, temp2, sizeof(UserPassword));
2432     else if (strcmp(temp, "--owner-password") == 0)
2433       strlcpy(OwnerPassword, temp2, sizeof(OwnerPassword));
2434     else if (strcmp(temp, "--path") == 0)
2435       strlcpy(Path, temp2, sizeof(Path) - 1);
2436     else if (strcmp(temp, "--proxy") == 0)
2437     {
2438       strlcpy(Proxy, temp2, sizeof(Proxy));
2439       file_proxy(Proxy);
2440     }
2441     else if (strcmp(temp, "--cookies") == 0)
2442       file_cookies(temp2);
2443   }
2444 }
2445 
2446 
2447 //
2448 // 'read_file()' - Read a file into the current document.
2449 //
2450 
2451 static int				// O  - 1 on success, 0 on failure
read_file(const char * filename,tree_t ** document,const char * path)2452 read_file(const char *filename,		// I  - File/URL to read
2453           tree_t     **document,	// IO - Current document
2454 	  const char *path)		// I  - Search path
2455 {
2456   FILE		*docfile;		// Document file
2457   tree_t	*file;			// HTML document file
2458   const char	*realname,		// Real name of file
2459 		*ext;			// Extension of filename
2460   char		base[1024];		// Base directory name of file
2461 
2462 
2463   DEBUG_printf(("read_file(filename=\"%s\", document=%p, path=\"%s\")\n", filename, (void *)document, path));
2464 
2465   if ((realname = file_find(path, filename)) != NULL)
2466   {
2467     if ((docfile = fopen(realname, "rb")) != NULL)
2468     {
2469       // Prepare to read the file...
2470       if (Verbosity > 0)
2471         progress_error(HD_ERROR_NONE, "INFO: Reading %s...", filename);
2472 
2473       _htmlPPI = 72.0f * _htmlBrowserWidth / (PageWidth - PageLeft - PageRight);
2474 
2475       strlcpy(base, file_directory(filename), sizeof(base));
2476       ext = file_extension(filename);
2477 
2478       file = htmlAddTree(NULL, MARKUP_FILE, NULL);
2479       htmlSetVariable(file, (uchar *)"_HD_URL", (uchar *)filename);
2480       htmlSetVariable(file, (uchar *)"_HD_FILENAME", (uchar *)file_basename(filename));
2481       htmlSetVariable(file, (uchar *)"_HD_BASE", (uchar *)base);
2482 
2483       if (ext && !strcmp(ext, "md"))
2484       {
2485         // Read markdown from a file...
2486         mdReadFile(file, docfile, base);
2487       }
2488       else
2489       {
2490         // Read HTML from a file...
2491         _htmlCurrentFile = filename;
2492         htmlReadFile(file, docfile, base);
2493       }
2494 
2495       fclose(docfile);
2496 
2497       if (*document == NULL)
2498         *document = file;
2499       else
2500       {
2501         while ((*document)->next != NULL)
2502           *document = (*document)->next;
2503 
2504         (*document)->next = file;
2505         file->prev        = *document;
2506       }
2507     }
2508     else
2509     {
2510       file = NULL;
2511       progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to open \"%s\" for reading...", filename);
2512     }
2513   }
2514   else
2515   {
2516     file = NULL;
2517     progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to find \"%s\"...", filename);
2518   }
2519 
2520   return (file != NULL);
2521 }
2522 
2523 
2524 //
2525 // 'set_permissions()' - Set the PDF permission bits.
2526 //
2527 
2528 void
set_permissions(const char * p)2529 set_permissions(const char *p)		// I - Permission string
2530 {
2531   char	*copyp,				// Copy of string
2532 	*start,				// Start of current keyword
2533 	*ptr;				// Pointer into string
2534 
2535 
2536   // Range check input...
2537   if (!p || !*p)
2538     return;
2539 
2540   // Make a copy of the string and parse it...
2541   copyp = strdup(p);
2542   if (!copyp)
2543     return;
2544 
2545   for (start = copyp; *start; start = ptr)
2546   {
2547     for (ptr = start; *ptr; ptr ++)
2548       if (*ptr == ',')
2549       {
2550 	*ptr++ = '\0';
2551 	break;
2552       }
2553 
2554     if (!strcasecmp(start, "all"))
2555       Permissions = -4;
2556     else if (!strcasecmp(start, "none"))
2557       Permissions = -64;
2558     else if (!strcasecmp(start, "print"))
2559       Permissions |= PDF_PERM_PRINT;
2560     else if (!strcasecmp(start, "no-print"))
2561       Permissions &= ~PDF_PERM_PRINT;
2562     else if (!strcasecmp(start, "modify"))
2563       Permissions |= PDF_PERM_MODIFY;
2564     else if (!strcasecmp(start, "no-modify"))
2565       Permissions &= ~PDF_PERM_MODIFY;
2566     else if (!strcasecmp(start, "copy"))
2567       Permissions |= PDF_PERM_COPY;
2568     else if (!strcasecmp(start, "no-copy"))
2569       Permissions &= ~PDF_PERM_COPY;
2570     else if (!strcasecmp(start, "annotate"))
2571       Permissions |= PDF_PERM_ANNOTATE;
2572     else if (!strcasecmp(start, "no-annotate"))
2573       Permissions &= ~PDF_PERM_ANNOTATE;
2574   }
2575 
2576   if (Permissions != -4)
2577     Encryption = 1;
2578 
2579   free(copyp);
2580 }
2581 
2582 
2583 #ifndef WIN32
2584 //
2585 // 'term_handler()' - Handle CTRL-C or kill signals...
2586 //
2587 
2588 static void
term_handler(int signum)2589 term_handler(int signum)	// I - Signal number
2590 {
2591   REF(signum);
2592 
2593   file_cleanup();
2594   image_flush_cache();
2595   exit(1);
2596 }
2597 #endif // !WIN32
2598 
2599 
2600 /*
2601  * 'usage()' - Show program version and command-line options.
2602  */
2603 
2604 static void
usage(const char * arg)2605 usage(const char *arg)			// I - Bad argument string
2606 {
2607   if (CGIMode)
2608     puts("Content-Type: text/plain\r\n\r");
2609 
2610   puts("HTMLDOC Version " SVERSION " Copyright 2011-2020 by Michael R Sweet.");
2611   puts("HTMLDOC is provided under the terms of the GNU General Public License and");
2612   puts("comes with absolutely no warranty.  This software is based in part on the work");
2613   puts("of the Independent JPEG Group.");
2614   puts("");
2615 
2616 #ifdef HAVE_SSL
2617   puts("This copy of HTMLDOC has been built to support both http: and https: URLs.");
2618 #else
2619   puts("This copy of HTMLDOC has been built to support http: URLs only.");
2620 #endif /* HAVE_SSL */
2621   puts("");
2622 
2623   if (CGIMode)
2624   {
2625     puts("HTMLDOC is running in CGI mode.  To disable CGI mode when running");
2626     puts("from a server-side script/page, set the HTMLDOC_NOCGI environment");
2627     puts("variable prior to running HTMLDOC.");
2628     puts("");
2629     puts("If you are trying to use CGI mode, make sure that the ServerName");
2630     puts("for the web server is accessible from the local system.  If you");
2631     puts("are using Apache 2.0.30 or later, make sure you set 'AcceptPathInfo'");
2632     puts("to 'On' for the HTMLDOC/cgi-bin directory.");
2633   }
2634   else
2635   {
2636     if (arg && arg[0] == '-')
2637       printf("ERROR: Bad option argument \"%s\"!\n\n", arg);
2638     else
2639       printf("ERROR: %s\n", arg);
2640 
2641     puts("");
2642     puts("Usage:");
2643     puts("  htmldoc [options] filename1.html [ ... filenameN.html ]");
2644 #ifdef HAVE_LIBFLTK
2645     puts("  htmldoc filename.book");
2646 #endif // HAVE_LIBFLTK
2647     puts("");
2648     puts("Options:");
2649     puts("");
2650     puts("  --batch filename.book");
2651     puts("  --bodycolor color");
2652     puts("  --bodyfont {courier,helvetica,monospace,sans,serif,times}");
2653     puts("  --bodyimage filename.{bmp,gif,jpg,png}");
2654     puts("  --book");
2655     puts("  --bottom margin{in,cm,mm}");
2656     puts("  --browserwidth pixels");
2657     puts("  --charset {cp-874...1258,iso-8859-1...-15,koi8-r,utf-8}");
2658     puts("  --color");
2659     puts("  --compression[=level]");
2660     puts("  --continuous");
2661     puts("  --cookies 'name=\"value with space\"; name=value'");
2662     puts("  --datadir directory");
2663     puts("  --duplex");
2664     puts("  --effectduration {0.1..10.0}");
2665     puts("  --embedfonts");
2666     puts("  --encryption");
2667     puts("  --firstpage {p1,toc,c1}");
2668     puts("  --fontsize {4.0..24.0}");
2669     puts("  --fontspacing {1.0..3.0}");
2670     puts("  --footer fff");
2671     puts("  {--format, -t} {epub,html,htmlsep,pdf11,pdf12,pdf13,pdf14,ps1,ps2,ps3}");
2672     puts("  --gray");
2673     puts("  --header fff");
2674     puts("  --header1 fff");
2675     puts("  --headfootfont {courier{-bold,-oblique,-boldoblique},\n"
2676 	 "                  helvetica{-bold,-oblique,-boldoblique},\n"
2677 	 "                  monospace{-bold,-oblique,-boldoblique},\n"
2678 	 "                  sans{-bold,-oblique,-boldoblique},\n"
2679 	 "                  serif{-bold,-italic,-bolditalic},\n"
2680 	 "                  times{-roman,-bold,-italic,-bolditalic}}\n");
2681     puts("  --headfootsize {6.0..24.0}");
2682     puts("  --headingfont {courier,helvetica,monospace,sans,serif,times}");
2683     puts("  --help");
2684 #ifdef HAVE_LIBFLTK
2685     puts("  --helpdir directory");
2686 #endif // HAVE_LIBFLTK
2687     for (int i = 0; i < MAX_HF_IMAGES; i ++)
2688       printf("  --hfimage%d filename.{bmp,gif,jpg,png}\n", i);
2689     puts("  --jpeg[=quality]");
2690     puts("  --landscape");
2691     puts("  --left margin{in,cm,mm}");
2692     puts("  --letterhead filename.{bmp,gif,jpg,png}");
2693     puts("  --linkcolor color");
2694     puts("  --links");
2695     puts("  --linkstyle {plain,underline}");
2696     puts("  --logoimage filename.{bmp,gif,jpg,png}");
2697     puts("  --no-compression");
2698     puts("  --no-duplex");
2699     puts("  --no-embedfonts");
2700     puts("  --no-encryption");
2701     puts("  --no-links");
2702     puts("  --no-localfiles");
2703     puts("  --no-numbered");
2704     puts("  --no-overflow");
2705     puts("  --no-pscommands");
2706     puts("  --no-strict");
2707     puts("  --no-title");
2708     puts("  --no-toc");
2709     puts("  --numbered");
2710     puts("  --nup {1,2,4,6,9,16}");
2711     puts("  {--outdir, -d} dirname");
2712     puts("  {--outfile, -f} filename.{epub,html,pdf,ps}");
2713     puts("  --overflow");
2714     puts("  --owner-password password");
2715     puts("  --pageduration {1.0..60.0}");
2716     puts("  --pageeffect {none,bi,bo,d,gd,gdr,gr,hb,hsi,hso,vb,vsi,vso,wd,wl,wr,wu}");
2717     puts("  --pagelayout {single,one,twoleft,tworight}");
2718     puts("  --pagemode {document,outline,fullscreen}");
2719     puts("  --path \"dir1;dir2;dir3;...;dirN\"");
2720     puts("  --permissions {all,annotate,copy,modify,print,no-annotate,no-copy,no-modify,no-print,none}");
2721     puts("  --portrait");
2722     puts("  --proxy http://host:port");
2723     puts("  --pscommands");
2724     puts("  --quiet");
2725     puts("  --referer url");
2726     puts("  --right margin{in,cm,mm}");
2727     puts("  --size {letter,a4,WxH{in,cm,mm},etc}");
2728     puts("  --strict");
2729     puts("  --textcolor color");
2730     puts("  --textfont {courier,times,helvetica}");
2731     puts("  --title");
2732     puts("  --titlefile filename.{htm,html,shtml}");
2733     puts("  --titleimage filename.{bmp,gif,jpg,png}");
2734     puts("  --tocfooter fff");
2735     puts("  --tocheader fff");
2736     puts("  --toclevels levels");
2737     puts("  --toctitle string");
2738     puts("  --top margin{in,cm,mm}");
2739     puts("  --user-password password");
2740     puts("  {--verbose, -v}");
2741     puts("  --version");
2742     puts("  --webpage");
2743     puts("");
2744     puts("  fff = heading format string; each \'f\' can be one of:");
2745     puts("");
2746     puts("        . = blank");
2747     puts("        / = n/N arabic page numbers (1/3, 2/3, 3/3)");
2748     puts("        : = c/C arabic chapter page numbers (1/2, 2/2, 1/4, 2/4, ...)");
2749     puts("        1 = arabic numbers (1, 2, 3, ...)");
2750     puts("        a = lowercase letters");
2751     puts("        A = uppercase letters");
2752     puts("        c = current chapter heading");
2753     puts("        C = current chapter page number (arabic)");
2754     puts("        d = current date");
2755     puts("        D = current date and time");
2756     puts("        h = current heading");
2757     puts("        i = lowercase roman numerals");
2758     puts("        I = uppercase roman numerals");
2759     puts("        l = logo image");
2760     puts("        L = letterhead image");
2761     puts("        t = title text");
2762     puts("        T = current time");
2763     puts("        u = current file/URL");
2764   }
2765 
2766   exit(1);
2767 }
2768