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