1 /* splitup -- take TeX or MF in C as a single stream on stdin,
2    and it produces several .c and .h files in the current directory
3    as its output.
4 
5    $Id: splitup.c 27708 2012-09-18 17:43:20Z peter $
6 
7    Tim Morgan  September 19, 1987.  */
8 
9 #include <w2c/config.h>
10 #include <kpathsea/getopt.h>
11 
12 #if defined (FATAL)
13 #undef FATAL
14 #endif
15 
16 #define FATAL(str) do {                                                 \
17         fprintf (stderr, "%s: fatal: ", argv[0]);                       \
18         fputs (str, stderr);                                            \
19         fputs (".\n", stderr); exit (1); } while (0)
20 
21 
22 #if defined (FATAL1)
23 #undef FATAL1
24 #endif
25 
26 #define FATAL1(str, e1) do {                                            \
27         fprintf (stderr, "%s: fatal: ", argv[0]);                       \
28         fprintf (stderr, str, e1);                                      \
29         fputs (".\n", stderr); exit (1); } while (0)
30 
31 
32 #ifdef VMS
33 #define unlink delete
34 #endif
35 
36 int filenumber = 0, ifdef_nesting = 0, lines_in_file = 0;
37 char *output_name = NULL;
38 boolean has_ini;
39 
40 /* This used to be a fixed 2000, but since bibtex.c is almost 10000 lines
41    (200+K), we may as well decrease the number of split files we create.
42    Probably faster for the compiler, definitely faster for the linker,
43    simpler for the Makefiles, and generally better.  Now we specify this
44    in 'convert'. */
45 long int max_lines;
46 
47 /* Do we split out a separate *ini.c file? */
48 boolean do_ini;
49 
50 /* Don't need long filenames, since we generate them all.  */
51 char buffer[1024], tempfile[100], filename[100], ini_name[100];
52 
53 FILE *out, *ini, *temp;
54 
55 /*
56  * Read a line of input into the buffer, returning `false' on EOF.
57  * If the line is of the form "#ifdef INI...", we set "has_ini"
58  * `true' else `false'.  We also keep up with the #ifdef/#endif nesting
59  * so we know when it's safe to finish writing the current file.
60  */
61 static int
read_line(void)62 read_line (void)
63 {
64   if (fgets (buffer, sizeof (buffer), stdin) == NULL)
65     return false;
66   if (strncmp (buffer, "#ifdef", 6) == 0
67       || strncmp (buffer, "#ifndef", 7) == 0)
68     {
69       ++ifdef_nesting;
70       if (strncmp (&buffer[7], "INI", 3) == 0)
71 	has_ini = true;
72     }
73   else if (strncmp (buffer, "#endif", 6) == 0)
74     --ifdef_nesting;
75   return true;
76 }
77 
78 #ifdef WIN32
79 #include <io.h>
80 #include <fcntl.h>
81 #endif
82 
83 int
main(int argc,string * argv)84 main (int argc, string *argv)
85 {
86   const_string coerce;
87   unsigned coerce_len;
88   int option;
89 
90 #ifdef WIN32
91   setmode(fileno(stdout), _O_BINARY);
92 #endif
93 
94   while ((option = getopt(argc, argv, "il:")) != -1) {
95     switch (option) {
96     case 'i':
97       do_ini = true;
98       break;
99     case 'l':
100       max_lines = atoi(optarg);
101       if (max_lines <= 0)
102         FATAL("[-i] [-l lines] name");
103       break;
104     default:
105       FATAL("[-i] [-l lines] name");
106       break;
107     }
108   }
109   if (optind + 1 != argc)
110     FATAL("[-i] [-l lines] name");
111   output_name = argv[optind];
112 
113   sprintf (filename, "%sd.h", output_name);
114   sprintf (tempfile, "%s.tmp", output_name);
115   out = xfopen (filename, FOPEN_W_MODE);
116   fputs ("#undef TRIP\n#undef TRAP\n", out);
117   /* We have only one binary that can do both ini stuff and vir stuff.  */
118   fputs ("#define STAT\n#define INI\n", out);
119 
120   if (STREQ (output_name, "mf")) {
121     fputs ("#define INIMF\n#define MF\n", out);
122     coerce = "mfcoerce.h";
123   } else if (STREQ (output_name, "tex")) {
124     fputs ("#define INITEX\n#define TeX\n#define onlyTeX\n", out);
125     coerce = "texcoerce.h";
126   } else if (STREQ (output_name, "aleph")) {
127     fputs ("#define INITEX\n#define TeX\n#define Aleph\n", out);
128     coerce = "alephcoerce.h";
129   } else if (STREQ (output_name, "etex")) {
130     fputs ("#define INITEX\n#define TeX\n#define eTeX\n", out);
131     coerce = "etexcoerce.h";
132   } else if (STREQ (output_name, "pdftex")) {
133     fputs ("#define INITEX\n#define TeX\n#define pdfTeX\n", out);
134     coerce = "pdftexcoerce.h";
135   } else if (STREQ (output_name, "ptex")) {
136     fputs ("#define INITEX\n#define TeX\n#define pTeX\n", out);
137     coerce = "ptexcoerce.h";
138   } else if (STREQ (output_name, "eptex")) {
139     fputs ("#define INITEX\n#define TeX\n#define epTeX\n", out);
140     coerce = "eptexcoerce.h";
141   } else if (STREQ (output_name, "euptex")) {
142     fputs ("#define INITEX\n#define TeX\n#define eupTeX\n", out);
143     coerce = "euptexcoerce.h";
144   } else if (STREQ (output_name, "uptex")) {
145     fputs ("#define INITEX\n#define TeX\n#define upTeX\n", out);
146     coerce = "uptexcoerce.h";
147   } else if (STREQ (output_name, "xetex")) {
148     fputs ("#define INITEX\n#define TeX\n#define XeTeX\n", out);
149     coerce = "xetexcoerce.h";
150   } else
151     FATAL1 ("Can only split mf, tex, aleph, eptex, euptex, etex, pdftex, ptex, uptex, or xetex,\n not %s", output_name);
152 
153   coerce_len = strlen (coerce);
154 
155   /* Read everything up to coerce.h.  */
156   while (fgets (buffer, sizeof (buffer), stdin))
157     {
158       if (strncmp (&buffer[10], coerce, coerce_len) == 0)
159 	break;
160 
161       if (buffer[0] == '#' || buffer[0] == '\n' || buffer[0] == '}'
162 	  || buffer[0] == '/' || buffer[0] == ' '
163 	  || strncmp (buffer, "typedef", 7) == 0)
164 	/*nothing */ ;
165       else
166 	fputs ("EXTERN ", out);
167 
168       fputs (buffer, out);
169     }
170 
171   if (strncmp (&buffer[10], coerce, coerce_len) != 0)
172     FATAL1 ("No #include %s line", coerce);
173 
174   fputs (buffer, out);
175   xfclose (out, filename);
176 
177   if (do_ini) {
178     sprintf (ini_name, "%sini.c", output_name);
179     ini = xfopen (ini_name, FOPEN_W_MODE);
180     fputs ("#define EXTERN extern\n", ini);
181     fprintf (ini, "#include \"%sd.h\"\n\n", output_name);
182   }
183 
184   sprintf (filename, "%s0.c", output_name);
185   out = xfopen (filename, FOPEN_W_MODE);
186   fputs ("#define EXTERN extern\n", out);
187   fprintf (out, "#include \"%sd.h\"\n\n", output_name);
188 
189   do
190     {
191       /* Read one routine into a temp file */
192       has_ini = false;
193       temp = xfopen (tempfile, "wb+");
194 
195       while (read_line ())
196 	{
197 	  fputs (buffer, temp);
198 	  if (buffer[0] == '}')
199 	    break;		/* End of procedure */
200 	}
201       while (ifdef_nesting > 0 && read_line ())
202 	fputs (buffer, temp);
203       rewind (temp);
204 
205       if (do_ini && has_ini)
206 	{			/* Contained "#ifdef INI..." */
207 	  while (fgets (buffer, sizeof (buffer), temp))
208 	    fputs (buffer, ini);
209 	}
210       else
211 	{			/* Doesn't contain "#ifdef INI..." */
212 	  while (fgets (buffer, sizeof (buffer), temp))
213 	    {
214 	      fputs (buffer, out);
215 	      lines_in_file++;
216 	    }
217 	}
218       xfclose (temp, tempfile);
219 
220       /* Switch to new output file.  */
221       if (max_lines && lines_in_file > max_lines)
222 	{
223 	  xfclose (out, filename);
224 	  sprintf (filename, "%s%d.c", output_name, ++filenumber);
225 	  out = xfopen (filename, FOPEN_W_MODE);
226 	  fputs ("#define EXTERN extern\n", out);
227 	  fprintf (out, "#include \"%sd.h\"\n\n", output_name);
228 	  lines_in_file = 0;
229 	}
230     }
231   while (!feof (stdin));
232 
233   xfclose (out, filename);
234   if (lines_in_file == 0)
235     unlink (filename);
236 
237   if (do_ini)
238     xfclose (ini, ini_name);
239 
240   if (unlink (tempfile)) {
241       perror (tempfile);
242       exit (EXIT_FAILURE);
243   }
244 
245   return EXIT_SUCCESS;
246 }
247