|
1 // parse.c - parser |
|
2 // |
|
3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved. |
|
4 // |
|
5 /* |
|
6 * This file is part of zsh, the Z shell. |
|
7 * |
|
8 * Copyright (c) 1992-1997 Paul Falstad |
|
9 * All rights reserved. |
|
10 * |
|
11 * Permission is hereby granted, without written agreement and without |
|
12 * license or royalty fees, to use, copy, modify, and distribute this |
|
13 * software and to distribute modified versions of this software for any |
|
14 * purpose, provided that the above copyright notice and the following |
|
15 * two paragraphs appear in all copies of this software. |
|
16 * |
|
17 * In no event shall Paul Falstad or the Zsh Development Group be liable |
|
18 * to any party for direct, indirect, special, incidental, or consequential |
|
19 * damages arising out of the use of this software and its documentation, |
|
20 * even if Paul Falstad and the Zsh Development Group have been advised of |
|
21 * the possibility of such damage. |
|
22 * |
|
23 * Paul Falstad and the Zsh Development Group specifically disclaim any |
|
24 * warranties, including, but not limited to, the implied warranties of |
|
25 * merchantability and fitness for a particular purpose. The software |
|
26 * provided hereunder is on an "as is" basis, and Paul Falstad and the |
|
27 * Zsh Development Group have no obligation to provide maintenance, |
|
28 * support, updates, enhancements, or modifications. |
|
29 * |
|
30 */ |
|
31 |
|
32 #include "zsh.mdh" |
|
33 #include "parse.pro" |
|
34 |
|
35 #ifdef __SYMBIAN32__ |
|
36 #ifdef __WINSCW__ |
|
37 #pragma warn_possunwant off |
|
38 #endif//__WINSCW__ |
|
39 #endif//__SYMBIAN32__ |
|
40 |
|
41 /* != 0 if we are about to read a command word */ |
|
42 |
|
43 /**/ |
|
44 mod_export int incmdpos; |
|
45 |
|
46 /**/ |
|
47 int aliasspaceflag; |
|
48 |
|
49 /* != 0 if we are in the middle of a [[ ... ]] */ |
|
50 |
|
51 /**/ |
|
52 mod_export int incond; |
|
53 |
|
54 /* != 0 if we are after a redirection (for ctxtlex only) */ |
|
55 |
|
56 /**/ |
|
57 mod_export int inredir; |
|
58 |
|
59 /* != 0 if we are about to read a case pattern */ |
|
60 |
|
61 /**/ |
|
62 int incasepat; |
|
63 |
|
64 /* != 0 if we just read a newline */ |
|
65 |
|
66 /**/ |
|
67 int isnewlin; |
|
68 |
|
69 /* != 0 if we are after a for keyword */ |
|
70 |
|
71 /**/ |
|
72 int infor; |
|
73 |
|
74 /* list of here-documents */ |
|
75 |
|
76 /**/ |
|
77 struct heredocs *hdocs; |
|
78 |
|
79 |
|
80 #define YYERROR(O) { tok = LEXERR; ecused = (O); return 0; } |
|
81 #define YYERRORV(O) { tok = LEXERR; ecused = (O); return; } |
|
82 #define COND_ERROR(X,Y) do { \ |
|
83 zwarn(X,Y,0); \ |
|
84 herrflush(); \ |
|
85 if (noerrs != 2) \ |
|
86 errflag = 1; \ |
|
87 YYERROR(ecused) \ |
|
88 } while(0) |
|
89 |
|
90 |
|
91 /* |
|
92 * Word code. |
|
93 * |
|
94 * The parser now produces word code, reducing memory consumption compared |
|
95 * to the nested structs we had before. |
|
96 * |
|
97 * Word code layout: |
|
98 * |
|
99 * WC_END |
|
100 * - end of program code |
|
101 * |
|
102 * WC_LIST |
|
103 * - data contains type (sync, ...) |
|
104 * - followed by code for this list |
|
105 * - if not (type & Z_END), followed by next WC_LIST |
|
106 * |
|
107 * WC_SUBLIST |
|
108 * - data contains type (&&, ||, END) and flags (coprog, not) |
|
109 * - followed by code for sublist |
|
110 * - if not (type == END), followed by next WC_SUBLIST |
|
111 * |
|
112 * WC_PIPE |
|
113 * - data contains type (end, mid) and LINENO |
|
114 * - if not (type == END), followed by offset to next WC_PIPE |
|
115 * - followed by command |
|
116 * - if not (type == END), followed by next WC_PIPE |
|
117 * |
|
118 * WC_REDIR |
|
119 * - must precede command-code (or WC_ASSIGN) |
|
120 * - data contains type (<, >, ...) |
|
121 * - followed by fd1 and name from struct redir |
|
122 * |
|
123 * WC_ASSIGN |
|
124 * - data contains type (scalar, array) and number of array-elements |
|
125 * - followed by name and value |
|
126 * |
|
127 * WC_SIMPLE |
|
128 * - data contains the number of arguments (plus command) |
|
129 * - followed by strings |
|
130 * |
|
131 * WC_SUBSH |
|
132 * - data unused |
|
133 * - followed by list |
|
134 * |
|
135 * WC_CURSH |
|
136 * - data unused |
|
137 * - followed by list |
|
138 * |
|
139 * WC_TIMED |
|
140 * - data contains type (followed by pipe or not) |
|
141 * - if (type == PIPE), followed by pipe |
|
142 * |
|
143 * WC_FUNCDEF |
|
144 * - data contains offset to after body |
|
145 * - followed by number of names |
|
146 * - followed by names |
|
147 * - followed by offset to first string |
|
148 * - followed by length of string table |
|
149 * - followed by number of patterns for body |
|
150 * - followed by codes for body |
|
151 * - followed by strings for body |
|
152 * |
|
153 * WC_FOR |
|
154 * - data contains type (list, ...) and offset to after body |
|
155 * - if (type == COND), followed by init, cond, advance expressions |
|
156 * - else if (type == PPARAM), followed by param name |
|
157 * - else if (type == LIST), followed by param name, num strings, strings |
|
158 * - followed by body |
|
159 * |
|
160 * WC_SELECT |
|
161 * - data contains type (list, ...) and offset to after body |
|
162 * - if (type == PPARAM), followed by param name |
|
163 * - else if (type == LIST), followed by param name, num strings, strings |
|
164 * - followed by body |
|
165 * |
|
166 * WC_WHILE |
|
167 * - data contains type (while, until) and offset to after body |
|
168 * - followed by condition |
|
169 * - followed by body |
|
170 * |
|
171 * WC_REPEAT |
|
172 * - data contains offset to after body |
|
173 * - followed by number-string |
|
174 * - followed by body |
|
175 * |
|
176 * WC_CASE |
|
177 * - first CASE is always of type HEAD, data contains offset to esac |
|
178 * - after that CASEs of type OR (;;) and AND (;&), data is offset to |
|
179 * next case |
|
180 * - each OR/AND case is followed by pattern, pattern-number, list |
|
181 * |
|
182 * WC_IF |
|
183 * - first IF is of type HEAD, data contains offset to fi |
|
184 * - after that IFs of type IF, ELIF, ELSE, data is offset to next |
|
185 * - each non-HEAD is followed by condition (only IF, ELIF) and body |
|
186 * |
|
187 * WC_COND |
|
188 * - data contains type |
|
189 * - if (type == AND/OR), data contains offset to after this one, |
|
190 * followed by two CONDs |
|
191 * - else if (type == NOT), followed by COND |
|
192 * - else if (type == MOD), followed by name and strings |
|
193 * - else if (type == MODI), followed by name, left, right |
|
194 * - else if (type == STR[N]EQ), followed by left, right, pattern-number |
|
195 * - else if (has two args) followed by left, right |
|
196 * - else followed by string |
|
197 * |
|
198 * WC_ARITH |
|
199 * - followed by string (there's only one) |
|
200 * |
|
201 * WC_AUTOFN |
|
202 * - only used by the autoload builtin |
|
203 * |
|
204 * Lists and sublists may also be simplified, indicated by the presence |
|
205 * of the Z_SIMPLE or WC_SUBLIST_SIMPLE flags. In this case they are only |
|
206 * followed by a slot containing the line number, not by a WC_SUBLIST or |
|
207 * WC_PIPE, respectively. The real advantage of simplified lists and |
|
208 * sublists is that they can be executed faster, see exec.c. In the |
|
209 * parser, the test if a list can be simplified is done quite simply |
|
210 * by passing a int* around which gets set to non-zero if the thing |
|
211 * just parsed is `complex', i.e. may need to be run by forking or |
|
212 * some such. |
|
213 * |
|
214 * In each of the above, strings are encoded as one word code. For empty |
|
215 * strings this is the bit pattern 11x, the lowest bit is non-zero if the |
|
216 * string contains tokens and zero otherwise (this is true for the other |
|
217 * ways to encode strings, too). For short strings (one to three |
|
218 * characters), this is the marker 01x with the 24 bits above that |
|
219 * containing the characters. Longer strings are encoded as the offset |
|
220 * into the strs character array stored in the eprog struct shifted by |
|
221 * two and ored with the bit pattern 0x. |
|
222 * The ecstrcode() function that adds the code for a string uses a simple |
|
223 * binary tree of strings already added so that long strings are encoded |
|
224 * only once. |
|
225 * |
|
226 * Note also that in the eprog struct the pattern, code, and string |
|
227 * arrays all point to the same memory block. |
|
228 * |
|
229 * |
|
230 * To make things even faster in future versions, we could not only |
|
231 * test if the strings contain tokens, but instead what kind of |
|
232 * expansions need to be done on strings. In the execution code we |
|
233 * could then use these flags for a specialized version of prefork() |
|
234 * to avoid a lot of string parsing and some more string duplication. |
|
235 */ |
|
236 |
|
237 /**/ |
|
238 int eclen, ecused, ecnpats; |
|
239 /**/ |
|
240 Wordcode ecbuf; |
|
241 /**/ |
|
242 Eccstr ecstrs; |
|
243 /**/ |
|
244 int ecsoffs, ecssub, ecnfunc; |
|
245 |
|
246 #define EC_INIT_SIZE 256 |
|
247 #define EC_DOUBLE_THRESHOLD 32768 |
|
248 #define EC_INCREMENT 1024 |
|
249 |
|
250 |
|
251 /* Adjust pointers in here-doc structs. */ |
|
252 |
|
253 static void |
|
254 ecadjusthere(int p, int d) |
|
255 { |
|
256 struct heredocs *h; |
|
257 |
|
258 for (h = hdocs; h; h = h->next) |
|
259 if (h->pc >= p) |
|
260 h->pc += d; |
|
261 } |
|
262 |
|
263 /* Insert n free code-slots at position p. */ |
|
264 |
|
265 static void |
|
266 ecispace(int p, int n) |
|
267 { |
|
268 int m; |
|
269 |
|
270 if ((eclen - ecused) < n) { |
|
271 int a = (eclen < EC_DOUBLE_THRESHOLD ? eclen : EC_INCREMENT); |
|
272 |
|
273 if (n > a) a = n; |
|
274 |
|
275 ecbuf = (Wordcode) zrealloc((char *) ecbuf, (eclen + a) * sizeof(wordcode)); |
|
276 eclen += a; |
|
277 } |
|
278 if ((m = ecused - p) > 0) |
|
279 memmove(ecbuf + p + n, ecbuf + p, m * sizeof(wordcode)); |
|
280 ecused += n; |
|
281 ecadjusthere(p, n); |
|
282 } |
|
283 |
|
284 /* Add one wordcode. */ |
|
285 |
|
286 static int |
|
287 ecadd(wordcode c) |
|
288 { |
|
289 if ((eclen - ecused) < 1) { |
|
290 int a = (eclen < EC_DOUBLE_THRESHOLD ? eclen : EC_INCREMENT); |
|
291 |
|
292 ecbuf = (Wordcode) zrealloc((char *) ecbuf, (eclen + a) * sizeof(wordcode)); |
|
293 eclen += a; |
|
294 } |
|
295 ecbuf[ecused] = c; |
|
296 ecused++; |
|
297 |
|
298 return ecused - 1; |
|
299 } |
|
300 |
|
301 /* Delete a wordcode. */ |
|
302 |
|
303 static void |
|
304 ecdel(int p) |
|
305 { |
|
306 int n = ecused - p - 1; |
|
307 |
|
308 if (n > 0) |
|
309 memmove(ecbuf + p, ecbuf + p + 1, n * sizeof(wordcode)); |
|
310 ecused--; |
|
311 ecadjusthere(p, -1); |
|
312 } |
|
313 |
|
314 /* Build the wordcode for a string. */ |
|
315 |
|
316 static wordcode |
|
317 ecstrcode(char *s) |
|
318 { |
|
319 int l, t = has_token(s); |
|
320 |
|
321 if ((l = strlen(s) + 1) && l <= 4) { |
|
322 wordcode c = (t ? 3 : 2); |
|
323 switch (l) { |
|
324 case 4: c |= ((wordcode) STOUC(s[2])) << 19; |
|
325 case 3: c |= ((wordcode) STOUC(s[1])) << 11; |
|
326 case 2: c |= ((wordcode) STOUC(s[0])) << 3; break; |
|
327 case 1: c = (t ? 7 : 6); break; |
|
328 } |
|
329 return c; |
|
330 } else { |
|
331 Eccstr p, *pp; |
|
332 int cmp; |
|
333 |
|
334 for (pp = &ecstrs; (p = *pp); ) { |
|
335 if (!(cmp = p->nfunc - ecnfunc) && !(cmp = strcmp(p->str, s))) |
|
336 return p->offs; |
|
337 pp = (cmp < 0 ? &(p->left) : &(p->right)); |
|
338 } |
|
339 p = *pp = (Eccstr) zhalloc(sizeof(*p)); |
|
340 p->left = p->right = 0; |
|
341 p->offs = ((ecsoffs - ecssub) << 2) | (t ? 1 : 0); |
|
342 p->aoffs = ecsoffs; |
|
343 p->str = s; |
|
344 p->nfunc = ecnfunc; |
|
345 ecsoffs += l; |
|
346 |
|
347 return p->offs; |
|
348 } |
|
349 } |
|
350 |
|
351 #define ecstr(S) ecadd(ecstrcode(S)) |
|
352 |
|
353 #define par_save_list(C) \ |
|
354 do { \ |
|
355 int eu = ecused; \ |
|
356 par_list(C); \ |
|
357 if (eu == ecused) ecadd(WCB_END()); \ |
|
358 } while (0) |
|
359 #define par_save_list1(C) \ |
|
360 do { \ |
|
361 int eu = ecused; \ |
|
362 par_list1(C); \ |
|
363 if (eu == ecused) ecadd(WCB_END()); \ |
|
364 } while (0) |
|
365 |
|
366 |
|
367 /* Initialise wordcode buffer. */ |
|
368 |
|
369 static void |
|
370 init_parse(void) |
|
371 { |
|
372 if (ecbuf) zfree(ecbuf, eclen); |
|
373 |
|
374 ecbuf = (Wordcode) zalloc((eclen = EC_INIT_SIZE) * sizeof(wordcode)); |
|
375 ecused = 0; |
|
376 ecstrs = NULL; |
|
377 ecsoffs = ecnpats = 0; |
|
378 ecssub = 0; |
|
379 ecnfunc = 0; |
|
380 } |
|
381 |
|
382 /* Build eprog. */ |
|
383 |
|
384 static void |
|
385 copy_ecstr(Eccstr s, char *p) |
|
386 { |
|
387 while (s) { |
|
388 memcpy(p + s->aoffs, s->str, strlen(s->str) + 1); |
|
389 copy_ecstr(s->left, p); |
|
390 s = s->right; |
|
391 } |
|
392 } |
|
393 |
|
394 static Eprog |
|
395 bld_eprog(void) |
|
396 { |
|
397 Eprog ret; |
|
398 int l; |
|
399 |
|
400 ecadd(WCB_END()); |
|
401 |
|
402 ret = (Eprog) zhalloc(sizeof(*ret)); |
|
403 ret->len = ((ecnpats * sizeof(Patprog)) + |
|
404 (ecused * sizeof(wordcode)) + |
|
405 ecsoffs); |
|
406 ret->npats = ecnpats; |
|
407 ret->nref = -1; /* Eprog is on the heap */ |
|
408 ret->pats = (Patprog *) zhalloc(ret->len); |
|
409 ret->prog = (Wordcode) (ret->pats + ecnpats); |
|
410 ret->strs = (char *) (ret->prog + ecused); |
|
411 ret->shf = NULL; |
|
412 ret->flags = EF_HEAP; |
|
413 ret->dump = NULL; |
|
414 for (l = 0; l < ecnpats; l++) |
|
415 ret->pats[l] = dummy_patprog1; |
|
416 memcpy(ret->prog, ecbuf, ecused * sizeof(wordcode)); |
|
417 copy_ecstr(ecstrs, ret->strs); |
|
418 |
|
419 zfree(ecbuf, eclen); |
|
420 ecbuf = NULL; |
|
421 |
|
422 return ret; |
|
423 } |
|
424 |
|
425 /**/ |
|
426 mod_export int |
|
427 empty_eprog(Eprog p) |
|
428 { |
|
429 return (!p || !p->prog || *p->prog == WCB_END()); |
|
430 } |
|
431 |
|
432 static void |
|
433 clear_hdocs() |
|
434 { |
|
435 struct heredocs *p, *n; |
|
436 |
|
437 for (p = hdocs; p; p = n) { |
|
438 n = p->next; |
|
439 zfree(p, sizeof(struct heredocs)); |
|
440 } |
|
441 hdocs = NULL; |
|
442 } |
|
443 |
|
444 /* |
|
445 * event : ENDINPUT |
|
446 * | SEPER |
|
447 * | sublist [ SEPER | AMPER | AMPERBANG ] |
|
448 */ |
|
449 |
|
450 /**/ |
|
451 Eprog |
|
452 parse_event(void) |
|
453 { |
|
454 tok = ENDINPUT; |
|
455 incmdpos = 1; |
|
456 aliasspaceflag = 0; |
|
457 yylex(); |
|
458 init_parse(); |
|
459 |
|
460 if (!par_event()) { |
|
461 clear_hdocs(); |
|
462 return NULL; |
|
463 } |
|
464 return bld_eprog(); |
|
465 } |
|
466 |
|
467 /**/ |
|
468 static int |
|
469 par_event(void) |
|
470 { |
|
471 int r = 0, p, c = 0; |
|
472 |
|
473 while (tok == SEPER) { |
|
474 if (isnewlin > 0) |
|
475 return 0; |
|
476 yylex(); |
|
477 } |
|
478 if (tok == ENDINPUT) |
|
479 return 0; |
|
480 |
|
481 p = ecadd(0); |
|
482 |
|
483 if (par_sublist(&c)) { |
|
484 if (tok == ENDINPUT) { |
|
485 set_list_code(p, Z_SYNC, c); |
|
486 r = 1; |
|
487 } else if (tok == SEPER) { |
|
488 set_list_code(p, Z_SYNC, c); |
|
489 if (isnewlin <= 0) |
|
490 yylex(); |
|
491 r = 1; |
|
492 } else if (tok == AMPER) { |
|
493 set_list_code(p, Z_ASYNC, c); |
|
494 yylex(); |
|
495 r = 1; |
|
496 } else if (tok == AMPERBANG) { |
|
497 set_list_code(p, (Z_ASYNC | Z_DISOWN), c); |
|
498 yylex(); |
|
499 r = 1; |
|
500 } |
|
501 } |
|
502 if (!r) { |
|
503 tok = LEXERR; |
|
504 if (errflag) { |
|
505 yyerror(0); |
|
506 ecused--; |
|
507 return 0; |
|
508 } |
|
509 yyerror(1); |
|
510 herrflush(); |
|
511 if (noerrs != 2) |
|
512 errflag = 1; |
|
513 ecused--; |
|
514 return 0; |
|
515 } else { |
|
516 int oec = ecused; |
|
517 |
|
518 if (!par_event()) { |
|
519 ecused = oec; |
|
520 ecbuf[p] |= wc_bdata(Z_END); |
|
521 } |
|
522 } |
|
523 return 1; |
|
524 } |
|
525 |
|
526 /**/ |
|
527 mod_export Eprog |
|
528 parse_list(void) |
|
529 { |
|
530 int c = 0; |
|
531 |
|
532 tok = ENDINPUT; |
|
533 incmdpos = 1; |
|
534 yylex(); |
|
535 init_parse(); |
|
536 par_list(&c); |
|
537 if (tok != ENDINPUT) { |
|
538 clear_hdocs(); |
|
539 tok = LEXERR; |
|
540 yyerror(0); |
|
541 return NULL; |
|
542 } |
|
543 return bld_eprog(); |
|
544 } |
|
545 |
|
546 /**/ |
|
547 mod_export Eprog |
|
548 parse_cond(void) |
|
549 { |
|
550 init_parse(); |
|
551 |
|
552 if (!par_cond()) { |
|
553 clear_hdocs(); |
|
554 return NULL; |
|
555 } |
|
556 return bld_eprog(); |
|
557 } |
|
558 |
|
559 /* This adds a list wordcode. The important bit about this is that it also |
|
560 * tries to optimise this to a Z_SIMPLE list code. */ |
|
561 |
|
562 /**/ |
|
563 static void |
|
564 set_list_code(int p, int type, int complex) |
|
565 { |
|
566 if (!complex && (type == Z_SYNC || type == (Z_SYNC | Z_END)) && |
|
567 WC_SUBLIST_TYPE(ecbuf[p + 1]) == WC_SUBLIST_END) { |
|
568 int ispipe = !(WC_SUBLIST_FLAGS(ecbuf[p + 1]) & WC_SUBLIST_SIMPLE); |
|
569 ecbuf[p] = WCB_LIST((type | Z_SIMPLE), ecused - 2 - p); |
|
570 ecdel(p + 1); |
|
571 if (ispipe) |
|
572 ecbuf[p + 1] = WC_PIPE_LINENO(ecbuf[p + 1]); |
|
573 } else |
|
574 ecbuf[p] = WCB_LIST(type, 0); |
|
575 } |
|
576 |
|
577 /* The same for sublists. */ |
|
578 |
|
579 /**/ |
|
580 static void |
|
581 set_sublist_code(int p, int type, int flags, int skip, int complex) |
|
582 { |
|
583 if (complex) |
|
584 ecbuf[p] = WCB_SUBLIST(type, flags, skip); |
|
585 else { |
|
586 ecbuf[p] = WCB_SUBLIST(type, (flags | WC_SUBLIST_SIMPLE), skip); |
|
587 ecbuf[p + 1] = WC_PIPE_LINENO(ecbuf[p + 1]); |
|
588 } |
|
589 } |
|
590 |
|
591 /* |
|
592 * list : { SEPER } [ sublist [ { SEPER | AMPER | AMPERBANG } list ] ] |
|
593 */ |
|
594 |
|
595 /**/ |
|
596 static int |
|
597 par_list(int *complex) |
|
598 { |
|
599 int p, lp = -1, c; |
|
600 |
|
601 rec: |
|
602 |
|
603 while (tok == SEPER) |
|
604 yylex(); |
|
605 |
|
606 p = ecadd(0); |
|
607 c = 0; |
|
608 |
|
609 if (par_sublist(&c)) { |
|
610 *complex |= c; |
|
611 if (tok == SEPER || tok == AMPER || tok == AMPERBANG) { |
|
612 if (tok != SEPER) |
|
613 *complex = 1; |
|
614 set_list_code(p, ((tok == SEPER) ? Z_SYNC : |
|
615 (tok == AMPER) ? Z_ASYNC : |
|
616 (Z_ASYNC | Z_DISOWN)), c); |
|
617 incmdpos = 1; |
|
618 do { |
|
619 yylex(); |
|
620 } while (tok == SEPER); |
|
621 lp = p; |
|
622 goto rec; |
|
623 } else |
|
624 set_list_code(p, (Z_SYNC | Z_END), c); |
|
625 return 1; |
|
626 } else { |
|
627 ecused--; |
|
628 if (lp >= 0) { |
|
629 ecbuf[lp] |= wc_bdata(Z_END); |
|
630 return 1; |
|
631 } |
|
632 return 0; |
|
633 } |
|
634 } |
|
635 |
|
636 /**/ |
|
637 static int |
|
638 par_list1(int *complex) |
|
639 { |
|
640 int p = ecadd(0), c = 0; |
|
641 |
|
642 if (par_sublist(&c)) { |
|
643 set_list_code(p, (Z_SYNC | Z_END), c); |
|
644 *complex |= c; |
|
645 return 1; |
|
646 } else { |
|
647 ecused--; |
|
648 return 0; |
|
649 } |
|
650 } |
|
651 |
|
652 /* |
|
653 * sublist : sublist2 [ ( DBAR | DAMPER ) { SEPER } sublist ] |
|
654 */ |
|
655 |
|
656 /**/ |
|
657 static int |
|
658 par_sublist(int *complex) |
|
659 { |
|
660 int f, p, c = 0; |
|
661 |
|
662 p = ecadd(0); |
|
663 |
|
664 if ((f = par_sublist2(&c)) != -1) { |
|
665 int e = ecused; |
|
666 |
|
667 *complex |= c; |
|
668 if (tok == DBAR || tok == DAMPER) { |
|
669 int qtok = tok, sl; |
|
670 |
|
671 cmdpush(tok == DBAR ? CS_CMDOR : CS_CMDAND); |
|
672 yylex(); |
|
673 while (tok == SEPER) |
|
674 yylex(); |
|
675 sl = par_sublist(complex); |
|
676 set_sublist_code(p, (sl ? (qtok == DBAR ? |
|
677 WC_SUBLIST_OR : WC_SUBLIST_AND) : |
|
678 WC_SUBLIST_END), |
|
679 f, (e - 1 - p), c); |
|
680 cmdpop(); |
|
681 } else |
|
682 set_sublist_code(p, WC_SUBLIST_END, f, (e - 1 - p), c); |
|
683 return 1; |
|
684 } else { |
|
685 ecused--; |
|
686 return 0; |
|
687 } |
|
688 } |
|
689 |
|
690 /* |
|
691 * sublist2 : [ COPROC | BANG ] pline |
|
692 */ |
|
693 |
|
694 /**/ |
|
695 static int |
|
696 par_sublist2(int *complex) |
|
697 { |
|
698 int f = 0; |
|
699 |
|
700 if (tok == COPROC) { |
|
701 *complex = 1; |
|
702 f |= WC_SUBLIST_COPROC; |
|
703 yylex(); |
|
704 } else if (tok == BANG) { |
|
705 *complex = 1; |
|
706 f |= WC_SUBLIST_NOT; |
|
707 yylex(); |
|
708 } |
|
709 if (!par_pline(complex) && !f) |
|
710 return -1; |
|
711 |
|
712 return f; |
|
713 } |
|
714 |
|
715 /* |
|
716 * pline : cmd [ ( BAR | BARAMP ) { SEPER } pline ] |
|
717 */ |
|
718 |
|
719 /**/ |
|
720 static int |
|
721 par_pline(int *complex) |
|
722 { |
|
723 int p, line = lineno; |
|
724 |
|
725 p = ecadd(0); |
|
726 |
|
727 if (!par_cmd(complex)) { |
|
728 ecused--; |
|
729 return 0; |
|
730 } |
|
731 if (tok == BAR) { |
|
732 *complex = 1; |
|
733 cmdpush(CS_PIPE); |
|
734 yylex(); |
|
735 while (tok == SEPER) |
|
736 yylex(); |
|
737 ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0)); |
|
738 ecispace(p + 1, 1); |
|
739 ecbuf[p + 1] = ecused - 1 - p; |
|
740 if (!par_pline(complex)) { |
|
741 tok = LEXERR; |
|
742 } |
|
743 cmdpop(); |
|
744 return 1; |
|
745 } else if (tok == BARAMP) { |
|
746 int r; |
|
747 |
|
748 for (r = p + 1; wc_code(ecbuf[r]) == WC_REDIR; r += 3); |
|
749 |
|
750 ecispace(r, 3); |
|
751 ecbuf[r] = WCB_REDIR(REDIR_MERGEOUT); |
|
752 ecbuf[r + 1] = 2; |
|
753 ecbuf[r + 2] = ecstrcode("1"); |
|
754 |
|
755 *complex = 1; |
|
756 cmdpush(CS_ERRPIPE); |
|
757 yylex(); |
|
758 while (tok == SEPER) |
|
759 yylex(); |
|
760 ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0)); |
|
761 ecispace(p + 1, 1); |
|
762 ecbuf[p + 1] = ecused - 1 - p; |
|
763 if (!par_pline(complex)) { |
|
764 tok = LEXERR; |
|
765 } |
|
766 cmdpop(); |
|
767 return 1; |
|
768 } else { |
|
769 ecbuf[p] = WCB_PIPE(WC_PIPE_END, (line >= 0 ? line + 1 : 0)); |
|
770 return 1; |
|
771 } |
|
772 } |
|
773 |
|
774 /* |
|
775 * cmd : { redir } ( for | case | if | while | repeat | |
|
776 * subsh | funcdef | time | dinbrack | dinpar | simple ) { redir } |
|
777 */ |
|
778 |
|
779 /**/ |
|
780 static int |
|
781 par_cmd(int *complex) |
|
782 { |
|
783 int r, nr = 0; |
|
784 |
|
785 r = ecused; |
|
786 |
|
787 if (IS_REDIROP(tok)) { |
|
788 *complex = 1; |
|
789 while (IS_REDIROP(tok)) { |
|
790 nr++; |
|
791 par_redir(&r); |
|
792 } |
|
793 } |
|
794 switch (tok) { |
|
795 case FOR: |
|
796 cmdpush(CS_FOR); |
|
797 par_for(complex); |
|
798 cmdpop(); |
|
799 break; |
|
800 case FOREACH: |
|
801 cmdpush(CS_FOREACH); |
|
802 par_for(complex); |
|
803 cmdpop(); |
|
804 break; |
|
805 case SELECT: |
|
806 *complex = 1; |
|
807 cmdpush(CS_SELECT); |
|
808 par_for(complex); |
|
809 cmdpop(); |
|
810 break; |
|
811 case CASE: |
|
812 cmdpush(CS_CASE); |
|
813 par_case(complex); |
|
814 cmdpop(); |
|
815 break; |
|
816 case IF: |
|
817 par_if(complex); |
|
818 break; |
|
819 case WHILE: |
|
820 cmdpush(CS_WHILE); |
|
821 par_while(complex); |
|
822 cmdpop(); |
|
823 break; |
|
824 case UNTIL: |
|
825 cmdpush(CS_UNTIL); |
|
826 par_while(complex); |
|
827 cmdpop(); |
|
828 break; |
|
829 case REPEAT: |
|
830 cmdpush(CS_REPEAT); |
|
831 par_repeat(complex); |
|
832 cmdpop(); |
|
833 break; |
|
834 case INPAR: |
|
835 *complex = 1; |
|
836 cmdpush(CS_SUBSH); |
|
837 par_subsh(complex); |
|
838 cmdpop(); |
|
839 break; |
|
840 case INBRACE: |
|
841 cmdpush(CS_CURSH); |
|
842 par_subsh(complex); |
|
843 cmdpop(); |
|
844 break; |
|
845 case FUNC: |
|
846 cmdpush(CS_FUNCDEF); |
|
847 par_funcdef(); |
|
848 cmdpop(); |
|
849 break; |
|
850 case DINBRACK: |
|
851 cmdpush(CS_COND); |
|
852 par_dinbrack(); |
|
853 cmdpop(); |
|
854 break; |
|
855 case DINPAR: |
|
856 ecadd(WCB_ARITH()); |
|
857 ecstr(tokstr); |
|
858 yylex(); |
|
859 break; |
|
860 case TIME: |
|
861 { |
|
862 static int inpartime = 0; |
|
863 |
|
864 if (!inpartime) { |
|
865 *complex = 1; |
|
866 inpartime = 1; |
|
867 par_time(); |
|
868 inpartime = 0; |
|
869 break; |
|
870 } |
|
871 } |
|
872 tok = STRING; |
|
873 /* fall through */ |
|
874 default: |
|
875 { |
|
876 int sr; |
|
877 |
|
878 if (!(sr = par_simple(complex, nr))) { |
|
879 if (!nr) |
|
880 return 0; |
|
881 } else { |
|
882 /* Three codes per redirection. */ |
|
883 if (sr > 1) { |
|
884 *complex = 1; |
|
885 r += (sr - 1) * 3; |
|
886 } |
|
887 } |
|
888 } |
|
889 break; |
|
890 } |
|
891 if (IS_REDIROP(tok)) { |
|
892 *complex = 1; |
|
893 while (IS_REDIROP(tok)) |
|
894 par_redir(&r); |
|
895 } |
|
896 incmdpos = 1; |
|
897 incasepat = 0; |
|
898 incond = 0; |
|
899 return 1; |
|
900 } |
|
901 |
|
902 /* |
|
903 * for : ( FOR DINPAR expr SEMI expr SEMI expr DOUTPAR | |
|
904 * ( FOR[EACH] | SELECT ) name ( "in" wordlist | INPAR wordlist OUTPAR ) ) |
|
905 * { SEPER } ( DO list DONE | INBRACE list OUTBRACE | list ZEND | list1 ) |
|
906 */ |
|
907 |
|
908 /**/ |
|
909 static void |
|
910 par_for(int *complex) |
|
911 { |
|
912 int oecused = ecused, csh = (tok == FOREACH), p, sel = (tok == SELECT); |
|
913 int type; |
|
914 |
|
915 p = ecadd(0); |
|
916 |
|
917 incmdpos = 0; |
|
918 infor = tok == FOR ? 2 : 0; |
|
919 yylex(); |
|
920 if (tok == DINPAR) { |
|
921 yylex(); |
|
922 if (tok != DINPAR) |
|
923 YYERRORV(oecused); |
|
924 ecstr(tokstr); |
|
925 yylex(); |
|
926 if (tok != DINPAR) |
|
927 YYERRORV(oecused); |
|
928 ecstr(tokstr); |
|
929 yylex(); |
|
930 if (tok != DOUTPAR) |
|
931 YYERRORV(oecused); |
|
932 ecstr(tokstr); |
|
933 infor = 0; |
|
934 incmdpos = 1; |
|
935 yylex(); |
|
936 type = WC_FOR_COND; |
|
937 } else { |
|
938 int np = 0, n, posix_in, ona = noaliases, onc = nocorrect; |
|
939 infor = 0; |
|
940 if (tok != STRING || !isident(tokstr)) |
|
941 YYERRORV(oecused); |
|
942 if (!sel) |
|
943 np = ecadd(0); |
|
944 n = 0; |
|
945 incmdpos = 1; |
|
946 noaliases = nocorrect = 1; |
|
947 for (;;) { |
|
948 n++; |
|
949 ecstr(tokstr); |
|
950 yylex(); |
|
951 if (tok != STRING || !strcmp(tokstr, "in") || sel) |
|
952 break; |
|
953 if (!isident(tokstr) || errflag) |
|
954 { |
|
955 noaliases = ona; |
|
956 nocorrect = onc; |
|
957 YYERRORV(oecused); |
|
958 } |
|
959 } |
|
960 noaliases = ona; |
|
961 nocorrect = onc; |
|
962 if (!sel) |
|
963 ecbuf[np] = n; |
|
964 posix_in = isnewlin; |
|
965 while (isnewlin) |
|
966 yylex(); |
|
967 if (tok == STRING && !strcmp(tokstr, "in")) { |
|
968 incmdpos = 0; |
|
969 yylex(); |
|
970 np = ecadd(0); |
|
971 n = par_wordlist(); |
|
972 if (tok != SEPER) |
|
973 YYERRORV(oecused); |
|
974 ecbuf[np] = n; |
|
975 type = (sel ? WC_SELECT_LIST : WC_FOR_LIST); |
|
976 } else if (!posix_in && tok == INPAR) { |
|
977 incmdpos = 0; |
|
978 yylex(); |
|
979 np = ecadd(0); |
|
980 n = par_nl_wordlist(); |
|
981 if (tok != OUTPAR) |
|
982 YYERRORV(oecused); |
|
983 ecbuf[np] = n; |
|
984 incmdpos = 1; |
|
985 yylex(); |
|
986 type = (sel ? WC_SELECT_LIST : WC_FOR_LIST); |
|
987 } else |
|
988 type = (sel ? WC_SELECT_PPARAM : WC_FOR_PPARAM); |
|
989 } |
|
990 incmdpos = 1; |
|
991 while (tok == SEPER) |
|
992 yylex(); |
|
993 if (tok == DOLOOP) { |
|
994 yylex(); |
|
995 par_save_list(complex); |
|
996 if (tok != DONE) |
|
997 YYERRORV(oecused); |
|
998 yylex(); |
|
999 } else if (tok == INBRACE) { |
|
1000 yylex(); |
|
1001 par_save_list(complex); |
|
1002 if (tok != OUTBRACE) |
|
1003 YYERRORV(oecused); |
|
1004 yylex(); |
|
1005 } else if (csh || isset(CSHJUNKIELOOPS)) { |
|
1006 par_save_list(complex); |
|
1007 if (tok != ZEND) |
|
1008 YYERRORV(oecused); |
|
1009 yylex(); |
|
1010 } else if (unset(SHORTLOOPS)) { |
|
1011 YYERRORV(oecused); |
|
1012 } else |
|
1013 par_save_list1(complex); |
|
1014 |
|
1015 ecbuf[p] = (sel ? |
|
1016 WCB_SELECT(type, ecused - 1 - p) : |
|
1017 WCB_FOR(type, ecused - 1 - p)); |
|
1018 } |
|
1019 |
|
1020 /* |
|
1021 * case : CASE STRING { SEPER } ( "in" | INBRACE ) |
|
1022 { { SEPER } STRING { BAR STRING } OUTPAR |
|
1023 list [ DSEMI | SEMIAMP ] } |
|
1024 { SEPER } ( "esac" | OUTBRACE ) |
|
1025 */ |
|
1026 |
|
1027 /**/ |
|
1028 static void |
|
1029 par_case(int *complex) |
|
1030 { |
|
1031 int oecused = ecused, brflag, p, pp, n = 1, type; |
|
1032 |
|
1033 p = ecadd(0); |
|
1034 |
|
1035 incmdpos = 0; |
|
1036 yylex(); |
|
1037 if (tok != STRING) |
|
1038 YYERRORV(oecused); |
|
1039 ecstr(tokstr); |
|
1040 |
|
1041 incmdpos = 1; |
|
1042 yylex(); |
|
1043 while (tok == SEPER) |
|
1044 yylex(); |
|
1045 if (!(tok == STRING && !strcmp(tokstr, "in")) && tok != INBRACE) |
|
1046 YYERRORV(oecused); |
|
1047 brflag = (tok == INBRACE); |
|
1048 incasepat = 1; |
|
1049 incmdpos = 0; |
|
1050 yylex(); |
|
1051 |
|
1052 for (;;) { |
|
1053 char *str; |
|
1054 |
|
1055 while (tok == SEPER) |
|
1056 yylex(); |
|
1057 if (tok == OUTBRACE) |
|
1058 break; |
|
1059 if (tok == INPAR) |
|
1060 yylex(); |
|
1061 if (tok != STRING) |
|
1062 YYERRORV(oecused); |
|
1063 if (!strcmp(tokstr, "esac")) |
|
1064 break; |
|
1065 str = dupstring(tokstr); |
|
1066 incasepat = 0; |
|
1067 incmdpos = 1; |
|
1068 type = WC_CASE_OR; |
|
1069 for (;;) { |
|
1070 yylex(); |
|
1071 if (tok == OUTPAR) { |
|
1072 incasepat = 0; |
|
1073 incmdpos = 1; |
|
1074 yylex(); |
|
1075 break; |
|
1076 } else if (tok == BAR) { |
|
1077 char *str2; |
|
1078 int sl = strlen(str); |
|
1079 |
|
1080 incasepat = 1; |
|
1081 incmdpos = 0; |
|
1082 str2 = hcalloc(sl + 2); |
|
1083 strcpy(str2, str); |
|
1084 str2[sl] = Bar; |
|
1085 str2[sl+1] = '\0'; |
|
1086 str = str2; |
|
1087 } else { |
|
1088 int sl = strlen(str); |
|
1089 |
|
1090 if (!sl || str[sl - 1] != Bar) { |
|
1091 /* POSIX allows (foo*) patterns */ |
|
1092 int pct; |
|
1093 char *s; |
|
1094 |
|
1095 for (s = str, pct = 0; *s; s++) { |
|
1096 if (*s == Inpar) |
|
1097 pct++; |
|
1098 if (!pct) |
|
1099 break; |
|
1100 if (pct == 1) { |
|
1101 if (*s == Bar || *s == Inpar) |
|
1102 while (iblank(s[1])) |
|
1103 chuck(s+1); |
|
1104 if (*s == Bar || *s == Outpar) |
|
1105 while (iblank(s[-1]) && |
|
1106 (s < str + 1 || s[-2] != Meta)) |
|
1107 chuck(--s); |
|
1108 } |
|
1109 if (*s == Outpar) |
|
1110 pct--; |
|
1111 } |
|
1112 if (*s || pct || s == str) |
|
1113 YYERRORV(oecused); |
|
1114 /* Simplify pattern by removing surrounding (...) */ |
|
1115 sl = strlen(str); |
|
1116 DPUTS(*str != Inpar || str[sl - 1] != Outpar, |
|
1117 "BUG: strange case pattern"); |
|
1118 str[sl - 1] = '\0'; |
|
1119 chuck(str); |
|
1120 break; |
|
1121 } else { |
|
1122 char *str2; |
|
1123 |
|
1124 if (tok != STRING) |
|
1125 YYERRORV(oecused); |
|
1126 str2 = hcalloc(sl + strlen(tokstr) + 1); |
|
1127 strcpy(str2, str); |
|
1128 strcpy(str2 + sl, tokstr); |
|
1129 str = str2; |
|
1130 } |
|
1131 } |
|
1132 } |
|
1133 pp = ecadd(0); |
|
1134 ecstr(str); |
|
1135 ecadd(ecnpats++); |
|
1136 par_save_list(complex); |
|
1137 n++; |
|
1138 if (tok == SEMIAMP) |
|
1139 type = WC_CASE_AND; |
|
1140 ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp); |
|
1141 if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag)) |
|
1142 break; |
|
1143 if (tok != DSEMI && tok != SEMIAMP) |
|
1144 YYERRORV(oecused); |
|
1145 incasepat = 1; |
|
1146 incmdpos = 0; |
|
1147 yylex(); |
|
1148 } |
|
1149 incmdpos = 1; |
|
1150 yylex(); |
|
1151 |
|
1152 ecbuf[p] = WCB_CASE(WC_CASE_HEAD, ecused - 1 - p); |
|
1153 } |
|
1154 |
|
1155 /* |
|
1156 * if : { ( IF | ELIF ) { SEPER } ( INPAR list OUTPAR | list ) |
|
1157 { SEPER } ( THEN list | INBRACE list OUTBRACE | list1 ) } |
|
1158 [ FI | ELSE list FI | ELSE { SEPER } INBRACE list OUTBRACE ] |
|
1159 (you get the idea...?) |
|
1160 */ |
|
1161 |
|
1162 /**/ |
|
1163 static void |
|
1164 par_if(int *complex) |
|
1165 { |
|
1166 int oecused = ecused, xtok, p, pp, type, usebrace = 0; |
|
1167 unsigned char nc; |
|
1168 |
|
1169 p = ecadd(0); |
|
1170 |
|
1171 for (;;) { |
|
1172 xtok = tok; |
|
1173 cmdpush(xtok == IF ? CS_IF : CS_ELIF); |
|
1174 yylex(); |
|
1175 if (xtok == FI) |
|
1176 break; |
|
1177 if (xtok == ELSE) |
|
1178 break; |
|
1179 while (tok == SEPER) |
|
1180 yylex(); |
|
1181 if (!(xtok == IF || xtok == ELIF)) { |
|
1182 cmdpop(); |
|
1183 YYERRORV(oecused); |
|
1184 } |
|
1185 pp = ecadd(0); |
|
1186 type = (xtok == IF ? WC_IF_IF : WC_IF_ELIF); |
|
1187 par_save_list(complex); |
|
1188 incmdpos = 1; |
|
1189 while (tok == SEPER) |
|
1190 yylex(); |
|
1191 xtok = FI; |
|
1192 nc = cmdstack[cmdsp - 1] == CS_IF ? CS_IFTHEN : CS_ELIFTHEN; |
|
1193 if (tok == THEN) { |
|
1194 usebrace = 0; |
|
1195 cmdpop(); |
|
1196 cmdpush(nc); |
|
1197 yylex(); |
|
1198 par_save_list(complex); |
|
1199 ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); |
|
1200 incmdpos = 1; |
|
1201 cmdpop(); |
|
1202 } else if (tok == INBRACE) { |
|
1203 usebrace = 1; |
|
1204 cmdpop(); |
|
1205 cmdpush(nc); |
|
1206 yylex(); |
|
1207 par_save_list(complex); |
|
1208 if (tok != OUTBRACE) { |
|
1209 cmdpop(); |
|
1210 YYERRORV(oecused); |
|
1211 } |
|
1212 ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); |
|
1213 yylex(); |
|
1214 incmdpos = 1; |
|
1215 if (tok == SEPER) |
|
1216 break; |
|
1217 cmdpop(); |
|
1218 } else if (unset(SHORTLOOPS)) { |
|
1219 cmdpop(); |
|
1220 YYERRORV(oecused); |
|
1221 } else { |
|
1222 cmdpop(); |
|
1223 cmdpush(nc); |
|
1224 par_save_list1(complex); |
|
1225 ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); |
|
1226 incmdpos = 1; |
|
1227 break; |
|
1228 } |
|
1229 } |
|
1230 cmdpop(); |
|
1231 if (xtok == ELSE) { |
|
1232 pp = ecadd(0); |
|
1233 cmdpush(CS_ELSE); |
|
1234 while (tok == SEPER) |
|
1235 yylex(); |
|
1236 if (tok == INBRACE && usebrace) { |
|
1237 yylex(); |
|
1238 par_save_list(complex); |
|
1239 if (tok != OUTBRACE) { |
|
1240 cmdpop(); |
|
1241 YYERRORV(oecused); |
|
1242 } |
|
1243 } else { |
|
1244 par_save_list(complex); |
|
1245 if (tok != FI) { |
|
1246 cmdpop(); |
|
1247 YYERRORV(oecused); |
|
1248 } |
|
1249 } |
|
1250 ecbuf[pp] = WCB_IF(WC_IF_ELSE, ecused - 1 - pp); |
|
1251 yylex(); |
|
1252 cmdpop(); |
|
1253 } |
|
1254 ecbuf[p] = WCB_IF(WC_IF_HEAD, ecused - 1 - p); |
|
1255 } |
|
1256 |
|
1257 /* |
|
1258 * while : ( WHILE | UNTIL ) ( INPAR list OUTPAR | list ) { SEPER } |
|
1259 ( DO list DONE | INBRACE list OUTBRACE | list ZEND ) |
|
1260 */ |
|
1261 |
|
1262 /**/ |
|
1263 static void |
|
1264 par_while(int *complex) |
|
1265 { |
|
1266 int oecused = ecused, p; |
|
1267 int type = (tok == UNTIL ? WC_WHILE_UNTIL : WC_WHILE_WHILE); |
|
1268 |
|
1269 p = ecadd(0); |
|
1270 yylex(); |
|
1271 par_save_list(complex); |
|
1272 incmdpos = 1; |
|
1273 while (tok == SEPER) |
|
1274 yylex(); |
|
1275 if (tok == DOLOOP) { |
|
1276 yylex(); |
|
1277 par_save_list(complex); |
|
1278 if (tok != DONE) |
|
1279 YYERRORV(oecused); |
|
1280 yylex(); |
|
1281 } else if (tok == INBRACE) { |
|
1282 yylex(); |
|
1283 par_save_list(complex); |
|
1284 if (tok != OUTBRACE) |
|
1285 YYERRORV(oecused); |
|
1286 yylex(); |
|
1287 } else if (isset(CSHJUNKIELOOPS)) { |
|
1288 par_save_list(complex); |
|
1289 if (tok != ZEND) |
|
1290 YYERRORV(oecused); |
|
1291 yylex(); |
|
1292 } else |
|
1293 YYERRORV(oecused); |
|
1294 |
|
1295 ecbuf[p] = WCB_WHILE(type, ecused - 1 - p); |
|
1296 } |
|
1297 |
|
1298 /* |
|
1299 * repeat : REPEAT STRING { SEPER } ( DO list DONE | list1 ) |
|
1300 */ |
|
1301 |
|
1302 /**/ |
|
1303 static void |
|
1304 par_repeat(int *complex) |
|
1305 { |
|
1306 int oecused = ecused, p; |
|
1307 |
|
1308 p = ecadd(0); |
|
1309 |
|
1310 incmdpos = 0; |
|
1311 yylex(); |
|
1312 if (tok != STRING) |
|
1313 YYERRORV(oecused); |
|
1314 ecstr(tokstr); |
|
1315 incmdpos = 1; |
|
1316 yylex(); |
|
1317 while (tok == SEPER) |
|
1318 yylex(); |
|
1319 if (tok == DOLOOP) { |
|
1320 yylex(); |
|
1321 par_save_list(complex); |
|
1322 if (tok != DONE) |
|
1323 YYERRORV(oecused); |
|
1324 yylex(); |
|
1325 } else if (tok == INBRACE) { |
|
1326 yylex(); |
|
1327 par_save_list(complex); |
|
1328 if (tok != OUTBRACE) |
|
1329 YYERRORV(oecused); |
|
1330 yylex(); |
|
1331 } else if (isset(CSHJUNKIELOOPS)) { |
|
1332 par_save_list(complex); |
|
1333 if (tok != ZEND) |
|
1334 YYERRORV(oecused); |
|
1335 yylex(); |
|
1336 } else if (unset(SHORTLOOPS)) { |
|
1337 YYERRORV(oecused); |
|
1338 } else |
|
1339 par_save_list1(complex); |
|
1340 |
|
1341 ecbuf[p] = WCB_REPEAT(ecused - 1 - p); |
|
1342 } |
|
1343 |
|
1344 /* |
|
1345 * subsh : INPAR list OUTPAR | |
|
1346 * INBRACE list OUTBRACE [ "always" INBRACE list OUTBRACE ] |
|
1347 */ |
|
1348 |
|
1349 /**/ |
|
1350 static void |
|
1351 par_subsh(int *complex) |
|
1352 { |
|
1353 int oecused = ecused, otok = tok, p, pp; |
|
1354 |
|
1355 p = ecadd(0); |
|
1356 /* Extra word only needed for always block */ |
|
1357 pp = ecadd(0); |
|
1358 yylex(); |
|
1359 par_list(complex); |
|
1360 ecadd(WCB_END()); |
|
1361 if (tok != ((otok == INPAR) ? OUTPAR : OUTBRACE)) |
|
1362 YYERRORV(oecused); |
|
1363 incmdpos = 1; |
|
1364 yylex(); |
|
1365 |
|
1366 /* Optional always block. No intervening SEPERs allowed. */ |
|
1367 if (otok == INBRACE && tok == STRING && !strcmp(tokstr, "always")) { |
|
1368 ecbuf[pp] = WCB_TRY(ecused - 1 - pp); |
|
1369 incmdpos = 1; |
|
1370 do { |
|
1371 yylex(); |
|
1372 } while (tok == SEPER); |
|
1373 |
|
1374 if (tok != INBRACE) |
|
1375 YYERRORV(oecused); |
|
1376 cmdpop(); |
|
1377 cmdpush(CS_ALWAYS); |
|
1378 |
|
1379 yylex(); |
|
1380 par_save_list(complex); |
|
1381 while (tok == SEPER) |
|
1382 yylex(); |
|
1383 |
|
1384 incmdpos = 1; |
|
1385 |
|
1386 if (tok != OUTBRACE) |
|
1387 YYERRORV(oecused); |
|
1388 yylex(); |
|
1389 ecbuf[p] = WCB_TRY(ecused - 1 - p); |
|
1390 } else { |
|
1391 ecbuf[p] = (otok == INPAR ? WCB_SUBSH(ecused - 1 - p) : |
|
1392 WCB_CURSH(ecused - 1 - p)); |
|
1393 } |
|
1394 } |
|
1395 |
|
1396 /* |
|
1397 * funcdef : FUNCTION wordlist [ INOUTPAR ] { SEPER } |
|
1398 * ( list1 | INBRACE list OUTBRACE ) |
|
1399 */ |
|
1400 |
|
1401 /**/ |
|
1402 static void |
|
1403 par_funcdef(void) |
|
1404 { |
|
1405 int oecused = ecused, oldlineno = lineno, num = 0, onp, p, c = 0; |
|
1406 int so, oecssub = ecssub; |
|
1407 |
|
1408 lineno = 0; |
|
1409 nocorrect = 1; |
|
1410 incmdpos = 0; |
|
1411 yylex(); |
|
1412 |
|
1413 p = ecadd(0); |
|
1414 ecadd(0); |
|
1415 |
|
1416 incmdpos = 1; |
|
1417 while (tok == STRING) { |
|
1418 if (*tokstr == Inbrace && !tokstr[1]) { |
|
1419 tok = INBRACE; |
|
1420 break; |
|
1421 } |
|
1422 ecstr(tokstr); |
|
1423 num++; |
|
1424 yylex(); |
|
1425 } |
|
1426 ecadd(0); |
|
1427 ecadd(0); |
|
1428 ecadd(0); |
|
1429 |
|
1430 nocorrect = 0; |
|
1431 if (tok == INOUTPAR) |
|
1432 yylex(); |
|
1433 while (tok == SEPER) |
|
1434 yylex(); |
|
1435 |
|
1436 ecnfunc++; |
|
1437 ecssub = so = ecsoffs; |
|
1438 onp = ecnpats; |
|
1439 ecnpats = 0; |
|
1440 |
|
1441 if (tok == INBRACE) { |
|
1442 yylex(); |
|
1443 par_list(&c); |
|
1444 if (tok != OUTBRACE) { |
|
1445 lineno += oldlineno; |
|
1446 ecnpats = onp; |
|
1447 ecssub = oecssub; |
|
1448 YYERRORV(oecused); |
|
1449 } |
|
1450 yylex(); |
|
1451 } else if (unset(SHORTLOOPS)) { |
|
1452 lineno += oldlineno; |
|
1453 ecnpats = onp; |
|
1454 ecssub = oecssub; |
|
1455 YYERRORV(oecused); |
|
1456 } else |
|
1457 par_list1(&c); |
|
1458 |
|
1459 ecadd(WCB_END()); |
|
1460 ecbuf[p + num + 2] = so - oecssub; |
|
1461 ecbuf[p + num + 3] = ecsoffs - so; |
|
1462 ecbuf[p + num + 4] = ecnpats; |
|
1463 ecbuf[p + 1] = num; |
|
1464 |
|
1465 lineno += oldlineno; |
|
1466 ecnpats = onp; |
|
1467 ecssub = oecssub; |
|
1468 ecnfunc++; |
|
1469 |
|
1470 ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p); |
|
1471 } |
|
1472 |
|
1473 /* |
|
1474 * time : TIME sublist2 |
|
1475 */ |
|
1476 |
|
1477 /**/ |
|
1478 static void |
|
1479 par_time(void) |
|
1480 { |
|
1481 int p, f, c = 0; |
|
1482 |
|
1483 yylex(); |
|
1484 |
|
1485 p = ecadd(0); |
|
1486 ecadd(0); |
|
1487 if ((f = par_sublist2(&c)) < 0) { |
|
1488 ecused--; |
|
1489 ecbuf[p] = WCB_TIMED(WC_TIMED_EMPTY); |
|
1490 } else { |
|
1491 ecbuf[p] = WCB_TIMED(WC_TIMED_PIPE); |
|
1492 set_sublist_code(p + 1, WC_SUBLIST_END, f, ecused - 2 - p, c); |
|
1493 } |
|
1494 } |
|
1495 |
|
1496 /* |
|
1497 * dinbrack : DINBRACK cond DOUTBRACK |
|
1498 */ |
|
1499 |
|
1500 /**/ |
|
1501 static void |
|
1502 par_dinbrack(void) |
|
1503 { |
|
1504 int oecused = ecused; |
|
1505 |
|
1506 incond = 1; |
|
1507 incmdpos = 0; |
|
1508 yylex(); |
|
1509 par_cond(); |
|
1510 if (tok != DOUTBRACK) |
|
1511 YYERRORV(oecused); |
|
1512 incond = 0; |
|
1513 incmdpos = 1; |
|
1514 yylex(); |
|
1515 } |
|
1516 |
|
1517 /* |
|
1518 * simple : { COMMAND | EXEC | NOGLOB | NOCORRECT | DASH } |
|
1519 { STRING | ENVSTRING | ENVARRAY wordlist OUTPAR | redir } |
|
1520 [ INOUTPAR { SEPER } ( list1 | INBRACE list OUTBRACE ) ] |
|
1521 */ |
|
1522 |
|
1523 /**/ |
|
1524 static int |
|
1525 par_simple(int *complex, int nr) |
|
1526 { |
|
1527 int oecused = ecused, isnull = 1, r, argc = 0, p, isfunc = 0, sr = 0; |
|
1528 int c = *complex; |
|
1529 |
|
1530 r = ecused; |
|
1531 for (;;) { |
|
1532 if (tok == NOCORRECT) { |
|
1533 *complex = c = 1; |
|
1534 nocorrect = 1; |
|
1535 } else if (tok == ENVSTRING) { |
|
1536 char *p, *name, *str; |
|
1537 |
|
1538 name = tokstr; |
|
1539 for (p = tokstr; *p && *p != Inbrack && *p != '=' && *p != '+'; |
|
1540 p++); |
|
1541 if (*p == Inbrack) skipparens(Inbrack, Outbrack, &p); |
|
1542 if (*p == '+') { |
|
1543 *p++ = '\0'; |
|
1544 ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, WC_ASSIGN_INC, 0)); |
|
1545 } else |
|
1546 ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, WC_ASSIGN_NEW, 0)); |
|
1547 |
|
1548 if (*p == '=') { |
|
1549 *p = '\0'; |
|
1550 str = p + 1; |
|
1551 } else |
|
1552 equalsplit(tokstr, &str); |
|
1553 ecstr(name); |
|
1554 ecstr(str); |
|
1555 isnull = 0; |
|
1556 } else if (tok == ENVARRAY) { |
|
1557 int oldcmdpos = incmdpos, n, type2; |
|
1558 |
|
1559 p = ecadd(0); |
|
1560 incmdpos = 0; |
|
1561 if ((type2 = strlen(tokstr) - 1) && tokstr[type2] == '+') { |
|
1562 tokstr[type2] = '\0'; |
|
1563 type2 = WC_ASSIGN_INC; |
|
1564 } else |
|
1565 type2 = WC_ASSIGN_NEW; |
|
1566 ecstr(tokstr); |
|
1567 cmdpush(CS_ARRAY); |
|
1568 yylex(); |
|
1569 n = par_nl_wordlist(); |
|
1570 ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_ARRAY, type2, n); |
|
1571 cmdpop(); |
|
1572 if (tok != OUTPAR) |
|
1573 YYERROR(oecused); |
|
1574 incmdpos = oldcmdpos; |
|
1575 isnull = 0; |
|
1576 } else |
|
1577 break; |
|
1578 yylex(); |
|
1579 } |
|
1580 if (tok == AMPER || tok == AMPERBANG) |
|
1581 YYERROR(oecused); |
|
1582 |
|
1583 p = ecadd(WCB_SIMPLE(0)); |
|
1584 |
|
1585 for (;;) { |
|
1586 if (tok == STRING) { |
|
1587 *complex = 1; |
|
1588 incmdpos = 0; |
|
1589 ecstr(tokstr); |
|
1590 argc++; |
|
1591 yylex(); |
|
1592 } else if (IS_REDIROP(tok)) { |
|
1593 *complex = c = 1; |
|
1594 par_redir(&r); |
|
1595 p += 3; /* 3 codes per redirection */ |
|
1596 sr++; |
|
1597 } else if (tok == INOUTPAR) { |
|
1598 int oldlineno = lineno, onp, so, oecssub = ecssub; |
|
1599 |
|
1600 *complex = c; |
|
1601 lineno = 0; |
|
1602 incmdpos = 1; |
|
1603 cmdpush(CS_FUNCDEF); |
|
1604 yylex(); |
|
1605 while (tok == SEPER) |
|
1606 yylex(); |
|
1607 |
|
1608 ecispace(p + 1, 1); |
|
1609 ecbuf[p + 1] = argc; |
|
1610 ecadd(0); |
|
1611 ecadd(0); |
|
1612 ecadd(0); |
|
1613 |
|
1614 ecnfunc++; |
|
1615 ecssub = so = ecsoffs; |
|
1616 onp = ecnpats; |
|
1617 ecnpats = 0; |
|
1618 |
|
1619 if (tok == INBRACE) { |
|
1620 int c = 0; |
|
1621 |
|
1622 yylex(); |
|
1623 par_list(&c); |
|
1624 if (tok != OUTBRACE) { |
|
1625 cmdpop(); |
|
1626 lineno += oldlineno; |
|
1627 ecnpats = onp; |
|
1628 ecssub = oecssub; |
|
1629 YYERROR(oecused); |
|
1630 } |
|
1631 yylex(); |
|
1632 } else { |
|
1633 int ll, sl, pl, c = 0; |
|
1634 |
|
1635 ll = ecadd(0); |
|
1636 sl = ecadd(0); |
|
1637 pl = ecadd(WCB_PIPE(WC_PIPE_END, 0)); |
|
1638 |
|
1639 par_cmd(&c); |
|
1640 if (!c) |
|
1641 YYERROR(oecused); |
|
1642 |
|
1643 set_sublist_code(sl, WC_SUBLIST_END, 0, ecused - 1 - sl, c); |
|
1644 set_list_code(ll, (Z_SYNC | Z_END), c); |
|
1645 } |
|
1646 cmdpop(); |
|
1647 |
|
1648 ecadd(WCB_END()); |
|
1649 ecbuf[p + argc + 2] = so - oecssub; |
|
1650 ecbuf[p + argc + 3] = ecsoffs - so; |
|
1651 ecbuf[p + argc + 4] = ecnpats; |
|
1652 |
|
1653 lineno += oldlineno; |
|
1654 ecnpats = onp; |
|
1655 ecssub = oecssub; |
|
1656 ecnfunc++; |
|
1657 |
|
1658 ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p); |
|
1659 |
|
1660 isfunc = 1; |
|
1661 isnull = 0; |
|
1662 break; |
|
1663 } else |
|
1664 break; |
|
1665 isnull = 0; |
|
1666 } |
|
1667 if (isnull && !(sr + nr)) { |
|
1668 ecused = p; |
|
1669 return 0; |
|
1670 } |
|
1671 incmdpos = 1; |
|
1672 |
|
1673 if (!isfunc) |
|
1674 ecbuf[p] = WCB_SIMPLE(argc); |
|
1675 |
|
1676 return sr + 1; |
|
1677 } |
|
1678 |
|
1679 /* |
|
1680 * redir : ( OUTANG | ... | TRINANG ) STRING |
|
1681 */ |
|
1682 |
|
1683 static int redirtab[TRINANG - OUTANG + 1] = { |
|
1684 REDIR_WRITE, |
|
1685 REDIR_WRITENOW, |
|
1686 REDIR_APP, |
|
1687 REDIR_APPNOW, |
|
1688 REDIR_READ, |
|
1689 REDIR_READWRITE, |
|
1690 REDIR_HEREDOC, |
|
1691 REDIR_HEREDOCDASH, |
|
1692 REDIR_MERGEIN, |
|
1693 REDIR_MERGEOUT, |
|
1694 REDIR_ERRWRITE, |
|
1695 REDIR_ERRWRITENOW, |
|
1696 REDIR_ERRAPP, |
|
1697 REDIR_ERRAPPNOW, |
|
1698 REDIR_HERESTR, |
|
1699 }; |
|
1700 |
|
1701 /**/ |
|
1702 static void |
|
1703 par_redir(int *rp) |
|
1704 { |
|
1705 int r = *rp, type, fd1, oldcmdpos, oldnc; |
|
1706 char *name; |
|
1707 |
|
1708 oldcmdpos = incmdpos; |
|
1709 incmdpos = 0; |
|
1710 oldnc = nocorrect; |
|
1711 if (tok != INANG && tok != INOUTANG) |
|
1712 nocorrect = 1; |
|
1713 type = redirtab[tok - OUTANG]; |
|
1714 fd1 = tokfd; |
|
1715 yylex(); |
|
1716 if (tok != STRING && tok != ENVSTRING) |
|
1717 YYERRORV(ecused); |
|
1718 incmdpos = oldcmdpos; |
|
1719 nocorrect = oldnc; |
|
1720 |
|
1721 /* assign default fd */ |
|
1722 if (fd1 == -1) |
|
1723 fd1 = IS_READFD(type) ? 0 : 1; |
|
1724 |
|
1725 name = tokstr; |
|
1726 |
|
1727 switch (type) { |
|
1728 case REDIR_HEREDOC: |
|
1729 case REDIR_HEREDOCDASH: { |
|
1730 /* <<[-] name */ |
|
1731 struct heredocs **hd; |
|
1732 |
|
1733 /* If we ever need more than three codes (or less), we have to change |
|
1734 * the factors in par_cmd() and par_simple(), too. */ |
|
1735 ecispace(r, 3); |
|
1736 *rp = r + 3; |
|
1737 ecbuf[r] = WCB_REDIR(type); |
|
1738 ecbuf[r + 1] = fd1; |
|
1739 |
|
1740 for (hd = &hdocs; *hd; hd = &(*hd)->next); |
|
1741 *hd = zalloc(sizeof(struct heredocs)); |
|
1742 (*hd)->next = NULL; |
|
1743 (*hd)->type = type; |
|
1744 (*hd)->pc = r; |
|
1745 (*hd)->str = tokstr; |
|
1746 |
|
1747 yylex(); |
|
1748 return; |
|
1749 } |
|
1750 case REDIR_WRITE: |
|
1751 case REDIR_WRITENOW: |
|
1752 if (tokstr[0] == Outang && tokstr[1] == Inpar) |
|
1753 /* > >(...) */ |
|
1754 type = REDIR_OUTPIPE; |
|
1755 else if (tokstr[0] == Inang && tokstr[1] == Inpar) |
|
1756 YYERRORV(ecused); |
|
1757 break; |
|
1758 case REDIR_READ: |
|
1759 if (tokstr[0] == Inang && tokstr[1] == Inpar) |
|
1760 /* < <(...) */ |
|
1761 type = REDIR_INPIPE; |
|
1762 else if (tokstr[0] == Outang && tokstr[1] == Inpar) |
|
1763 YYERRORV(ecused); |
|
1764 break; |
|
1765 case REDIR_READWRITE: |
|
1766 if ((tokstr[0] == Inang || tokstr[0] == Outang) && tokstr[1] == Inpar) |
|
1767 type = tokstr[0] == Inang ? REDIR_INPIPE : REDIR_OUTPIPE; |
|
1768 break; |
|
1769 } |
|
1770 yylex(); |
|
1771 |
|
1772 /* If we ever need more than three codes (or less), we have to change |
|
1773 * the factors in par_cmd() and par_simple(), too. */ |
|
1774 ecispace(r, 3); |
|
1775 *rp = r + 3; |
|
1776 ecbuf[r] = WCB_REDIR(type); |
|
1777 ecbuf[r + 1] = fd1; |
|
1778 ecbuf[r + 2] = ecstrcode(name); |
|
1779 } |
|
1780 |
|
1781 /**/ |
|
1782 void |
|
1783 setheredoc(int pc, int type, char *str) |
|
1784 { |
|
1785 ecbuf[pc] = WCB_REDIR(type); |
|
1786 ecbuf[pc + 2] = ecstrcode(str); |
|
1787 } |
|
1788 |
|
1789 /* |
|
1790 * wordlist : { STRING } |
|
1791 */ |
|
1792 |
|
1793 /**/ |
|
1794 static int |
|
1795 par_wordlist(void) |
|
1796 { |
|
1797 int num = 0; |
|
1798 while (tok == STRING) { |
|
1799 ecstr(tokstr); |
|
1800 num++; |
|
1801 yylex(); |
|
1802 } |
|
1803 return num; |
|
1804 } |
|
1805 |
|
1806 /* |
|
1807 * nl_wordlist : { STRING | SEPER } |
|
1808 */ |
|
1809 |
|
1810 /**/ |
|
1811 static int |
|
1812 par_nl_wordlist(void) |
|
1813 { |
|
1814 int num = 0; |
|
1815 |
|
1816 while (tok == STRING || tok == SEPER) { |
|
1817 if (tok != SEPER) { |
|
1818 ecstr(tokstr); |
|
1819 num++; |
|
1820 } |
|
1821 yylex(); |
|
1822 } |
|
1823 return num; |
|
1824 } |
|
1825 |
|
1826 /* |
|
1827 * condlex is yylex for normal parsing, but is altered to allow |
|
1828 * the test builtin to use par_cond. |
|
1829 */ |
|
1830 |
|
1831 /**/ |
|
1832 void (*condlex) _((void)) = yylex; |
|
1833 |
|
1834 /* |
|
1835 * cond : cond_1 { SEPER } [ DBAR { SEPER } cond ] |
|
1836 */ |
|
1837 |
|
1838 /**/ |
|
1839 static int |
|
1840 par_cond(void) |
|
1841 { |
|
1842 int p = ecused, r; |
|
1843 |
|
1844 r = par_cond_1(); |
|
1845 while (tok == SEPER) |
|
1846 condlex(); |
|
1847 if (tok == DBAR) { |
|
1848 condlex(); |
|
1849 while (tok == SEPER) |
|
1850 condlex(); |
|
1851 ecispace(p, 1); |
|
1852 par_cond(); |
|
1853 ecbuf[p] = WCB_COND(COND_OR, ecused - 1 - p); |
|
1854 return 1; |
|
1855 } |
|
1856 return r; |
|
1857 } |
|
1858 |
|
1859 /* |
|
1860 * cond_1 : cond_2 { SEPER } [ DAMPER { SEPER } cond_1 ] |
|
1861 */ |
|
1862 |
|
1863 /**/ |
|
1864 static int |
|
1865 par_cond_1(void) |
|
1866 { |
|
1867 int r, p = ecused; |
|
1868 |
|
1869 r = par_cond_2(); |
|
1870 while (tok == SEPER) |
|
1871 condlex(); |
|
1872 if (tok == DAMPER) { |
|
1873 condlex(); |
|
1874 while (tok == SEPER) |
|
1875 condlex(); |
|
1876 ecispace(p, 1); |
|
1877 par_cond_1(); |
|
1878 ecbuf[p] = WCB_COND(COND_AND, ecused - 1 - p); |
|
1879 return 1; |
|
1880 } |
|
1881 return r; |
|
1882 } |
|
1883 |
|
1884 /* |
|
1885 * cond_2 : BANG cond_2 |
|
1886 | INPAR { SEPER } cond_2 { SEPER } OUTPAR |
|
1887 | STRING STRING STRING |
|
1888 | STRING STRING |
|
1889 | STRING ( INANG | OUTANG ) STRING |
|
1890 */ |
|
1891 |
|
1892 /**/ |
|
1893 static int |
|
1894 par_cond_2(void) |
|
1895 { |
|
1896 char *s1, *s2, *s3; |
|
1897 int dble = 0; |
|
1898 |
|
1899 if (condlex == testlex) { |
|
1900 /* See the description of test in POSIX 1003.2 */ |
|
1901 if (tok == NULLTOK) |
|
1902 /* no arguments: false */ |
|
1903 return par_cond_double(dupstring("-n"), dupstring("")); |
|
1904 if (!*testargs) { |
|
1905 /* one argument: [ foo ] is equivalent to [ -n foo ] */ |
|
1906 s1 = tokstr; |
|
1907 condlex(); |
|
1908 return par_cond_double(dupstring("-n"), s1); |
|
1909 } |
|
1910 if (testargs[1]) { |
|
1911 /* three arguments: if the second argument is a binary operator, * |
|
1912 * perform that binary test on the first and the third argument */ |
|
1913 if (!strcmp(*testargs, "=") || |
|
1914 !strcmp(*testargs, "==") || |
|
1915 !strcmp(*testargs, "!=") || |
|
1916 (**testargs == '-' && get_cond_num(*testargs + 1) >= 0)) { |
|
1917 s1 = tokstr; |
|
1918 condlex(); |
|
1919 s2 = tokstr; |
|
1920 condlex(); |
|
1921 s3 = tokstr; |
|
1922 condlex(); |
|
1923 return par_cond_triple(s1, s2, s3); |
|
1924 } |
|
1925 } |
|
1926 } |
|
1927 if (tok == BANG) { |
|
1928 condlex(); |
|
1929 ecadd(WCB_COND(COND_NOT, 0)); |
|
1930 return par_cond_2(); |
|
1931 } |
|
1932 if (tok == INPAR) { |
|
1933 int r; |
|
1934 |
|
1935 condlex(); |
|
1936 while (tok == SEPER) |
|
1937 condlex(); |
|
1938 r = par_cond(); |
|
1939 while (tok == SEPER) |
|
1940 condlex(); |
|
1941 if (tok != OUTPAR) |
|
1942 YYERROR(ecused); |
|
1943 condlex(); |
|
1944 return r; |
|
1945 } |
|
1946 if (tok != STRING) { |
|
1947 if (tok && tok != LEXERR && condlex == testlex) { |
|
1948 s1 = tokstr; |
|
1949 condlex(); |
|
1950 return par_cond_double("-n", s1); |
|
1951 } else |
|
1952 YYERROR(ecused); |
|
1953 } |
|
1954 s1 = tokstr; |
|
1955 if (condlex == testlex) |
|
1956 dble = (*s1 == '-' && strspn(s1+1, "abcdefghknoprstuwxzLONGS") == 1 |
|
1957 && !s1[2]); |
|
1958 condlex(); |
|
1959 if (tok == INANG || tok == OUTANG) { |
|
1960 int xtok = tok; |
|
1961 condlex(); |
|
1962 if (tok != STRING) |
|
1963 YYERROR(ecused); |
|
1964 s3 = tokstr; |
|
1965 condlex(); |
|
1966 ecadd(WCB_COND((xtok == INANG ? COND_STRLT : COND_STRGTR), 0)); |
|
1967 ecstr(s1); |
|
1968 ecstr(s3); |
|
1969 return 1; |
|
1970 } |
|
1971 if (tok != STRING) { |
|
1972 if (tok != LEXERR && condlex == testlex) { |
|
1973 if (!dble) |
|
1974 return par_cond_double("-n", s1); |
|
1975 else if (!strcmp(s1, "-t")) |
|
1976 return par_cond_double(s1, "1"); |
|
1977 } else |
|
1978 YYERROR(ecused); |
|
1979 } |
|
1980 s2 = tokstr; |
|
1981 incond++; /* parentheses do globbing */ |
|
1982 condlex(); |
|
1983 incond--; /* parentheses do grouping */ |
|
1984 if (tok == STRING && !dble) { |
|
1985 s3 = tokstr; |
|
1986 condlex(); |
|
1987 if (tok == STRING) { |
|
1988 LinkList l = newlinklist(); |
|
1989 |
|
1990 addlinknode(l, s2); |
|
1991 addlinknode(l, s3); |
|
1992 |
|
1993 while (tok == STRING) { |
|
1994 addlinknode(l, tokstr); |
|
1995 condlex(); |
|
1996 } |
|
1997 return par_cond_multi(s1, l); |
|
1998 } else |
|
1999 return par_cond_triple(s1, s2, s3); |
|
2000 } else |
|
2001 return par_cond_double(s1, s2); |
|
2002 } |
|
2003 |
|
2004 /**/ |
|
2005 static int |
|
2006 par_cond_double(char *a, char *b) |
|
2007 { |
|
2008 if (a[0] != '-' || !a[1]) |
|
2009 COND_ERROR("parse error: condition expected: %s", a); |
|
2010 else if (!a[2] && strspn(a+1, "abcdefgknoprstuwxzhLONGS") == 1) { |
|
2011 ecadd(WCB_COND(a[1], 0)); |
|
2012 ecstr(b); |
|
2013 } else { |
|
2014 ecadd(WCB_COND(COND_MOD, 1)); |
|
2015 ecstr(a); |
|
2016 ecstr(b); |
|
2017 } |
|
2018 return 1; |
|
2019 } |
|
2020 |
|
2021 /**/ |
|
2022 static int |
|
2023 get_cond_num(char *tst) |
|
2024 { |
|
2025 static char *condstrs[] = |
|
2026 { |
|
2027 "nt", "ot", "ef", "eq", "ne", "lt", "gt", "le", "ge", NULL |
|
2028 }; |
|
2029 int t0; |
|
2030 |
|
2031 for (t0 = 0; condstrs[t0]; t0++) |
|
2032 if (!strcmp(condstrs[t0], tst)) |
|
2033 return t0; |
|
2034 return -1; |
|
2035 } |
|
2036 |
|
2037 /**/ |
|
2038 static int |
|
2039 par_cond_triple(char *a, char *b, char *c) |
|
2040 { |
|
2041 int t0; |
|
2042 |
|
2043 if ((b[0] == Equals || b[0] == '=') && |
|
2044 (!b[1] || ((b[1] == Equals || b[1] == '=') && !b[2]))) { |
|
2045 ecadd(WCB_COND(COND_STREQ, 0)); |
|
2046 ecstr(a); |
|
2047 ecstr(c); |
|
2048 ecadd(ecnpats++); |
|
2049 } else if (b[0] == '!' && (b[1] == Equals || b[1] == '=') && !b[2]) { |
|
2050 ecadd(WCB_COND(COND_STRNEQ, 0)); |
|
2051 ecstr(a); |
|
2052 ecstr(c); |
|
2053 ecadd(ecnpats++); |
|
2054 } else if (b[0] == '-') { |
|
2055 if ((t0 = get_cond_num(b + 1)) > -1) { |
|
2056 ecadd(WCB_COND(t0 + COND_NT, 0)); |
|
2057 ecstr(a); |
|
2058 ecstr(c); |
|
2059 } else { |
|
2060 ecadd(WCB_COND(COND_MODI, 0)); |
|
2061 ecstr(b); |
|
2062 ecstr(a); |
|
2063 ecstr(c); |
|
2064 } |
|
2065 } else if (a[0] == '-' && a[1]) { |
|
2066 ecadd(WCB_COND(COND_MOD, 2)); |
|
2067 ecstr(a); |
|
2068 ecstr(b); |
|
2069 ecstr(c); |
|
2070 } else |
|
2071 COND_ERROR("condition expected: %s", b); |
|
2072 |
|
2073 return 1; |
|
2074 } |
|
2075 |
|
2076 /**/ |
|
2077 static int |
|
2078 par_cond_multi(char *a, LinkList l) |
|
2079 { |
|
2080 if (a[0] != '-' || !a[1]) |
|
2081 COND_ERROR("condition expected: %s", a); |
|
2082 else { |
|
2083 LinkNode n; |
|
2084 |
|
2085 ecadd(WCB_COND(COND_MOD, countlinknodes(l))); |
|
2086 ecstr(a); |
|
2087 for (n = firstnode(l); n; incnode(n)) |
|
2088 ecstr((char *) getdata(n)); |
|
2089 } |
|
2090 return 1; |
|
2091 } |
|
2092 |
|
2093 /**/ |
|
2094 static void |
|
2095 yyerror(int noerr) |
|
2096 { |
|
2097 int t0; |
|
2098 char *t; |
|
2099 |
|
2100 if ((t = dupstring(yytext))) |
|
2101 untokenize(t); |
|
2102 |
|
2103 for (t0 = 0; t0 != 20; t0++) |
|
2104 if (!t || !t[t0] || t[t0] == '\n') |
|
2105 break; |
|
2106 if (t0 == 20) |
|
2107 zwarn("parse error near `%l...'", t, 20); |
|
2108 else if (t0) |
|
2109 zwarn("parse error near `%l'", t, t0); |
|
2110 else |
|
2111 zwarn("parse error", NULL, 0); |
|
2112 if (!noerr && noerrs != 2) |
|
2113 errflag = 1; |
|
2114 } |
|
2115 |
|
2116 /**/ |
|
2117 mod_export Eprog |
|
2118 dupeprog(Eprog p, int heap) |
|
2119 { |
|
2120 Eprog r; |
|
2121 int i; |
|
2122 Patprog *pp; |
|
2123 |
|
2124 if (p == &dummy_eprog) |
|
2125 return p; |
|
2126 |
|
2127 r = (heap ? (Eprog) zhalloc(sizeof(*r)) : (Eprog) zalloc(sizeof(*r))); |
|
2128 r->flags = (heap ? EF_HEAP : EF_REAL) | (p->flags & EF_RUN); |
|
2129 r->dump = NULL; |
|
2130 r->len = p->len; |
|
2131 r->npats = p->npats; |
|
2132 /* |
|
2133 * If Eprog is on the heap, reference count is not valid. |
|
2134 * Otherwise, initialise reference count to 1 so that a freeeprog() |
|
2135 * will delete it if it is not in use. |
|
2136 */ |
|
2137 r->nref = heap ? -1 : 1; |
|
2138 pp = r->pats = (heap ? (Patprog *) hcalloc(r->len) : |
|
2139 (Patprog *) zshcalloc(r->len)); |
|
2140 r->prog = (Wordcode) (r->pats + r->npats); |
|
2141 r->strs = ((char *) r->prog) + (p->strs - ((char *) p->prog)); |
|
2142 memcpy(r->prog, p->prog, r->len - (p->npats * sizeof(Patprog))); |
|
2143 r->shf = NULL; |
|
2144 |
|
2145 for (i = r->npats; i--; pp++) |
|
2146 *pp = dummy_patprog1; |
|
2147 |
|
2148 return r; |
|
2149 } |
|
2150 |
|
2151 |
|
2152 /* |
|
2153 * Pair of functions to mark an Eprog as in use, and to delete it |
|
2154 * when it is no longer in use, by means of the reference count in |
|
2155 * then nref element. |
|
2156 * |
|
2157 * If nref is negative, the Eprog is on the heap and is never freed. |
|
2158 */ |
|
2159 |
|
2160 /* Increase the reference count of an Eprog so it won't be deleted. */ |
|
2161 |
|
2162 /**/ |
|
2163 mod_export void |
|
2164 useeprog(Eprog p) |
|
2165 { |
|
2166 if (p && p != &dummy_eprog && p->nref >= 0) |
|
2167 p->nref++; |
|
2168 } |
|
2169 |
|
2170 /* Free an Eprog if we have finished with it */ |
|
2171 |
|
2172 /**/ |
|
2173 mod_export void |
|
2174 freeeprog(Eprog p) |
|
2175 { |
|
2176 int i; |
|
2177 Patprog *pp; |
|
2178 |
|
2179 if (p && p != &dummy_eprog) { |
|
2180 /* paranoia */ |
|
2181 DPUTS(p->nref > 0 && (p->flags & EF_HEAP), "Heap EPROG has nref > 0"); |
|
2182 DPUTS(p->nref < 0 && !(p->flags & EF_HEAP), "Real EPROG has nref < 0"); |
|
2183 DPUTS(p->nref < -1, "Uninitialised EPROG nref"); |
|
2184 #ifdef MAX_FUNCTION_DEPTH |
|
2185 DPUTS(p->nref > MAX_FUNCTION_DEPTH + 10, "Overlarge EPROG nref"); |
|
2186 #endif |
|
2187 if (p->nref > 0 && !--p->nref) { |
|
2188 for (i = p->npats, pp = p->pats; i--; pp++) |
|
2189 freepatprog(*pp); |
|
2190 if (p->dump) { |
|
2191 decrdumpcount(p->dump); |
|
2192 zfree(p->pats, p->npats * sizeof(Patprog)); |
|
2193 } else |
|
2194 zfree(p->pats, p->len); |
|
2195 zfree(p, sizeof(*p)); |
|
2196 } |
|
2197 } |
|
2198 } |
|
2199 |
|
2200 /**/ |
|
2201 char * |
|
2202 ecgetstr(Estate s, int dup, int *tok) |
|
2203 { |
|
2204 static char buf[4]; |
|
2205 wordcode c = *s->pc++; |
|
2206 char *r; |
|
2207 |
|
2208 if (c == 6 || c == 7) |
|
2209 r = ""; |
|
2210 else if (c & 2) { |
|
2211 buf[0] = (char) ((c >> 3) & 0xff); |
|
2212 buf[1] = (char) ((c >> 11) & 0xff); |
|
2213 buf[2] = (char) ((c >> 19) & 0xff); |
|
2214 buf[3] = '\0'; |
|
2215 r = dupstring(buf); |
|
2216 dup = EC_NODUP; |
|
2217 } else { |
|
2218 r = s->strs + (c >> 2); |
|
2219 } |
|
2220 if (tok) |
|
2221 *tok = (c & 1); |
|
2222 |
|
2223 /*** Since function dump files are mapped read-only, avoiding to |
|
2224 * to duplicate strings when they don't contain tokens may fail |
|
2225 * when one of the many utility functions happens to write to |
|
2226 * one of the strings (without really modifying it). |
|
2227 * If that happens to you and you don't feel like debugging it, |
|
2228 * just change the line below to: |
|
2229 * |
|
2230 * return (dup ? dupstring(r) : r); |
|
2231 */ |
|
2232 |
|
2233 return ((dup == EC_DUP || (dup && (c & 1))) ? dupstring(r) : r); |
|
2234 } |
|
2235 |
|
2236 /**/ |
|
2237 char * |
|
2238 ecrawstr(Eprog p, Wordcode pc, int *tok) |
|
2239 { |
|
2240 static char buf[4]; |
|
2241 wordcode c = *pc; |
|
2242 |
|
2243 if (c == 6 || c == 7) { |
|
2244 if (tok) |
|
2245 *tok = (c & 1); |
|
2246 return ""; |
|
2247 } else if (c & 2) { |
|
2248 buf[0] = (char) ((c >> 3) & 0xff); |
|
2249 buf[1] = (char) ((c >> 11) & 0xff); |
|
2250 buf[2] = (char) ((c >> 19) & 0xff); |
|
2251 buf[3] = '\0'; |
|
2252 if (tok) |
|
2253 *tok = (c & 1); |
|
2254 return buf; |
|
2255 } else { |
|
2256 if (tok) |
|
2257 *tok = (c & 1); |
|
2258 return p->strs + (c >> 2); |
|
2259 } |
|
2260 } |
|
2261 |
|
2262 /**/ |
|
2263 char ** |
|
2264 ecgetarr(Estate s, int num, int dup, int *tok) |
|
2265 { |
|
2266 char **ret, **rp; |
|
2267 int tf = 0, tmp = 0; |
|
2268 |
|
2269 ret = rp = (char **) zhalloc((num + 1) * sizeof(char *)); |
|
2270 |
|
2271 while (num--) { |
|
2272 *rp++ = ecgetstr(s, dup, &tmp); |
|
2273 tf |= tmp; |
|
2274 } |
|
2275 *rp = NULL; |
|
2276 if (tok) |
|
2277 *tok = tf; |
|
2278 |
|
2279 return ret; |
|
2280 } |
|
2281 |
|
2282 /**/ |
|
2283 LinkList |
|
2284 ecgetlist(Estate s, int num, int dup, int *tok) |
|
2285 { |
|
2286 if (num) { |
|
2287 LinkList ret; |
|
2288 int i, tf = 0, tmp = 0; |
|
2289 |
|
2290 ret = newsizedlist(num); |
|
2291 for (i = 0; i < num; i++) { |
|
2292 setsizednode(ret, i, ecgetstr(s, dup, &tmp)); |
|
2293 tf |= tmp; |
|
2294 } |
|
2295 if (tok) |
|
2296 *tok = tf; |
|
2297 return ret; |
|
2298 } |
|
2299 if (tok) |
|
2300 *tok = 0; |
|
2301 return NULL; |
|
2302 } |
|
2303 |
|
2304 /**/ |
|
2305 LinkList |
|
2306 ecgetredirs(Estate s) |
|
2307 { |
|
2308 LinkList ret = newlinklist(); |
|
2309 wordcode code = *s->pc++; |
|
2310 |
|
2311 while (wc_code(code) == WC_REDIR) { |
|
2312 Redir r = (Redir) zhalloc(sizeof(*r)); |
|
2313 |
|
2314 r->type = WC_REDIR_TYPE(code); |
|
2315 r->fd1 = *s->pc++; |
|
2316 r->name = ecgetstr(s, EC_DUP, NULL); |
|
2317 |
|
2318 addlinknode(ret, r); |
|
2319 |
|
2320 code = *s->pc++; |
|
2321 } |
|
2322 s->pc--; |
|
2323 |
|
2324 return ret; |
|
2325 } |
|
2326 |
|
2327 /**/ |
|
2328 mod_export struct eprog dummy_eprog; |
|
2329 |
|
2330 static wordcode dummy_eprog_code; |
|
2331 |
|
2332 /**/ |
|
2333 void |
|
2334 init_eprog(void) |
|
2335 { |
|
2336 dummy_eprog_code = WCB_END(); |
|
2337 dummy_eprog.len = sizeof(wordcode); |
|
2338 dummy_eprog.prog = &dummy_eprog_code; |
|
2339 dummy_eprog.strs = NULL; |
|
2340 } |
|
2341 |
|
2342 /* Code for function dump files. |
|
2343 * |
|
2344 * Dump files consist of a header and the function bodies (the wordcode |
|
2345 * plus the string table) and that twice: once for the byte-order of the |
|
2346 * host the file was created on and once for the other byte-order. The |
|
2347 * header describes where the beginning of the `other' version is and it |
|
2348 * is up to the shell reading the file to decide which version it needs. |
|
2349 * This is done by checking if the first word is FD_MAGIC (then the |
|
2350 * shell reading the file has the same byte order as the one that created |
|
2351 * the file) or if it is FD_OMAGIC, then the `other' version has to be |
|
2352 * read. |
|
2353 * The header is the magic number, a word containing the flags (if the |
|
2354 * file should be mapped or read and if this header is the `other' one), |
|
2355 * the version string in a field of 40 characters and the descriptions |
|
2356 * for the functions in the dump file. |
|
2357 * |
|
2358 * NOTES: |
|
2359 * - This layout has to be kept; everything after it may be changed. |
|
2360 * - When incompatible changes are made, the FD_MAGIC and FD_OMAGIC |
|
2361 * numbers have to be changed. |
|
2362 * |
|
2363 * Each description consists of a struct fdhead followed by the name, |
|
2364 * aligned to sizeof(wordcode) (i.e. 4 bytes). |
|
2365 */ |
|
2366 |
|
2367 #include "version.h" |
|
2368 |
|
2369 #define FD_EXT ".zwc" |
|
2370 #define FD_MINMAP 4096 |
|
2371 |
|
2372 #define FD_PRELEN 12 |
|
2373 #define FD_MAGIC 0x04050607 |
|
2374 #define FD_OMAGIC 0x07060504 |
|
2375 |
|
2376 #define FDF_MAP 1 |
|
2377 #define FDF_OTHER 2 |
|
2378 |
|
2379 typedef struct fdhead *FDHead; |
|
2380 |
|
2381 struct fdhead { |
|
2382 wordcode start; /* offset to function definition */ |
|
2383 wordcode len; /* length of wordcode/strings */ |
|
2384 wordcode npats; /* number of patterns needed */ |
|
2385 wordcode strs; /* offset to strings */ |
|
2386 wordcode hlen; /* header length (incl. name) */ |
|
2387 wordcode flags; /* flags and offset to name tail */ |
|
2388 }; |
|
2389 |
|
2390 #define fdheaderlen(f) (((Wordcode) (f))[FD_PRELEN]) |
|
2391 |
|
2392 #define fdmagic(f) (((Wordcode) (f))[0]) |
|
2393 #define fdsetbyte(f,i,v) \ |
|
2394 ((((unsigned char *) (((Wordcode) (f)) + 1))[i]) = ((unsigned char) (v))) |
|
2395 #define fdbyte(f,i) ((wordcode) (((unsigned char *) (((Wordcode) (f)) + 1))[i])) |
|
2396 #define fdflags(f) fdbyte(f, 0) |
|
2397 #define fdsetflags(f,v) fdsetbyte(f, 0, v) |
|
2398 #define fdother(f) (fdbyte(f, 1) + (fdbyte(f, 2) << 8) + (fdbyte(f, 3) << 16)) |
|
2399 #define fdsetother(f, o) \ |
|
2400 do { \ |
|
2401 fdsetbyte(f, 1, ((o) & 0xff)); \ |
|
2402 fdsetbyte(f, 2, (((o) >> 8) & 0xff)); \ |
|
2403 fdsetbyte(f, 3, (((o) >> 16) & 0xff)); \ |
|
2404 } while (0) |
|
2405 #define fdversion(f) ((char *) ((f) + 2)) |
|
2406 |
|
2407 #define firstfdhead(f) ((FDHead) (((Wordcode) (f)) + FD_PRELEN)) |
|
2408 #define nextfdhead(f) ((FDHead) (((Wordcode) (f)) + (f)->hlen)) |
|
2409 |
|
2410 #define fdhflags(f) (((FDHead) (f))->flags) |
|
2411 #define fdhtail(f) (((FDHead) (f))->flags >> 2) |
|
2412 #define fdhbldflags(f,t) ((f) | ((t) << 2)) |
|
2413 |
|
2414 #define FDHF_KSHLOAD 1 |
|
2415 #define FDHF_ZSHLOAD 2 |
|
2416 |
|
2417 #define fdname(f) ((char *) (((FDHead) (f)) + 1)) |
|
2418 |
|
2419 /* This is used when building wordcode files. */ |
|
2420 |
|
2421 typedef struct wcfunc *WCFunc; |
|
2422 |
|
2423 struct wcfunc { |
|
2424 char *name; |
|
2425 Eprog prog; |
|
2426 int flags; |
|
2427 }; |
|
2428 |
|
2429 /* Try to find the description for the given function name. */ |
|
2430 |
|
2431 static FDHead |
|
2432 dump_find_func(Wordcode h, char *name) |
|
2433 { |
|
2434 FDHead n, e = (FDHead) (h + fdheaderlen(h)); |
|
2435 |
|
2436 for (n = firstfdhead(h); n < e; n = nextfdhead(n)) |
|
2437 if (!strcmp(name, fdname(n) + fdhtail(n))) |
|
2438 return n; |
|
2439 |
|
2440 return NULL; |
|
2441 } |
|
2442 #ifndef __SYMBIAN32__ |
|
2443 /**/ |
|
2444 int |
|
2445 bin_zcompile(char *nam, char **args, Options ops, UNUSED(int func)) |
|
2446 { |
|
2447 int map, flags, ret; |
|
2448 char *dump; |
|
2449 #ifdef __SYMBIAN32__ |
|
2450 func=func; |
|
2451 #endif |
|
2452 if ((OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) || |
|
2453 (OPT_ISSET(ops,'R') && OPT_ISSET(ops,'M')) || |
|
2454 (OPT_ISSET(ops,'c') && |
|
2455 (OPT_ISSET(ops,'U') || OPT_ISSET(ops,'k') || OPT_ISSET(ops,'z'))) || |
|
2456 (!(OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a')) && OPT_ISSET(ops,'m'))) { |
|
2457 zwarnnam(nam, "illegal combination of options", NULL, 0); |
|
2458 return 1; |
|
2459 } |
|
2460 if ((OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a')) && isset(KSHAUTOLOAD)) |
|
2461 zwarnnam(nam, "functions will use zsh style autoloading", NULL, 0); |
|
2462 |
|
2463 flags = (OPT_ISSET(ops,'k') ? FDHF_KSHLOAD : |
|
2464 (OPT_ISSET(ops,'z') ? FDHF_ZSHLOAD : 0)); |
|
2465 |
|
2466 if (OPT_ISSET(ops,'t')) { |
|
2467 Wordcode f; |
|
2468 |
|
2469 if (!*args) { |
|
2470 zwarnnam(nam, "too few arguments", NULL, 0); |
|
2471 return 1; |
|
2472 } |
|
2473 if (!(f = load_dump_header(nam, (strsfx(FD_EXT, *args) ? *args : |
|
2474 dyncat(*args, FD_EXT)), 1))) |
|
2475 return 1; |
|
2476 |
|
2477 if (args[1]) { |
|
2478 for (args++; *args; args++) |
|
2479 if (!dump_find_func(f, *args)) |
|
2480 return 1; |
|
2481 return 0; |
|
2482 } else { |
|
2483 FDHead h, e = (FDHead) (f + fdheaderlen(f)); |
|
2484 |
|
2485 printf("zwc file (%s) for zsh-%s\n", |
|
2486 ((fdflags(f) & FDF_MAP) ? "mapped" : "read"), fdversion(f)); |
|
2487 for (h = firstfdhead(f); h < e; h = nextfdhead(h)) |
|
2488 printf("%s\n", fdname(h)); |
|
2489 return 0; |
|
2490 } |
|
2491 } |
|
2492 if (!*args) { |
|
2493 zwarnnam(nam, "too few arguments", NULL, 0); |
|
2494 return 1; |
|
2495 } |
|
2496 map = (OPT_ISSET(ops,'M') ? 2 : (OPT_ISSET(ops,'R') ? 0 : 1)); |
|
2497 |
|
2498 if (!args[1] && !(OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a'))) { |
|
2499 queue_signals(); |
|
2500 ret = build_dump(nam, dyncat(*args, FD_EXT), args, OPT_ISSET(ops,'U'), |
|
2501 map, flags); |
|
2502 unqueue_signals(); |
|
2503 return ret; |
|
2504 } |
|
2505 dump = (strsfx(FD_EXT, *args) ? *args : dyncat(*args, FD_EXT)); |
|
2506 |
|
2507 queue_signals(); |
|
2508 ret = ((OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a')) ? |
|
2509 build_cur_dump(nam, dump, args + 1, OPT_ISSET(ops,'m'), map, |
|
2510 (OPT_ISSET(ops,'c') ? 1 : 0) | |
|
2511 (OPT_ISSET(ops,'a') ? 2 : 0)) : |
|
2512 build_dump(nam, dump, args + 1, OPT_ISSET(ops,'U'), map, flags)); |
|
2513 unqueue_signals(); |
|
2514 |
|
2515 return ret; |
|
2516 } |
|
2517 #endif //__SYMBIAN32__ |
|
2518 |
|
2519 /* Load the header of a dump file. Returns NULL if the file isn't a |
|
2520 * valid dump file. */ |
|
2521 |
|
2522 /**/ |
|
2523 static Wordcode |
|
2524 load_dump_header(char *nam, char *name, int err) |
|
2525 { |
|
2526 int fd, v = 0; |
|
2527 wordcode buf[FD_PRELEN + 1]; |
|
2528 |
|
2529 if ((fd = open(name, O_RDONLY)) < 0) { |
|
2530 if (err) |
|
2531 zwarnnam(nam, "can't open zwc file: %s", name, 0); |
|
2532 return NULL; |
|
2533 } |
|
2534 if (read(fd, buf, (FD_PRELEN + 1) * sizeof(wordcode)) != |
|
2535 ((FD_PRELEN + 1) * sizeof(wordcode)) || |
|
2536 (v = (fdmagic(buf) != FD_MAGIC && fdmagic(buf) != FD_OMAGIC))) { |
|
2537 if (err) { |
|
2538 if (v) { |
|
2539 char msg[80]; |
|
2540 |
|
2541 sprintf(msg, "zwc file has wrong version (zsh-%s): %%s", |
|
2542 fdversion(buf)); |
|
2543 zwarnnam(nam, msg , name, 0); |
|
2544 } else |
|
2545 zwarnnam(nam, "invalid zwc file: %s" , name, 0); |
|
2546 } |
|
2547 close(fd); |
|
2548 return NULL; |
|
2549 } else { |
|
2550 int len; |
|
2551 Wordcode head; |
|
2552 |
|
2553 if (fdmagic(buf) == FD_MAGIC) { |
|
2554 len = fdheaderlen(buf) * sizeof(wordcode); |
|
2555 head = (Wordcode) zhalloc(len); |
|
2556 } |
|
2557 else { |
|
2558 int o = fdother(buf); |
|
2559 |
|
2560 if (lseek(fd, o, 0) == -1 || |
|
2561 read(fd, buf, (FD_PRELEN + 1) * sizeof(wordcode)) != |
|
2562 ((FD_PRELEN + 1) * sizeof(wordcode))) { |
|
2563 zwarnnam(nam, "invalid zwc file: %s" , name, 0); |
|
2564 close(fd); |
|
2565 return NULL; |
|
2566 } |
|
2567 len = fdheaderlen(buf) * sizeof(wordcode); |
|
2568 head = (Wordcode) zhalloc(len); |
|
2569 } |
|
2570 memcpy(head, buf, (FD_PRELEN + 1) * sizeof(wordcode)); |
|
2571 |
|
2572 len -= (FD_PRELEN + 1) * sizeof(wordcode); |
|
2573 if (read(fd, head + (FD_PRELEN + 1), len) != len) { |
|
2574 close(fd); |
|
2575 zwarnnam(nam, "invalid zwc file: %s" , name, 0); |
|
2576 return NULL; |
|
2577 } |
|
2578 close(fd); |
|
2579 return head; |
|
2580 } |
|
2581 } |
|
2582 |
|
2583 /* Swap the bytes in a wordcode. */ |
|
2584 |
|
2585 static void |
|
2586 fdswap(Wordcode p, int n) |
|
2587 { |
|
2588 wordcode c; |
|
2589 |
|
2590 for (; n--; p++) { |
|
2591 c = *p; |
|
2592 *p = (((c & 0xff) << 24) | |
|
2593 ((c & 0xff00) << 8) | |
|
2594 ((c & 0xff0000) >> 8) | |
|
2595 ((c & 0xff000000) >> 24)); |
|
2596 } |
|
2597 } |
|
2598 |
|
2599 /* Write a dump file. */ |
|
2600 |
|
2601 static void |
|
2602 write_dump(int dfd, LinkList progs, int map, int hlen, int tlen) |
|
2603 { |
|
2604 LinkNode node; |
|
2605 WCFunc wcf; |
|
2606 int other = 0, ohlen, tmp; |
|
2607 wordcode pre[FD_PRELEN]; |
|
2608 char *tail, *n; |
|
2609 struct fdhead head; |
|
2610 Eprog prog; |
|
2611 |
|
2612 if (map == 1) |
|
2613 map = (tlen >= FD_MINMAP); |
|
2614 |
|
2615 for (ohlen = hlen; ; hlen = ohlen) { |
|
2616 fdmagic(pre) = (other ? FD_OMAGIC : FD_MAGIC); |
|
2617 fdsetflags(pre, ((map ? FDF_MAP : 0) | other)); |
|
2618 fdsetother(pre, tlen); |
|
2619 strcpy(fdversion(pre), ZSH_VERSION); |
|
2620 write(dfd, pre, FD_PRELEN * sizeof(wordcode)); |
|
2621 |
|
2622 for (node = firstnode(progs); node; incnode(node)) { |
|
2623 wcf = (WCFunc) getdata(node); |
|
2624 n = wcf->name; |
|
2625 prog = wcf->prog; |
|
2626 head.start = hlen; |
|
2627 hlen += (prog->len - (prog->npats * sizeof(Patprog)) + |
|
2628 sizeof(wordcode) - 1) / sizeof(wordcode); |
|
2629 head.len = prog->len - (prog->npats * sizeof(Patprog)); |
|
2630 head.npats = prog->npats; |
|
2631 head.strs = prog->strs - ((char *) prog->prog); |
|
2632 head.hlen = (sizeof(struct fdhead) / sizeof(wordcode)) + |
|
2633 (strlen(n) + sizeof(wordcode)) / sizeof(wordcode); |
|
2634 if ((tail = strrchr(n, '/'))) |
|
2635 tail++; |
|
2636 else |
|
2637 tail = n; |
|
2638 head.flags = fdhbldflags(wcf->flags, (tail - n)); |
|
2639 if (other) |
|
2640 fdswap((Wordcode) &head, sizeof(head) / sizeof(wordcode)); |
|
2641 write(dfd, &head, sizeof(head)); |
|
2642 tmp = strlen(n) + 1; |
|
2643 write(dfd, n, tmp); |
|
2644 if ((tmp &= (sizeof(wordcode) - 1))) |
|
2645 write(dfd, &head, sizeof(wordcode) - tmp); |
|
2646 } |
|
2647 for (node = firstnode(progs); node; incnode(node)) { |
|
2648 prog = ((WCFunc) getdata(node))->prog; |
|
2649 tmp = (prog->len - (prog->npats * sizeof(Patprog)) + |
|
2650 sizeof(wordcode) - 1) / sizeof(wordcode); |
|
2651 if (other) |
|
2652 fdswap(prog->prog, (((Wordcode) prog->strs) - prog->prog)); |
|
2653 write(dfd, prog->prog, tmp * sizeof(wordcode)); |
|
2654 } |
|
2655 if (other) |
|
2656 break; |
|
2657 other = FDF_OTHER; |
|
2658 } |
|
2659 } |
|
2660 |
|
2661 /**/ |
|
2662 static int |
|
2663 build_dump(char *nam, char *dump, char **files, int ali, int map, int flags) |
|
2664 { |
|
2665 int dfd, fd, hlen, tlen, flen, ona = noaliases; |
|
2666 LinkList progs; |
|
2667 char *file; |
|
2668 Eprog prog; |
|
2669 WCFunc wcf; |
|
2670 |
|
2671 if (!strsfx(FD_EXT, dump)) |
|
2672 dump = dyncat(dump, FD_EXT); |
|
2673 |
|
2674 unlink(dump); |
|
2675 if ((dfd = open(dump, O_WRONLY|O_CREAT, 0444)) < 0) { |
|
2676 zwarnnam(nam, "can't write zwc file: %s", dump, 0); |
|
2677 return 1; |
|
2678 } |
|
2679 progs = newlinklist(); |
|
2680 noaliases = ali; |
|
2681 |
|
2682 for (hlen = FD_PRELEN, tlen = 0; *files; files++) { |
|
2683 if (!strcmp(*files, "-k")) { |
|
2684 flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_KSHLOAD; |
|
2685 continue; |
|
2686 } else if (!strcmp(*files, "-z")) { |
|
2687 flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_ZSHLOAD; |
|
2688 continue; |
|
2689 } |
|
2690 if ((fd = open(*files, O_RDONLY)) < 0 || |
|
2691 (flen = lseek(fd, 0, 2)) == -1) { |
|
2692 if (fd >= 0) |
|
2693 close(fd); |
|
2694 close(dfd); |
|
2695 zwarnnam(nam, "can't open file: %s", *files, 0); |
|
2696 noaliases = ona; |
|
2697 unlink(dump); |
|
2698 return 1; |
|
2699 } |
|
2700 file = (char *) zalloc(flen + 1); |
|
2701 file[flen] = '\0'; |
|
2702 lseek(fd, 0, 0); |
|
2703 if (read(fd, file, flen) != flen) { |
|
2704 close(fd); |
|
2705 close(dfd); |
|
2706 zfree(file, flen); |
|
2707 zwarnnam(nam, "can't read file: %s", *files, 0); |
|
2708 noaliases = ona; |
|
2709 unlink(dump); |
|
2710 return 1; |
|
2711 } |
|
2712 close(fd); |
|
2713 file = metafy(file, flen, META_REALLOC); |
|
2714 |
|
2715 if (!(prog = parse_string(file)) || errflag) { |
|
2716 errflag = 0; |
|
2717 close(dfd); |
|
2718 zfree(file, flen); |
|
2719 zwarnnam(nam, "can't read file: %s", *files, 0); |
|
2720 noaliases = ona; |
|
2721 unlink(dump); |
|
2722 return 1; |
|
2723 } |
|
2724 zfree(file, flen); |
|
2725 |
|
2726 wcf = (WCFunc) zhalloc(sizeof(*wcf)); |
|
2727 wcf->name = *files; |
|
2728 wcf->prog = prog; |
|
2729 wcf->flags = ((prog->flags & EF_RUN) ? FDHF_KSHLOAD : flags); |
|
2730 addlinknode(progs, wcf); |
|
2731 |
|
2732 flen = (strlen(*files) + sizeof(wordcode)) / sizeof(wordcode); |
|
2733 hlen += (sizeof(struct fdhead) / sizeof(wordcode)) + flen; |
|
2734 |
|
2735 tlen += (prog->len - (prog->npats * sizeof(Patprog)) + |
|
2736 sizeof(wordcode) - 1) / sizeof(wordcode); |
|
2737 } |
|
2738 noaliases = ona; |
|
2739 |
|
2740 tlen = (tlen + hlen) * sizeof(wordcode); |
|
2741 |
|
2742 write_dump(dfd, progs, map, hlen, tlen); |
|
2743 |
|
2744 close(dfd); |
|
2745 |
|
2746 return 0; |
|
2747 } |
|
2748 |
|
2749 static int |
|
2750 cur_add_func(char *nam, Shfunc shf, LinkList names, LinkList progs, |
|
2751 int *hlen, int *tlen, int what) |
|
2752 { |
|
2753 Eprog prog; |
|
2754 WCFunc wcf; |
|
2755 |
|
2756 if (shf->flags & PM_UNDEFINED) { |
|
2757 int ona = noaliases; |
|
2758 |
|
2759 if (!(what & 2)) { |
|
2760 zwarnnam(nam, "function is not loaded: %s", shf->nam, 0); |
|
2761 return 1; |
|
2762 } |
|
2763 noaliases = (shf->flags & PM_UNALIASED); |
|
2764 if (!(prog = getfpfunc(shf->nam, NULL)) || prog == &dummy_eprog) { |
|
2765 noaliases = ona; |
|
2766 zwarnnam(nam, "can't load function: %s", shf->nam, 0); |
|
2767 return 1; |
|
2768 } |
|
2769 if (prog->dump) |
|
2770 prog = dupeprog(prog, 1); |
|
2771 noaliases = ona; |
|
2772 } else { |
|
2773 if (!(what & 1)) { |
|
2774 zwarnnam(nam, "function is already loaded: %s", shf->nam, 0); |
|
2775 return 1; |
|
2776 } |
|
2777 prog = dupeprog(shf->funcdef, 1); |
|
2778 } |
|
2779 wcf = (WCFunc) zhalloc(sizeof(*wcf)); |
|
2780 wcf->name = shf->nam; |
|
2781 wcf->prog = prog; |
|
2782 wcf->flags = ((prog->flags & EF_RUN) ? FDHF_KSHLOAD : FDHF_ZSHLOAD); |
|
2783 addlinknode(progs, wcf); |
|
2784 addlinknode(names, shf->nam); |
|
2785 |
|
2786 *hlen += ((sizeof(struct fdhead) / sizeof(wordcode)) + |
|
2787 ((strlen(shf->nam) + sizeof(wordcode)) / sizeof(wordcode))); |
|
2788 *tlen += (prog->len - (prog->npats * sizeof(Patprog)) + |
|
2789 sizeof(wordcode) - 1) / sizeof(wordcode); |
|
2790 |
|
2791 return 0; |
|
2792 } |
|
2793 |
|
2794 /**/ |
|
2795 static int |
|
2796 build_cur_dump(char *nam, char *dump, char **names, int match, int map, |
|
2797 int what) |
|
2798 { |
|
2799 int dfd, hlen, tlen; |
|
2800 LinkList progs, lnames; |
|
2801 Shfunc shf = NULL; |
|
2802 |
|
2803 if (!strsfx(FD_EXT, dump)) |
|
2804 dump = dyncat(dump, FD_EXT); |
|
2805 |
|
2806 unlink(dump); |
|
2807 if ((dfd = open(dump, O_WRONLY|O_CREAT, 0444)) < 0) { |
|
2808 zwarnnam(nam, "can't write zwc file: %s", dump, 0); |
|
2809 return 1; |
|
2810 } |
|
2811 progs = newlinklist(); |
|
2812 lnames = newlinklist(); |
|
2813 |
|
2814 hlen = FD_PRELEN; |
|
2815 tlen = 0; |
|
2816 |
|
2817 if (!*names) { |
|
2818 int i; |
|
2819 HashNode hn; |
|
2820 |
|
2821 for (i = 0; i < shfunctab->hsize; i++) |
|
2822 for (hn = shfunctab->nodes[i]; hn; hn = hn->next) |
|
2823 if (cur_add_func(nam, (Shfunc) hn, lnames, progs, |
|
2824 &hlen, &tlen, what)) { |
|
2825 errflag = 0; |
|
2826 close(dfd); |
|
2827 unlink(dump); |
|
2828 return 1; |
|
2829 } |
|
2830 } else if (match) { |
|
2831 char *pat; |
|
2832 Patprog pprog; |
|
2833 int i; |
|
2834 HashNode hn; |
|
2835 |
|
2836 for (; *names; names++) { |
|
2837 tokenize(pat = dupstring(*names)); |
|
2838 if (!(pprog = patcompile(pat, PAT_STATIC, NULL))) { |
|
2839 zwarnnam(nam, "bad pattern: %s", *names, 0); |
|
2840 close(dfd); |
|
2841 unlink(dump); |
|
2842 return 1; |
|
2843 } |
|
2844 for (i = 0; i < shfunctab->hsize; i++) |
|
2845 for (hn = shfunctab->nodes[i]; hn; hn = hn->next) |
|
2846 if (!listcontains(lnames, hn->nam) && |
|
2847 pattry(pprog, hn->nam) && |
|
2848 cur_add_func(nam, (Shfunc) hn, lnames, progs, |
|
2849 &hlen, &tlen, what)) { |
|
2850 errflag = 0; |
|
2851 close(dfd); |
|
2852 unlink(dump); |
|
2853 return 1; |
|
2854 } |
|
2855 } |
|
2856 } else { |
|
2857 for (; *names; names++) { |
|
2858 if (errflag || |
|
2859 !(shf = (Shfunc) shfunctab->getnode(shfunctab, *names))) { |
|
2860 zwarnnam(nam, "unknown function: %s", *names, 0); |
|
2861 errflag = 0; |
|
2862 close(dfd); |
|
2863 unlink(dump); |
|
2864 return 1; |
|
2865 } |
|
2866 if (cur_add_func(nam, shf, lnames, progs, &hlen, &tlen, what)) { |
|
2867 errflag = 0; |
|
2868 close(dfd); |
|
2869 unlink(dump); |
|
2870 return 1; |
|
2871 } |
|
2872 } |
|
2873 } |
|
2874 if (empty(progs)) { |
|
2875 zwarnnam(nam, "no functions", NULL, 0); |
|
2876 errflag = 0; |
|
2877 close(dfd); |
|
2878 unlink(dump); |
|
2879 return 1; |
|
2880 } |
|
2881 tlen = (tlen + hlen) * sizeof(wordcode); |
|
2882 |
|
2883 write_dump(dfd, progs, map, hlen, tlen); |
|
2884 |
|
2885 close(dfd); |
|
2886 |
|
2887 return 0; |
|
2888 } |
|
2889 |
|
2890 #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP) && defined(HAVE_MUNMAP) |
|
2891 |
|
2892 #include <sys/mman.h> |
|
2893 |
|
2894 #if defined(MAP_SHARED) && defined(PROT_READ) |
|
2895 |
|
2896 #define USE_MMAP 1 |
|
2897 |
|
2898 #endif |
|
2899 #endif |
|
2900 |
|
2901 #ifdef USE_MMAP |
|
2902 |
|
2903 /* List of dump files mapped. */ |
|
2904 |
|
2905 static FuncDump dumps; |
|
2906 |
|
2907 /**/ |
|
2908 static int |
|
2909 zwcstat(char *filename, struct stat *buf, FuncDump dumps) |
|
2910 { |
|
2911 if (stat(filename, buf)) { |
|
2912 #ifdef HAVE_FSTAT |
|
2913 FuncDump f; |
|
2914 |
|
2915 for (f = dumps; f; f = f->next) { |
|
2916 if (!strncmp(filename, f->filename, strlen(f->filename)) && |
|
2917 !fstat(f->fd, buf)) |
|
2918 return 0; |
|
2919 } |
|
2920 #endif |
|
2921 return 1; |
|
2922 } else return 0; |
|
2923 } |
|
2924 |
|
2925 /* Load a dump file (i.e. map it). */ |
|
2926 |
|
2927 static void |
|
2928 load_dump_file(char *dump, struct stat *sbuf, int other, int len) |
|
2929 { |
|
2930 FuncDump d; |
|
2931 Wordcode addr; |
|
2932 int fd, off, mlen; |
|
2933 |
|
2934 if (other) { |
|
2935 static size_t pgsz = 0; |
|
2936 |
|
2937 if (!pgsz) { |
|
2938 |
|
2939 #ifdef _SC_PAGESIZE |
|
2940 pgsz = sysconf(_SC_PAGESIZE); /* SVR4 */ |
|
2941 #else |
|
2942 # ifdef _SC_PAGE_SIZE |
|
2943 pgsz = sysconf(_SC_PAGE_SIZE); /* HPUX */ |
|
2944 # else |
|
2945 pgsz = getpagesize(); |
|
2946 # endif |
|
2947 #endif |
|
2948 |
|
2949 pgsz--; |
|
2950 } |
|
2951 off = len & ~pgsz; |
|
2952 mlen = len + (len - off); |
|
2953 } else { |
|
2954 off = 0; |
|
2955 mlen = len; |
|
2956 } |
|
2957 if ((fd = open(dump, O_RDONLY)) < 0) |
|
2958 return; |
|
2959 |
|
2960 fd = movefd(fd); |
|
2961 |
|
2962 if ((addr = (Wordcode) mmap(NULL, mlen, PROT_READ, MAP_SHARED, fd, off)) == |
|
2963 ((Wordcode) -1)) { |
|
2964 close(fd); |
|
2965 return; |
|
2966 } |
|
2967 d = (FuncDump) zalloc(sizeof(*d)); |
|
2968 d->next = dumps; |
|
2969 dumps = d; |
|
2970 d->dev = sbuf->st_dev; |
|
2971 d->ino = sbuf->st_ino; |
|
2972 d->fd = fd; |
|
2973 d->map = addr + (other ? (len - off) / sizeof(wordcode) : 0); |
|
2974 d->addr = addr; |
|
2975 d->len = len; |
|
2976 d->count = 0; |
|
2977 d->filename = ztrdup(dump); |
|
2978 } |
|
2979 |
|
2980 #else |
|
2981 |
|
2982 #define zwcstat(f, b, d) stat(f, b) |
|
2983 |
|
2984 #endif |
|
2985 |
|
2986 /* Try to load a function from one of the possible wordcode files for it. |
|
2987 * The first argument is a element of $fpath, the second one is the name |
|
2988 * of the function searched and the last one is the possible name for the |
|
2989 * uncompiled function file (<path>/<func>). */ |
|
2990 |
|
2991 /**/ |
|
2992 Eprog |
|
2993 try_dump_file(char *path, char *name, char *file, int *ksh) |
|
2994 { |
|
2995 Eprog prog; |
|
2996 struct stat std, stc, stn; |
|
2997 int rd, rc, rn; |
|
2998 char *dig, *wc; |
|
2999 |
|
3000 if (strsfx(FD_EXT, path)) { |
|
3001 queue_signals(); |
|
3002 prog = check_dump_file(path, NULL, name, ksh); |
|
3003 unqueue_signals(); |
|
3004 return prog; |
|
3005 } |
|
3006 dig = dyncat(path, FD_EXT); |
|
3007 wc = dyncat(file, FD_EXT); |
|
3008 |
|
3009 rd = zwcstat(dig, &std, dumps); |
|
3010 rc = stat(wc, &stc); |
|
3011 rn = stat(file, &stn); |
|
3012 |
|
3013 /* See if there is a digest file for the directory, it is younger than |
|
3014 * both the uncompiled function file and its compiled version (or they |
|
3015 * don't exist) and the digest file contains the definition for the |
|
3016 * function. */ |
|
3017 queue_signals(); |
|
3018 if (!rd && |
|
3019 (rc || std.st_mtime > stc.st_mtime) && |
|
3020 (rn || std.st_mtime > stn.st_mtime) && |
|
3021 (prog = check_dump_file(dig, &std, name, ksh))) { |
|
3022 unqueue_signals(); |
|
3023 return prog; |
|
3024 } |
|
3025 /* No digest file. Now look for the per-function compiled file. */ |
|
3026 if (!rc && |
|
3027 (rn || stc.st_mtime > stn.st_mtime) && |
|
3028 (prog = check_dump_file(wc, &stc, name, ksh))) { |
|
3029 unqueue_signals(); |
|
3030 return prog; |
|
3031 } |
|
3032 /* No compiled file for the function. The caller (getfpfunc() will |
|
3033 * check if the directory contains the uncompiled file for it. */ |
|
3034 unqueue_signals(); |
|
3035 return NULL; |
|
3036 } |
|
3037 |
|
3038 /* Almost the same, but for sourced files. */ |
|
3039 |
|
3040 /**/ |
|
3041 Eprog |
|
3042 try_source_file(char *file) |
|
3043 { |
|
3044 Eprog prog; |
|
3045 struct stat stc, stn; |
|
3046 int rc, rn; |
|
3047 char *wc, *tail; |
|
3048 |
|
3049 if ((tail = strrchr(file, '/')) || (tail = strrchr(file, '\\'))) |
|
3050 tail++; |
|
3051 else |
|
3052 tail = file; |
|
3053 |
|
3054 if (strsfx(FD_EXT, file)) { |
|
3055 queue_signals(); |
|
3056 prog = check_dump_file(file, NULL, tail, NULL); |
|
3057 unqueue_signals(); |
|
3058 return prog; |
|
3059 } |
|
3060 wc = dyncat(file, FD_EXT); |
|
3061 |
|
3062 rc = stat(wc, &stc); |
|
3063 rn = stat(file, &stn); |
|
3064 |
|
3065 queue_signals(); |
|
3066 if (!rc && (rn || stc.st_mtime > stn.st_mtime) && |
|
3067 (prog = check_dump_file(wc, &stc, tail, NULL))) { |
|
3068 unqueue_signals(); |
|
3069 return prog; |
|
3070 } |
|
3071 unqueue_signals(); |
|
3072 return NULL; |
|
3073 } |
|
3074 |
|
3075 /* See if `file' names a wordcode dump file and that contains the |
|
3076 * definition for the function `name'. If so, return an eprog for it. */ |
|
3077 |
|
3078 /**/ |
|
3079 static Eprog |
|
3080 check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh) |
|
3081 { |
|
3082 int isrec = 0; |
|
3083 Wordcode d; |
|
3084 FDHead h; |
|
3085 FuncDump f; |
|
3086 struct stat lsbuf; |
|
3087 |
|
3088 if (!sbuf) { |
|
3089 if (zwcstat(file, &lsbuf, dumps)) |
|
3090 return NULL; |
|
3091 sbuf = &lsbuf; |
|
3092 } |
|
3093 |
|
3094 #ifdef USE_MMAP |
|
3095 |
|
3096 rec: |
|
3097 |
|
3098 #endif |
|
3099 |
|
3100 d = NULL; |
|
3101 |
|
3102 #ifdef USE_MMAP |
|
3103 |
|
3104 for (f = dumps; f; f = f->next) |
|
3105 if (f->dev == sbuf->st_dev && f->ino == sbuf->st_ino) { |
|
3106 d = f->map; |
|
3107 break; |
|
3108 } |
|
3109 |
|
3110 #else |
|
3111 |
|
3112 f = NULL; |
|
3113 |
|
3114 #endif |
|
3115 |
|
3116 if (!f && (isrec || !(d = load_dump_header(NULL, file, 0)))) |
|
3117 return NULL; |
|
3118 |
|
3119 if ((h = dump_find_func(d, name))) { |
|
3120 /* Found the name. If the file is already mapped, return the eprog, |
|
3121 * otherwise map it and just go up. */ |
|
3122 |
|
3123 #ifdef USE_MMAP |
|
3124 |
|
3125 if (f) { |
|
3126 Eprog prog = (Eprog) zalloc(sizeof(*prog)); |
|
3127 Patprog *pp; |
|
3128 int np; |
|
3129 |
|
3130 prog->flags = EF_MAP; |
|
3131 prog->len = h->len; |
|
3132 prog->npats = np = h->npats; |
|
3133 prog->nref = 1; /* allocated from permanent storage */ |
|
3134 prog->pats = pp = (Patprog *) zalloc(np * sizeof(Patprog)); |
|
3135 prog->prog = f->map + h->start; |
|
3136 prog->strs = ((char *) prog->prog) + h->strs; |
|
3137 prog->shf = NULL; |
|
3138 prog->dump = f; |
|
3139 |
|
3140 incrdumpcount(f); |
|
3141 |
|
3142 while (np--) |
|
3143 *pp++ = dummy_patprog1; |
|
3144 |
|
3145 if (ksh) |
|
3146 *ksh = ((fdhflags(h) & FDHF_KSHLOAD) ? 2 : |
|
3147 ((fdhflags(h) & FDHF_ZSHLOAD) ? 0 : 1)); |
|
3148 |
|
3149 return prog; |
|
3150 } else if (fdflags(d) & FDF_MAP) { |
|
3151 load_dump_file(file, sbuf, (fdflags(d) & FDF_OTHER), fdother(d)); |
|
3152 isrec = 1; |
|
3153 goto rec; |
|
3154 } else |
|
3155 |
|
3156 #endif |
|
3157 |
|
3158 { |
|
3159 Eprog prog; |
|
3160 Patprog *pp; |
|
3161 int np, fd, po = h->npats * sizeof(Patprog); |
|
3162 |
|
3163 if ((fd = open(file, O_RDONLY)) < 0 || |
|
3164 lseek(fd, ((h->start * sizeof(wordcode)) + |
|
3165 ((fdflags(d) & FDF_OTHER) ? fdother(d) : 0)), 0) < 0) { |
|
3166 if (fd >= 0) |
|
3167 close(fd); |
|
3168 return NULL; |
|
3169 } |
|
3170 d = (Wordcode) zalloc(h->len + po); |
|
3171 |
|
3172 if (read(fd, ((char *) d) + po, h->len) != (int)h->len) { |
|
3173 close(fd); |
|
3174 zfree(d, h->len); |
|
3175 |
|
3176 return NULL; |
|
3177 } |
|
3178 close(fd); |
|
3179 |
|
3180 prog = (Eprog) zalloc(sizeof(*prog)); |
|
3181 |
|
3182 prog->flags = EF_REAL; |
|
3183 prog->len = h->len + po; |
|
3184 prog->npats = np = h->npats; |
|
3185 prog->nref = 1; /* allocated from permanent storage */ |
|
3186 prog->pats = pp = (Patprog *) d; |
|
3187 prog->prog = (Wordcode) (((char *) d) + po); |
|
3188 prog->strs = ((char *) prog->prog) + h->strs; |
|
3189 prog->shf = NULL; |
|
3190 prog->dump = f; |
|
3191 |
|
3192 while (np--) |
|
3193 *pp++ = dummy_patprog1; |
|
3194 |
|
3195 if (ksh) |
|
3196 *ksh = ((fdhflags(h) & FDHF_KSHLOAD) ? 2 : |
|
3197 ((fdhflags(h) & FDHF_ZSHLOAD) ? 0 : 1)); |
|
3198 |
|
3199 return prog; |
|
3200 } |
|
3201 } |
|
3202 return NULL; |
|
3203 } |
|
3204 |
|
3205 #ifdef USE_MMAP |
|
3206 |
|
3207 /* Increment the reference counter for a dump file. */ |
|
3208 |
|
3209 /**/ |
|
3210 void |
|
3211 incrdumpcount(FuncDump f) |
|
3212 { |
|
3213 f->count++; |
|
3214 } |
|
3215 |
|
3216 /* Decrement the reference counter for a dump file. If zero, unmap the file. */ |
|
3217 |
|
3218 /**/ |
|
3219 void |
|
3220 decrdumpcount(FuncDump f) |
|
3221 { |
|
3222 f->count--; |
|
3223 if (!f->count) { |
|
3224 FuncDump p, q; |
|
3225 |
|
3226 for (q = NULL, p = dumps; p && p != f; q = p, p = p->next); |
|
3227 if (p) { |
|
3228 if (q) |
|
3229 q->next = p->next; |
|
3230 else |
|
3231 dumps = p->next; |
|
3232 munmap((void *) f->addr, f->len); |
|
3233 zclose(f->fd); |
|
3234 zsfree(f->filename); |
|
3235 zfree(f, sizeof(*f)); |
|
3236 } |
|
3237 } |
|
3238 } |
|
3239 |
|
3240 /**/ |
|
3241 mod_export void |
|
3242 closedumps(void) |
|
3243 { |
|
3244 FuncDump p; |
|
3245 |
|
3246 for (p = dumps; p; p = p->next) |
|
3247 zclose(p->fd); |
|
3248 } |
|
3249 |
|
3250 #else |
|
3251 |
|
3252 void |
|
3253 incrdumpcount(FuncDump f) |
|
3254 { |
|
3255 } |
|
3256 |
|
3257 void |
|
3258 decrdumpcount(FuncDump f) |
|
3259 { |
|
3260 } |
|
3261 |
|
3262 /**/ |
|
3263 mod_export void |
|
3264 closedumps(void) |
|
3265 { |
|
3266 } |
|
3267 |
|
3268 #endif |
|
3269 |
|
3270 /**/ |
|
3271 int |
|
3272 dump_autoload(char *nam, char *file, int on, Options ops, int func) |
|
3273 { |
|
3274 Wordcode h; |
|
3275 FDHead n, e; |
|
3276 Shfunc shf; |
|
3277 int ret = 0; |
|
3278 |
|
3279 if (!strsfx(FD_EXT, file)) |
|
3280 file = dyncat(file, FD_EXT); |
|
3281 |
|
3282 if (!(h = load_dump_header(nam, file, 1))) |
|
3283 return 1; |
|
3284 |
|
3285 for (n = firstfdhead(h), e = (FDHead) (h + fdheaderlen(h)); n < e; |
|
3286 n = nextfdhead(n)) { |
|
3287 shf = (Shfunc) zshcalloc(sizeof *shf); |
|
3288 shf->flags = on; |
|
3289 shf->funcdef = mkautofn(shf); |
|
3290 shfunctab->addnode(shfunctab, ztrdup(fdname(n) + fdhtail(n)), shf); |
|
3291 if (OPT_ISSET(ops,'X') && eval_autoload(shf, shf->nam, ops, func)) |
|
3292 ret = 1; |
|
3293 } |
|
3294 return ret; |
|
3295 } |
|
3296 |