3 /* Copyright (c) 1994 Stanford University
7 This software is provided under the terms described in
8 the "suif_copyright.h" include file. */
10 #include <suif_copyright.h>
12 /* PSCC Compiler Driver */
28 #define SUIF_NEED_RLIMIT
29 #include <machine_dependent.h>
30 #undef SUIF_NEED_RLIMIT
31 #endif /* RLIMIT_STACK */
33 int main(int argc
, char **argv
)
35 start_suif(argc
, argv
);
38 int interesting_files
= 0;
42 /* Try to get environment variables from the environment. If they
43 don't exist, just use the defaults. */
44 if ((suif_top
= getenv("SUIFHOME")) == 0)
45 suif_top
= STRINGIFY(SUIF_TOP
);
46 if ((suif_path
= getenv("SUIFPATH")) == 0)
47 suif_path
= STRINGIFY(SUIFPATH
);
48 if ((tmpdir
= getenv("TMPDIR")) == 0)
52 /* unlimit the stack */
54 assert(getrlimit(RLIMIT_STACK
, &rl
) == 0);
55 rl
.rlim_cur
= rl
.rlim_max
;
56 assert(setrlimit(RLIMIT_STACK
, &rl
) == 0);
59 /* initialize the command table */
60 for (p
= 0; p
< last_pass
; p
++) {
62 pp
->flags
= new String
*[MAX_FLAGS
];
63 for (int flag_index
= 0; flag_index
< MAX_FLAGS
; ++flag_index
)
64 pp
->flags
[flag_index
] = NULL
;
65 pp
->pass_options
= new String
;
69 /* create the lists of input and output filenames */
70 infiles
= new filelist
;
71 outfiles
= new filelist
;
72 tmpfiles
= new filelist
;
74 /* default: compile to an executable (a.out) file */
77 /* default target machine: unknown */
78 target_machine
= NULL
;
80 /* save the name of this program (usually "pscc") */
83 /* generate a base for temporary file names */
84 tmpbase
= new char[10];
85 sprintf(tmpbase
, "pscc%05lu", (unsigned long)getpid());
87 /* trap signals and cleanup when we get them */
88 signal(SIGINT
, interrupt
);
89 signal(SIGTERM
, interrupt
);
90 /* catch SIGHUP if it was not previously ignored */
91 if ((void *)signal(SIGHUP
, (void (*)(int))SIG_IGN
) != (void *)SIG_IGN
) {
92 signal(SIGHUP
, interrupt
);
95 /* read command line options */
99 if (argv
[0][0] == '-') {
101 argv
= read_flag(argv
);
105 /* if not a flag, this must be an input file */
107 Suffix s
= getsfx(argv
[0]);
109 /* special case: pass .a files to the linker */
110 *passtbl
[LD
].pass_options
+= argv
[0];
111 *passtbl
[LD
].pass_options
+= " ";
113 if (s
== s_f
|| s
== s_F
) sf2c_flag
= TRUE
;
114 String
the_name(argv
[0]);
115 infile
= new filename(the_name
, base_from_name(the_name
),
116 find_start_pass(argv
[0]), FALSE
);
117 outfiles
->append(infile
);
128 base_cmd_name
= "suif";
132 base_cmd_name
= strrchr(cmdnam
, '/');
133 if (base_cmd_name
== NULL
)
134 base_cmd_name
= cmdnam
;
138 fprintf(stderr
, "%s %s%s\n", base_cmd_name
, prog_ver_string
,
143 if (interesting_files
== 0) usage();
145 if (reassociate_arrays
== UNKNOWN
) reassociate_arrays
= (opt_level
> 0);
146 if (target_machine
== NULL
) target_machine
= pscc_machine
;
149 *passtbl
[BACKEND_CC
].pass_options
+= " -S";
152 passtbl
[LD
].cmdname
= "cc";
155 default_path
= new String
*[2];
156 default_path
[0] = new String(suif_bin
);
157 default_path
[1] = NULL
;
159 } else if (suif_path
) {
161 /* count the colons in the path */
165 if (*c
++ == ':') num_paths
++;
167 default_path
= new String
*[num_paths
];
169 /* copy the paths into the default path array */
174 /* copy the string */
175 default_path
[path_num
] = new String
;
176 while ((*c
!= '\0') && (*c
!= ':')) {
177 *default_path
[path_num
] += *c
++;
179 *default_path
[path_num
] += '\0';
181 /* go to the next element of the path */
183 } while (*c
++ != '\0');
185 default_path
[path_num
] = NULL
;
188 default_path
= new String
*[2];
189 default_path
[0] = new String(suif_top
);
190 *default_path
[0] += "/";
191 *default_path
[0] += pscc_machine
;
192 *default_path
[0] += "/bin";
193 default_path
[1] = NULL
;
196 /* set the include directory name */
197 String
*incl_tmp
= new String(suif_top
);
199 *incl_tmp
+= target_machine
;
200 *incl_tmp
+= "/include";
201 suif_include
= incl_tmp
->string();
203 /* set the lib directory name */
204 String
*lib_tmp
= new String(suif_top
);
206 *lib_tmp
+= target_machine
;
208 suif_lib
= lib_tmp
->string();
210 /* set up the pass table */
211 for (p
= 0; p
< last_pass
; p
++) {
213 pp
->dir
= (*pp
->set_dir
)();
214 (*pp
->set_flags
)(pp
);
215 /* allow -yes and -no options to override defaults */
216 if (pp
->exec
== UNKNOWN
) pp
->exec
= (*pp
->set_exec
)();
219 /* run the passes.... */
226 extern void string_from_file(char *file_name
, String
*the_string
)
228 FILE *fp
= fopen(file_name
, "r");
231 int inchar
= fgetc(fp
);
232 while (inchar
!= EOF
)
234 if ((inchar
== '\n') || (inchar
== 0))
237 *the_string
+= (char)inchar
;
243 char ** read_flag(char **argv
)
247 switch (argv
[0][1]) {
250 if (!strcmp(argv
[0], "-automatic")) {
251 automatic_flag
= TRUE
;
257 if (!strcmp(argv
[0], "-checkwarn")) {
261 if (!strcmp(argv
[0], "-checkfail")) {
266 if (!strcmp(argv
[0], "-cc")) {
268 error(1, "usage: -cc <back-end C compiler name>");
269 passtbl
[BACKEND_CC
].cmdname
= argv
[1];
270 passtbl
[LD
].cmdname
= argv
[1];
275 if (!strcmp(argv
[0], "-c")) {
285 if (!strcmp(argv
[0], "-f2c")) {
292 if (!strcmp(argv
[0], "-g")) {
299 if (!strcmp(argv
[0], "-keep")) {
301 if (keepflag
> 1) tmpdir
= ".";
304 if (!strcmp(argv
[0], "-k")) {
311 *passtbl
[LD
].pass_options
+= argv
[0];
312 *passtbl
[LD
].pass_options
+= " ";
316 if (!strcmp(argv
[0],"-multi")) {
323 if (!strcmp(argv
[0], "-no")) {
324 if (argv
[1] == 0) error(1, "usage: -no <pass>");
325 if ((p
= find_pass(argv
[1])) == last_pass
)
326 error(1, "-no: unknown pass \"%s\"", argv
[1]);
327 passtbl
[p
].exec
= FALSE
;
331 if (!strcmp(argv
[0], "-noreassoc")) {
332 reassociate_arrays
= FALSE
;
338 if (!strcmp(argv
[0],"-option")) {
339 if (argv
[1] == 0 || argv
[2] == 0)
340 error(1, "usage: -option <pass> <option>");
341 if ((p
= find_pass(argv
[1])) == last_pass
)
342 error(1, "-option: unknown pass \"%s\"", argv
[1]);
343 *passtbl
[p
].pass_options
+= argv
[2];
344 *passtbl
[p
].pass_options
+= " ";
348 if (!strcmp(argv
[0], "-o")) {
350 error(1, "-o must have file argument");
351 if (outfilename
!= NULL
)
352 error(1, "multiple -o files specified");
353 outfilename
= new String(argv
[1]);
360 if (!strcmp(argv
[0], "-parallel")) {
361 option_parallel
= TRUE
;
367 if (!strcmp(argv
[0], "-reassoc")) {
368 reassociate_arrays
= TRUE
;
374 if (!strcmp(argv
[0], "-s2c")) {
377 if (!strcmp(argv
[0], "-sf2c")) {
381 if (!strcmp(argv
[0], "-static")) {
382 automatic_flag
= FALSE
;
385 if (!strcmp(argv
[0], "-show")) {
389 if (!strcmp(argv
[0], "-suif-link")) {
390 option_linksuif
= TRUE
;
396 tmpdir
= &argv
[0][2];
397 if (argv
[0][2] == 0) tmpdir
= ".";
401 if (!strcmp(argv
[0], "-version")) {
405 if (!strcmp(argv
[0], "-v")) {
412 if (!strcmp(argv
[0], "-w")) {
419 if (!strcmp(argv
[0], "-yes")) {
421 error(1, "usage: -yes <pass>");
422 if ((p
= find_pass(argv
[1])) == last_pass
)
423 error(1, "-yes: unknown pass \"%s\"", argv
[1]);
424 passtbl
[p
].exec
= TRUE
;
431 suif_bin
= &argv
[0][2];
432 if (argv
[0][2] == '\0')
433 error(1, "usage: -Bprefix");
437 if (!strcmp(argv
[0],"-E")) {
439 out_to_stdout
= TRUE
;
445 if (!strcmp(argv
[0], "-G")) {
446 if (argv
[1] == 0) error(1, "-G must have argument");
448 Gnum
= strtol(argv
[1], &p
, 10);
449 if (*p
) error(1, "-G must have number argument");
451 error(1, "-G must have non-negative argument");
458 *passtbl
[LD
].pass_options
+= argv
[0];
459 *passtbl
[LD
].pass_options
+= " ";
463 if (!strcmp(argv
[0], "-M")) {
465 out_to_stdout
= TRUE
;
472 *passtbl
[SF2C
].pass_options
+= argv
[0];
473 *passtbl
[SF2C
].pass_options
+= " ";
476 case 'D': /* defines for cpp */
477 case 'I': /* include directory for cpp */
478 case 'U': /* undefines for cpp */
479 *passtbl
[CPP
].pass_options
+= argv
[0];
480 *passtbl
[CPP
].pass_options
+= " ";
483 case 'O': /* run scalar opts */
484 if (!strncmp(argv
[0], "-O", 2)) {
485 if (argv
[0][2] == 0) {
487 } else if ((argv
[0][2] >= '0') && (argv
[0][2] <= '9') &&
489 opt_level
= argv
[0][2] - '0';
499 if (!strcmp(argv
[0], "-S")) {
507 if (!strcmp(argv
[0], "-T")) {
509 } else if (!strcmp(argv
[0], "-Target")) {
511 error(1, "usage: -Target <target machine name>");
512 target_machine
= argv
[1];
521 if (!strcmp(argv
[0], "-V")) {
528 if (!strcmp(argv
[0], "-Wall")) {
529 no_warn_flag
= FALSE
;
535 for (s_target
= s_c
; s_target
<= s_o
; s_target
++) {
536 if (!strcmp(&argv
[0][2], suffixes
[s_target
]))
539 if (s_target
> s_o
) {
540 char buf
[1024], buf2
[10];
541 sprintf(buf
, "bad -. option: %s\nUse one of: ",
543 for (s_target
= s_c
; s_target
<= s_o
; s_target
++) {
544 sprintf(buf2
, "-.%s ", suffixes
[s_target
]);
560 passes
find_pass(char *name
)
564 for (p
= 0; p
< last_pass
; p
++) {
565 if (!strcmp(name
, passtbl
[p
].passname
)) break;
573 /* Find the first pass to run over the input file, based on the suffix of
576 passes
find_start_pass(char *infile
)
578 Suffix infile_sfx
, pass_sfx
;
581 infile_sfx
= getsfx(infile
);
582 if (infile_sfx
== s_tmp
) {
583 error(1, "Unknown suffix (%s)", infile
);
586 /* search the command table for the first pass which produces files with
587 * a suffix that is greater than or equal to the infile suffix */
588 for (p
= 0; p
< last_pass
; p
++) {
589 pass_sfx
= passtbl
[p
].suffix
;
590 if ((pass_sfx
!= s_tmp
) && (pass_sfx
>= infile_sfx
)) break;
593 /* skip over passes that produce the same suffix as the infile suffix */
594 while (pass_sfx
== infile_sfx
) {
596 pass_sfx
= passtbl
[p
].suffix
;
606 passes p
, last_real_sfx
;
607 int next_many_in_pass
;
609 boolean reached_target
= FALSE
;
612 while (p
<= last_pass
) {
614 /* Search through the pass table from the current pass until finding
615 * a pass that requires all of the source files at once (as indicated
616 * by the file_counts flag) or that generates the desired target. */
618 for (next_many_in_pass
= p
; next_many_in_pass
< last_pass
;
619 next_many_in_pass
++) {
621 if (reached_target
) break;
622 pp
= &passtbl
[next_many_in_pass
];
624 if (pp
->suffix
!= s_tmp
) {
625 if (pp
->suffix
> s_target
) {
626 reached_target
= TRUE
;
627 next_many_in_pass
= last_real_sfx
+ 1;
630 last_real_sfx
= (passes
)next_many_in_pass
;
633 if (!pp
->exec
) continue;
634 if ((pp
->file_counts
== MANY_IN_ONE_OUT
) ||
635 (pp
->file_counts
== MANY_IN_MANY_OUT
)) {
638 if (pp
->suffix
== s_target
) {
639 reached_target
= TRUE
;
643 /* Compile the individual files up to the next requiring all input
644 * files at once. Note: here and throughout the remaining steps of
645 * the compilation, we make sure that each filename is kept on one
646 * of the filelists (infiles, * outfiles, or tmpfiles) so that we
647 * can clean things up correctly if we're interrupted. */
649 filelistiter
fiter(outfiles
);
650 while (!fiter
.is_empty()) {
651 filename
*test_file
= (filename
*)(fiter
.step());
652 if (test_file
->start_pass
< next_many_in_pass
) {
653 transfer_filename(test_file
, outfiles
, tmpfiles
);
657 parallel_passes
= contains_multiple_files(tmpfiles
);
659 fiter
.reset(tmpfiles
);
660 while (!fiter
.is_empty()) {
661 filename
*infile
= (filename
*)(fiter
.step());
662 run_passes(infile
, (passes
)next_many_in_pass
);
665 parallel_passes
= FALSE
;
667 if (reached_target
|| (next_many_in_pass
>= last_pass
)) break;
669 run_many_in_pass((passes
)next_many_in_pass
);
670 if (passtbl
[next_many_in_pass
].suffix
== s_target
)
671 reached_target
= TRUE
;
673 p
= (passes
)(next_many_in_pass
+ 1);
679 /* This returns true if and only if the_list contains at least two files. */
681 boolean
contains_multiple_files(filelist
*the_list
)
683 filelistiter
fiter(the_list
);
684 if (fiter
.is_empty())
686 (void)(fiter
.step());
687 return !(fiter
.is_empty());
692 /* Run a series of passes over the input file, beginning with the pass
693 specified in the filename structure and stopping BEFORE running the
694 stop_pass. The name of the final output file is returned. */
696 void run_passes(filename
*orig_infile
, passes stop_pass
)
698 filename
*infile
, *outfile
;
701 /* ignore files that are not used until after stop_pass */
702 passes start_pass
= orig_infile
->start_pass
;
703 if (start_pass
>= stop_pass
)
706 /* the original infile is kept around to record the filename base */
707 infile
= orig_infile
;
708 transfer_filename(infile
, tmpfiles
, outfiles
);
710 for (p
= start_pass
; p
< stop_pass
; p
++) {
712 /* skip over passes that don't execute */
713 if (!passtbl
[p
].exec
) continue;
715 transfer_filename(infile
, outfiles
, infiles
);
716 outfile
= choose_output_file((passes
)p
, infile
->basename
, TRUE
);
717 outfiles
->append(outfile
);
719 run_pass_one_in_one_out((passes
)p
, infile
->name
.string(),
720 outfile
->name
.string());
722 /* the output of this pass becomes the input for the next */
729 /* List the names of all the files in the given filelist in a single string,
730 separated by single space characters */
732 String
list_names(filelist
*files
)
735 boolean first
= TRUE
;
737 filelistiter
fiter(files
);
738 while (!fiter
.is_empty()) {
739 filename
*infile
= (filename
*)(fiter
.step());
744 result
+= infile
->name
;
752 filename
*choose_output_file(passes the_pass
, String base
,
755 /* find the appropriate suffix for the output of this pass */
756 Suffix outfile_sfx
= passtbl
[the_pass
].suffix
;
758 Suffix next_sfx
= s_tmp
;
759 Suffix save_sfx
= s_tmp
;
760 passes the_next_pass
= (passes
)(the_pass
+ 1);
762 /* check through the passes that won't be executed */
763 while (!passtbl
[the_next_pass
].exec
) {
764 Suffix pass_sfx
= passtbl
[the_next_pass
].suffix
;
765 if ((pass_sfx
!= s_tmp
) && (pass_sfx
<= s_target
)) {
767 /* save the previous value of next_sfx */
768 if (pass_sfx
!= next_sfx
) save_sfx
= next_sfx
;
772 the_next_pass
= (passes
)(the_next_pass
+ 1);
773 if (the_next_pass
>= last_pass
) break;
776 /* go back to saved suffix if found a pass that will generate next_sfx */
777 if ((the_next_pass
< last_pass
) &&
778 (passtbl
[the_next_pass
].suffix
== next_sfx
)) {
782 /* replace the suffix if this pass produces a file with a temporary suffix
783 or if this is the last pass before the target suffix is reached */
784 if ((outfile_sfx
== s_tmp
) || (next_sfx
== s_target
)) {
785 outfile_sfx
= next_sfx
;
788 String suffix_name
= suffix_to_string(outfile_sfx
);
794 if (outfilename
!= NULL
) {
795 base_used
= base_from_name(*outfilename
);
797 /* default name is "a"; this causes the linker to produce
805 if (outfile_sfx
== s_target
) {
807 if (!out_to_stdout
) {
808 if (parallel_passes
) {
809 if (outfilename
!= NULL
) {
810 error(0, "Multiple output files: \"-o %s\" ignored.\n",
811 outfilename
->string());
813 the_name
= base_used
;
815 the_name
+= suffix_name
;
817 if (outfilename
!= NULL
) {
818 the_name
= *outfilename
;
820 the_name
= base_used
;
822 the_name
+= suffix_name
;
827 will_erase
= ((keepflag
== 0) ||
828 ((keepflag
== 1) && (outfile_sfx
== s_tmp
)));
830 the_name
= new_temp_base();
832 the_name
= base_used
;
835 the_name
+= suffix_name
;
838 return new filename(the_name
, base_used
, the_next_pass
, will_erase
);
843 /* This returns everything before the extension of a file name. */
845 String
base_from_name(String the_name
)
847 char *name_string
= the_name
.string();
848 char *extension
= NULL
;
851 char *follow
= name_string
;
852 while (*follow
!= 0) {
855 else if (*follow
== '.')
859 if (extension
== NULL
)
862 buffer
= new char[(extension
- name_string
) + 1];
863 strncpy(buffer
, name_string
, (extension
- name_string
));
864 buffer
[extension
- name_string
] = 0;
865 String
return_value(buffer
);
872 /* If the suffix is a temporary, this returns a new unique suffix.
873 Otherwise, it returns the string for that suffix. */
875 String
suffix_to_string(Suffix the_suffix
)
877 static long int suffix_number
= 0;
880 if (the_suffix
== s_tmp
) {
883 sprintf(buf
, "%ld", suffix_number
++);
886 return_value
+= suffixes
[the_suffix
];
893 /* Run a pass that requires all of the input files at once. The input
894 files are removed from the infiles list, and the output file (as well as
895 any of the input files which will be used in future passes) is added to
898 void run_many_in_pass(passes this_pass
)
900 String outfile_string
;
901 String in_out_string
;
903 /* Search through the output files and add any files that should be
904 processed by this pass to the input files list. */
906 filelistiter
fiter(outfiles
);
907 while (!fiter
.is_empty()) {
908 filename
*test_file
= (filename
*)(fiter
.step());
909 if (test_file
->start_pass
<= this_pass
) {
910 transfer_filename(test_file
, outfiles
, infiles
);
914 if (passtbl
[this_pass
].file_counts
== MANY_IN_ONE_OUT
) {
916 filename
*outfile
= choose_output_file(this_pass
, dummy
, FALSE
);
917 outfiles
->append(outfile
);
918 outfile_string
+= outfile
->name
;
919 in_out_string
+= list_names(infiles
);
920 in_out_string
+= ' ';
921 in_out_string
+= outfile
->name
;
923 parallel_passes
= contains_multiple_files(infiles
);
924 filelistiter
fiter(infiles
);
925 while (!fiter
.is_empty()) {
926 filename
*one_file
= (filename
*)(fiter
.step());
928 choose_output_file(this_pass
, one_file
->basename
, TRUE
);
929 outfiles
->append(outfile
);
930 outfile_string
+= outfile
->name
;
931 in_out_string
+= one_file
->name
;
932 in_out_string
+= ' ';
933 in_out_string
+= outfile
->name
;
934 if (!fiter
.is_empty()) {
935 outfile_string
+= ' ';
936 in_out_string
+= ' ';
939 parallel_passes
= FALSE
;
942 if (!uses_specified_output(this_pass
)) {
943 error(0, "Pass %s cannot have multiple input files.\n"
944 "(the output file is not specified)",
945 passtbl
[this_pass
].passname
);
949 String infiles_string
= list_names(infiles
);
950 run_pass_basic(this_pass
, infiles_string
.string(),
951 outfile_string
.string(), in_out_string
.string());
956 /* This function returns whether or not a particular pass uses the output
957 name pscc gives it or not. It bases this decision on whether or not the
958 %o flag is included in that pass's format string. */
960 boolean
uses_specified_output(passes p
)
962 pass
*pp
= &passtbl
[p
];
964 char *fmt_index
= pp
->cmdfmt
;
966 if (*fmt_index
== '%') {
968 if ((*fmt_index
== 'o') || (*fmt_index
== 'a')) {
972 } while (*fmt_index
++ != '\0');
979 void run_pass_one_in_one_out(passes p
, char *infile
, char *outfile
)
981 /* if the command format string doesn't include a %o field, then the
982 * output file name cannot be specified; this flag is used to detect
983 * the presence of the %o flag in the format string. */
984 boolean used_outfile
= uses_specified_output(p
);
986 String in_out_string
;
987 in_out_string
+= infile
;
988 in_out_string
+= ' ';
989 in_out_string
+= outfile
;
990 run_pass_basic(p
, infile
, outfile
, in_out_string
.string());
994 /* Find the name of the output file. This assumes that if the output
995 * filename cannot be specified that it defaults to just changing the
996 * suffix of the input file. We just replace the suffix of the input
999 /* the pass must have a named suffix */
1000 Suffix pass_sfx
= passtbl
[p
].suffix
;
1001 if (pass_sfx
== s_tmp
) {
1002 error(0, "Pass %s must be given a named suffix.\n"
1003 "(the output file is not specified)", passtbl
[p
].passname
);
1007 /* if the command didn't put the output in the right file,
1008 * we have to move it there. */
1009 String
infile_name(infile
);
1010 String actual_outfile
= base_from_name(infile_name
);
1011 actual_outfile
+= '.';
1012 actual_outfile
+= suffix_to_string(pass_sfx
);
1013 move_file(actual_outfile
.string(), outfile
);
1019 /* Run a pass over the specified input file(s) and put the output in the
1020 specified file. The format for the command line, as well as the flags
1021 and pass_options, are read from the global pass table. */
1023 void run_pass_basic(passes p
, char *infile_names
, char *outfiles
,
1026 String command_line
;
1028 pass
*pp
= &passtbl
[p
];
1031 command_line
+= TIMECMD
;
1032 command_line
+= " ";
1035 command_line
+= select_path(pp
->cmdname
, pp
->dir
);
1036 command_line
+= "/";
1037 command_line
+= pp
->cmdname
;
1038 command_line
+= " ";
1040 /* Now we have to parse the command format string.... */
1041 char *fmt_index
= pp
->cmdfmt
;
1043 if (*fmt_index
!= '%') {
1044 command_line
+= *fmt_index
;
1047 switch (*fmt_index
) {
1049 command_line
+= infile_names
;
1053 command_line
+= outfiles
;
1057 command_line
+= in_out_files
;
1061 if (pp
->flags
[flag_index
]) {
1062 command_line
+= *pp
->flags
[flag_index
];
1064 if (++flag_index
> MAX_FLAGS
) {
1065 error(0, "Too many flags in command format for %s\n",
1072 command_line
+= *pp
->pass_options
;
1076 error(0,"Unrecognized flag %%%c in command format for %s\n",
1077 *fmt_index
, pp
->passname
);
1081 } while (*fmt_index
++ != '\0');
1084 fprintf(stderr
, "%s: %s\n", pp
->passname
, command_line
.string());
1087 int stat
= execute_cmd(command_line
.string());
1091 if (checksuif
&& (pp
->out_file_format
== OUTPUT_SUIF
)) {
1092 String check_command_line
;
1095 check_command_line
+= TIMECMD
;
1096 check_command_line
+= " ";
1099 check_command_line
+= select_path("checksuif", NULL
);
1100 check_command_line
+= "/";
1101 check_command_line
+= "checksuif ";
1103 check_command_line
+= "-fail ";
1105 check_command_line
+= "-warn ";
1106 check_command_line
+= outfiles
;
1107 stat
= execute_cmd(check_command_line
.string());
1113 /* delete any temporary files */
1114 erase_files(infiles
);
1119 /* Find a directory containing the executable cmd. The optional directory
1120 argument is checked first if it is provided. Otherwise, the directories
1121 in the default_path array are checked. If none of the directories
1122 contain the executable, then an error is signaled and the program exits. */
1124 const char * select_path(const char *cmd
, const char *dir
)
1128 /* first try the specified directory */
1133 if (!access(path
.string(), X_OK
)) return dir
;
1136 /* otherwise, try the default directories */
1138 while ((p
= default_path
[path_num
++])) {
1140 path
+= p
->string();
1143 if (!access(path
.string(), X_OK
)) return p
->string();
1146 /* none of the paths worked */
1147 error(0, "Cannot find an executable file for \"%s\".\n"
1148 "Check the value of your SUIFPATH variable.", cmd
);
1155 /* Execute a command. First, we have to break the command string into
1156 words and store the individual words into an array. Next, we fork off
1157 a new process and exec the specified command, and finally, we check
1158 the return status of the child process. Note: I tried using the system()
1159 call to execute commands via the shell. This avoids having to split
1160 the command into words and allows use of wildcards and other shell
1161 features. Unfortunately, the return status did not indicate whether
1162 the child process had been killed, so I went back to directly executing
1165 /* make it all look like system V */
1167 #define WIFSTOPPED WIFSIGNALED
1168 #define WSTOPSIG WIFTEMSIG
1171 int execute_cmd(char *cmd
)
1174 static char *cmd_items
[100];
1176 /* break the command into words */
1183 /* skip any leading blanks */
1184 while (*start
== ' ') start
++;
1185 if (*start
== '\0') break;
1187 /* find the end of the word */
1188 boolean inside_quote
= FALSE
;
1189 boolean inside_dblquote
= FALSE
;
1192 if (*end
== '\0') break;
1195 inside_quote
= FALSE
;
1196 } else if (!inside_dblquote
) {
1197 inside_quote
= TRUE
;
1201 if (inside_dblquote
) {
1202 inside_dblquote
= FALSE
;
1203 } else if (!inside_quote
) {
1204 inside_dblquote
= TRUE
;
1207 if (!inside_quote
&& !inside_dblquote
&& (*end
== ' ')) break;
1211 /* store the word into the array */
1212 cmd_items
[i
] = new char[(end
- start
) + 1];
1213 strncpy(cmd_items
[i
], start
, (end
- start
));
1214 cmd_items
[i
][(end
- start
)] = '\0';
1217 if (*end
== '\0') break;
1220 cmd_items
[i
] = NULL
;
1222 if ((pid
= fork()) == -1) syscallerr("fork");
1224 /* check if this is now the child process */
1226 /* execute the command */
1227 execv(cmd_items
[0], cmd_items
);
1228 /* should never reach this point */
1229 syscallerr("execv");
1231 /* otherwise, this must be the parent process */
1233 /* delete the command items */
1234 for (i
= i
- 1; i
>= 0; i
--) {
1235 delete[] cmd_items
[i
];
1238 /* wait for the child to finish */
1240 while ((w
= wait(&retcode
)) != pid
) {
1241 if (w
== -1) syscallerr("wait");
1242 /* I suppose w == 0 and I'm about to be interrupted. Not sure. */
1245 if (WIFEXITED(retcode
)) {
1247 int rc
= WEXITSTATUS(retcode
);
1249 fprintf(stderr
, "%s\nFAILED (exit status 0x%x)\n", cmd
, rc
);
1253 } else if (WIFSTOPPED(retcode
)) {
1254 /* child process caught a signal */
1255 int sig
= WSTOPSIG(retcode
);
1256 fprintf(stderr
, "%s\nFAILED (caught signal 0x%x)\n", cmd
, sig
);
1260 /* I have no idea, time to panic */
1261 fprintf(stderr
, "%s\nFAILED (wait code 0x%x)\n", cmd
, retcode
);
1270 /* Return a new unique temporary file base name. */
1272 String
new_temp_base()
1275 static long int base_number
= 0;
1281 sprintf(buf
, "%ld", base_number
++);
1288 /* Return the suffix of the given filename */
1290 Suffix
getsfx(char *s
)
1296 /* scan through the string and record the position of the last dot */
1297 while ((c
= *s
++)) {
1298 if (c
== '.') sfx
= s
;
1301 error(0, "missing suffix, file \"%s\"", fs
);
1305 /* compare the suffix to all of those in the suffixes[] array */
1307 for (r
= s_F
; r
< s_tmp
; r
++) {
1308 if (!strcmp(suffixes
[r
], sfx
)) break;
1316 /* If the filenames are not identical, move the first file to the second. */
1318 void move_file(char *f1
, char *f2
)
1323 if (strcmp(f1
, f2
)) {
1324 String
mvcmd(MVCMD
);
1329 int stat
= execute_cmd(mvcmd
.string());
1331 error(0, "Unable to move temporary file \"%s\" to \"%s\".", f1
, f2
);
1339 /* The interrupt() function is called when we catch a signal. This gives
1340 us a chance to remove any temporary output files before exiting. */
1349 void bad_option(char *s
)
1351 error(1, "unrecognized flag: %s", s
);
1358 fprintf(stderr
, "Usage: %s [flags] file ...\n", cmdnam
);
1364 void error(int rc
, char *msg
, ...)
1369 fprintf(stderr
, "%s: ", cmdnam
);
1370 vfprintf(stderr
, msg
, ap
);
1373 if (rc
!= 0) exit(rc
);
1378 /* Get rid of temporary files after detecting an error of some sort. */
1382 if (keepflag
> 1) exit(-1);
1384 erase_files(infiles
);
1385 erase_files(outfiles
);
1386 erase_files(tmpfiles
);
1387 if (moving_file
!= NULL
)
1388 unlink(moving_file
);
1395 /* Remove any temporary files on the specified list (also removes all of
1396 the filenames from the list and deletes them). */
1398 void erase_files(filelist
*flist
)
1402 /* delete any temporary files */
1403 while (!flist
->is_empty()) {
1404 f
= (filename
*)(flist
->pop());
1405 /* try to remove the file -- don't worry if it fails */
1406 if (f
->erase
) unlink(f
->name
.string());
1413 void syscallerr(char *s
)
1415 fprintf(stderr
, "system call error: %s\n", s
);
1421 /* Safely transfer a file from one list to another, so it is always on at
1422 least one list or in the variable moving_file. That way whenever we catch
1423 a signal, every temporary file will be recorded in at least one place, so
1424 it will be properly removed. */
1426 void transfer_filename(filename
*to_transfer
, filelist
*from
, filelist
*to
)
1428 moving_file
= to_transfer
->name
.string();
1429 from
->remove(to_transfer
);
1430 to
->append(to_transfer
);
1436 filename::filename(String the_name
, String the_basename
,
1437 passes the_start_pass
, boolean will_erase
)
1440 basename
= the_basename
;
1441 start_pass
= the_start_pass
;