1 /*------------------------------------------------------------*
2  | init.c                                                     |
3  | copyright 1999,  Andrew Sumner                             |
4  | copyright 1991,  Michael D. Brennan                        |
5  |                                                            |
6  | This is a source file for the awka package, a translator   |
7  | of the AWK programming language to ANSI C.                 |
8  |                                                            |
9  | The file is a modified version of init.c from              |
10  | Mawk, an implementation of the AWK processing language,    |
11  | distributed by Michael Brennan under the GPL.              |
12  |                                                            |
13  | This program is free software; you can redistribute it     |
14  | and/or modify it under the terms of the GNU General Public |
15  | License as published by the Free Software Foundation;      |
16  | either version 2 of the License, or any later version.     |
17  |                                                            |
18  | This program is distributed in the hope that it will be    |
19  | useful, but WITHOUT ANY WARRANTY; without even the implied |
20  | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR    |
21  | PURPOSE.  See the GNU General Public License for more      |
22  | details.                                                   |
23  |                                                            |
24  | You should have received a copy of the GNU General Public  |
25  | License along with this program; if not, write to the      |
26  | Free Software Foundation, Inc., 675 Mass Ave, Cambridge,   |
27  | MA 02139, USA.                                             |
28  *-----------------------------------------------------------*/
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 /* init.c */
35 #include "awka.h"
36 #include "msg.h"
37 #include "code.h"
38 #include "memory.h"
39 #include "symtype.h"
40 #include "init.h"
41 #include "bi_vars.h"
42 #include "field.h"
43 
44 static void PROTO(process_cmdline, (int, char **)) ;
45 static void PROTO(set_ARGV, (int, char **, int)) ;
46 static void PROTO(bad_option, (char *)) ;
47 static void PROTO(no_program, (void)) ;
48 
49 extern void PROTO(print_version, (void)) ;
50 extern int PROTO(is_cmdline_assign, (char *)) ;
51 
52 extern int awka_main;
53 extern char *awka_main_func;
54 
55 char *progname, *uoutfile = NULL ;
56 extern char *int_argv;
57 short interactive_flag = 0 ;
58 char awka_exe = FALSE, awka_comp = FALSE;
59 char awka_tmp = FALSE;
60 int exe_argc = 0;
61 char **exe_argv = NULL;
62 char **incfile = NULL, **incdir = NULL, **libfile = NULL, **libdir = NULL;
63 int incf_allc = 0, incf_used = 0, incd_allc = 0, incd_used = 0, libf_allc = 0, libf_used = 0, libd_allc = 0, libd_used = 0;
64 int dump = 0, warning_msg = 0;
65 
66 #ifndef         SET_PROGNAME
67 #define         SET_PROGNAME() \
68    {char *p = strrchr(argv[0],'/') ;\
69     progname = p ? p+1 : argv[0] ; }
70 #endif
71 
72 void
initialize(argc,argv)73 initialize(argc, argv)
74 int argc ; char **argv ;
75 {
76 
77    SET_PROGNAME() ;
78 
79    bi_vars_init() ;                 /* load the builtin variables */
80    bi_funct_init() ;                 /* load the builtin functions */
81    kw_init() ;                         /* load the keywords */
82    field_init() ;
83 
84    process_cmdline(argc, argv) ;
85 
86    code_init() ;
87 }
88 
89 int dump_code_flag ;                 /* if on dump internal code */
90 short posix_space_flag ;
91 
92 #ifdef         DEBUG
93 int dump_RE ;                         /* if on dump compiled REs  */
94 #endif
95 
96 
97 static void
bad_option(s)98 bad_option(s)
99    char *s ;
100 {
101    errmsg(0, "not an option: %s", s) ; exit(2) ;
102 }
103 
104 static void
no_program()105 no_program()
106 {
107    exit(0) ;
108 }
109 
110 static void
process_cmdline(argc,argv)111 process_cmdline(argc, argv)
112    int argc ;
113    char **argv ;
114 {
115    int i, j, nextarg ;
116    char *optarg, *p ;
117    PFILE dummy ;                 /* starts linked list of filenames */
118    PFILE *tail = &dummy ;
119 
120    for (i = 1; i < argc && argv[i][0] == '-'; i = nextarg)
121    {
122       if (argv[i][1] == 0)        /* -  alone */
123       {
124          if (!pfile_name) no_program() ;
125          break ;                 /* the for loop */
126       }
127       /* safe to look at argv[i][2] */
128 
129       j = 1;
130       if (argv[i][j] == '-' && argv[i][0] == '-') j++;
131 
132       if (argv[i][j+1] == 0)
133       {
134          if (i == argc - 1 && argv[i][j] != '-' &&
135              argv[i][j] != 'u' && argv[i][j] != 'v' &&
136              argv[i][j] != 'h')
137          {
138             /* there are no more arguments - does this option need one? */
139             if (strchr("IiLlaocfxwt-", argv[i][j]))
140             {
141                errmsg(0, "option %s lacks argument", argv[i]) ;
142                exit(2) ;
143             }
144             bad_option(argv[i]) ;
145          }
146          else if (strchr("-DxtX", argv[i][j]))
147          {
148            nextarg = i + 1;
149          }
150          else
151          {
152            optarg = argv[i + 1] ;
153            nextarg = i + 2 ;
154          }
155       }
156       else if (!strcmp(argv[i], "--"))
157       {
158         if (!awka_exe)
159         {
160           fprintf(stderr,"Need a \"-x\" argument for \"--\" to make any sense.\n");
161           exit(0);
162         }
163         if (pfile_name)
164           scan_init((char *) 0);
165         else
166         {
167           if (i == 0)  no_program() ;
168           scan_init(argv[i-1]) ;
169         }
170         goto exe_opts;
171       }
172       else  /* argument glued to option mb */
173       {
174          if (argv[i][j-1] == '-')
175          {
176            optarg = &argv[i][j] ;
177            nextarg = i + 1 ;
178            if (argv[i][j] != 'h' && argv[i][j] != 'v' && argv[i][j] != 'u')
179              j++;
180          }
181          else
182          {
183            optarg = &argv[i][j] ;
184            nextarg = i + 1 ;
185          }
186       }
187 
188       switch (argv[i][j])
189       {
190          case 'v':
191             print_version() ;
192             break ;
193 
194          case 'f':
195             /* first file goes in pfile_name ; any more go
196                on a list */
197             if (!pfile_name)  pfile_name = optarg ;
198             else
199             {
200                tail = tail->link = ZMALLOC(PFILE) ;
201                tail->fname = optarg ;
202             }
203             break ;
204 
205          case 'c':
206             awka_main = 1;
207             awka_exe = awka_comp = awka_tmp = FALSE;
208             if (argv[i+1][0] == '-')
209             {
210               fprintf(stderr,"Command Line Error: Expecting function-name after -c argument.\n");
211               exit(1);
212             }
213             awka_main_func = argv[i+1];
214             break;
215 
216          case 'w':    /* warning messages */
217             if (argv[i+1][0] == '-')
218             {
219               fprintf(stderr,"Command Line Error: Expecting message flags 'abcdefg' after -w argument.\n");
220               exit(1);
221             }
222             for (p=argv[i+1]; *p; p++)
223             {
224               switch (*p) {
225                 case 'a':
226                   warning_msg |= MSG_LIST; break;
227                 case 'b':
228                   warning_msg |= MSG_SETnREF; break;
229                 case 'c':
230                   warning_msg |= MSG_REFnSET; break;
231                 case 'd':
232                   warning_msg |= MSG_GLOBinFUNC; break;
233                 case 'e':
234                   warning_msg |= MSG_GLOBoinFUNC; break;
235                 case 'f':
236                   warning_msg |= MSG_VARDECLARE; break;
237                 case 'g':
238                   warning_msg |= MSG_ASGNasTRUTH; break;
239               }
240             }
241             break;
242 
243          case 'i':  /* include file */
244             if (!incf_allc)
245             {
246               incf_allc = 8;
247               incfile = (char **) malloc( incf_allc * sizeof(char *) );
248             }
249             else if (incf_used == incf_allc)
250             {
251               incf_allc *= 2;
252               incfile = (char **) realloc( incfile, incf_allc * sizeof(char *) );
253             }
254 
255             incfile[incf_used] = (char *) malloc( strlen(argv[++i])+1 );
256             strcpy(incfile[incf_used++], argv[i]);
257             break;
258 
259          case 'I':  /* include directory */
260             if (!incd_allc)
261             {
262               incd_allc = 8;
263               incdir = (char **) malloc( incd_allc * sizeof(char *) );
264             }
265             else if (incd_used == incd_allc)
266             {
267               incd_allc *= 2;
268               incdir = (char **) realloc( incdir, incd_allc * sizeof(char *) );
269             }
270 
271             incdir[incd_used] = (char *) malloc( strlen(argv[++i])+1 );
272             strcpy(incdir[incd_used++], argv[i]);
273             break;
274 
275          case 'l':  /* library */
276             if (!libf_allc)
277             {
278               libf_allc = 8;
279               libfile = (char **) malloc( libf_allc * sizeof(char *) );
280             }
281             else if (libf_used == libf_allc)
282             {
283               libf_allc *= 2;
284               libfile = (char **) realloc( libfile, libf_allc * sizeof(char *) );
285             }
286 
287             libfile[libf_used] = (char *) malloc( strlen(argv[++i])+1 );
288             strcpy(libfile[libf_used++], argv[i]);
289             break;
290 
291          case 'L':  /* library directory */
292             if (!libd_allc)
293             {
294               libd_allc = 8;
295               libdir = (char **) malloc( libd_allc * sizeof(char *) );
296             }
297             else if (libd_used == libd_allc)
298             {
299               libd_allc *= 2;
300               libdir = (char **) realloc( libdir, libd_allc * sizeof(char *) );
301             }
302 
303             libdir[libd_used] = (char *) malloc( strlen(argv[++i])+1 );
304             strcpy(libdir[libd_used++], argv[i]);
305             break;
306 
307          case 'X':
308             awka_comp = TRUE;
309             awka_exe = FALSE;
310             awka_main = FALSE;
311             break;
312 
313          case 'x':
314             awka_exe = TRUE;
315             awka_comp = FALSE;
316             awka_main = FALSE;
317             break;
318 
319          case 't':
320             awka_tmp = TRUE;
321             break;
322 
323          case 'D':
324             dump = TRUE;
325             break;
326 
327          case 'a':
328             if (++i >= argc)
329             {
330               fprintf(stderr,"Command Line Error: Expecting filename after -a argument.\n");
331               exit(1);
332             }
333             int_argv = (char *) malloc(strlen(argv[i])+1);
334             strcpy(int_argv, argv[i]);
335             break;
336 
337          case 'o':
338             if (++i >= argc)
339             {
340               fprintf(stderr,"Command Line Error: Expecting filename after -o argument.\n");
341               exit(1);
342             }
343             uoutfile = (char *) malloc(strlen(argv[i])+1);
344             strcpy(uoutfile, argv[i]);
345             break;
346 
347          case 'u':
348          case 'h':
349             fprintf(stderr,"\nusage: awka [-c fn] [-X] [-x -t] [-w flags] [-f filename] program_string [--] [exe-args]\n");
350             fprintf(stderr,"       awka [-h] [-v]\n\n");
351             fprintf(stderr,"    -c fn  Awka will generate a 'fn' function rather\n");
352             fprintf(stderr,"           than a main function\n");
353             fprintf(stderr,"    -x     Translates, compiles then executes program\n");
354             fprintf(stderr,"    -t     If -x specified, the temporary C and executable\n");
355             fprintf(stderr,"           files will be deleted following execution.\n");
356             fprintf(stderr,"           Without this argument, -x will produce awka_out.c\n");
357 #ifdef __CYGWIN32__
358             fprintf(stderr,"           and awka_out.exe in the current directory.\n");
359 #else
360             fprintf(stderr,"           and awka.out in the current directory.\n");
361 #endif
362             fprintf(stderr,"    -X     This will create the C file awka_out.c and compile\n");
363 #ifdef __CYGWIN32__
364             fprintf(stderr,"           an executable 'awka_out.exe'.  Awka will stop after\n");
365 #else
366             fprintf(stderr,"           an executable 'awka.out'.  Awka will stop after\n");
367 #endif
368             fprintf(stderr,"           the compile is complete.\n");
369             fprintf(stderr,"    -o fil If -x used, this will create an executable called 'fil'\n");
370 #ifdef __CYGWIN32__
371             fprintf(stderr,"           instead of the default 'awka_out.exe'\n");
372 #else
373             fprintf(stderr,"           instead of the default 'awka.out'\n");
374 #endif
375             fprintf(stderr,"    -f     AWK Program file(s)\n");
376             fprintf(stderr,"    --     If -x specified, all arguments after this point\n");
377             fprintf(stderr,"           will be passed to the compiled executable.\n");
378             fprintf(stderr,"    -a str The executable command-line arguments in 'str' will\n");
379             fprintf(stderr,"           be hard-coded in the translated C output.\n");
380             fprintf(stderr,"    -w flg Prints various warnings to stderr, useful in debugging\n");
381             fprintf(stderr,"           large, complex programs.  The argument can contain the\n");
382             fprintf(stderr,"           following characters:-\n");
383             fprintf(stderr,"       'a' print a list of all global variables & their usage\n");
384             fprintf(stderr,"       'b' warn about variables set but not referenced.\n");
385             fprintf(stderr,"       'c' warn about variables referenced but not set.\n");
386             fprintf(stderr,"       'd' report global vars used in any function.\n");
387             fprintf(stderr,"       'e' report global vars used in just one function.\n");
388             fprintf(stderr,"       'f' require global variables to be listed in a VDECL comment\n");
389             fprintf(stderr,"       'g' warn about assignments used as truth expressions\n");
390             fprintf(stderr,"    -v     Prints version information\n\n");
391             exit(0);
392 
393          default:
394             bad_option(argv[i]) ;
395       }
396    }
397 
398  no_more_opts:
399 
400    tail->link = (PFILE *) 0 ;
401    pfile_list = dummy.link ;
402 
403    if (pfile_name)
404       scan_init((char *) 0) ;
405    else         /* program on command line */
406    {
407       if (i == argc)  no_program() ;
408       scan_init(argv[i]) ;
409 /* #endif  */
410    }
411    i++;
412 
413  exe_opts:
414    /* if (i < argc-1 && !strcmp(argv[i+1], "--")) */
415    if (i < argc-1 && !strcmp(argv[i], "--"))
416    {
417      /* i += 2; */
418      i++;
419      exe_argc = argc - i;
420      exe_argv = (char **) malloc(exe_argc * sizeof(char *));
421      for (j=0; i<argc; i++, j++)
422      {
423         exe_argv[j] = (char *) malloc(strlen(argv[i])+1);
424         strcpy(exe_argv[j], argv[i]);
425      }
426    }
427 }
428 
429