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: }