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