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 | @@ -1420,7 +1425,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 | @@ -1429,7 +1435,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 | @@ -2410,7 +2416,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 | @@ -2427,7 +2434,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 | @@ -2790,6 +2800,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 | @@ -2855,6 +3002,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; |
213 | |