5 * Contains the main program body for trueprint. The structure of the code
6 * is very simple - main() initialises various things, using handle_options()
7 * to read options and set up defaults. Then it calls print_page() until
8 * the end of input without printing anything (first pass) to get page numbers
9 * & etc. for the indices. The two indices are then printed, followed by
10 * the second pass when the text is printed out by once again calling
11 * print_page() until end of input.
16 * 2 Internal error or resource problem
22 #include <sys/types.h>
46 int close(int fildes
);
50 #include "trueprint.h"
56 #include "postscript.h"
59 #include "printers_fl.h"
60 #include "print_prompt.h"
69 /******************************************************************************
73 unsigned int no_of_files
;
74 char *current_filename
;
76 unsigned int file_number
;
80 boolean use_environment
;
85 static boolean no_print_body
;
86 static boolean no_print_file_index
;
87 static boolean no_print_function_index
;
88 static char *destination
;
89 static char *printer_destination
;
90 static short no_of_copies
;
91 static char **file_names
;
92 static char *output_filename
;
93 static boolean redirect_output
;
98 int main(int, char**);
99 static void setup_main(void);
100 static void print_files(void);
101 static void set_dest(const char *p
, const char *o
, char *value
);
102 static void set_dest_default(char *value
);
103 static void print_help(const char *p
, const char *o
, char *value
);
104 static void print_version(const char *p
, const char *o
);
107 static void write_log(void);
112 /******************************************************************************
116 * Analyse parameters,
117 * Sort out font and page size,
118 * perform first pass to sort out function names, etc.,
119 * sort out output stream (either stdout or x9700|opr)
120 * print the index pages,
121 * perform second pass, printing out pages.
123 int main(int argc
, char **argv
)
126 unsigned int last_param_used
;
127 int pipe_handle
= -1;
129 FILE *pipe_fhandle
= NULL
;
133 * Need to set this here as it is used by setup_printers_fl()
135 use_environment
= TRUE
;
138 * Set up various modules, including option declaration.
139 * setup_options() must come first.
151 setup_print_prompter();
155 * Handle command line options.
158 * use_environment is itself used when setting options, so
159 * initialize it here. The default is to use environment stuff,
160 * so set it to 1 (true).
165 * Note that the debug option will not be set before this line - the dm
166 * function should not be called before this function call.
168 last_param_used
= handle_options(argc
, argv
);
171 * Next check $TP_OPTS to see if the user has customised anything...
173 dm('o',1,"Looking at TP_OPTS options\n");
174 handle_string_options(getenv("TP_OPTS"));
177 * Write the log file - this doesn't do anything if LOGTOOL
183 * Set file_names to the first unused parameter - all remaining
184 * parameters are source file names.
186 dm('P',1,"Checking parameters\n");
187 if (last_param_used
< (unsigned int)argc
)
189 file_names
= &(argv
[last_param_used
]);
190 no_of_files
= (unsigned int)argc
- last_param_used
;
191 dm('P',1,"Got %d file names\n", no_of_files
);
196 * No file names - use a list with just "-" for stdin
198 static char *stdin_filenames
[] =
200 file_names
= stdin_filenames
;
202 dm('P',1,"No filenames - reading stdin\n");
206 * End of the user options, so set the default options for
208 * If language has been set then this will use it instead of filename.
210 dm('l',1,"Setting language for filename %s\n", file_names
[0]);
211 handle_string_options(language_defaults(file_names
[0]));
214 * Now set up the other defaults that haven't been overridden yet.
215 * DEFAULT_OPTS used to be the mechanism for setting defaults -
216 * now (v3.7) it has been replaced by set_option_defaults(),
217 * but DEFAULT_OPTS is kept in case somebody wants to override
218 * the default defaults in trueprint.h. Note that if --ignore-environment
219 * is set then the defaults from DEFAULT_OPTS are ignored; otherwise
220 * make check would fail if DEFAULT_OPTS is not empty.
222 dm('o',1,"Setting default options\n");
224 handle_string_options(DEFAULT_OPTS
);
225 set_option_defaults();
228 * And finally calculate the page dimensions.
230 PS_pagesize(destination
, &page_width
, &page_length
);
231 dm('O',1,"Page width is %d, page length is %d\n", page_width
, page_length
);
234 * If redirect_output is set then calculate the output filename.
235 * Do it now so we can catch the error condition that redirect-output
236 * is being used with stdin.
240 if (strcmp(file_names
[0],"-") == 0)
242 fprintf(stderr
, gettext(CMD_NAME
": cannot use redirect-output option with stdin\n"));
246 /* Grab a buffer long enough for filename plus .ps plus NULL */
247 output_filename
= xmalloc(strlen(file_names
[0])+4);
248 strcpy(output_filename
,file_names
[0]);
250 /* Add .ps to the filename */
254 /* point suffix to the dot, if any, in the filename */
255 suffix
= strrchr(output_filename
,'.');
257 /* If there is no . in filename then point suffix to the string end */
260 suffix
= output_filename
+strlen(output_filename
);
263 /* Now write .ps to the end of the string */
270 dm('O',1,"main.c:main() Redirecting output to %s\n",output_filename
);
274 * Perform first pass to get function names and locations.
276 dm('p', 1, "Starting first pass\n");
284 total_pages
= page_number
;
288 fprintf(stderr
, gettext(CMD_NAME
": empty input, not submitting print job\n"));
292 dm('p', 1, "Starting second pass\n");
299 * Now set up output stream to print command. Put the filehandle into
303 if ((strlen(output_filename
) > 0) && (strcmp(output_filename
,"-") != 0))
306 pipe_handle
= _creat(output_filename
, _S_IREAD
| _S_IWRITE
);
308 pipe_handle
= creat(output_filename
, 0666);
310 if (pipe_handle
== -1)
312 fprintf(stderr
, gettext(CMD_NAME
": cannot open %s for writing, %s\n"),
313 output_filename
, strerror(errno
));
317 /* now dup the pipe_handle into stdout so all stdout goes to the pipe */
319 if (!((close(1) == 0) && (_dup(pipe_handle
) == 1)))
322 if (!((close(1) == 0) && (dup(pipe_handle
) == 1)))
326 dm('O',1,"Sending output to %s\n",output_filename
);
328 #if defined(PRINT_CMD)
329 else if (strcmp(output_filename
,"-") == 0)
335 * In the case that the output filename is "-" or there isn't a print
336 * command, leave stdout alone so that all output goes simply to stdout.
339 #if defined(PRINT_CMD)
342 char print_cmd_line
[200];
343 char *tp_print_cmd
= getenv("TP_PRINT_CMD");
345 dm('P',1,"Setting up pipe for printer\n");
347 if ((tp_print_cmd
!= NULL
) && (*tp_print_cmd
!= '\0'))
349 sprintf(print_cmd_line
,"%s", getenv("TP_PRINT_CMD"));
353 sprintf(print_cmd_line
,"%s %s %s%d", PRINT_CMD
, printer_destination
, PRINT_CMD_COUNT_FLAG
, no_of_copies
);
356 dm('P',1,"Printer command is %s\n", print_cmd_line
);
359 pipe_fhandle
= _popen(print_cmd_line
, "w");
360 if (pipe_fhandle
== NULL
) abort();
362 /* now dup the pipe_handle into stdout so all stdout goes to the pipe */
363 if (!((close(1) == 0) && (dup(_fileno(pipe_fhandle
)) == 1)))
366 /* openpipe exits on failure, so don't bother to check return code */
367 pipe_handle
= openpipe(print_cmd_line
, "w");
369 /* now dup the pipe_handle into stdout so all stdout goes to the pipe */
370 if (!((close(1) == 0) && (dup(pipe_handle
) == 1)))
374 #endif /* defined(PRINT_CMD) */
377 * Print out the Postscript header
378 * If use_environment is not set, use an old version id
380 dm('P',1,"Print out postscript header\n");
381 PS_header(use_environment
?VERSION
:"3.6.5", !no_print_body
);
384 * These function calls do precisely what you think they do...
386 dm('i',1,"sort function names & print indices if necessary\n");
387 sort_function_names();
389 if ((no_print_function_index
== FALSE
)
390 && (print_prompt(PAGE_SPECIAL
, 0, "function index") == TRUE
))
393 if ((no_of_files
> 1)
394 && (no_print_file_index
== FALSE
)
395 && (print_prompt(PAGE_SPECIAL
, 0, "file index") == TRUE
))
396 print_out_file_index();
399 * Now perform second pass to print out listings.
401 if (no_print_body
== FALSE
)
408 * Finish up the postscript output
416 if (pipe_fhandle
!= NULL
)
417 _pclose(pipe_fhandle
);
419 if (pipe_handle
!= -1)
420 closepipe(pipe_handle
);
426 /******************************************************************************
429 * Print files one at a time, opening the file and setting the stream
430 * for the input routines. Sets global variables current_filename
438 static int stdin_stream
= -1;
443 for (file_number
= 0; file_names
[file_number
]; file_number
++)
446 current_filename
= file_names
[file_number
];
448 dm('p', 3, "Looking at file %s\n", current_filename
);
450 if (strcmp(current_filename
, "-") == 0)
455 * Create a temporary file and copy stdin to it, then use it.
456 * Note that we can only use stdin once.
458 char input_buffer
[BUFFER_SIZE
];
461 if (stdin_stream
!= -1)
463 fprintf(stderr
, gettext(CMD_NAME
": cannot specify stdin twice on command line\n"));
467 stdin_stream
= fileno(tmpfile());
469 while ((buffer_size
= read(fileno(stdin
),input_buffer
,BUFFER_SIZE
)) > 0)
471 if (write (stdin_stream
, input_buffer
, buffer_size
) <= 0)
473 perror(CMD_NAME
": cannot write to tmp file");
479 if (lseek(stdin_stream
,0,SEEK_SET
) == (off_t
)-1)
480 perror(CMD_NAME
": cannot seek to start of tmp file");
482 stream
= stdin_stream
;
486 open(file_names
[file_number
], O_RDONLY
)) == -1)
488 fprintf(stderr
, gettext(CMD_NAME
": cannot open file %s, %s\n"),
489 current_filename
, strerror(errno
));
493 dm('f',3,"Opened stream %d to read file %s\n",stream
,file_names
[file_number
]);
496 dm('i',3,"Pass file %s to index module\n",current_filename
);
497 add_file(current_filename
, file_number
, page_number
+1);
501 * set_input_stream will return FALSE if there is something wrong
502 * with the file, e.g. if it is empty.
504 if (set_input_stream(stream
))
507 dm('d',3,"Init diffs for pass %d, file %s\n", pass
, current_filename
);
508 init_diffs(current_filename
);
512 dm('d',3,"Ending diffs for pass %d, file %s\n", pass
, current_filename
);
517 fprintf(stderr
, gettext(CMD_NAME
": cannot read %s - possibly an empty file\n"), current_filename
);
520 /* Close file unless it was tmp file storing stdin */
521 if (strcmp(file_names
[file_number
],"-") != 0)
524 if (close(stream
) == -1)
526 fprintf(stderr
, gettext(CMD_NAME
": cannot close %s, %s\n"),
527 file_names
[file_number
],strerror(errno
));
534 dm('i',3,"End file for index module\n");
535 end_file(file_number
, page_number
);
543 * Print blank pages until the end of the current (last) physical page.
544 * The global file_number was left as one more than the last file number
545 * by the for loop, so we need to decrement it.
548 fill_sheet_with_blank_pages();
553 /******************************************************************************
556 * Simply declare options and initialize global variables
565 printer_destination
= "";
569 * -d and -P have the same meaning - one is from SYSV and the other
572 string_option("d", "printer", "", NULL
, &set_dest
, &set_dest_default
,
574 "use printer <string>");
576 string_option("P", "printer", "", NULL
, &set_dest
, &set_dest_default
,
578 "use printer <string>");
580 string_option("s", "output", "", &output_filename
, NULL
, NULL
,
582 "send output to filename <string>; use - for stdout");
584 boolean_option("r", "redirect-output", "no-redirect-output",
589 "redirect output to .ps file named after first filename",
590 "don't redirect output");
592 short_option("c", "copies", 1,
594 1, 200, &no_of_copies
, NULL
, NULL
,
596 "specify number of copies to be printed", NULL
);
598 boolean_option("F", "no-file-index", "file-index", FALSE
, &no_print_file_index
, NULL
, NULL
,
600 "don't print file index", "print file index");
602 boolean_option("f", "no-function-index", "function-index", FALSE
, &no_print_function_index
, NULL
, NULL
,
604 "don't print function index", "print function index");
606 optional_string_option("H", "help", &print_help
,
608 "Type help information\n"
609 " --help=all-options - list all options\n"
610 " --help=misc-options - list miscellaneous options\n"
611 " --help=page-furniture-options - list page furniture options\n"
612 " --help=text-format-options - list text formatting options\n"
613 " --help=print-options - list options that select what to print\n"
614 " --help=page-format-options - list page format options\n"
615 " --help=output-options - list options that affect where output goes\n"
616 " --help=language - list languages\n"
617 " --help=prompt - format for --print-pages string\n"
618 " --help=debug - format for --debug string\n"
619 " --help=header - format for header & footer strings\n"
620 " --help=report - file format for --language=report input\n"
621 " --help=environment - list environment vars used"
624 noparm_option("V", "version", FALSE
, &print_version
, NULL
,
626 "Type version information");
628 boolean_option("B", "no-print-body", "print-body", FALSE
, &no_print_body
, NULL
, NULL
,
630 "don't print body of text", "print body of text");
632 boolean_option("N", "use-environment", "ignore-environment", TRUE
, &use_environment
, NULL
, NULL
,
634 "use environment variables",
635 "don't use values from environment, such as time,\n"
636 " $USER, etc. This is for test purposes, to make test results\n"
637 " more reproducible");
639 int_option("w", "line-wrap", -1,
641 -1, 200, &page_width
, NULL
, NULL
,
643 "specify the line-wrap column.",
644 "turn off line-wrap");
646 int_option("l", "page-length", -1,
648 5, 200, &page_length
, NULL
, NULL
,
650 "specify number of lines on a page, point size is\n"
651 " calculated appropriately",
655 /******************************************************************************
658 * Handler for -d option to set default
660 void set_dest_default(char *value
)
662 set_dest(NULL
,NULL
,value
);
665 /******************************************************************************
668 * Handler for -d option
670 void set_dest(const char *p
, const char *o
, char *value
)
673 if (destination
) return;
676 destination
= getenv("PRINTER");
680 destination
= strdup(value
);
683 dm('O',1,"Setting destination to %s\n",destination
);
685 if (destination
&& (*destination
!= '\0'))
687 printer_destination
= xmalloc(strlen(destination
)+strlen(PRINT_CMD_DEST_FLAG
)+2);
688 sprintf(printer_destination
, "%s %s", PRINT_CMD_DEST_FLAG
, destination
);
692 printer_destination
= "";
699 /******************************************************************************
702 * Handler for -H option
704 void print_help(const char *p
, const char *o
, char *value
)
708 printf(gettext("Help for %s:\n"),value
);
709 if (strcmp(value
,"all-options") == 0)
711 print_usage_msgs(OPT_MISC
);
712 print_usage_msgs(OPT_PAGE_FURNITURE
);
713 print_usage_msgs(OPT_TEXT_FORMAT
);
714 print_usage_msgs(OPT_PRINT
);
715 print_usage_msgs(OPT_PAGE_FORMAT
);
716 print_usage_msgs(OPT_OUTPUT
);
718 else if (strcmp(value
,"misc-options") == 0)
720 print_usage_msgs(OPT_MISC
);
722 else if (strcmp(value
,"page-furniture-options") == 0)
724 print_usage_msgs(OPT_PAGE_FURNITURE
);
726 else if (strcmp(value
,"text-format-options") == 0)
728 print_usage_msgs(OPT_TEXT_FORMAT
);
730 else if (strcmp(value
,"print-options") == 0)
732 print_usage_msgs(OPT_PRINT
);
734 else if (strcmp(value
,"page-format-options") == 0)
736 print_usage_msgs(OPT_PAGE_FORMAT
);
738 else if (strcmp(value
,"output-options") == 0)
740 print_usage_msgs(OPT_OUTPUT
);
742 else if (strcmp(value
,"language") == 0)
744 printf("%s",gettext(language_list
));
746 else if (strcmp(value
,"environment") == 0)
750 " Environment variables used by trueprint:\n"
751 " TP_DIFF_CMD: command used to generate diffs, devault is diff\n"
752 " USER: username for headers, footers, coversheet, etc.\n"
753 " TP_OPTS: default trueprint options, overridden by command line opts\n"
754 " TP_PRINT_CMD: command used to print output, default is lp or lpr\n"
755 " PRINTER: name of printer to send output to\n"
758 else if (strcmp(value
,"prompt") == 0)
762 "--print-pages <pagelist>\n"
763 " Format for <pagelist>:\n"
764 " <pagelist> is a comma separated list of specifiers. A specifier can be\n"
765 " a single page number, a range of page numbers, a function name, or a\n"
767 " A range of pages is specified by the lower number, then a dash, then the\n"
769 " A special letter can be d, D, f, F or c for\n"
770 " changed pages, changed functions, function index, file index or cross\n"
771 " reference information respectively - note that the page will only be printed\n"
772 " if it would have been printed without the -A option\n"
773 " For example: trueprint --print-pages 1-5,main,f main.c\n"
774 " will print out pages 1-5, all pages for function main, and the function index\n"));
776 else if (strcmp(value
,"header") == 0)
780 " Format for <string>:\n"
781 " <string> is used to specify header and footer contents, and can contain the\n"
782 " following sequences:\n"
783 " %% a percent character\n"
784 " %m month of year\n"
786 " %y year e.g. 1993\n"
787 " %D date mm/dd/yy\n"
788 " %L long date e.g. Fri Oct 8 11:49:51 1993\n"
789 " %c file modification date mm/dd/yy\n"
790 " %C file modification date in long format\n"
794 " %T time HH:MM:SS\n"
795 " %j day of year ddd\n"
796 " %w day of week (Sunday = 0)\n"
797 " %a abbreviated weekday\n"
798 " %h abbreviated month\n"
799 " %r time in am/pm notation\n"
800 " %p page number in current file\n"
801 " %P overall page number\n"
802 " %f number of pages in current file\n"
803 " %F final overall page number\n"
804 " %n current filename\n"
805 " %N current functionname\n"
806 " %l login name\n"));
808 else if (strcmp(value
,"debug") == 0)
812 " Format for <debug-string>: series of char/digit pairs where char\n"
813 " specifies information, digit specifies level of detail, in\n"
814 " general 1=stuff that happens once, 2=per-pass, 3=per-file,\n"
815 " 4=per-page, 8=per-line - but this is not fully implemented...\n"
816 " Current chars are: o=options, i=index, O=output, P=parameters\n"
817 " l=language, p=pass, h=headers/footers, I=input,\n"
818 " d=diffs, f=file/stream handling, D=destination/printer\n"
819 " @=all of the above\n"));
821 else if (strcmp(value
,"report") == 0)
825 " Format for files when using --language=report:\n"
826 " Strings between ^B amd ^E are printed in bold and\n"
827 " are indexed as function names.\n"
828 " Strings between ^C and ^C are printed in italics\n"
833 printf(gettext(CMD_NAME
": Unrecognized help option:%s\nUse --help for valid options\n"),value
);
840 "Usage: trueprint <options> <filenames>\n"
842 " --help=all-options - list all options\n"
843 " --help=misc-options - list miscellaneous options\n"
844 " --help=page-furniture-options - list page furniture options\n"
845 " --help=text-format-options - list text formatting options\n"
846 " --help=print-options - list options that select what to print\n"
847 " --help=page-format-options - list page format options\n"
848 " --help=output-options - list options that affect where output goes\n"
849 " --help=language - list languages\n"
850 " --help=prompt - format for --print-pages string\n"
851 " --help=debug - format for --debug string\n"
852 " --help=header - format for header & footer strings\n"
853 " --help=report - file format for --language=report input\n"
854 " --help=environment - list environment vars used\n"
858 printf(gettext("Report bugs to bug-trueprint@gnu.org\n"));
862 /******************************************************************************
865 * Handler for -V option
867 void print_version(const char *p
, const char *o
)
869 printf("GNU Trueprint %s\n", VERSION
);
871 "Copyright (C) 2013 Free Software Foundation, Inc.\n"
872 "GNU Trueprint comes with NO WARRANTY,\n"
873 "to the extent permitted by law.\n"
874 "You may redistribute copies of GNU Trueprint\n"
875 "under the terms of the GNU General Public License.\n"
876 "For more information about these matters,\n"
877 "see the file named COPYING.\n"
879 printf("%s\n","http://www.gnu.org/licenses/gpl.html");
885 /******************************************************************************
895 size_t log_cmd_length
=COMMAND_LEN
;
899 if (use_environment
!= TRUE
) return;
901 log_cmd
= xmalloc(log_cmd_length
);
904 tp_opts
= getenv("TP_OPTS");
906 sprintf(log_cmd
,"%s %s", LOGTOOL
, "trueprint");
908 sprintf(log_cmd
, "%s %s%s%s", log_cmd
, "TPOPTS=\"<",tp_opts
,">\"");
910 for (i
=1; i
<argc
; i
++)
912 if ( (strlen(log_cmd
) + 6 + strlen(argv
[i
])) > log_cmd_length
)
914 log_cmd_length
+= COMMAND_LEN
;
915 log_cmd
= xmalloc(log_cmd_length
)
918 sprintf(log_cmd
, "%s \" <%s>\"", log_cmd
, argv
[i
]);