1: /* Copyright (c) 1979 Regents of the University of California */ 2: #include "ex.h" 3: #include "ex_argv.h" 4: #include "ex_temp.h" 5: #include "ex_tty.h" 6: #include "ex_vis.h" 7: 8: bool pflag, nflag; 9: int poffset; 10: 11: /* 12: * Subroutines for major command loop. 13: */ 14: 15: /* 16: * Is there a single letter indicating a named buffer next? 17: */ 18: cmdreg() 19: { 20: register int c = 0; 21: register int wh = skipwh(); 22: 23: if (wh && isalpha(peekchar())) 24: c = getchar(); 25: return (c); 26: } 27: 28: /* 29: * Tell whether the character ends a command 30: */ 31: endcmd(ch) 32: int ch; 33: { 34: switch (ch) { 35: 36: case '\n': 37: case EOF: 38: endline = 1; 39: return (1); 40: 41: case '|': 42: case '"': 43: endline = 0; 44: return (1); 45: } 46: return (0); 47: } 48: 49: /* 50: * Insist on the end of the command. 51: */ 52: eol() 53: { 54: 55: if (!skipend()) 56: error("Extra chars|Extra characters at end of command"); 57: ignnEOF(); 58: } 59: 60: /* 61: * Print out the message in the error message file at str, 62: * with i an integer argument to printf. 63: */ 64: /*VARARGS2*/ 65: error(str, i) 66: #ifdef lint 67: register char *str; 68: #else 69: register int str; 70: #endif 71: int i; 72: { 73: 74: error0(); 75: merror(str, i); 76: error1(str); 77: } 78: 79: /* 80: * Rewind the argument list. 81: */ 82: erewind() 83: { 84: 85: argc = argc0; 86: argv = argv0; 87: args = args0; 88: if (argc > 1 && !hush) { 89: printf(mesg("%d files@to edit"), argc); 90: if (inopen) 91: putchar(' '); 92: else 93: putNFL(); 94: } 95: } 96: 97: /* 98: * Guts of the pre-printing error processing. 99: * If in visual and catching errors, then we dont mung up the internals, 100: * just fixing up the echo area for the print. 101: * Otherwise we reset a number of externals, and discard unused input. 102: */ 103: error0() 104: { 105: 106: if (laste) { 107: laste = 0; 108: sync(); 109: } 110: if (vcatch) { 111: if (splitw == 0) 112: fixech(); 113: if (!SO || !SE) 114: dingdong(); 115: return; 116: } 117: if (input) { 118: input = strend(input) - 1; 119: if (*input == '\n') 120: setlastchar('\n'); 121: input = 0; 122: } 123: setoutt(); 124: flush(); 125: resetflav(); 126: if (!SO || !SE) 127: dingdong(); 128: if (inopen) { 129: /* 130: * We are coming out of open/visual ungracefully. 131: * Restore COLUMNS, undo, and fix tty mode. 132: */ 133: COLUMNS = OCOLUMNS; 134: undvis(); 135: ostop(normf); 136: putpad(VE); 137: putnl(); 138: } 139: inopen = 0; 140: holdcm = 0; 141: } 142: 143: /* 144: * Post error printing processing. 145: * Close the i/o file if left open. 146: * If catching in visual then throw to the visual catch, 147: * else if a child after a fork, then exit. 148: * Otherwise, in the normal command mode error case, 149: * finish state reset, and throw to top. 150: */ 151: error1(str) 152: char *str; 153: { 154: bool die; 155: 156: if (io > 0) { 157: close(io); 158: io = -1; 159: } 160: die = (getpid() != ppid); /* Only children die */ 161: if (vcatch && !die) { 162: inglobal = 0; 163: inopen = 1; 164: vcatch = 0; 165: fixol(); 166: longjmp(vreslab,1); 167: } 168: if (str && !vcatch) 169: putNFL(); 170: if (die) 171: exit(1); 172: lseek(0, 0L, 2); 173: if (inglobal) 174: setlastchar('\n'); 175: inglobal = 0; 176: globp = 0; 177: while (lastchar() != '\n' && lastchar() != EOF) 178: ignchar(); 179: ungetchar(0); 180: endline = 1; 181: reset(); 182: } 183: 184: fixol() 185: { 186: if (Outchar != vputchar) { 187: flush(); 188: #ifdef OPENCODE 189: if (state == ONEOPEN || state == HARDOPEN) 190: outline = destline = 0; 191: #endif 192: Outchar = vputchar; 193: vcontin(1); 194: } else { 195: if (destcol) 196: vclreol(); 197: vclean(); 198: } 199: } 200: 201: /* 202: * Does an ! character follow in the command stream? 203: */ 204: exclam() 205: { 206: 207: if (peekchar() == '!') { 208: ignchar(); 209: return (1); 210: } 211: return (0); 212: } 213: 214: /* 215: * Make an argument list for e.g. next. 216: */ 217: makargs() 218: { 219: 220: glob(&frob); 221: argc0 = frob.argc0; 222: argv0 = frob.argv; 223: args0 = argv0[0]; 224: erewind(); 225: } 226: 227: /* 228: * Advance to next file in argument list. 229: */ 230: next() 231: { 232: 233: if (argc == 0) 234: error("No more files@to edit"); 235: morargc = argc; 236: if (savedfile[0]) 237: CP(altfile, savedfile); 238: CP(savedfile, args); 239: argc--; 240: args = argv ? *++argv : strend(args) + 1; 241: } 242: 243: /* 244: * Eat trailing flags and offsets after a command, 245: * saving for possible later post-command prints. 246: */ 247: newline() 248: { 249: register int c; 250: 251: resetflav(); 252: for (;;) { 253: c = getchar(); 254: switch (c) { 255: 256: case '^': 257: case '-': 258: poffset--; 259: break; 260: 261: case '+': 262: poffset++; 263: break; 264: 265: case 'l': 266: listf++; 267: break; 268: 269: case '#': 270: nflag++; 271: break; 272: 273: case 'p': 274: listf = 0; 275: break; 276: 277: case ' ': 278: case '\t': 279: continue; 280: 281: case '"': 282: comment(); 283: setflav(); 284: return; 285: 286: default: 287: if (!endcmd(c)) 288: serror("Extra chars|Extra characters at end of \"%s\" command", Command); 289: if (c == EOF) 290: ungetchar(c); 291: setflav(); 292: return; 293: } 294: pflag++; 295: } 296: } 297: 298: /* 299: * Before quit or respec of arg list, check that there are 300: * no more files in the arg list. 301: */ 302: nomore() 303: { 304: 305: if (argc == 0 || morargc == argc) 306: return; 307: morargc = argc; 308: merror("%d more file", argc); 309: serror("%s@to edit", plural((long) argc)); 310: } 311: 312: /* 313: * Before edit of new file check that either an ! follows 314: * or the file has not been changed. 315: */ 316: quickly() 317: { 318: 319: if (exclam()) 320: return (1); 321: if (chng && dol > zero) { 322: /* 323: chng = 0; 324: */ 325: xchng = 0; 326: error("No write@since last change (:%s! overrides)", Command); 327: } 328: return (0); 329: } 330: 331: /* 332: * Reset the flavor of the output to print mode with no numbering. 333: */ 334: resetflav() 335: { 336: 337: if (inopen) 338: return; 339: listf = 0; 340: nflag = 0; 341: pflag = 0; 342: poffset = 0; 343: setflav(); 344: } 345: 346: /* 347: * Print an error message with a %s type argument to printf. 348: * Message text comes from error message file. 349: */ 350: serror(str, cp) 351: #ifdef lint 352: register char *str; 353: #else 354: register int str; 355: #endif 356: char *cp; 357: { 358: 359: error0(); 360: smerror(str, cp); 361: error1(str); 362: } 363: 364: /* 365: * Set the flavor of the output based on the flags given 366: * and the number and list options to either number or not number lines 367: * and either use normally decoded (ARPAnet standard) characters or list mode, 368: * where end of lines are marked and tabs print as ^I. 369: */ 370: setflav() 371: { 372: 373: if (inopen) 374: return; 375: setnumb(nflag || value(NUMBER)); 376: setlist(listf || value(LIST)); 377: setoutt(); 378: } 379: 380: /* 381: * Skip white space and tell whether command ends then. 382: */ 383: skipend() 384: { 385: 386: pastwh(); 387: return (endcmd(peekchar()) && peekchar() != '"'); 388: } 389: 390: /* 391: * Set the command name for non-word commands. 392: */ 393: tailspec(c) 394: int c; 395: { 396: static char foocmd[2]; 397: 398: foocmd[0] = c; 399: Command = foocmd; 400: } 401: 402: /* 403: * Try to read off the rest of the command word. 404: * If alphabetics follow, then this is not the command we seek. 405: */ 406: tail(comm) 407: char *comm; 408: { 409: 410: tailprim(comm, 1, 0); 411: } 412: 413: tail2of(comm) 414: char *comm; 415: { 416: 417: tailprim(comm, 2, 0); 418: } 419: 420: char tcommand[20]; 421: 422: tailprim(comm, i, notinvis) 423: register char *comm; 424: int i; 425: bool notinvis; 426: { 427: register char *cp; 428: register int c; 429: 430: Command = comm; 431: for (cp = tcommand; i > 0; i--) 432: *cp++ = *comm++; 433: while (*comm && peekchar() == *comm) 434: *cp++ = getchar(), comm++; 435: c = peekchar(); 436: if (notinvis || isalpha(c)) { 437: /* 438: * Of the trailing lp funny business, only dl and dp 439: * survive the move from ed to ex. 440: */ 441: if (tcommand[0] == 'd' && any(c, "lp")) 442: goto ret; 443: while (cp < &tcommand[19] && isalpha(peekchar())) 444: *cp++ = getchar(); 445: *cp = 0; 446: if (notinvis) 447: serror("What?|%s: No such command from open/visual", tcommand); 448: else 449: serror("What?|%s: Not an editor command", tcommand); 450: } 451: ret: 452: *cp = 0; 453: } 454: 455: /* 456: * Continue after a shell escape from open/visual. 457: */ 458: vcontin(ask) 459: bool ask; 460: { 461: 462: if (vcnt > 0) 463: vcnt = -vcnt; 464: if (inopen) { 465: #ifdef OPENCODE 466: if (state != VISUAL) { 467: /* 468: * We don't know what a shell command may have left on 469: * the screen, so we move the cursor to the right place 470: * and then put out a newline. But this makes an extra 471: * blank line most of the time so we only do it for :sh 472: * since the prompt gets left on the screen. 473: * 474: * BUG: :!echo longer than current line \\c 475: * will screw it up, but be reasonable! 476: */ 477: if (state == CRTOPEN) { 478: termreset(); 479: vgoto(WECHO, 0); 480: } 481: if (!ask) { 482: putch('\r'); 483: putch('\n'); 484: } 485: return; 486: } 487: #endif 488: if (ask) { 489: merror("[Hit return to continue] "); 490: flush(); 491: } 492: #ifndef CBREAK 493: vraw(); 494: #endif 495: if (ask) { 496: #ifdef EATQS 497: /* 498: * Gobble ^Q/^S since the tty driver should be eating 499: * them (as far as the user can see) 500: */ 501: while (peekkey() == CTRL(Q) || peekkey() == CTRL(S)) 502: ignore(getkey()); 503: #endif 504: if(getkey() == ':') 505: ungetkey(':'); 506: } 507: vclrech(0); 508: putpad(VS); 509: } 510: } 511: 512: /* 513: * Put out a newline (before a shell escape) 514: * if in open/visual. 515: */ 516: vnfl() 517: { 518: 519: if (inopen) { 520: #ifdef OPENCODE 521: if (state != VISUAL && state != CRTOPEN && destline <= WECHO) 522: vclean(); 523: else 524: #endif 525: vmoveitup(1, 0); 526: vgoto(WECHO, 0); 527: vclrbyte(vtube[WECHO], WCOLS); 528: putpad(VE); 529: } 530: flush(); 531: }