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