1 /*------------------------------------------------------------*
2  | init.c                                                     |
3  | copyright 1999,  Andrew Sumner (andrewsumner@yahoo.com)    |
4  |                                                            |
5  | This is a source file for the awka package, a translator   |
6  | of the AWK programming language to ANSI C.                 |
7  |                                                            |
8  | This library is free software; you can redistribute it     |
9  | and/or modify it under the terms of the GNU General        |
10  | Public License (GPL).                                      |
11  |                                                            |
12  | This library is distributed in the hope that it will be    |
13  | useful, but WITHOUT ANY WARRANTY; without even the implied |
14  | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR    |
15  | PURPOSE.                                                   |
16  *------------------------------------------------------------*/
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #define _INIT_C
23 
24 #define _IN_LIBRARY
25 #include "libawka.h"
26 
27 extern void _awka_arrayinitargv( char **, int, char *argv[] );
28 extern void _awka_arrayinitenviron( char **, int );
29 extern char _a_char[256], _interactive;
30 extern struct gvar_struct *_gvar;
31 struct awka_fn_struct *_awkafn;
32 extern struct a_VAR **_lvar;
33 
34 char **awka_filein = NULL;
35 int awka_filein_no = 0, _awka_fileoffset = 0;
36 char **_argv = NULL, **_int_argv = NULL;
37 int _argc, _int_argc = 0, _orig_argc = 0;
38 extern char _a_space[256];
39 char _env_used = 0;
40 char *patch_str, *date_str;
41 
42 struct ivar_idx
43 {
44   char *name;
45   int  var;
46 } ivar[] = {
47   "ARGC",        a_ARGC,
48   "ARGIND",      a_ARGIND,
49   "ARGV",        a_ARGV,
50   "CONVFMT",     a_CONVFMT,
51   "ENVIRON",     a_ENVIRON,
52   "FIELDWIDTHS", a_FIELDWIDTHS,
53   "FILENAME",    a_FILENAME,
54   "FNR",         a_FNR,
55   "FS",          a_FS,
56   "NF",          a_NF,
57   "NR",          a_NR,
58   "OFMT",        a_OFMT,
59   "OFS",         a_OFS,
60   "ORS",         a_ORS,
61   "PROCINFO",    a_PROCINFO,
62   "RLENGTH",     a_RLENGTH,
63   "RS",          a_RS,
64   "RSTART",      a_RSTART,
65   "RT",          a_RT,
66   "SAVEWIDTHS",  a_SAVEWIDTHS,
67   "SORTTYPE",    a_SORTTYPE,
68   "SUBSEP",      a_SUBSEP
69 };
70 
71 #define IVAR_MAX 20
72 
73 int
findivar(char * c)74 findivar(char *c)
75 {
76   int i = IVAR_MAX / 2, hi = IVAR_MAX, lo = 0;
77   int x;
78 
79   while (1)
80   {
81     if (!(x = strcmp(ivar[i].name, c)))
82       return i;
83     else if (x > 0)
84     {
85       if (i == lo)
86         return -1;
87       else if (i-1 == lo)
88       {
89         if (!strcmp(ivar[lo].name, c))
90           return lo;
91         return -1;
92       }
93       hi = i;
94       i = lo + ((hi - lo) / 2);
95     }
96     else
97     {
98       if (i == hi)
99         return -1;
100       else if (i+1 == hi)
101       {
102         if (!strcmp(ivar[hi].name, c))
103           return hi;
104         return -1;
105       }
106       lo = i;
107       i = lo + ((hi - lo) / 2);
108     }
109   }
110 }
111 
112 void
awka_initgvar(int idx,char * name,a_VAR * var)113 awka_initgvar(int idx, char *name, a_VAR *var)
114 {
115   int i = strlen(name);
116   malloc( &_gvar[idx].name, i+1);
117   strncpy(_gvar[idx].name, name, i-4);
118   _gvar[idx].name[i-4] = 0;
119   _gvar[idx].var = var;
120 }
121 
122 void
_awka_initstreams()123 _awka_initstreams()
124 {
125   int i;
126   _a_ioallc = 5;
127   malloc( &_a_iostream, 5 * sizeof(_a_IOSTREAM) );
128 
129   for (i=0; i<5; i++)
130   {
131     _a_iostream[i].name = _a_iostream[i].buf = _a_iostream[i].end = _a_iostream[i].current = NULL;
132     _a_iostream[i].io = _a_IO_CLOSED;
133     _a_iostream[i].fp = NULL;
134     _a_iostream[i].alloc = _a_iostream[i].interactive = 0;
135   }
136 
137   if (_interactive == TRUE)
138   {
139     setvbuf(stdin, NULL, _IONBF, 0);
140     setvbuf(stdout, NULL, _IONBF, 0);
141   }
142 
143   malloc( &_a_iostream[0].name, 12 );
144   strcpy(_a_iostream[0].name, "/dev/stdout");
145   _a_iostream[0].fp = stdout;
146   fflush(_a_iostream[0].fp);
147 
148   malloc( &_a_iostream[1].name, 12 );
149   strcpy(_a_iostream[1].name, "/dev/stderr");
150   _a_iostream[1].fp = stderr;
151   fflush(_a_iostream[1].fp);
152 
153   _a_iostream[0].buf = _a_iostream[1].buf = NULL;
154   _a_iostream[0].alloc = _a_iostream[1].alloc = 0;
155   _a_iostream[0].current = _a_iostream[0].end = NULL;
156   _a_iostream[1].current = _a_iostream[1].end = NULL;
157   _a_iostream[0].io = _a_iostream[1].io = _a_IO_WRITE;
158   _a_iostream[0].pipe = _a_iostream[1].pipe = FALSE;
159   _a_ioused = 2;
160 }
161 
162 static INLINE void
_awka_initchar()163 _awka_initchar()
164 {
165   register int i;
166 
167   memset(_a_char, ' ', 256);
168   _a_char['\n'] = '\n';
169   _a_char['\t'] = '\t';
170   for (i=32; i<127; i++)
171     _a_char[i] = (char) i;
172 
173   memset(_a_space, 0, 256);
174   _a_space['\n'] = 1;
175   _a_space['\t'] = 1;
176   _a_space['\f'] = 1;
177   _a_space['\r'] = 1;
178   _a_space['\013'] = 1;
179   _a_space[' '] = 1;
180 }
181 
182 #ifdef PROCINFO_READY_TO_USE
183 void
_awka_init_procinfo(a_VAR * procinfo)184 _awka_init_procinfo( a_VAR *procinfo )
185 {
186   a_VAR *ret, *tmp = NULL;
187   awka_varinit(tmp);
188 
189   /* egid */
190   /* euid */
191 
192   /* FS */
193   awka_strcpy(tmp, "FS");
194   ret = awka_arraysearch1( procinfo, tmp, a_ARR_CREATE, 0 );
195   awka_strcpy(ret, "FS");
196   ret->type = a_VARUNK;
197 
198   /* gid */
199   /* pgrpid */
200   /* pid */
201   /* ppid */
202   /* uid */
203 }
204 #endif
205 
206 void
_awka_init_ivar(int i)207 _awka_init_ivar(int i)
208 {
209   if (a_bivar[i]) return;
210 
211   malloc( &a_bivar[i], sizeof(a_VAR) );
212   a_bivar[i]->slen = 0;
213   a_bivar[i]->allc = 0;
214   a_bivar[i]->dval = 0;
215   a_bivar[i]->ptr = NULL;
216   a_bivar[i]->type2 = 0;
217   a_bivar[i]->temp = 0;
218   a_bivar[i]->type = a_VARNUL;
219 
220   switch (i) {
221     case a_ARGV:
222       a_bivar[i]->type = a_VARARR;
223       awka_arraycreate(a_bivar[i], a_ARR_TYPE_SPLIT);
224       break;
225 
226     case a_CONVFMT:
227     case a_OFMT:
228       a_bivar[i]->type = a_VARSTR;
229       a_bivar[i]->allc = malloc( &a_bivar[i]->ptr, 5 );
230       a_bivar[i]->slen = 4;
231       strcpy(a_bivar[i]->ptr, "%.6g");
232       break;
233 
234     case a_ENVIRON:
235       a_bivar[i]->type = a_VARARR;
236       _awka_arrayinitenviron(&(a_bivar[i]->ptr), _env_used);
237       break;
238 
239     case a_FILENAME:
240     case a_DOL0:
241       a_bivar[i]->type = a_VARUNK;
242       a_bivar[i]->allc = malloc( &a_bivar[i]->ptr, 1 );
243       a_bivar[i]->ptr[0] = '\0';
244       a_bivar[i]->slen = 0;
245       break;
246 
247     case a_FS:
248     case a_OFS:
249       a_bivar[i]->type = a_VARSTR;
250       a_bivar[i]->allc = malloc( &a_bivar[i]->ptr, 5 );
251       a_bivar[i]->ptr[0] = ' ';
252       a_bivar[i]->ptr[1] = '\0';
253       a_bivar[i]->slen = 1;
254       break;
255 
256     case a_ARGC:
257     case a_ARGIND:
258     case a_NF:
259     case a_FNR:
260     case a_NR:
261     case a_RLENGTH:
262     case a_RSTART:
263       a_bivar[i]->type = a_VARDBL;
264       break;
265 
266     case a_FIELDWIDTHS:
267     case a_SAVEWIDTHS:
268       a_bivar[i]->type = a_VARSTR;
269       a_bivar[i]->allc = malloc( &a_bivar[i]->ptr, 1 );
270       a_bivar[i]->ptr[0] = '\0';
271       break;
272 
273     case a_RT:
274     case a_RS:
275     case a_ORS:
276       a_bivar[i]->type = a_VARSTR;
277       a_bivar[i]->allc = malloc( &a_bivar[i]->ptr, 5 );
278       a_bivar[i]->ptr[0] = '\n';
279       a_bivar[i]->ptr[1] = '\0';
280       a_bivar[i]->slen = 1;
281       break;
282 
283     case a_SUBSEP:
284       a_bivar[i]->type = a_VARSTR;
285       a_bivar[i]->allc = malloc( &a_bivar[i]->ptr, 5 );
286       a_bivar[i]->ptr[0] = '\034';
287       a_bivar[i]->ptr[1] = '\0';
288       a_bivar[i]->slen = 1;
289       break;
290 
291     case a_DOLN:
292       a_bivar[i]->type = a_VARARR;
293       awka_arraycreate(a_bivar[i], a_ARR_TYPE_SPLIT);
294       break;
295 
296     case a_PROCINFO:
297       a_bivar[i]->type = a_VARARR;
298       awka_arraycreate(a_bivar[i], a_ARR_TYPE_HSH);
299       /* _awka_init_procinfo( a_bivar[i] ); */
300   }
301 }
302 
303 void
_awka_kill_ivar()304 _awka_kill_ivar()
305 {
306   int i;
307 
308   for (i=0; i<a_BIVARS; i++)
309   {
310     if (!(a_bivar[i])) continue;
311 
312     awka_killvar(a_bivar[i]);
313     free(a_bivar[i]);
314     a_bivar[i] = NULL;
315   }
316 
317   if (awka_filein)
318   {
319     for (i=0; i<awka_filein_no; i++)
320       if (awka_filein[i])
321         free(awka_filein[i]);
322     free(awka_filein);
323   }
324   awka_filein = NULL;
325   awka_filein_no = 0;
326 
327   if (_orig_argc)
328   {
329     for (i=0; i<_orig_argc; i++)
330       if (_argv[i])
331         free(_argv[i]);
332     free(_argv);
333   }
334   _argv = NULL;
335   _argc = 0;
336 }
337 
338 void
_awka_kill_gvar()339 _awka_kill_gvar()
340 {
341   struct gvar_struct *gvar = _gvar;
342 
343   if (_gvar)
344   {
345     while (gvar->name)
346     {
347       free(gvar->name);
348       awka_killvar(gvar->var);
349       gvar++;
350     }
351     free(_gvar);
352     _gvar = NULL;
353   }
354 }
355 
356 void
_awka_kill_fn()357 _awka_kill_fn()
358 {
359   if (_awkafn)
360     free(_awkafn);
361   _awkafn = NULL;
362 }
363 
364 void
awka_init(int argc,char * argv[],char * patch_string,char * date_string)365 awka_init(int argc, char *argv[], char *patch_string, char *date_string)
366 {
367   int i=0, j;
368   extern void _awka_gc_init();
369 
370   patch_str = patch_string;
371   date_str = date_string;
372 
373   _argc = argc + _int_argc;
374   _orig_argc = argc;
375   malloc( &_argv, argc * sizeof(char *) );
376 
377   if (argc)
378   {
379     i++;
380     malloc( &_argv[0], strlen(argv[0])+1 );
381     strcpy(_argv[0], argv[0]);
382   }
383 
384   for (j=0; j<_int_argc; j++)
385   {
386     malloc( &_argv[j+i], strlen(_int_argv[j])+1 );
387     strcpy(_argv[j+i], _int_argv[j]);
388   }
389 
390   for (; i<argc; i++)
391   {
392     malloc( &_argv[i+j], strlen(argv[i])+1 );
393     strcpy(_argv[i+j], argv[i]);
394   }
395 
396   _awka_gc_init();
397 
398   for (i=0; i<a_BIVARS; i++) a_bivar[i] = NULL;
399   _awka_init_ivar(a_ARGC);
400   _awka_init_ivar(a_ARGV);
401 
402   awka_parsecmdline(1);
403 
404   /* set up internal variables */
405   for (i=0; i<a_BIVARS; i++)
406     if (i != a_ARGC && i != a_ARGV)
407       _awka_init_ivar(i);
408 
409   /* set up output streams */
410   _awka_initstreams();
411   _awka_initchar();
412 
413 #ifndef a_DUMP_ON_ERROR
414   /* handle signals */
415   awka_init_parachute();
416 #endif
417 }
418 
419 void
_awka_printhelp()420 _awka_printhelp()
421 {
422   fprintf(stderr,"\nThis executable was generated from an AWK program using Awka.\n\n");
423   fprintf(stderr,"Command-line Options:\n\n");
424   fprintf(stderr,"  -We           All following arguments will be added to the ARGV array.\n");
425   fprintf(stderr,"  -Wi           Interactive mode.  Input from stdin will be unbuffered.\n");
426   fprintf(stderr,"  -v var=value  Sets variable 'var' to 'value'.  'var' must be a defined\n");
427   fprintf(stderr,"                variable else an error message will be printed.\n");
428   fprintf(stderr,"  -Fvalue       Sets FS to value.\n");
429   fprintf(stderr,"  -showarg      shows compiled-in arguments.\n");
430   fprintf(stderr,"  -awkaversion  prints version of awka that generated this executable\n");
431   fprintf(stderr,"  -help         prints this message.\n\n");
432   exit(1);
433 }
434 
435 #define _setp \
436   if (_argv[i][2] == '\0')  \
437   { \
438     i++; \
439     if (i >= _argc)  \
440        awka_error("command line parse: expecting argument after %s.\n",_argv[i-1]); \
441     p = _argv[i]; \
442   } \
443   else \
444     p = _argv[i]+2
445 
446 void
awka_parsecmdline(int first)447 awka_parsecmdline(int first)
448 {
449   int i = 1, j, argc, options_done = FALSE;
450   char c, *p, *p1, *p2, tmp[128];
451   a_VAR *var;
452 
453   awka_getd(a_bivar[a_ARGC]);
454 
455   if (!first)
456   {
457     for (i=1; i<_argc; i++)
458       if (_argv[i])
459         free(_argv[i]);
460 
461     argc = _argc;
462     _argc = (int) awka_getd(a_bivar[a_ARGC]);
463 
464     if (argc != _argc)
465       realloc( &_argv, _argc * sizeof(char *));
466 
467     for (i=0; i<_argc; i++)
468     {
469       var = awka_arraysearch1(a_bivar[a_ARGV], awka_tmp_dbl2var(i), a_ARR_QUERY, 0);
470       if (var->slen != -1)
471       {
472         var = awka_arraysearch1(a_bivar[a_ARGV], awka_tmp_dbl2var(i), a_ARR_CREATE, 0);
473         p1 = awka_gets1(var);
474         malloc( &_argv[i], var->slen+1);
475         strcpy(_argv[i], p1);
476       }
477       else
478       {
479         _argv[i] = NULL;
480       }
481     }
482 
483     if (awka_filein_no)
484     {
485       for (i=0; i<awka_filein_no; i++)
486         free(awka_filein[i]);
487       free(awka_filein);
488       awka_filein_no = 0;
489     }
490 
491     a_bivar[a_ARGC]->dval = 0;
492   }
493   else
494   {
495     a_bivar[a_ARGC]->dval = 0;
496     awka_strcpy(awka_arraysearch1(a_bivar[a_ARGV], a_bivar[a_ARGC], a_ARR_CREATE, 1), _argv[0]);
497   }
498 
499   i = 1;
500   while (i < _argc)
501   {
502     if (!_argv[i]) { i++; continue; }
503     c = _argv[i][0];
504 
505     if (options_done == FALSE && c == '-' && _argv[i][1] != '\0')
506     {
507       switch (_argv[i][1])
508       {
509         case 'F':
510           _setp;
511           if (!first) break;
512           if (!a_bivar[a_FS])
513             _awka_init_ivar(a_FS);
514           awka_strcpy(a_bivar[a_FS], p);
515           break;
516 
517         case '-':
518           switch (_argv[i][2])
519           {
520             case 'h':
521             case 'u':
522               _awka_printhelp();
523             default:
524               awka_error("command line parse: unknown option %s\n",_argv[i]);
525 
526             case 'a':
527               break;
528           }
529         case 'a':
530           fprintf(stderr,"\n\"%s\" was generated by Awka (http://awka.sourceforge.net)\n",_argv[0]);
531           fprintf(stderr,"   - translator version %s, %s\n",patch_str,date_str);
532           fprintf(stderr,"   - library version %s, %s\n\n",AWKAVERSION,DATE_STRING);
533           exit(0);
534 
535         case 'v':
536           _setp;
537           if (!first) break;
538           strcpy(tmp, p);
539           p1 = p2 = tmp;
540           while (*p2 && *p2 != '=') p2++;
541           if (*p2 == '=')
542             *p2++ = '\0';
543           else
544             awka_error("command line parse: expected 'var=value' after -v.\n");
545           if (p1 == p2-1)
546             awka_error("command line parse: null value for 'var' in 'var=value' after -v.\n");
547 
548           j = 0;
549           while (_gvar[j].name)
550           {
551             if (!strcmp(_gvar[j].name, tmp))
552               break;
553             j++;
554           }
555           if (!_gvar[j].name)
556           {
557             if ((j = findivar(tmp)) == -1)
558               awka_error("command line parse: variable '%s' not defined.\n",tmp);
559             if (!a_bivar[ivar[j].var])
560               _awka_init_ivar(ivar[j].var);
561             if (a_bivar[ivar[j].var]->type == a_VARARR)
562               awka_error("command line parse: array variable '%s' used as scalar.\n",tmp);
563             awka_strcpy(a_bivar[ivar[j].var], p2);
564             a_bivar[ivar[j].var]->type = a_VARUNK;
565             break;
566           }
567           else if (_gvar[j].var->type == a_VARARR)
568             awka_error("command line parse: array variable '%s' used as scalar.\n",tmp);
569           awka_strcpy(_gvar[j].var, p2);
570           _gvar[j].var->type = a_VARUNK;
571           break;
572 
573         case 'W':
574           _setp;
575           switch (*p)
576           {
577             case 'e':
578               options_done = TRUE;
579               break;
580 
581             case 'i':
582               _interactive = TRUE;
583               break;
584 
585             default:
586               awka_error("command line parse: unknown option -W%s\n",p);
587           }
588           break;
589 
590         case 's':
591           if (_int_argc == 0)
592             fprintf(stderr,"No compiled-in arguments.\n");
593           else
594           {
595             fprintf(stderr,"The following arguments were compiled into this executable:-\n  ");
596             for (j=0; j<_int_argc; j++)
597               fprintf(stderr," %s", _int_argv[j]);
598             fprintf(stderr,"\n");
599           }
600           exit(1);
601 
602         case 'h':
603           _awka_printhelp();
604 
605         default:
606           awka_error("command-line parse error: unknown argument '%s' - type \"-help\" for more info.\n",_argv[i]);
607       }
608     }
609     else if (_argv[i][0] != '\0')
610     {
611       a_bivar[a_ARGC]->dval++;
612       var = awka_arraysearch1(a_bivar[a_ARGV], a_bivar[a_ARGC], a_ARR_CREATE, 0);
613       awka_strcpy(var, _argv[i]);
614       var->type = a_VARUNK;
615       if (!awka_filein_no)
616         malloc( &awka_filein, (_argc + i) * sizeof(char *) );
617 
618       malloc( &awka_filein[awka_filein_no], strlen(_argv[i])+1 );
619       strcpy(awka_filein[awka_filein_no++], _argv[i]);
620       if (!_awka_fileoffset) _awka_fileoffset = i;
621     }
622 
623     i++;
624   }
625   a_bivar[a_ARGC]->dval++;
626 
627   if (!awka_filein_no)
628   {
629     malloc( &awka_filein, sizeof(char *) );
630     malloc( &awka_filein[0], 3 );
631     strcpy(awka_filein[0], "-");
632     awka_filein_no = 1;
633     _awka_fileoffset = -1;
634   }
635 }
636 
637