b185408a9905b71fb3690daf518255e654b714c9
[openwrt-10.03/.git] / package / busybox / patches / 510-awk_include.patch
1 --- a/editors/awk.c
2 +++ b/editors/awk.c
3 @@ -53,9 +53,14 @@ typedef struct chain_s {
4  } chain;
5  
6  /* Function */
7 +typedef var *(*awk_cfunc)(var *res, var *args, int nargs);
8  typedef struct func_s {
9         unsigned nargs;
10 +       enum { AWKFUNC, CFUNC } type;
11 +       union {
12 +               awk_cfunc cfunc;
13         struct chain_s body;
14 +       } x;
15  } func;
16  
17  /* I/O stream */
18 @@ -1400,7 +1405,8 @@ static void parse_program(char *p)
19                         next_token(TC_FUNCTION);
20                         g_pos++;
21                         f = newfunc(t_string);
22 -                       f->body.first = NULL;
23 +                       f->type = AWKFUNC;
24 +                       f->x.body.first = NULL;
25                         f->nargs = 0;
26                         while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
27                                 v = findvar(ahash, t_string);
28 @@ -1409,7 +1415,7 @@ static void parse_program(char *p)
29                                 if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
30                                         break;
31                         }
32 -                       seq = &(f->body);
33 +                       seq = &(f->x.body);
34                         chain_group();
35                         clear_array(ahash);
36  
37 @@ -2374,7 +2380,8 @@ static var *evaluate(node *op, var *res)
38                         break;
39  
40                 case XC( OC_FUNC ):
41 -                       if (!op->r.f->body.first)
42 +                       if ((op->r.f->type == AWKFUNC) &&
43 +                               !op->r.f->x.body.first)
44                                 syntax_error(EMSG_UNDEF_FUNC);
45  
46                         X.v = R.v = nvalloc(op->r.f->nargs+1);
47 @@ -2391,7 +2398,10 @@ static var *evaluate(node *op, var *res)
48                         fnargs = X.v;
49  
50                         L.s = g_progname;
51 -                       res = evaluate(op->r.f->body.first, res);
52 +                       if (op->r.f->type == AWKFUNC)
53 +                               res = evaluate(op->r.f->x.body.first, res);
54 +                       else if (op->r.f->type == CFUNC)
55 +                               res = op->r.f->x.cfunc(res, fnargs, op->r.f->nargs);
56                         g_progname = L.s;
57  
58                         nvfree(fnargs);
59 @@ -2754,6 +2764,143 @@ static rstream *next_input_file(void)
60  #undef files_happen
61  }
62  
63 +/* read the contents of an entire file */
64 +static char *get_file(const char *fname)
65 +{
66 +       FILE *F;
67 +       char *s = NULL;
68 +       int i, j, flen;
69 +
70 +       F = fopen(fname, "r");
71 +       if (!F) {
72 +               return NULL;
73 +       }
74 +
75 +       if (fseek(F, 0, SEEK_END) == 0) {
76 +               flen = ftell(F);
77 +               s = (char *)xmalloc(flen+4);
78 +               fseek(F, 0, SEEK_SET);
79 +               i = 1 + fread(s+1, 1, flen, F);
80 +       } else {
81 +               for (i=j=1; j>0; i+=j) {
82 +                       s = (char *)xrealloc(s, i+4096);
83 +                       j = fread(s+i, 1, 4094, F);
84 +               }
85 +       }
86 +
87 +       s[i] = '\0';
88 +       fclose(F);
89 +       return s;
90 +}
91 +
92 +
93 +/* parse_include():
94 + *
95 + * taken from parse_program from awk.c
96 + * END{} is not parsed here, and BEGIN{} is executed immediately
97 + */
98 +static void parse_include(char *p)
99 +{
100 +       uint32_t tclass;
101 +       chain *initseq = NULL;
102 +       chain tmp;
103 +       func *f;
104 +       var *v, *tv;
105 +
106 +       tv = nvalloc(1);
107 +       memset(&tmp, 0, sizeof(tmp));
108 +       g_pos = p;
109 +       t_lineno = 1;
110 +       while ((tclass = next_token(TC_EOF | TC_OPSEQ |
111 +                               TC_OPTERM | TC_BEGIN | TC_FUNCDECL)) != TC_EOF) {
112 +               if (tclass & TC_OPTERM)
113 +                       continue;
114 +
115 +               seq = &tmp;
116 +               if (tclass & TC_BEGIN) {
117 +                       initseq = xzalloc(sizeof(chain));
118 +                       seq = initseq;
119 +                       chain_group();
120 +               } else if (tclass & TC_FUNCDECL) {
121 +                       next_token(TC_FUNCTION);
122 +                       g_pos++;
123 +                       f = newfunc(t_string);
124 +                       f->type = AWKFUNC;
125 +                       f->x.body.first = NULL;
126 +                       f->nargs = 0;
127 +                       while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
128 +                               v = findvar(ahash, t_string);
129 +                               v->x.aidx = (f->nargs)++;
130 +
131 +                               if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
132 +                                       break;
133 +                       }
134 +                       seq = &(f->x.body);
135 +                       chain_group();
136 +                       clear_array(ahash);
137 +               }
138 +       }
139 +       if (initseq && initseq->first)
140 +               tv = evaluate(initseq->first, tv);
141 +       nvfree(tv);
142 +}
143 +
144 +
145 +/* include an awk file and run its BEGIN{} section */
146 +static xhash *includes = NULL;
147 +static void include_file(const char *filename)
148 +{
149 +       char *s;
150 +       var *v;
151 +       int oldlnr = g_lineno;
152 +       const char *oldprg = g_progname;
153 +
154 +       if (!includes)
155 +               includes = hash_init();
156 +
157 +       /* find out if the file has been included already */
158 +       v = findvar(includes, filename);
159 +       if (istrue(v))
160 +               return;
161 +       setvar_s(v, "1");
162 +
163 +       /* read include file */
164 +       s = get_file(filename);
165 +       if (!s) {
166 +               fprintf(stderr, "Could not open file.\n");
167 +               return;
168 +       }
169 +       g_lineno = 1;
170 +       g_progname = xstrdup(filename);
171 +       parse_include(s+1);
172 +       free(s);
173 +       g_lineno = oldlnr;
174 +       g_progname = oldprg;
175 +}
176 +
177 +static var *include(var *res, var *args, int nargs)
178 +{
179 +       const char *s;
180 +
181 +       nargs = nargs; /* shut up, gcc */
182 +       s = getvar_s(args);
183 +       if (s && (strlen(s) > 0))
184 +               include_file(s);
185 +
186 +       return res;
187 +}
188 +
189 +/* registers a global c function for the awk interpreter */
190 +static void register_cfunc(const char *name, awk_cfunc cfunc, int nargs)
191 +{
192 +       func *f;
193 +
194 +       f = newfunc(name);
195 +       f->type = CFUNC;
196 +       f->x.cfunc = cfunc;
197 +       f->nargs = nargs;
198 +}
199 +
200  int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
201  int awk_main(int argc, char **argv)
202  {
203 @@ -2819,6 +2966,9 @@ int awk_main(int argc, char **argv)
204                         *s1 = '=';
205                 }
206         }
207 +
208 +       register_cfunc("include", include, 1);
209 +
210         opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
211         opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
212         argv += optind;