Commit | Line | Data |
8d063cd8 |
1 | /* $Header: cmd.c,v 1.0 87/12/18 13:04:51 root Exp $ |
2 | * |
3 | * $Log: cmd.c,v $ |
4 | * Revision 1.0 87/12/18 13:04:51 root |
5 | * Initial revision |
6 | * |
7 | */ |
8 | |
9 | #include "handy.h" |
10 | #include "EXTERN.h" |
11 | #include "search.h" |
12 | #include "util.h" |
13 | #include "perl.h" |
14 | |
15 | static STR str_chop; |
16 | |
17 | /* This is the main command loop. We try to spend as much time in this loop |
18 | * as possible, so lots of optimizations do their activities in here. This |
19 | * means things get a little sloppy. |
20 | */ |
21 | |
22 | STR * |
23 | cmd_exec(cmd) |
24 | register CMD *cmd; |
25 | { |
26 | SPAT *oldspat; |
27 | #ifdef DEBUGGING |
28 | int olddlevel; |
29 | int entdlevel; |
30 | #endif |
31 | register STR *retstr; |
32 | register char *tmps; |
33 | register int cmdflags; |
34 | register bool match; |
35 | register char *go_to = goto_targ; |
36 | ARG *arg; |
37 | FILE *fp; |
38 | |
39 | retstr = &str_no; |
40 | #ifdef DEBUGGING |
41 | entdlevel = dlevel; |
42 | #endif |
43 | tail_recursion_entry: |
44 | #ifdef DEBUGGING |
45 | dlevel = entdlevel; |
46 | #endif |
47 | if (cmd == Nullcmd) |
48 | return retstr; |
49 | cmdflags = cmd->c_flags; /* hopefully load register */ |
50 | if (go_to) { |
51 | if (cmd->c_label && strEQ(go_to,cmd->c_label)) |
52 | goto_targ = go_to = Nullch; /* here at last */ |
53 | else { |
54 | switch (cmd->c_type) { |
55 | case C_IF: |
56 | oldspat = curspat; |
57 | #ifdef DEBUGGING |
58 | olddlevel = dlevel; |
59 | #endif |
60 | retstr = &str_yes; |
61 | if (cmd->ucmd.ccmd.cc_true) { |
62 | #ifdef DEBUGGING |
63 | debname[dlevel] = 't'; |
64 | debdelim[dlevel++] = '_'; |
65 | #endif |
66 | retstr = cmd_exec(cmd->ucmd.ccmd.cc_true); |
67 | } |
68 | if (!goto_targ) { |
69 | go_to = Nullch; |
70 | } else { |
71 | retstr = &str_no; |
72 | if (cmd->ucmd.ccmd.cc_alt) { |
73 | #ifdef DEBUGGING |
74 | debname[dlevel] = 'e'; |
75 | debdelim[dlevel++] = '_'; |
76 | #endif |
77 | retstr = cmd_exec(cmd->ucmd.ccmd.cc_alt); |
78 | } |
79 | } |
80 | if (!goto_targ) |
81 | go_to = Nullch; |
82 | curspat = oldspat; |
83 | #ifdef DEBUGGING |
84 | dlevel = olddlevel; |
85 | #endif |
86 | break; |
87 | case C_BLOCK: |
88 | case C_WHILE: |
89 | if (!(cmdflags & CF_ONCE)) { |
90 | cmdflags |= CF_ONCE; |
91 | loop_ptr++; |
92 | loop_stack[loop_ptr].loop_label = cmd->c_label; |
93 | #ifdef DEBUGGING |
94 | if (debug & 4) { |
95 | deb("(Pushing label #%d %s)\n", |
96 | loop_ptr,cmd->c_label); |
97 | } |
98 | #endif |
99 | } |
100 | switch (setjmp(loop_stack[loop_ptr].loop_env)) { |
101 | case O_LAST: /* not done unless go_to found */ |
102 | go_to = Nullch; |
103 | retstr = &str_no; |
104 | #ifdef DEBUGGING |
105 | olddlevel = dlevel; |
106 | #endif |
107 | curspat = oldspat; |
108 | #ifdef DEBUGGING |
109 | if (debug & 4) { |
110 | deb("(Popping label #%d %s)\n",loop_ptr, |
111 | loop_stack[loop_ptr].loop_label); |
112 | } |
113 | #endif |
114 | loop_ptr--; |
115 | cmd = cmd->c_next; |
116 | goto tail_recursion_entry; |
117 | case O_NEXT: /* not done unless go_to found */ |
118 | go_to = Nullch; |
119 | goto next_iter; |
120 | case O_REDO: /* not done unless go_to found */ |
121 | go_to = Nullch; |
122 | goto doit; |
123 | } |
124 | oldspat = curspat; |
125 | #ifdef DEBUGGING |
126 | olddlevel = dlevel; |
127 | #endif |
128 | if (cmd->ucmd.ccmd.cc_true) { |
129 | #ifdef DEBUGGING |
130 | debname[dlevel] = 't'; |
131 | debdelim[dlevel++] = '_'; |
132 | #endif |
133 | cmd_exec(cmd->ucmd.ccmd.cc_true); |
134 | } |
135 | if (!goto_targ) { |
136 | go_to = Nullch; |
137 | goto next_iter; |
138 | } |
139 | #ifdef DEBUGGING |
140 | dlevel = olddlevel; |
141 | #endif |
142 | if (cmd->ucmd.ccmd.cc_alt) { |
143 | #ifdef DEBUGGING |
144 | debname[dlevel] = 'a'; |
145 | debdelim[dlevel++] = '_'; |
146 | #endif |
147 | cmd_exec(cmd->ucmd.ccmd.cc_alt); |
148 | } |
149 | if (goto_targ) |
150 | break; |
151 | go_to = Nullch; |
152 | goto finish_while; |
153 | } |
154 | cmd = cmd->c_next; |
155 | if (cmd && cmd->c_head == cmd) /* reached end of while loop */ |
156 | return retstr; /* targ isn't in this block */ |
157 | goto tail_recursion_entry; |
158 | } |
159 | } |
160 | |
161 | until_loop: |
162 | |
163 | #ifdef DEBUGGING |
164 | if (debug & 2) { |
165 | deb("%s (%lx) r%lx t%lx a%lx n%lx cs%lx\n", |
166 | cmdname[cmd->c_type],cmd,cmd->c_expr, |
167 | cmd->ucmd.ccmd.cc_true,cmd->ucmd.ccmd.cc_alt,cmd->c_next,curspat); |
168 | } |
169 | debname[dlevel] = cmdname[cmd->c_type][0]; |
170 | debdelim[dlevel++] = '!'; |
171 | #endif |
172 | while (tmps_max >= 0) /* clean up after last eval */ |
173 | str_free(tmps_list[tmps_max--]); |
174 | |
175 | /* Here is some common optimization */ |
176 | |
177 | if (cmdflags & CF_COND) { |
178 | switch (cmdflags & CF_OPTIMIZE) { |
179 | |
180 | case CFT_FALSE: |
181 | retstr = cmd->c_first; |
182 | match = FALSE; |
183 | if (cmdflags & CF_NESURE) |
184 | goto maybe; |
185 | break; |
186 | case CFT_TRUE: |
187 | retstr = cmd->c_first; |
188 | match = TRUE; |
189 | if (cmdflags & CF_EQSURE) |
190 | goto flipmaybe; |
191 | break; |
192 | |
193 | case CFT_REG: |
194 | retstr = STAB_STR(cmd->c_stab); |
195 | match = str_true(retstr); /* => retstr = retstr, c2 should fix */ |
196 | if (cmdflags & (match ? CF_EQSURE : CF_NESURE)) |
197 | goto flipmaybe; |
198 | break; |
199 | |
200 | case CFT_ANCHOR: /* /^pat/ optimization */ |
201 | if (multiline) { |
202 | if (*cmd->c_first->str_ptr && !(cmdflags & CF_EQSURE)) |
203 | goto scanner; /* just unanchor it */ |
204 | else |
205 | break; /* must evaluate */ |
206 | } |
207 | /* FALL THROUGH */ |
208 | case CFT_STROP: /* string op optimization */ |
209 | retstr = STAB_STR(cmd->c_stab); |
210 | if (*cmd->c_first->str_ptr == *str_get(retstr) && |
211 | strnEQ(cmd->c_first->str_ptr, str_get(retstr), |
212 | cmd->c_flen) ) { |
213 | if (cmdflags & CF_EQSURE) { |
214 | match = !(cmdflags & CF_FIRSTNEG); |
215 | retstr = &str_yes; |
216 | goto flipmaybe; |
217 | } |
218 | } |
219 | else if (cmdflags & CF_NESURE) { |
220 | match = cmdflags & CF_FIRSTNEG; |
221 | retstr = &str_no; |
222 | goto flipmaybe; |
223 | } |
224 | break; /* must evaluate */ |
225 | |
226 | case CFT_SCAN: /* non-anchored search */ |
227 | scanner: |
228 | retstr = STAB_STR(cmd->c_stab); |
229 | if (instr(str_get(retstr),cmd->c_first->str_ptr)) { |
230 | if (cmdflags & CF_EQSURE) { |
231 | match = !(cmdflags & CF_FIRSTNEG); |
232 | retstr = &str_yes; |
233 | goto flipmaybe; |
234 | } |
235 | } |
236 | else if (cmdflags & CF_NESURE) { |
237 | match = cmdflags & CF_FIRSTNEG; |
238 | retstr = &str_no; |
239 | goto flipmaybe; |
240 | } |
241 | break; /* must evaluate */ |
242 | |
243 | case CFT_GETS: /* really a while (<file>) */ |
244 | last_in_stab = cmd->c_stab; |
245 | fp = last_in_stab->stab_io->fp; |
246 | retstr = defstab->stab_val; |
247 | if (fp && str_gets(retstr, fp)) { |
248 | last_in_stab->stab_io->lines++; |
249 | match = TRUE; |
250 | } |
251 | else if (last_in_stab->stab_io->flags & IOF_ARGV) |
252 | goto doeval; /* doesn't necessarily count as EOF yet */ |
253 | else { |
254 | retstr = &str_no; |
255 | match = FALSE; |
256 | } |
257 | goto flipmaybe; |
258 | case CFT_EVAL: |
259 | break; |
260 | case CFT_UNFLIP: |
261 | retstr = eval(cmd->c_expr,Null(char***)); |
262 | match = str_true(retstr); |
263 | if (cmd->c_expr->arg_type == O_FLIP) /* undid itself? */ |
264 | cmdflags = copyopt(cmd,cmd->c_expr[3].arg_ptr.arg_cmd); |
265 | goto maybe; |
266 | case CFT_CHOP: |
267 | retstr = cmd->c_stab->stab_val; |
268 | match = (retstr->str_cur != 0); |
269 | tmps = str_get(retstr); |
270 | tmps += retstr->str_cur - match; |
271 | str_set(&str_chop,tmps); |
272 | *tmps = '\0'; |
273 | retstr->str_nok = 0; |
274 | retstr->str_cur = tmps - retstr->str_ptr; |
275 | retstr = &str_chop; |
276 | goto flipmaybe; |
277 | } |
278 | |
279 | /* we have tried to make this normal case as abnormal as possible */ |
280 | |
281 | doeval: |
282 | retstr = eval(cmd->c_expr,Null(char***)); |
283 | match = str_true(retstr); |
284 | goto maybe; |
285 | |
286 | /* if flipflop was true, flop it */ |
287 | |
288 | flipmaybe: |
289 | if (match && cmdflags & CF_FLIP) { |
290 | if (cmd->c_expr->arg_type == O_FLOP) { /* currently toggled? */ |
291 | retstr = eval(cmd->c_expr,Null(char***)); /* let eval undo it */ |
292 | cmdflags = copyopt(cmd,cmd->c_expr[3].arg_ptr.arg_cmd); |
293 | } |
294 | else { |
295 | retstr = eval(cmd->c_expr,Null(char***)); /* let eval do it */ |
296 | if (cmd->c_expr->arg_type == O_FLOP) /* still toggled? */ |
297 | cmdflags = copyopt(cmd,cmd->c_expr[4].arg_ptr.arg_cmd); |
298 | } |
299 | } |
300 | else if (cmdflags & CF_FLIP) { |
301 | if (cmd->c_expr->arg_type == O_FLOP) { /* currently toggled? */ |
302 | match = TRUE; /* force on */ |
303 | } |
304 | } |
305 | |
306 | /* at this point, match says whether our expression was true */ |
307 | |
308 | maybe: |
309 | if (cmdflags & CF_INVERT) |
310 | match = !match; |
311 | if (!match && cmd->c_type != C_IF) { |
312 | cmd = cmd->c_next; |
313 | goto tail_recursion_entry; |
314 | } |
315 | } |
316 | |
317 | /* now to do the actual command, if any */ |
318 | |
319 | switch (cmd->c_type) { |
320 | case C_NULL: |
321 | fatal("panic: cmd_exec\n"); |
322 | case C_EXPR: /* evaluated for side effects */ |
323 | if (cmd->ucmd.acmd.ac_expr) { /* more to do? */ |
324 | retstr = eval(cmd->ucmd.acmd.ac_expr,Null(char***)); |
325 | } |
326 | break; |
327 | case C_IF: |
328 | oldspat = curspat; |
329 | #ifdef DEBUGGING |
330 | olddlevel = dlevel; |
331 | #endif |
332 | if (match) { |
333 | retstr = &str_yes; |
334 | if (cmd->ucmd.ccmd.cc_true) { |
335 | #ifdef DEBUGGING |
336 | debname[dlevel] = 't'; |
337 | debdelim[dlevel++] = '_'; |
338 | #endif |
339 | retstr = cmd_exec(cmd->ucmd.ccmd.cc_true); |
340 | } |
341 | } |
342 | else { |
343 | retstr = &str_no; |
344 | if (cmd->ucmd.ccmd.cc_alt) { |
345 | #ifdef DEBUGGING |
346 | debname[dlevel] = 'e'; |
347 | debdelim[dlevel++] = '_'; |
348 | #endif |
349 | retstr = cmd_exec(cmd->ucmd.ccmd.cc_alt); |
350 | } |
351 | } |
352 | curspat = oldspat; |
353 | #ifdef DEBUGGING |
354 | dlevel = olddlevel; |
355 | #endif |
356 | break; |
357 | case C_BLOCK: |
358 | case C_WHILE: |
359 | if (!(cmdflags & CF_ONCE)) { /* first time through here? */ |
360 | cmdflags |= CF_ONCE; |
361 | loop_ptr++; |
362 | loop_stack[loop_ptr].loop_label = cmd->c_label; |
363 | #ifdef DEBUGGING |
364 | if (debug & 4) { |
365 | deb("(Pushing label #%d %s)\n", |
366 | loop_ptr,cmd->c_label); |
367 | } |
368 | #endif |
369 | } |
370 | switch (setjmp(loop_stack[loop_ptr].loop_env)) { |
371 | case O_LAST: |
372 | retstr = &str_no; |
373 | curspat = oldspat; |
374 | #ifdef DEBUGGING |
375 | if (debug & 4) { |
376 | deb("(Popping label #%d %s)\n",loop_ptr, |
377 | loop_stack[loop_ptr].loop_label); |
378 | } |
379 | #endif |
380 | loop_ptr--; |
381 | cmd = cmd->c_next; |
382 | goto tail_recursion_entry; |
383 | case O_NEXT: |
384 | goto next_iter; |
385 | case O_REDO: |
386 | goto doit; |
387 | } |
388 | oldspat = curspat; |
389 | #ifdef DEBUGGING |
390 | olddlevel = dlevel; |
391 | #endif |
392 | doit: |
393 | if (cmd->ucmd.ccmd.cc_true) { |
394 | #ifdef DEBUGGING |
395 | debname[dlevel] = 't'; |
396 | debdelim[dlevel++] = '_'; |
397 | #endif |
398 | cmd_exec(cmd->ucmd.ccmd.cc_true); |
399 | } |
400 | /* actually, this spot is never reached anymore since the above |
401 | * cmd_exec() returns through longjmp(). Hooray for structure. |
402 | */ |
403 | next_iter: |
404 | #ifdef DEBUGGING |
405 | dlevel = olddlevel; |
406 | #endif |
407 | if (cmd->ucmd.ccmd.cc_alt) { |
408 | #ifdef DEBUGGING |
409 | debname[dlevel] = 'a'; |
410 | debdelim[dlevel++] = '_'; |
411 | #endif |
412 | cmd_exec(cmd->ucmd.ccmd.cc_alt); |
413 | } |
414 | finish_while: |
415 | curspat = oldspat; |
416 | #ifdef DEBUGGING |
417 | dlevel = olddlevel - 1; |
418 | #endif |
419 | if (cmd->c_type != C_BLOCK) |
420 | goto until_loop; /* go back and evaluate conditional again */ |
421 | } |
422 | if (cmdflags & CF_LOOP) { |
423 | cmdflags |= CF_COND; /* now test the condition */ |
424 | goto until_loop; |
425 | } |
426 | cmd = cmd->c_next; |
427 | goto tail_recursion_entry; |
428 | } |
429 | |
430 | #ifdef DEBUGGING |
431 | /*VARARGS1*/ |
432 | deb(pat,a1,a2,a3,a4,a5,a6,a7,a8) |
433 | char *pat; |
434 | { |
435 | register int i; |
436 | |
437 | for (i=0; i<dlevel; i++) |
438 | fprintf(stderr,"%c%c ",debname[i],debdelim[i]); |
439 | fprintf(stderr,pat,a1,a2,a3,a4,a5,a6,a7,a8); |
440 | } |
441 | #endif |
442 | |
443 | copyopt(cmd,which) |
444 | register CMD *cmd; |
445 | register CMD *which; |
446 | { |
447 | cmd->c_flags &= CF_ONCE|CF_COND|CF_LOOP; |
448 | cmd->c_flags |= which->c_flags; |
449 | cmd->c_first = which->c_first; |
450 | cmd->c_flen = which->c_flen; |
451 | cmd->c_stab = which->c_stab; |
452 | return cmd->c_flags; |
453 | } |