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