1 /* Copyright (c) 1980 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_subr.c 5.1 08/20/80"; 3 #include "ex.h" 4 #include "ex_re.h" 5 #include "ex_tty.h" 6 #include "ex_vis.h" 7 8 /* 9 * Random routines, in alphabetical order. 10 */ 11 12 any(c, s) 13 int c; 14 register char *s; 15 { 16 register int x; 17 18 while (x = *s++) 19 if (x == c) 20 return (1); 21 return (0); 22 } 23 24 backtab(i) 25 register int i; 26 { 27 register int j; 28 29 j = i % value(SHIFTWIDTH); 30 if (j == 0) 31 j = value(SHIFTWIDTH); 32 i -= j; 33 if (i < 0) 34 i = 0; 35 return (i); 36 } 37 38 change() 39 { 40 41 tchng++; 42 chng = tchng; 43 } 44 45 /* 46 * Column returns the number of 47 * columns occupied by printing the 48 * characters through position cp of the 49 * current line. 50 */ 51 column(cp) 52 register char *cp; 53 { 54 55 if (cp == 0) 56 cp = &linebuf[LBSIZE - 2]; 57 return (qcolumn(cp, (char *) 0)); 58 } 59 60 /* 61 * Ignore a comment to the end of the line. 62 * This routine eats the trailing newline so don't call newline(). 63 */ 64 comment() 65 { 66 register int c; 67 68 do { 69 c = getchar(); 70 } while (c != '\n' && c != EOF); 71 if (c == EOF) 72 ungetchar(c); 73 } 74 75 Copy(to, from, size) 76 register char *from, *to; 77 register int size; 78 { 79 80 if (size > 0) 81 do 82 *to++ = *from++; 83 while (--size > 0); 84 } 85 86 copyw(to, from, size) 87 register line *from, *to; 88 register int size; 89 { 90 91 if (size > 0) 92 do 93 *to++ = *from++; 94 while (--size > 0); 95 } 96 97 copywR(to, from, size) 98 register line *from, *to; 99 register int size; 100 { 101 102 while (--size >= 0) 103 to[size] = from[size]; 104 } 105 106 ctlof(c) 107 int c; 108 { 109 110 return (c == TRIM ? '?' : c | ('A' - 1)); 111 } 112 113 dingdong() 114 { 115 116 if (VB) 117 putpad(VB); 118 else if (value(ERRORBELLS)) 119 putch('\207'); 120 } 121 122 fixindent(indent) 123 int indent; 124 { 125 register int i; 126 register char *cp; 127 128 i = whitecnt(genbuf); 129 cp = vpastwh(genbuf); 130 if (*cp == 0 && i == indent && linebuf[0] == 0) { 131 genbuf[0] = 0; 132 return (i); 133 } 134 CP(genindent(i), cp); 135 return (i); 136 } 137 138 filioerr(cp) 139 char *cp; 140 { 141 register int oerrno = errno; 142 143 lprintf("\"%s\"", cp); 144 errno = oerrno; 145 syserror(); 146 } 147 148 char * 149 genindent(indent) 150 register int indent; 151 { 152 register char *cp; 153 154 for (cp = genbuf; indent >= value(TABSTOP); indent -= value(TABSTOP)) 155 *cp++ = '\t'; 156 for (; indent > 0; indent--) 157 *cp++ = ' '; 158 return (cp); 159 } 160 161 getDOT() 162 { 163 164 getline(*dot); 165 } 166 167 line * 168 getmark(c) 169 register int c; 170 { 171 register line *addr; 172 173 for (addr = one; addr <= dol; addr++) 174 if (names[c - 'a'] == (*addr &~ 01)) { 175 return (addr); 176 } 177 return (0); 178 } 179 180 getn(cp) 181 register char *cp; 182 { 183 register int i = 0; 184 185 while (isdigit(*cp)) 186 i = i * 10 + *cp++ - '0'; 187 if (*cp) 188 return (0); 189 return (i); 190 } 191 192 ignnEOF() 193 { 194 register int c = getchar(); 195 196 if (c == EOF) 197 ungetchar(c); 198 else if (c=='"') 199 comment(); 200 } 201 202 iswhite(c) 203 int c; 204 { 205 206 return (c == ' ' || c == '\t'); 207 } 208 209 junk(c) 210 register int c; 211 { 212 213 if (c && !value(BEAUTIFY)) 214 return (0); 215 if (c >= ' ' && c != TRIM) 216 return (0); 217 switch (c) { 218 219 case '\t': 220 case '\n': 221 case '\f': 222 return (0); 223 224 default: 225 return (1); 226 } 227 } 228 229 killed() 230 { 231 232 killcnt(addr2 - addr1 + 1); 233 } 234 235 killcnt(cnt) 236 register int cnt; 237 { 238 239 if (inopen) { 240 notecnt = cnt; 241 notenam = notesgn = ""; 242 return; 243 } 244 if (!notable(cnt)) 245 return; 246 printf("%d lines", cnt); 247 if (value(TERSE) == 0) { 248 printf(" %c%s", Command[0] | ' ', Command + 1); 249 if (Command[strlen(Command) - 1] != 'e') 250 putchar('e'); 251 putchar('d'); 252 } 253 putNFL(); 254 } 255 256 lineno(a) 257 line *a; 258 { 259 260 return (a - zero); 261 } 262 263 lineDOL() 264 { 265 266 return (lineno(dol)); 267 } 268 269 lineDOT() 270 { 271 272 return (lineno(dot)); 273 } 274 275 markDOT() 276 { 277 278 markpr(dot); 279 } 280 281 markpr(which) 282 line *which; 283 { 284 285 if ((inglobal == 0 || inopen) && which <= endcore) { 286 names['z'-'a'+1] = *which & ~01; 287 if (inopen) 288 ncols['z'-'a'+1] = cursor; 289 } 290 } 291 292 markreg(c) 293 register int c; 294 { 295 296 if (c == '\'' || c == '`') 297 return ('z' + 1); 298 if (c >= 'a' && c <= 'z') 299 return (c); 300 return (0); 301 } 302 303 /* 304 * Mesg decodes the terse/verbose strings. Thus 305 * 'xxx@yyy' -> 'xxx' if terse, else 'xxx yyy' 306 * 'xxx|yyy' -> 'xxx' if terse, else 'yyy' 307 * All others map to themselves. 308 */ 309 char * 310 mesg(str) 311 register char *str; 312 { 313 register char *cp; 314 315 str = strcpy(genbuf, str); 316 for (cp = str; *cp; cp++) 317 switch (*cp) { 318 319 case '@': 320 if (value(TERSE)) 321 *cp = 0; 322 else 323 *cp = ' '; 324 break; 325 326 case '|': 327 if (value(TERSE) == 0) 328 return (cp + 1); 329 *cp = 0; 330 break; 331 } 332 return (str); 333 } 334 335 /*VARARGS2*/ 336 merror(seekpt, i) 337 #ifdef VMUNIX 338 char *seekpt; 339 #else 340 # ifdef lint 341 char *seekpt; 342 # else 343 int seekpt; 344 # endif 345 #endif 346 int i; 347 { 348 register char *cp = linebuf; 349 350 if (seekpt == 0) 351 return; 352 merror1(seekpt); 353 if (*cp == '\n') 354 putnl(), cp++; 355 if (inopen && CE) 356 vclreol(); 357 if (SO && SE) 358 putpad(SO); 359 printf(mesg(cp), i); 360 if (SO && SE) 361 putpad(SE); 362 } 363 364 merror1(seekpt) 365 #ifdef VMUNIX 366 char *seekpt; 367 #else 368 # ifdef lint 369 char *seekpt; 370 # else 371 int seekpt; 372 # endif 373 #endif 374 { 375 376 #ifdef VMUNIX 377 strcpy(linebuf, seekpt); 378 #else 379 lseek(erfile, (long) seekpt, 0); 380 if (read(erfile, linebuf, 128) < 2) 381 CP(linebuf, "ERROR"); 382 #endif 383 } 384 385 morelines() 386 { 387 388 if ((int) sbrk(1024 * sizeof (line)) == -1) 389 return (-1); 390 endcore += 1024; 391 return (0); 392 } 393 394 nonzero() 395 { 396 397 if (addr1 == zero) { 398 notempty(); 399 error("Nonzero address required@on this command"); 400 } 401 } 402 403 notable(i) 404 int i; 405 { 406 407 return (hush == 0 && !inglobal && i > value(REPORT)); 408 } 409 410 411 notempty() 412 { 413 414 if (dol == zero) 415 error("No lines@in the buffer"); 416 } 417 418 419 netchHAD(cnt) 420 int cnt; 421 { 422 423 netchange(lineDOL() - cnt); 424 } 425 426 netchange(i) 427 register int i; 428 { 429 register char *cp; 430 431 if (i > 0) 432 notesgn = cp = "more "; 433 else 434 notesgn = cp = "fewer ", i = -i; 435 if (inopen) { 436 notecnt = i; 437 notenam = ""; 438 return; 439 } 440 if (!notable(i)) 441 return; 442 printf(mesg("%d %slines@in file after %s"), i, cp, Command); 443 putNFL(); 444 } 445 446 putmark(addr) 447 line *addr; 448 { 449 450 putmk1(addr, putline()); 451 } 452 453 putmk1(addr, n) 454 register line *addr; 455 int n; 456 { 457 register line *markp; 458 register oldglobmk; 459 460 oldglobmk = *addr & 1; 461 *addr &= ~1; 462 for (markp = (anymarks ? names : &names['z'-'a'+1]); 463 markp <= &names['z'-'a'+1]; markp++) 464 if (*markp == *addr) 465 *markp = n; 466 *addr = n | oldglobmk; 467 } 468 469 char * 470 plural(i) 471 long i; 472 { 473 474 return (i == 1 ? "" : "s"); 475 } 476 477 int qcount(); 478 short vcntcol; 479 480 qcolumn(lim, gp) 481 register char *lim, *gp; 482 { 483 register int x; 484 int (*OO)(); 485 486 OO = Outchar; 487 Outchar = qcount; 488 vcntcol = 0; 489 if (lim != NULL) 490 x = lim[1], lim[1] = 0; 491 pline(0); 492 if (lim != NULL) 493 lim[1] = x; 494 if (gp) 495 while (*gp) 496 putchar(*gp++); 497 Outchar = OO; 498 return (vcntcol); 499 } 500 501 int 502 qcount(c) 503 int c; 504 { 505 506 if (c == '\t') { 507 vcntcol += value(TABSTOP) - vcntcol % value(TABSTOP); 508 return; 509 } 510 vcntcol++; 511 } 512 513 reverse(a1, a2) 514 register line *a1, *a2; 515 { 516 register line t; 517 518 for (;;) { 519 t = *--a2; 520 if (a2 <= a1) 521 return; 522 *a2 = *a1; 523 *a1++ = t; 524 } 525 } 526 527 save(a1, a2) 528 line *a1; 529 register line *a2; 530 { 531 register int more; 532 533 if (!FIXUNDO) 534 return; 535 #ifdef TRACE 536 if (trace) 537 vudump("before save"); 538 #endif 539 undkind = UNDNONE; 540 undadot = dot; 541 more = (a2 - a1 + 1) - (unddol - dol); 542 while (more > (endcore - truedol)) 543 if (morelines() < 0) 544 error("Out of memory@saving lines for undo - try using ed or re"); 545 if (more) 546 (*(more > 0 ? copywR : copyw))(unddol + more + 1, unddol + 1, 547 (truedol - unddol)); 548 unddol += more; 549 truedol += more; 550 copyw(dol + 1, a1, a2 - a1 + 1); 551 undkind = UNDALL; 552 unddel = a1 - 1; 553 undap1 = a1; 554 undap2 = a2 + 1; 555 #ifdef TRACE 556 if (trace) 557 vudump("after save"); 558 #endif 559 } 560 561 save12() 562 { 563 564 save(addr1, addr2); 565 } 566 567 saveall() 568 { 569 570 save(one, dol); 571 } 572 573 span() 574 { 575 576 return (addr2 - addr1 + 1); 577 } 578 579 sync() 580 { 581 582 chng = 0; 583 tchng = 0; 584 xchng = 0; 585 } 586 587 588 skipwh() 589 { 590 register int wh; 591 592 wh = 0; 593 while (iswhite(peekchar())) { 594 wh++; 595 ignchar(); 596 } 597 return (wh); 598 } 599 600 /*VARARGS2*/ 601 smerror(seekpt, cp) 602 #ifdef lint 603 char *seekpt; 604 #else 605 int seekpt; 606 #endif 607 char *cp; 608 { 609 610 if (seekpt == 0) 611 return; 612 merror1(seekpt); 613 if (inopen && CE) 614 vclreol(); 615 if (SO && SE) 616 putpad(SO); 617 lprintf(mesg(linebuf), cp); 618 if (SO && SE) 619 putpad(SE); 620 } 621 622 #define std_nerrs (sizeof std_errlist / sizeof std_errlist[0]) 623 624 #define error(i) i 625 626 #ifdef lint 627 char *std_errlist[] = { 628 #else 629 # ifdef VMUNIX 630 char *std_errlist[] = { 631 # else 632 short std_errlist[] = { 633 # endif 634 #endif 635 error("Error 0"), 636 error("Not super-user"), 637 error("No such file or directory"), 638 error("No such process"), 639 error("Interrupted system call"), 640 error("Physical I/O error"), 641 error("No such device or address"), 642 error("Argument list too long"), 643 error("Exec format error"), 644 error("Bad file number"), 645 error("No children"), 646 error("No more processes"), 647 error("Not enough core"), 648 error("Permission denied"), 649 error("Bad address"), 650 error("Block device required"), 651 error("Mount device busy"), 652 error("File exists"), 653 error("Cross-device link"), 654 error("No such device"), 655 error("Not a directory"), 656 error("Is a directory"), 657 error("Invalid argument"), 658 error("File table overflow"), 659 error("Too many open files"), 660 error("Not a typewriter"), 661 error("Text file busy"), 662 error("File too large"), 663 error("No space left on device"), 664 error("Illegal seek"), 665 error("Read-only file system"), 666 error("Too many links"), 667 error("Broken pipe") 668 #ifndef QUOTA 669 , error("Math argument") 670 , error("Result too large") 671 #else 672 , error("Quota exceeded") 673 #endif 674 }; 675 676 #undef error 677 678 char * 679 strend(cp) 680 register char *cp; 681 { 682 683 while (*cp) 684 cp++; 685 return (cp); 686 } 687 688 strcLIN(dp) 689 char *dp; 690 { 691 692 CP(linebuf, dp); 693 } 694 695 syserror() 696 { 697 register int e = errno; 698 699 dirtcnt = 0; 700 putchar(' '); 701 if (e >= 0 && errno <= std_nerrs) 702 error(std_errlist[e]); 703 else 704 error("System error %d", e); 705 } 706 707 /* 708 * Return the column number that results from being in column col and 709 * hitting a tab, where tabs are set every ts columns. Work right for 710 * the case where col > COLUMNS, even if ts does not divide COLUMNS. 711 */ 712 tabcol(col, ts) 713 int col, ts; 714 { 715 int offset, result; 716 717 if (col >= COLUMNS) { 718 offset = COLUMNS * (col/COLUMNS); 719 col -= offset; 720 } else 721 offset = 0; 722 result = col + ts - (col % ts) + offset; 723 return (result); 724 } 725 726 char * 727 vfindcol(i) 728 int i; 729 { 730 register char *cp; 731 register int (*OO)() = Outchar; 732 733 Outchar = qcount; 734 ignore(qcolumn(linebuf - 1, NOSTR)); 735 for (cp = linebuf; *cp && vcntcol < i; cp++) 736 putchar(*cp); 737 if (cp != linebuf) 738 cp--; 739 Outchar = OO; 740 return (cp); 741 } 742 743 char * 744 vskipwh(cp) 745 register char *cp; 746 { 747 748 while (iswhite(*cp) && cp[1]) 749 cp++; 750 return (cp); 751 } 752 753 754 char * 755 vpastwh(cp) 756 register char *cp; 757 { 758 759 while (iswhite(*cp)) 760 cp++; 761 return (cp); 762 } 763 764 whitecnt(cp) 765 register char *cp; 766 { 767 register int i; 768 769 i = 0; 770 for (;;) 771 switch (*cp++) { 772 773 case '\t': 774 i += value(TABSTOP) - i % value(TABSTOP); 775 break; 776 777 case ' ': 778 i++; 779 break; 780 781 default: 782 return (i); 783 } 784 } 785 786 #ifdef lint 787 Ignore(a) 788 char *a; 789 { 790 791 a = a; 792 } 793 794 Ignorf(a) 795 int (*a)(); 796 { 797 798 a = a; 799 } 800 #endif 801 802 markit(addr) 803 line *addr; 804 { 805 806 if (addr != dot && addr >= one && addr <= dol) 807 markDOT(); 808 } 809