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