1441Smark /* Copyright (c) 1979 Regents of the University of California */ 2441Smark #include "ex.h" 3441Smark #include "ex_re.h" 4441Smark #include "ex_tty.h" 5441Smark #include "ex_vis.h" 6441Smark 7441Smark /* 8441Smark * Random routines, in alphabetical order. 9441Smark */ 10441Smark 11441Smark any(c, s) 12441Smark int c; 13441Smark register char *s; 14441Smark { 15441Smark register int x; 16441Smark 17441Smark while (x = *s++) 18441Smark if (x == c) 19441Smark return (1); 20441Smark return (0); 21441Smark } 22441Smark 23441Smark backtab(i) 24441Smark register int i; 25441Smark { 26441Smark register int j; 27441Smark 28441Smark j = i % value(SHIFTWIDTH); 29441Smark if (j == 0) 30441Smark j = value(SHIFTWIDTH); 31441Smark i -= j; 32441Smark if (i < 0) 33441Smark i = 0; 34441Smark return (i); 35441Smark } 36441Smark 37441Smark change() 38441Smark { 39441Smark 40441Smark tchng++; 41441Smark chng = tchng; 42441Smark } 43441Smark 44441Smark /* 45441Smark * Column returns the number of 46441Smark * columns occupied by printing the 47441Smark * characters through position cp of the 48441Smark * current line. 49441Smark */ 50441Smark column(cp) 51441Smark register char *cp; 52441Smark { 53441Smark 54441Smark if (cp == 0) 55441Smark cp = &linebuf[LBSIZE - 2]; 56441Smark return (qcolumn(cp, (char *) 0)); 57441Smark } 58441Smark 59441Smark Copy(to, from, size) 60441Smark register char *from, *to; 61441Smark register int size; 62441Smark { 63441Smark 64441Smark if (size > 0) 65441Smark do 66441Smark *to++ = *from++; 67441Smark while (--size > 0); 68441Smark } 69441Smark 70441Smark copyw(to, from, size) 71441Smark register line *from, *to; 72441Smark register int size; 73441Smark { 74441Smark 75441Smark if (size > 0) 76441Smark do 77441Smark *to++ = *from++; 78441Smark while (--size > 0); 79441Smark } 80441Smark 81441Smark copywR(to, from, size) 82441Smark register line *from, *to; 83441Smark register int size; 84441Smark { 85441Smark 86441Smark while (--size >= 0) 87441Smark to[size] = from[size]; 88441Smark } 89441Smark 90441Smark ctlof(c) 91441Smark int c; 92441Smark { 93441Smark 94441Smark return (c == TRIM ? '?' : c | ('A' - 1)); 95441Smark } 96441Smark 97441Smark dingdong() 98441Smark { 99441Smark 100441Smark if (VB) 101441Smark putpad(VB); 102441Smark else if (value(ERRORBELLS)) 103441Smark putch('\207'); 104441Smark } 105441Smark 106441Smark fixindent(indent) 107441Smark int indent; 108441Smark { 109441Smark register int i; 110441Smark register char *cp; 111441Smark 112441Smark i = whitecnt(genbuf); 113441Smark cp = vpastwh(genbuf); 114441Smark if (*cp == 0 && i == indent && linebuf[0] == 0) { 115441Smark genbuf[0] = 0; 116441Smark return (i); 117441Smark } 118441Smark CP(genindent(i), cp); 119441Smark return (i); 120441Smark } 121441Smark 122441Smark filioerr(cp) 123441Smark char *cp; 124441Smark { 125441Smark register int oerrno = errno; 126441Smark 127441Smark lprintf("\"%s\"", cp); 128441Smark errno = oerrno; 129441Smark syserror(); 130441Smark } 131441Smark 132441Smark char * 133441Smark genindent(indent) 134441Smark register int indent; 135441Smark { 136441Smark register char *cp; 137441Smark 138441Smark for (cp = genbuf; indent >= value(TABSTOP); indent -= value(TABSTOP)) 139441Smark *cp++ = '\t'; 140441Smark for (; indent > 0; indent--) 141441Smark *cp++ = ' '; 142441Smark return (cp); 143441Smark } 144441Smark 145441Smark getDOT() 146441Smark { 147441Smark 148441Smark getline(*dot); 149441Smark } 150441Smark 151441Smark line * 152441Smark getmark(c) 153441Smark register int c; 154441Smark { 155441Smark register line *addr; 156441Smark 157441Smark for (addr = one; addr <= dol; addr++) 158441Smark if (names[c - 'a'] == (*addr &~ 01)) { 159441Smark return (addr); 160441Smark } 161441Smark return (0); 162441Smark } 163441Smark 164441Smark getn(cp) 165441Smark register char *cp; 166441Smark { 167441Smark register int i = 0; 168441Smark 169441Smark while (isdigit(*cp)) 170441Smark i = i * 10 + *cp++ - '0'; 171441Smark if (*cp) 172441Smark return (0); 173441Smark return (i); 174441Smark } 175441Smark 176441Smark ignnEOF() 177441Smark { 178441Smark register int c = getchar(); 179441Smark 180441Smark if (c == EOF) 181441Smark ungetchar(c); 182441Smark } 183441Smark 184441Smark iswhite(c) 185441Smark int c; 186441Smark { 187441Smark 188441Smark return (c == ' ' || c == '\t'); 189441Smark } 190441Smark 191441Smark junk(c) 192441Smark register int c; 193441Smark { 194441Smark 195441Smark if (c && !value(BEAUTIFY)) 196441Smark return (0); 197441Smark if (c >= ' ' && c != TRIM) 198441Smark return (0); 199441Smark switch (c) { 200441Smark 201441Smark case '\t': 202441Smark case '\n': 203441Smark case '\f': 204441Smark return (0); 205441Smark 206441Smark default: 207441Smark return (1); 208441Smark } 209441Smark } 210441Smark 211441Smark killed() 212441Smark { 213441Smark 214441Smark killcnt(addr2 - addr1 + 1); 215441Smark } 216441Smark 217441Smark killcnt(cnt) 218441Smark register int cnt; 219441Smark { 220441Smark 221441Smark if (inopen) { 222441Smark notecnt = cnt; 223441Smark notenam = notesgn = ""; 224441Smark return; 225441Smark } 226441Smark if (!notable(cnt)) 227441Smark return; 228441Smark printf("%d lines", cnt); 229441Smark if (value(TERSE) == 0) { 230441Smark printf(" %c%s", Command[0] | ' ', Command + 1); 231441Smark if (Command[strlen(Command) - 1] != 'e') 232441Smark putchar('e'); 233441Smark putchar('d'); 234441Smark } 235441Smark putNFL(); 236441Smark } 237441Smark 238441Smark lineno(a) 239441Smark line *a; 240441Smark { 241441Smark 242441Smark return (a - zero); 243441Smark } 244441Smark 245441Smark lineDOL() 246441Smark { 247441Smark 248441Smark return (lineno(dol)); 249441Smark } 250441Smark 251441Smark lineDOT() 252441Smark { 253441Smark 254441Smark return (lineno(dot)); 255441Smark } 256441Smark 257441Smark markDOT() 258441Smark { 259441Smark 260441Smark markpr(dot); 261441Smark } 262441Smark 263441Smark markpr(which) 264441Smark line *which; 265441Smark { 266441Smark 267441Smark if ((inglobal == 0 || inopen) && which <= endcore) { 268441Smark names['z'-'a'+1] = *which & ~01; 269441Smark if (inopen) 270441Smark ncols['z'-'a'+1] = cursor; 271441Smark } 272441Smark } 273441Smark 274441Smark markreg(c) 275441Smark register int c; 276441Smark { 277441Smark 278441Smark if (c == '\'' || c == '`') 279441Smark return ('z' + 1); 280441Smark if (c >= 'a' && c <= 'z') 281441Smark return (c); 282441Smark return (0); 283441Smark } 284441Smark 285441Smark /* 286441Smark * Mesg decodes the terse/verbose strings. Thus 287441Smark * 'xxx@yyy' -> 'xxx' if terse, else 'xxx yyy' 288441Smark * 'xxx|yyy' -> 'xxx' if terse, else 'yyy' 289441Smark * All others map to themselves. 290441Smark */ 291441Smark char * 292441Smark mesg(str) 293441Smark register char *str; 294441Smark { 295441Smark register char *cp; 296441Smark 297441Smark str = strcpy(genbuf, str); 298441Smark for (cp = str; *cp; cp++) 299441Smark switch (*cp) { 300441Smark 301441Smark case '@': 302441Smark if (value(TERSE)) 303441Smark *cp = 0; 304441Smark else 305441Smark *cp = ' '; 306441Smark break; 307441Smark 308441Smark case '|': 309441Smark if (value(TERSE) == 0) 310441Smark return (cp + 1); 311441Smark *cp = 0; 312441Smark break; 313441Smark } 314441Smark return (str); 315441Smark } 316441Smark 317441Smark /*VARARGS2*/ 318441Smark merror(seekpt, i) 319474Smark #ifdef VMUNIX 320441Smark char *seekpt; 321441Smark #else 322474Smark # ifdef lint 323474Smark char *seekpt; 324474Smark # else 325441Smark int seekpt; 326474Smark # endif 327441Smark #endif 328441Smark int i; 329441Smark { 330441Smark register char *cp = linebuf; 331441Smark 332441Smark if (seekpt == 0) 333441Smark return; 334441Smark merror1(seekpt); 335441Smark if (*cp == '\n') 336441Smark putnl(), cp++; 337441Smark if (inopen && CE) 338441Smark vclreol(); 339441Smark if (SO && SE) 340441Smark putpad(SO); 341441Smark printf(mesg(cp), i); 342441Smark if (SO && SE) 343441Smark putpad(SE); 344441Smark } 345441Smark 346441Smark merror1(seekpt) 347474Smark #ifdef VMUNIX 348441Smark char *seekpt; 349441Smark #else 350474Smark # ifdef lint 351474Smark char *seekpt; 352474Smark # else 353441Smark int seekpt; 354474Smark # endif 355441Smark #endif 356441Smark { 357441Smark 358474Smark #ifdef VMUNIX 359474Smark strcpy(linebuf, seekpt); 360474Smark #else 361441Smark lseek(erfile, (long) seekpt, 0); 362441Smark if (read(erfile, linebuf, 128) < 2) 363441Smark CP(linebuf, "ERROR"); 364474Smark #endif 365441Smark } 366441Smark 367441Smark morelines() 368441Smark { 369441Smark 370441Smark if ((int) sbrk(1024 * sizeof (line)) == -1) 371441Smark return (-1); 372441Smark endcore += 1024; 373441Smark return (0); 374441Smark } 375441Smark 376441Smark nonzero() 377441Smark { 378441Smark 379441Smark if (addr1 == zero) { 380441Smark notempty(); 381441Smark error("Nonzero address required@on this command"); 382441Smark } 383441Smark } 384441Smark 385441Smark notable(i) 386441Smark int i; 387441Smark { 388441Smark 389441Smark return (hush == 0 && !inglobal && i > value(REPORT)); 390441Smark } 391441Smark 392441Smark 393441Smark notempty() 394441Smark { 395441Smark 396441Smark if (dol == zero) 397441Smark error("No lines@in the buffer"); 398441Smark } 399441Smark 400441Smark 401441Smark netchHAD(cnt) 402441Smark int cnt; 403441Smark { 404441Smark 405441Smark netchange(lineDOL() - cnt); 406441Smark } 407441Smark 408441Smark netchange(i) 409441Smark register int i; 410441Smark { 411441Smark register char *cp; 412441Smark 413441Smark if (i > 0) 414441Smark notesgn = cp = "more "; 415441Smark else 416441Smark notesgn = cp = "fewer ", i = -i; 417441Smark if (inopen) { 418441Smark notecnt = i; 419441Smark notenam = ""; 420441Smark return; 421441Smark } 422441Smark if (!notable(i)) 423441Smark return; 424441Smark printf(mesg("%d %slines@in file after %s"), i, cp, Command); 425441Smark putNFL(); 426441Smark } 427441Smark 428441Smark putmark(addr) 429441Smark line *addr; 430441Smark { 431441Smark 432441Smark putmk1(addr, putline()); 433441Smark } 434441Smark 435441Smark putmk1(addr, n) 436441Smark register line *addr; 437441Smark int n; 438441Smark { 439441Smark register line *markp; 440441Smark 441441Smark *addr &= ~1; 442441Smark for (markp = (anymarks ? names : &names['z'-'a'+1]); 443441Smark markp <= &names['z'-'a'+1]; markp++) 444441Smark if (*markp == *addr) 445441Smark *markp = n; 446441Smark *addr = n; 447441Smark } 448441Smark 449441Smark char * 450441Smark plural(i) 451441Smark long i; 452441Smark { 453441Smark 454441Smark return (i == 1 ? "" : "s"); 455441Smark } 456441Smark 457441Smark int qcount(); 458441Smark short vcntcol; 459441Smark 460441Smark qcolumn(lim, gp) 461441Smark register char *lim, *gp; 462441Smark { 463441Smark register int x; 464441Smark int (*OO)(); 465441Smark 466441Smark OO = Outchar; 467441Smark Outchar = qcount; 468441Smark vcntcol = 0; 469441Smark if (lim != NULL) 470441Smark x = lim[1], lim[1] = 0; 471441Smark pline(0); 472441Smark if (lim != NULL) 473441Smark lim[1] = x; 474441Smark if (gp) 475441Smark while (*gp) 476441Smark putchar(*gp++); 477441Smark Outchar = OO; 478441Smark return (vcntcol); 479441Smark } 480441Smark 481441Smark int 482441Smark qcount(c) 483441Smark int c; 484441Smark { 485441Smark 486441Smark if (c == '\t') { 487441Smark vcntcol += value(TABSTOP) - vcntcol % value(TABSTOP); 488441Smark return; 489441Smark } 490441Smark vcntcol++; 491441Smark } 492441Smark 493441Smark reverse(a1, a2) 494441Smark register line *a1, *a2; 495441Smark { 496441Smark register line t; 497441Smark 498441Smark for (;;) { 499441Smark t = *--a2; 500441Smark if (a2 <= a1) 501441Smark return; 502441Smark *a2 = *a1; 503441Smark *a1++ = t; 504441Smark } 505441Smark } 506441Smark 507441Smark save(a1, a2) 508441Smark line *a1; 509441Smark register line *a2; 510441Smark { 511441Smark register int more; 512441Smark 513*493Smark if (!FIXUNDO) 514*493Smark return; 515*493Smark #ifdef TRACE 516*493Smark if (trace) 517*493Smark vudump("before save"); 518*493Smark #endif 519441Smark undkind = UNDNONE; 520441Smark undadot = dot; 521441Smark more = (a2 - a1 + 1) - (unddol - dol); 522441Smark while (more > (endcore - truedol)) 523441Smark if (morelines() < 0) 524441Smark error("Out of memory@saving lines for undo - try using ed or re"); 525441Smark if (more) 526441Smark (*(more > 0 ? copywR : copyw))(unddol + more + 1, unddol + 1, 527441Smark (truedol - unddol)); 528441Smark unddol += more; 529441Smark truedol += more; 530441Smark copyw(dol + 1, a1, a2 - a1 + 1); 531441Smark undkind = UNDALL; 532441Smark unddel = a1 - 1; 533441Smark undap1 = a1; 534441Smark undap2 = a2 + 1; 535*493Smark #ifdef TRACE 536*493Smark if (trace) 537*493Smark vudump("after save"); 538*493Smark #endif 539441Smark } 540441Smark 541441Smark save12() 542441Smark { 543441Smark 544441Smark save(addr1, addr2); 545441Smark } 546441Smark 547441Smark saveall() 548441Smark { 549441Smark 550441Smark save(one, dol); 551441Smark } 552441Smark 553441Smark span() 554441Smark { 555441Smark 556441Smark return (addr2 - addr1 + 1); 557441Smark } 558441Smark 559441Smark sync() 560441Smark { 561441Smark 562441Smark chng = 0; 563441Smark tchng = 0; 564441Smark xchng = 0; 565441Smark } 566441Smark 567441Smark 568441Smark skipwh() 569441Smark { 570441Smark register int wh; 571441Smark 572441Smark wh = 0; 573441Smark while (iswhite(peekchar())) { 574441Smark wh++; 575441Smark ignchar(); 576441Smark } 577441Smark return (wh); 578441Smark } 579441Smark 580441Smark /*VARARGS2*/ 581441Smark smerror(seekpt, cp) 582441Smark #ifdef lint 583441Smark char *seekpt; 584441Smark #else 585441Smark int seekpt; 586441Smark #endif 587441Smark char *cp; 588441Smark { 589441Smark 590441Smark if (seekpt == 0) 591441Smark return; 592441Smark merror1(seekpt); 593441Smark if (inopen && CE) 594441Smark vclreol(); 595441Smark if (SO && SE) 596441Smark putpad(SO); 597441Smark lprintf(mesg(linebuf), cp); 598441Smark if (SO && SE) 599441Smark putpad(SE); 600441Smark } 601441Smark 602441Smark #define std_nerrs (sizeof std_errlist / sizeof std_errlist[0]) 603441Smark 604441Smark #define error(i) i 605441Smark 606441Smark #ifdef lint 607441Smark char *std_errlist[] = { 608441Smark #else 609*493Smark # ifdef VMUNIX 610474Smark char *std_errlist[] = { 611*493Smark # else 612441Smark short std_errlist[] = { 613*493Smark # endif 614441Smark #endif 615441Smark error("Error 0"), 616441Smark error("Not super-user"), 617441Smark error("No such file or directory"), 618441Smark error("No such process"), 619441Smark error("Interrupted system call"), 620441Smark error("Physical I/O error"), 621441Smark error("No such device or address"), 622441Smark error("Argument list too long"), 623441Smark error("Exec format error"), 624441Smark error("Bad file number"), 625441Smark error("No children"), 626441Smark error("No more processes"), 627441Smark error("Not enough core"), 628441Smark error("Permission denied"), 629441Smark error("Bad address"), 630441Smark error("Block device required"), 631441Smark error("Mount device busy"), 632441Smark error("File exists"), 633441Smark error("Cross-device link"), 634441Smark error("No such device"), 635441Smark error("Not a directory"), 636441Smark error("Is a directory"), 637441Smark error("Invalid argument"), 638441Smark error("File table overflow"), 639441Smark error("Too many open files"), 640441Smark error("Not a typewriter"), 641441Smark error("Text file busy"), 642441Smark error("File too large"), 643441Smark error("No space left on device"), 644441Smark error("Illegal seek"), 645441Smark error("Read-only file system"), 646441Smark error("Too many links"), 647441Smark error("Broken pipe") 648441Smark #ifndef QUOTA 649441Smark , error("Math argument") 650441Smark , error("Result too large") 651441Smark #else 652441Smark , error("Quota exceeded") 653441Smark #endif 654441Smark }; 655441Smark 656441Smark #undef error 657441Smark 658441Smark char * 659441Smark strend(cp) 660441Smark register char *cp; 661441Smark { 662441Smark 663441Smark while (*cp) 664441Smark cp++; 665441Smark return (cp); 666441Smark } 667441Smark 668441Smark strcLIN(dp) 669441Smark char *dp; 670441Smark { 671441Smark 672441Smark CP(linebuf, dp); 673441Smark } 674441Smark 675441Smark syserror() 676441Smark { 677441Smark register int e = errno; 678441Smark 679441Smark dirtcnt = 0; 680441Smark putchar(' '); 681441Smark if (e >= 0 && errno <= std_nerrs) 682441Smark error(std_errlist[e]); 683441Smark else 684441Smark error("System error %d", e); 685441Smark } 686441Smark 687441Smark char * 688441Smark vfindcol(i) 689441Smark int i; 690441Smark { 691441Smark register char *cp; 692441Smark register int (*OO)() = Outchar; 693441Smark 694441Smark Outchar = qcount; 695441Smark ignore(qcolumn(linebuf - 1, NOSTR)); 696441Smark for (cp = linebuf; *cp && vcntcol < i; cp++) 697441Smark putchar(*cp); 698441Smark if (cp != linebuf) 699441Smark cp--; 700441Smark Outchar = OO; 701441Smark return (cp); 702441Smark } 703441Smark 704441Smark char * 705441Smark vskipwh(cp) 706441Smark register char *cp; 707441Smark { 708441Smark 709441Smark while (iswhite(*cp) && cp[1]) 710441Smark cp++; 711441Smark return (cp); 712441Smark } 713441Smark 714441Smark 715441Smark char * 716441Smark vpastwh(cp) 717441Smark register char *cp; 718441Smark { 719441Smark 720441Smark while (iswhite(*cp)) 721441Smark cp++; 722441Smark return (cp); 723441Smark } 724441Smark 725441Smark whitecnt(cp) 726441Smark register char *cp; 727441Smark { 728441Smark register int i; 729441Smark 730441Smark i = 0; 731441Smark for (;;) 732441Smark switch (*cp++) { 733441Smark 734441Smark case '\t': 735441Smark i += value(TABSTOP) - i % value(TABSTOP); 736441Smark break; 737441Smark 738441Smark case ' ': 739441Smark i++; 740441Smark break; 741441Smark 742441Smark default: 743441Smark return (i); 744441Smark } 745441Smark } 746441Smark 747441Smark #ifdef lint 748441Smark Ignore(a) 749441Smark char *a; 750441Smark { 751441Smark 752441Smark a = a; 753441Smark } 754441Smark 755441Smark Ignorf(a) 756441Smark int (*a)(); 757441Smark { 758441Smark 759441Smark a = a; 760441Smark } 761441Smark #endif 762441Smark 763441Smark markit(addr) 764441Smark line *addr; 765441Smark { 766441Smark 767441Smark if (addr != dot && addr >= one && addr <= dol) 768441Smark markDOT(); 769441Smark } 770441Smark 771