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