1 /* Copyright (c) 1981 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_cmds2.c 7.1 07/08/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 } 557