1 /* igawk C version
2 * Katsuyuki Okabe
3 * April 26, 1997
4 * Last change: August 5, 1998
5 */
6 #include <ctype.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <io.h>
10 #include <malloc.h>
11 #include <signal.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <process.h>
17 #ifndef __GO32__
18 #ifdef WIN32
19 #include "xargs32.h"
20 #else
21 #include "xargs.h"
22 #endif
23 #endif
24
25 static const char *version_string = "1.0";
26
27
28 #if (defined (_MSC_VER) || defined (__TURBOC__)) && !defined(WIN32)
29 #define NEAR _near
30 #else
31 #define NEAR
32 #endif
33
34 #define STREQ(s1,s2) (strcmp ((s1), (s2)) == 0)
35 #define STRNEQ(s1,s2,n) (strncmp ((s1), (s2), (n)) == 0)
36 #define tmpfile_open(f) file_open ((f), tmpnam ((char *) 0))
37
38 struct args {
39 int size;
40 int argc;
41 char **argv;
42 };
43
44 struct file {
45 FILE *fp;
46 char *name;
47 };
48
49 static const char igawk_awk[] =
50 #include "igawk.d"
51 ;
52
53 static const char *program_name;
54 static const char *gawk_path;
55 static struct file igs, ige;
56
57 static void NEAR error (int, const char *, ...)
58 #if defined (__GNUC__) && __GNUC__ >= 2
59 __attribute__ ((noreturn, format (printf, 2, 3)))
60 #endif
61 ;
62 static void * NEAR xmalloc (size_t);
63 static void * NEAR xrealloc (void *, size_t);
64 static char * NEAR xstrdup (const char *);
65 static int NEAR strempty (const char *);
66 static struct file * NEAR file_open (struct file *, const char *);
67 static int NEAR file_close (struct file *);
68 static int NEAR file_remove (struct file *);
69 static void NEAR args_init (struct args *);
70 static void NEAR args_add (struct args *, const char *);
71 static void NEAR args_cat (struct args *, const char *);
72 static void NEAR parse_arguments (struct args *, struct file *, int, char **);
73 static void NEAR filter_program (const char *, int);
74 static int NEAR run_program (struct args *);
75 static void remove_files (void);
76 static void sigint (int);
77
78 static void NEAR
error(int errnum,const char * message,...)79 error (int errnum, const char *message, ...)
80 {
81 va_list ap;
82
83 fprintf (stderr, "%s: ", program_name);
84
85 va_start (ap, message);
86 vfprintf (stderr, message, ap);
87 va_end (ap);
88
89 if (errnum)
90 fprintf (stderr, ": %s", strerror (errnum));
91 putc ('\n', stderr);
92 fflush (stderr);
93
94 exit (EXIT_FAILURE);
95 }
96
97 static void * NEAR
xmalloc(size_t size)98 xmalloc (size_t size)
99 {
100 void *ptr;
101
102 ptr = (void *) malloc (size ? size : 1);
103 if (ptr == (void *) 0)
104 error (0, "Memory exhausted");
105 return ptr;
106 }
107
108 static void * NEAR
xrealloc(void * ptr,size_t size)109 xrealloc (void *ptr, size_t size)
110 {
111 if (ptr == (void *) 0)
112 return xmalloc (size);
113
114 ptr = (void *) realloc (ptr, size ? size : 1);
115 if (ptr == (void *) 0)
116 error (0, "Memory exhausted");
117 return ptr;
118 }
119
120 static char * NEAR
xstrdup(const char * str)121 xstrdup (const char *str)
122 {
123 return strcpy (xmalloc (strlen (str) + 1), str);
124 }
125
126 static int NEAR
strempty(const char * str)127 strempty (const char *str)
128 {
129 while (isspace ((unsigned char) *str))
130 str++;
131 return *str == '\0';
132 }
133
134 static struct file * NEAR
file_open(struct file * f,const char * path)135 file_open (struct file *f, const char *path)
136 {
137 f->name = xstrdup (path);
138 if ((f->fp = fopen (path, "w")) == (FILE *) 0)
139 error (errno, "Opening %s", path);
140
141 return f;
142 }
143
144 static int NEAR
file_close(struct file * f)145 file_close (struct file *f)
146 {
147 if (f == 0)
148 return -1;
149
150 if (f->fp)
151 fclose (f->fp);
152 f->fp = (FILE *) 0;
153
154 return 0;
155 }
156
157 static int NEAR
file_remove(struct file * f)158 file_remove (struct file *f)
159 {
160 if (file_close (f) < 0)
161 return -1;
162
163 if (f->name)
164 {
165 remove (f->name);
166 free (f->name);
167 }
168 f->name = (char *) 0;
169
170 return 0;
171 }
172
173 static void NEAR
args_init(struct args * args)174 args_init (struct args *args)
175 {
176 args->size = 0;
177 args->argc = 0;
178 args->argv = (char **) 0;
179 }
180
181 static void NEAR
args_add(struct args * args,const char * arg)182 args_add (struct args *args, const char *arg)
183 {
184 if (args->argc >= args->size)
185 {
186 args->size += 16;
187 args->argv = (char **) xrealloc (args->argv, sizeof (char *) * args->size);
188 }
189
190 if (arg)
191 args->argv[args->argc++] = xstrdup (arg);
192 else
193 args->argv[args->argc] = (char *) 0;
194 }
195
196 static void NEAR
args_cat(struct args * args,const char * arg)197 args_cat (struct args *args, const char *arg)
198 {
199 int idx;
200 char *p;
201
202 if (args->argc == 0)
203 {
204 args_add (args, arg);
205 return;
206 }
207
208 if (arg == (char *) 0)
209 return;
210
211 idx = args->argc - 1;
212 p = args->argv[idx];
213 args->argv[idx] = strcat (xrealloc (p, strlen (p) + strlen (arg) + 1), arg);
214 }
215
216 static void NEAR
parse_arguments(struct args * args_p,struct file * f,int argc,char ** argv)217 parse_arguments (struct args *args_p, struct file *f, int argc, char **argv)
218 {
219 int program_in_f = 0;
220 int i;
221
222 for (i = 1; i < argc && argv[i][0] == '-'; i++)
223 {
224 char *arg = argv[i] + 1;
225
226 if (STREQ (arg, "-"))
227 {
228 i++;
229 break;
230 }
231 else if (STREQ (arg, "W"))
232 {
233 i++;
234 if (i < argc)
235 {
236 arg = (char *) alloca (strlen (argv[i]) + 3);
237 strcat (strcpy (arg, "-W"), argv[i]);
238 arg++;
239 }
240 else
241 {
242 args_add (args_p, "-W");
243 break;
244 }
245 }
246
247 if (arg[0] == 'v' || arg[0] == 'F')
248 {
249 args_add (args_p, arg - 1);
250 if (arg[1] == '\0' && ++i < argc)
251 args_cat (args_p, argv[i]);
252 }
253 else if (arg[0] == 'f')
254 {
255 if (arg[1])
256 fprintf (f->fp, "@include %s\n", arg + 1);
257 else
258 fprintf (f->fp, "@include %s\n", ++i < argc ? argv[i] : "");
259 program_in_f = 1;
260 }
261 else if (arg[0] == '-' || arg[0] == 'W')
262 {
263 arg++;
264 if (STRNEQ (arg, "file=", 5))
265 {
266 fprintf (f->fp, "@include %s\n", arg + 5);
267 program_in_f = 1;
268 }
269 else if (STREQ (arg, "file"))
270 {
271 fprintf (f->fp, "@include %s\n", ++i < argc ? argv[i] : "");
272 program_in_f = 1;
273 }
274 else if (STRNEQ (arg, "source=", 7))
275 {
276 fputs (arg + 7, f->fp);
277 putc ('\n', f->fp);
278 program_in_f = 1;
279 }
280 else if (STREQ (arg, "source"))
281 {
282 if (++i < argc)
283 {
284 fputs (argv[i], f->fp);
285 putc ('\n', f->fp);
286 program_in_f = 1;
287 }
288 }
289 else if (STREQ (arg, "version"))
290 {
291 fprintf (stderr, "igawk: C version %s\n", version_string);
292 if (spawnlp (P_WAIT, gawk_path, "gawk", "--version", (char *) 0) < 0)
293 error (errno, "Cannot exec gawk");
294 exit (EXIT_SUCCESS);
295 }
296 else if (STREQ (arg, "help"))
297 {
298 if (spawnlp (P_WAIT, gawk_path, "igawk", "--help", (char *) 0) < 0)
299 error (errno, "Cannot exec gawk");
300 exit (EXIT_SUCCESS);
301 }
302 else
303 args_add (args_p, arg - 2);
304 }
305 else
306 break;
307 }
308
309 if (! program_in_f)
310 if (i >= argc || strempty (argv[i]))
311 error (0, "no program!");
312 else
313 {
314 fputs (argv[i++], igs.fp);
315 putc ('\n', igs.fp);
316 }
317
318 file_close (f);
319
320 if (i < argc)
321 {
322 args_add (args_p, "--");
323 while (i < argc)
324 args_add (args_p, argv[i++]);
325 }
326 }
327
328 static void NEAR
filter_program(const char * in_path,int out_fd)329 filter_program (const char *in_path, int out_fd)
330 {
331 struct file awk;
332 int fd1;
333 int status;
334 int err;
335
336 tmpfile_open (&awk);
337 fputs (igawk_awk, awk.fp);
338 file_close (&awk);
339
340 if ((fd1 = dup (1)) < 0)
341 error (errno, "Cannot duplicate STDOUT");
342 dup2 (out_fd, 1);
343 status = spawnlp (P_WAIT, gawk_path, "gawk", "-f", awk.name, in_path, (char *) 0);
344 err = errno;
345 dup2 (fd1, 1);
346 close (fd1);
347 file_remove (&awk);
348 if (status < 0)
349 error (err, "Cannot exec gawk");
350 }
351
352 static int NEAR
run_program(struct args * args_p)353 run_program (struct args *args_p)
354 {
355 #if defined (__DJGPP__) && (__DJGPP__ > 2 || (__DJGPP__ == 2 && __DJGPP_MINOR__ >= 1))
356 return spawnvp (P_WAIT, gawk_path, args_p->argv);
357 #else
358 struct file res;
359 char *p;
360 int status;
361 int i;
362 int c;
363
364 tmpfile_open (&res);
365 for (i = 1; i < args_p->argc; i++)
366 if (strpbrk (args_p->argv[i], " \t\n"))
367 {
368 putc ('"', res.fp);
369 p = args_p->argv[i];
370 while ((c = (unsigned char) *p++) != '\0')
371 {
372 if (c == '"')
373 putc ('\\', res.fp);
374 putc (c, res.fp);
375 }
376 fputs ("\"\n", res.fp);
377 }
378 else
379 {
380 fputs (args_p->argv[i], res.fp);
381 putc ('\n', res.fp);
382 }
383 file_close (&res);
384
385 p = (char *) alloca (strlen (res.name) + 2);
386 strcat (strcpy (p, "@"), res.name);
387 status = spawnlp (P_WAIT, gawk_path, "gawk", p, (char *) 0);
388 file_remove (&res);
389
390 return status;
391 #endif
392 }
393
394 static void
remove_files(void)395 remove_files (void)
396 {
397 file_remove (&igs);
398 file_remove (&ige);
399 }
400
401 static void
sigint(int sig)402 sigint (int sig)
403 {
404 exit (EXIT_FAILURE);
405 }
406
407 int
main(int argc,char ** argv)408 main (int argc, char **argv)
409 {
410 struct args opts;
411
412 #ifdef __EMX__
413 _response (&argc, &argv);
414 #else
415 #ifndef __GO32__
416 #ifndef XARGS_USELFN
417 #define XARGS_USELFN 0
418 #endif
419 xargs_modify_rule (XARGS_DOTBREAK | XARGS_USELFN, XARGS_DOTBREAK | XARGS_USELFN);
420 xargs (&argc, &argv);
421 #endif
422 #endif
423
424 program_name = argv[0];
425
426 gawk_path = getenv ("GAWK_PATH");
427 if (gawk_path == (char *) 0)
428 gawk_path = "gawk.exe";
429
430 atexit (remove_files);
431 signal (SIGINT, sigint);
432
433 tmpfile_open (&igs);
434 tmpfile_open (&ige);
435
436 args_init (&opts);
437 args_add (&opts, "gawk");
438 args_add (&opts, "-f");
439 args_add (&opts, ige.name);
440 parse_arguments (&opts, &igs, argc, argv);
441 args_add (&opts, (char *) 0);
442 filter_program (igs.name, fileno (ige.fp));
443 return run_program (&opts);
444 }
445