a "replacement" for awk and sed
[p5sagit/p5-mst-13.2.git] / cmd.c
CommitLineData
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
15static 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
22STR *
23cmd_exec(cmd)
24register 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
43tail_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
161until_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*/
432deb(pat,a1,a2,a3,a4,a5,a6,a7,a8)
433char *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
443copyopt(cmd,which)
444register CMD *cmd;
445register 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}