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