1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  27 /*        All Rights Reserved   */
  28 
  29 
  30 /* Copyright (c) 1981 Regents of the University of California */
  31 
  32 #include <sys/stropts.h>
  33 #include <sys/eucioctl.h>
  34 #ifndef PRESUNEUC
  35 #include <locale.h>
  36 /* Undef putchar/getchar if they're defined. */
  37 #ifdef putchar
  38 #       undef putchar
  39 #endif
  40 #ifdef getchar
  41 #       undef getchar
  42 #endif
  43 #endif /* PRESUNEUC */
  44 
  45 #include "ex.h"
  46 #include "ex_re.h"
  47 #include "ex_tty.h"
  48 #include "ex_vis.h"
  49 
  50 /*
  51  * Random routines, in alphabetical order.
  52  */
  53 
  54 int
  55 any(int c, unsigned char *s)
  56 {
  57         int x;
  58 
  59         while (x = *s++)
  60                 if (x == c)
  61                         return (1);
  62         return (0);
  63 }
  64 
  65 int
  66 backtab(int i)
  67 {
  68         int j;
  69 
  70         j = i % value(vi_SHIFTWIDTH);
  71         if (j == 0)
  72                 j = value(vi_SHIFTWIDTH);
  73         i -= j;
  74         if (i < 0)
  75                 i = 0;
  76         return (i);
  77 }
  78 
  79 void
  80 change(void)
  81 {
  82 
  83         tchng++;
  84         chng = tchng;
  85 }
  86 
  87 /*
  88  * Column returns the number of
  89  * columns occupied by printing the
  90  * characters through position cp of the
  91  * current line.
  92  */
  93 int
  94 column(unsigned char *cp)
  95 {
  96 
  97         if (cp == 0)
  98                 cp = &linebuf[LBSIZE - 2];
  99         return (qcolumn(cp, (unsigned char *)0));
 100 }
 101 
 102 /* lcolumn is same as column except it returns number of columns
 103  * occupied by characters before position
 104  * cp of the current line
 105  */
 106 int
 107 lcolumn(unsigned char *cp)
 108 {
 109 
 110         if (cp == 0)
 111                 cp = &linebuf[LBSIZE - 2];
 112         return (nqcolumn(lastchr(linebuf, cp), (unsigned char *)0));
 113 }
 114 
 115 /*
 116  * Ignore a comment to the end of the line.
 117  * This routine eats the trailing newline so don't call donewline().
 118  */
 119 void
 120 comment(void)
 121 {
 122         int c;
 123 
 124         do {
 125                 c = getchar();
 126         } while (c != '\n' && c != EOF);
 127         if (c == EOF)
 128                 ungetchar(c);
 129 }
 130 
 131 void
 132 Copy(unsigned char *to, unsigned char *from, int size)
 133 {
 134 
 135         if (size > 0)
 136                 do
 137                         *to++ = *from++;
 138                 while (--size > 0);
 139 }
 140 
 141 void
 142 copyw(line *to, line *from, int size)
 143 {
 144 
 145         if (size > 0)
 146                 do
 147                         *to++ = *from++;
 148                 while (--size > 0);
 149 }
 150 
 151 void
 152 copywR(line *to, line *from, int size)
 153 {
 154 
 155         while (--size >= 0)
 156                 to[size] = from[size];
 157 }
 158 
 159 int
 160 ctlof(int c)
 161 {
 162 
 163         return (c == DELETE ? '?' : c | ('A' - 1));
 164 }
 165 
 166 void
 167 dingdong(void)
 168 {
 169 
 170         if (flash_screen && value(vi_FLASH))
 171                 putpad((unsigned char *)flash_screen);
 172         else if (value(vi_ERRORBELLS))
 173                 putpad((unsigned char *)bell);
 174 }
 175 
 176 int
 177 fixindent(int indent)
 178 {
 179         int i;
 180         unsigned char *cp;
 181 
 182         i = whitecnt(genbuf);
 183         cp = vpastwh(genbuf);
 184         if (*cp == 0 && i == indent && linebuf[0] == 0) {
 185                 genbuf[0] = 0;
 186                 return (i);
 187         }
 188         CP(genindent(i), cp);
 189         return (i);
 190 }
 191 
 192 void
 193 filioerr(unsigned char *cp)
 194 {
 195         int oerrno = errno;
 196 
 197         lprintf("\"%s\"", cp);
 198         errno = oerrno;
 199         syserror(1);
 200 }
 201 
 202 unsigned char *
 203 genindent(indent)
 204         int indent;
 205 {
 206         unsigned char *cp;
 207 
 208         for (cp = genbuf; indent >= value(vi_TABSTOP); indent -= value(vi_TABSTOP))
 209                 *cp++ = '\t';
 210         for (; indent > 0; indent--)
 211                 *cp++ = ' ';
 212         return (cp);
 213 }
 214 
 215 void
 216 getDOT(void)
 217 {
 218 
 219         getaline(*dot);
 220 }
 221 
 222 line *
 223 getmark(c)
 224         int c;
 225 {
 226         line *addr;
 227         
 228         for (addr = one; addr <= dol; addr++)
 229                 if (names[c - 'a'] == (*addr &~ 01)) {
 230                         return (addr);
 231                 }
 232         return (0);
 233 }
 234 
 235 void
 236 ignnEOF(void)
 237 {
 238         int c = getchar();
 239 
 240         if (c == EOF)
 241                 ungetchar(c);
 242         else if (c=='"')
 243                 comment();
 244 }
 245 
 246 int
 247 iswhite(int c)
 248 {
 249 
 250         return (c == ' ' || c == '\t');
 251 }
 252 
 253 int
 254 junk(wchar_t c)
 255 {
 256 
 257         if (c && !value(vi_BEAUTIFY))
 258                 return (0);
 259         if (c >= ' ' && c != DELETE)
 260                 return (0);
 261         switch (c) {
 262 
 263         case '\t':
 264         case '\n':
 265         case '\f':
 266                 return (0);
 267 
 268         default:
 269                 return (1);
 270         }
 271 }
 272 
 273 void
 274 killed(void)
 275 {
 276 
 277         killcnt(addr2 - addr1 + 1);
 278 }
 279 
 280 void
 281 killcnt(int cnt)
 282 {
 283         extern char *verbalize();
 284 
 285         if (inopen) {
 286                 notecnt = cnt;
 287                 notenam = notesgn = (unsigned char *)"";
 288                 return;
 289         }
 290         if (!notable(cnt))
 291                 return;
 292         if (value(vi_TERSE) == 0) {
 293                 verbalize(cnt, Command, "");
 294         } else {
 295                 if (cnt == 1) {
 296                         viprintf(gettext("1 line"), cnt);
 297                 } else {
 298                         viprintf(gettext("%d lines"), cnt);
 299                 }
 300         }
 301         putNFL();
 302 }
 303 
 304 int
 305 lineno(line *a)
 306 {
 307 
 308         return (a - zero);
 309 }
 310 
 311 int
 312 lineDOL(void)
 313 {
 314 
 315         return (lineno(dol));
 316 }
 317 
 318 int
 319 lineDOT(void)
 320 {
 321 
 322         return (lineno(dot));
 323 }
 324 
 325 void
 326 markDOT(void)
 327 {
 328 
 329         markpr(dot);
 330 }
 331 
 332 void
 333 markpr(line *which)
 334 {
 335 
 336         if ((inglobal == 0 || inopen) && which <= endcore) {
 337                 names['z'-'a'+1] = *which & ~01;
 338                 if (inopen)
 339                         ncols['z'-'a'+1] = cursor;
 340         }
 341 }
 342 
 343 int
 344 markreg(int c)
 345 {
 346 
 347         if (c == '\'' || c == '`')
 348                 return ('z' + 1);
 349         if (c >= 'a' && c <= 'z')
 350                 return (c);
 351         return (0);
 352 }
 353 
 354 /*
 355  * Mesg decodes the terse/verbose strings. Thus
 356  *      'xxx@yyy' -> 'xxx' if terse, else 'xxx yyy'
 357  *      'xxx|yyy' -> 'xxx' if terse, else 'yyy'
 358  * All others map to themselves.
 359  */
 360 /*
 361  * The feature described above was disabled for localizable messaging.
 362  */
 363 unsigned char *
 364 mesg(str)
 365         unsigned char *str;
 366 {
 367         unsigned char *cp;
 368 
 369         str = (unsigned char *)strcpy(genbuf, str);
 370         /* commented out for localizable messaging */
 371 /*      for (cp = str; *cp; cp++)
 372                 switch (*cp) {
 373 
 374                 case '@':
 375                         if (value(vi_TERSE))
 376                                 *cp = 0;
 377                         else
 378                                 *cp = ' ';
 379                         break;
 380 
 381                 case '|':
 382                         if (value(vi_TERSE) == 0)
 383                                 return (cp + 1);
 384                         *cp = 0;
 385                         break;
 386                 }       */
 387         return (str);
 388 }
 389 
 390 /*VARARGS2*/
 391 void
 392 merror(unsigned char *seekpt, int i)
 393 {
 394         unsigned char *cp = linebuf;
 395 
 396         if (seekpt == 0)
 397                 return;
 398         merror1(seekpt);
 399         if (*cp == '\n')
 400                 putnl(), cp++;
 401         if (inopen > 0 && clr_eol)
 402                 vclreol();
 403         if (enter_standout_mode && exit_bold)
 404                 putpad((unsigned char *)enter_standout_mode);
 405 #ifdef PRESUNEUC
 406         viprintf(mesg(cp), i);
 407 #else
 408         viprintf((char *)mesg(cp), i);
 409 #endif /* PRESUNEUC */
 410         if (enter_standout_mode && exit_bold)
 411                 putpad((unsigned char *)exit_bold);
 412 }
 413 
 414 void
 415 merror1(unsigned char *seekpt)
 416 {
 417 
 418         strcpy(linebuf, seekpt);
 419 }
 420 
 421 #define MAXDATA (56*1024)
 422 int
 423 morelines(void)
 424 {
 425         unsigned char *end;
 426 
 427         if ((int) sbrk(1024 * sizeof (line)) == -1) {
 428                 if (endcore >= (line *) MAXDATA)
 429                         return -1;
 430                 end = (unsigned char *) MAXDATA;
 431                 /*
 432                  * Ask for end+2 sice we want end to be the last used location.
 433                  */
 434                 while (brk(end+2) == -1)
 435                         end -= 64;
 436                 if (end <= (unsigned char *) endcore)
 437                         return -1;
 438                 endcore = (line *) end;
 439         } else {
 440                 endcore += 1024;
 441         }
 442         return (0);
 443 }
 444 
 445 void
 446 nonzero(void)
 447 {
 448 
 449         if (addr1 == zero) {
 450                 notempty();
 451                 error(value(vi_TERSE) ? gettext("Nonzero address required") :
 452 gettext("Nonzero address required on this command"));
 453         }
 454 }
 455 
 456 int
 457 notable(int i)
 458 {
 459 
 460         return (hush == 0 && !inglobal && i > value(vi_REPORT));
 461 }
 462 
 463 
 464 void
 465 notempty(void)
 466 {
 467 
 468         if (dol == zero)
 469                 error(value(vi_TERSE) ? gettext("No lines") :
 470 gettext("No lines in the buffer"));
 471 }
 472 
 473 
 474 void
 475 netchHAD(int cnt)
 476 {
 477 
 478         netchange(lineDOL() - cnt);
 479 }
 480 
 481 void
 482 netchange(int i)
 483 {
 484         unsigned char *cp;
 485 
 486         if (i > 0)
 487                 notesgn = cp = (unsigned char *)"more ";
 488         else
 489                 notesgn = cp = (unsigned char *)"fewer ", i = -i;
 490         if (inopen) {
 491                 notecnt = i;
 492                 notenam = (unsigned char *)"";
 493                 return;
 494         }
 495         if (!notable(i))
 496                 return;
 497         if (*cp == 'm') /* for ease of messge localization */
 498 #ifdef PRESUNEUC
 499                 viprintf(mesg(value(vi_TERSE) ?
 500 #else
 501                 viprintf((char *)mesg(value(vi_TERSE) ?
 502 #endif /* PRESUNEUC */
 503 gettext("%d more lines") :
 504                 /*
 505                  * TRANSLATION_NOTE
 506                  *      Reference order of arguments must not
 507                  *      be changed using '%digit$', since vi's
 508                  *      viprintf() does not support it.
 509                  */
 510 gettext("%d more lines in file after %s")), i, Command);
 511         else
 512 #ifdef PRESUNEUC
 513                 viprintf(mesg(value(vi_TERSE) ?
 514 #else
 515                 viprintf((char *)mesg(value(vi_TERSE) ?
 516 #endif /* PRESUNEUC */
 517 gettext("%d fewer lines") :
 518                 /*
 519                  * TRANSLATION_NOTE
 520                  *      Reference order of arguments must not
 521                  *      be changed using '%digit$', since vi's
 522                  *      viprintf() does not support it.
 523                  */
 524 gettext("%d fewer lines in file after %s")), i, Command);
 525         putNFL();
 526 }
 527 
 528 void
 529 putmark(line *addr)
 530 {
 531 
 532         putmk1(addr, putline());
 533 }
 534 
 535 void
 536 putmk1(line *addr, int n)
 537 {
 538         line *markp;
 539         int oldglobmk;
 540 
 541         oldglobmk = *addr & 1;
 542         *addr &= ~1;
 543         for (markp = (anymarks ? names : &names['z'-'a'+1]);
 544           markp <= &names['z'-'a'+1]; markp++)
 545                 if (*markp == *addr)
 546                         *markp = n;
 547         *addr = n | oldglobmk;
 548 }
 549 
 550 unsigned char *
 551 plural(i)
 552         long i;
 553 {
 554 
 555         return (i == 1 ? (unsigned char *)"" : (unsigned char *)"s");
 556 }
 557 
 558 int     qcount();
 559 short   vcntcol;
 560 
 561 int
 562 qcolumn(unsigned char *lim, unsigned char *gp)
 563 {
 564         int x, length;
 565         int     col;
 566         wchar_t wchar;
 567         int (*OO)();
 568 
 569         OO = Outchar;
 570         Outchar = qcount;
 571         vcntcol = 0;
 572         if (lim != NULL) {
 573                 if(lim == linebuf - 1 || lim == &linebuf[LBSIZE-2])
 574                         length = 1;
 575                 else
 576                         length = mbtowc(&wchar, (char *)lim, MULTI_BYTE_MAX);
 577                 if(length < 0)
 578                         length = 1;
 579                 x = lim[length]; 
 580                 lim[length] = 0;
 581         }
 582         pline(0);
 583         if (lim != NULL)
 584                 lim[length] = x;
 585         if(length > 1 && !gp) {
 586                 /* put cursor at beginning of multibyte character */
 587                 if ((col = wcwidth(wchar)) < 0)
 588                         col = 0;
 589                 vcntcol = vcntcol - col + 1;
 590         }
 591         if (gp)
 592                 while (*gp) {
 593                         length = mbtowc(&wchar, (char *)gp, MULTI_BYTE_MAX);
 594                         if(length < 0) {
 595                                 putoctal = 1;
 596                                 putchar(*gp++);
 597                                 putoctal = 0;
 598                         } else {
 599                                 putchar(wchar);
 600                                 gp += length;
 601                         }
 602                 }
 603         Outchar = OO;
 604         return (vcntcol);
 605 }
 606 
 607 /* This routine puts cursor after multibyte character */
 608 int
 609 nqcolumn(unsigned char *lim, unsigned char *gp)
 610 {
 611         int x, length;
 612         wchar_t wchar;
 613         int (*OO)();
 614 
 615         OO = Outchar;
 616         Outchar = qcount;
 617         vcntcol = 0;
 618         if (lim != NULL) {
 619                 if(lim == linebuf - 1 || lim == &linebuf[LBSIZE-2])
 620                         length = 1;
 621                 else
 622                         length = mbtowc(&wchar, (char *)lim, MULTI_BYTE_MAX);
 623                 if(length < 0)
 624                         length = 1;
 625                 x = lim[length]; 
 626                 lim[length] = 0;
 627         }
 628         pline(0);
 629         if (lim != NULL)
 630                 lim[length] = x;
 631         if (gp)
 632                 while (*gp) {
 633                         length = mbtowc(&wchar, (char *)gp, MULTI_BYTE_MAX);
 634                         if(length < 0) {
 635                                 putoctal = 1;
 636                                 putchar(*gp++);
 637                                 putoctal = 0;
 638                         } else {
 639                                 putchar(wchar);
 640                                 gp += length;
 641                         }
 642                 }
 643         Outchar = OO;
 644         return (vcntcol);
 645 }
 646 
 647 int
 648 qcount(c)
 649 wchar_t c;
 650 {
 651         int cols;
 652 #ifndef PRESUNEUC
 653         int remcols;
 654         short OWCOLS;
 655 #endif /* PRESUNEUC */
 656 
 657         if (c == '\t') {
 658                 vcntcol += value(vi_TABSTOP) - vcntcol % value(vi_TABSTOP);
 659                 return (0);
 660         }
 661 #ifdef PRESUNEUC
 662         if ((cols = wcwidth(c)) > 0)
 663                 vcntcol += cols;
 664 #else
 665         if ((cols = wcwidth(c)) < 0)
 666                 cols = 0;
 667         OWCOLS = WCOLS;
 668         if (WCOLS == 0)
 669                 WCOLS = columns;
 670         if ((mc_wrap) == 1 && (remcols = (WCOLS - (vcntcol % WCOLS))) < cols)
 671                 vcntcol += remcols;
 672         WCOLS = OWCOLS;
 673         vcntcol += cols;
 674 #endif /* PRESUNEUC */
 675         return (0);
 676 }
 677 
 678 void
 679 reverse(line *a1, line *a2)
 680 {
 681         line t;
 682 
 683         for (;;) {
 684                 t = *--a2;
 685                 if (a2 <= a1)
 686                         return;
 687                 *a2 = *a1;
 688                 *a1++ = t;
 689         }
 690 }
 691 
 692 void
 693 save(line *a1, line *a2)
 694 {
 695         int more;
 696 
 697         if (!FIXUNDO)
 698                 return;
 699 #ifdef UNDOTRACE
 700         if (trace)
 701                 vudump("before save");
 702 #endif
 703         undkind = UNDNONE;
 704         undadot = dot;
 705         more = (a2 - a1 + 1) - (unddol - dol);
 706         while (more > (endcore - truedol))
 707                 if (morelines() < 0)
 708                         error(value(vi_TERSE) ? gettext("Out of memory") :
 709 gettext("Out of memory saving lines for undo - try using ed"));
 710         if (more)
 711                 (*(more > 0 ? copywR : copyw))(unddol + more + 1, unddol + 1,
 712                     (truedol - unddol));
 713         unddol += more;
 714         truedol += more;
 715         copyw(dol + 1, a1, a2 - a1 + 1);
 716         undkind = UNDALL;
 717         unddel = a1 - 1;
 718         undap1 = a1;
 719         undap2 = a2 + 1;
 720 #ifdef UNDOTRACE
 721         if (trace)
 722                 vudump("after save");
 723 #endif
 724 }
 725 
 726 void
 727 save12(void)
 728 {
 729 
 730         save(addr1, addr2);
 731 }
 732 
 733 void
 734 saveall(void)
 735 {
 736 
 737         save(one, dol);
 738 }
 739 
 740 int
 741 span(void)
 742 {
 743 
 744         return (addr2 - addr1 + 1);
 745 }
 746 
 747 void
 748 sync(void)
 749 {
 750 
 751         chng = 0;
 752         tchng = 0;
 753         xchng = 0;
 754 }
 755 
 756 
 757 int
 758 skipwh(void)
 759 {
 760         int wh;
 761 
 762         wh = 0;
 763         while (iswhite(peekchar())) {
 764                 wh++;
 765                 ignchar();
 766         }
 767         return (wh);
 768 }
 769 
 770 /*VARARGS2*/
 771 void
 772 smerror(unsigned char *seekpt, unsigned char *cp)
 773 {
 774 
 775         errcnt++;
 776         merror1(seekpt);
 777         if (inopen && clr_eol)
 778                 vclreol();
 779         if (enter_standout_mode && exit_bold)
 780                 putpad((unsigned char *)enter_standout_mode);
 781         lprintf(mesg(linebuf), cp);
 782         if (enter_standout_mode && exit_bold)
 783                 putpad((unsigned char *)exit_bold);
 784 }
 785 
 786 unsigned char *
 787 strend(cp)
 788         unsigned char *cp;
 789 {
 790 
 791         while (*cp)
 792                 cp++;
 793         return (cp);
 794 }
 795 
 796 void
 797 strcLIN(unsigned char *dp)
 798 {
 799 
 800         CP(linebuf, dp);
 801 }
 802 
 803 /*
 804  * A system error has occurred that we need to perror.
 805  * danger is true if we are unsure of the contents of
 806  * the file or our buffer, e.g. a write error in the
 807  * middle of a write operation, or a temp file error.
 808  */
 809 void
 810 syserror(int danger)
 811 {
 812         int e = errno;
 813         char *errstr;
 814         extern char *strerror();
 815 
 816         dirtcnt = 0;
 817         putchar(' ');
 818         if (danger)
 819                 edited = 0;     /* for temp file errors, for example */
 820         if ((errstr = strerror(e)) != NULL)
 821                 error(errstr);
 822         else
 823                 error(gettext("System error %d"), e);
 824 }
 825 
 826 /*
 827  * Return the column number that results from being in column col and
 828  * hitting a tab, where tabs are set every ts columns.  Work right for
 829  * the case where col > columns, even if ts does not divide columns.
 830  */
 831 int
 832 tabcol(int col, int ts)
 833 {
 834         int offset, result;
 835 
 836         if (col >= columns) {
 837                 offset = columns * (col/columns);
 838                 col -= offset;
 839         } else
 840                 offset = 0;
 841         result = col + ts - (col % ts) + offset;
 842         return (result);
 843 }
 844 
 845 unsigned char *
 846 vfindcol(i)
 847         int i;
 848 {
 849         unsigned char *cp, *oldcp;
 850         int (*OO)() = Outchar;
 851         int length;
 852         unsigned char x;
 853         wchar_t wchar;
 854 
 855         Outchar = qcount;
 856         (void) qcolumn(linebuf - 1, (unsigned char *)NOSTR);
 857         for (cp = linebuf; *cp && vcntcol < i; ) {
 858                 oldcp = cp;
 859                 length = mbtowc(&wchar, (char *)cp, MULTI_BYTE_MAX);
 860                 if(length < 0) {
 861                         putoctal = 1;
 862                         putchar(*cp++);
 863                         putoctal = 0;
 864                 } else {
 865                         putchar(wchar);
 866                         cp += length;
 867                 }
 868         }
 869         if (cp != linebuf)
 870                 cp = oldcp;
 871         Outchar = OO;
 872         return (cp);
 873 }
 874 
 875 unsigned char *
 876 vskipwh(cp)
 877         unsigned char *cp;
 878 {
 879 
 880         while (iswhite(*cp) && cp[1])
 881                 cp++;
 882         return (cp);
 883 }
 884 
 885 
 886 unsigned char *
 887 vpastwh(cp)
 888         unsigned char *cp;
 889 {
 890 
 891         while (iswhite(*cp))
 892                 cp++;
 893         return (cp);
 894 }
 895 
 896 int
 897 whitecnt(unsigned char *cp)
 898 {
 899         int i;
 900 
 901         i = 0;
 902         for (;;)
 903                 switch (*cp++) {
 904 
 905                 case '\t':
 906                         i += value(vi_TABSTOP) - i % value(vi_TABSTOP);
 907                         break;
 908 
 909                 case ' ':
 910                         i++;
 911                         break;
 912 
 913                 default:
 914                         return (i);
 915                 }
 916 }
 917 
 918 void
 919 markit(line *addr)
 920 {
 921 
 922         if (addr != dot && addr >= one && addr <= dol)
 923                 markDOT();
 924 }
 925 
 926 /*
 927  * The following code is defensive programming against a bug in the
 928  * pdp-11 overlay implementation.  Sometimes it goes nuts and asks
 929  * for an overlay with some garbage number, which generates an emt
 930  * trap.  This is a less than elegant solution, but it is somewhat
 931  * better than core dumping and losing your work, leaving your tty
 932  * in a weird state, etc.
 933  */
 934 int _ovno;
 935 
 936 /*ARGSUSED*/
 937 void 
 938 onemt(sig)
 939 int sig;
 940 {
 941         int oovno;
 942 
 943         signal(SIGEMT, onemt);
 944         oovno = _ovno;
 945         /* 2 and 3 are valid on 11/40 type vi, so */
 946         if (_ovno < 0 || _ovno > 3)
 947                 _ovno = 0;
 948         error(value(vi_TERSE) ? gettext("emt trap, _ovno is %d ") :
 949 gettext("emt trap, _ovno is %d   - try again"));
 950 }
 951 
 952 /*
 953  * When a hangup occurs our actions are similar to a preserve
 954  * command.  If the buffer has not been [Modified], then we do
 955  * nothing but remove the temporary files and exit.
 956  * Otherwise, we sync the temp file and then attempt a preserve.
 957  * If the preserve succeeds, we unlink our temp files.
 958  * If the preserve fails, we leave the temp files as they are
 959  * as they are a backup even without preservation if they
 960  * are not removed.
 961  */
 962 
 963 /*ARGSUSED*/
 964 void 
 965 onhup(sig)
 966 int sig;
 967 {
 968 
 969         /*
 970          * USG tty driver can send multiple HUP's!!
 971          */
 972         signal(SIGINT, SIG_IGN);
 973         signal(SIGHUP, SIG_IGN);
 974         if (chng == 0) {
 975                 cleanup(1);
 976                 exit(++errcnt);
 977         }
 978         if (setexit() == 0) {
 979                 if (preserve()) {
 980                         cleanup(1);
 981                         exit(++errcnt);
 982                 }
 983         }
 984         if (kflag)
 985                 crypt_close(perm);
 986         if (xtflag)
 987                 crypt_close(tperm);
 988         exit(++errcnt);
 989 }
 990 
 991 /*
 992  * Similar to onhup.  This happens when any random core dump occurs,
 993  * e.g. a bug in vi.  We preserve the file and then generate a core.
 994  */
 995 void oncore(sig)
 996 int sig;
 997 {
 998         static int timescalled = 0;
 999         char *messagep; /* for message localization */
1000 
1001         /*
1002          * USG tty driver can send multiple HUP's!!
1003          */
1004         signal(SIGINT, SIG_IGN);
1005         signal(SIGHUP, SIG_IGN);
1006         signal(sig, SIG_DFL);   /* Insure that we don't catch it again */
1007         messagep = (char *)gettext("\r\nYour file has been preserved\r\n");
1008         if (timescalled++ == 0 && chng && setexit() == 0) {
1009                 if (inopen)
1010                         vsave();
1011                 (void) preserve();
1012                 write(1, messagep, strlen(messagep));
1013         }
1014         if (timescalled < 2) {
1015                 normal(normf);
1016                 cleanup(2);
1017                 kill(getpid(), sig);    /* Resend ourselves the same signal */
1018                 /* We won't get past here */
1019         }
1020         if (kflag)
1021                 crypt_close(perm);
1022         if (xtflag)
1023                 crypt_close(tperm);
1024         exit(++errcnt);
1025 }
1026 
1027 /*
1028  * An interrupt occurred.  Drain any output which
1029  * is still in the output buffering pipeline.
1030  * Catch interrupts again.  Unless we are in visual
1031  * reset the output state (out of -nl mode, e.g).
1032  * Then like a normal error (with the \n before Interrupt
1033  * suppressed in visual mode).
1034  */
1035 
1036 /*ARGSUSED*/
1037 void 
1038 onintr(sig)
1039 int sig;
1040 {
1041 #ifndef CBREAK
1042         signal(SIGINT, onintr);
1043 #else
1044         signal(SIGINT, inopen ? vintr : onintr);
1045 #endif
1046         cancelalarm();
1047         draino();
1048         if (!inopen) {
1049                 pstop();
1050                 setlastchar('\n');
1051 #ifdef CBREAK
1052         }
1053 #else
1054         } else
1055                 vraw();
1056 #endif
1057         error(gettext("\nInterrupt") + (inopen!=0));
1058 }
1059 
1060 /*
1061  * If we are interruptible, enable interrupts again.
1062  * In some critical sections we turn interrupts off,
1063  * but not very often.
1064  */
1065 void
1066 setrupt(void)
1067 {
1068 
1069         if (ruptible) {
1070 #ifndef CBREAK
1071                 signal(SIGINT, onintr);
1072 #else
1073                 signal(SIGINT, inopen ? vintr : onintr);
1074 #endif
1075 #ifdef SIGTSTP
1076                 if (dosusp)
1077                         signal(SIGTSTP, onsusp);
1078 #endif
1079         }
1080 }
1081 
1082 int
1083 preserve(void)
1084 {
1085 
1086 #ifdef VMUNIX
1087         tflush();
1088 #endif
1089         synctmp();
1090         pid = fork();
1091         if (pid < 0)
1092                 return (0);
1093         if (pid == 0) {
1094                 close(0);
1095                 dup(tfile);
1096                 execlp(EXPRESERVE, "expreserve", (char *) 0);
1097                 exit(++errcnt);
1098         }
1099         waitfor();
1100         if (rpid == pid && status == 0)
1101                 return (1);
1102         return (0);
1103 }
1104 
1105 #ifndef V6
1106 void exit(i)
1107         int i;
1108 {
1109 
1110         extern void _exit(int) __NORETURN;
1111 #ifdef TRACE
1112         if (trace)
1113                 fclose(trace);
1114 #endif
1115         _exit(i);
1116 }
1117 #endif
1118 
1119 #ifdef SIGTSTP
1120 /*
1121  * We have just gotten a susp.  Suspend and prepare to resume.
1122  */
1123 extern void redraw();
1124 
1125 /*ARGSUSED*/
1126 void 
1127 onsusp(sig)
1128 int sig;
1129 {
1130         ttymode f;
1131         int savenormtty;
1132 
1133         f = setty(normf);
1134         vnfl();
1135         putpad((unsigned char *)exit_ca_mode);
1136         flush();
1137         resetterm();
1138         savenormtty = normtty;
1139         normtty = 0;
1140 
1141         signal(SIGTSTP, SIG_DFL);
1142         kill(0, SIGTSTP);
1143 
1144         /* the pc stops here */
1145 
1146         signal(SIGTSTP, onsusp);
1147         normtty = savenormtty;
1148         vcontin(0);
1149         flush();
1150         setty(f);
1151         if (!inopen)
1152                 error(0);
1153         else {
1154                 if(vcnt < 0) {
1155                         vcnt = -vcnt;
1156                         if(state == VISUAL)
1157                                 vclear();
1158                         else if(state == CRTOPEN)
1159                                 vcnt = 0;
1160                 }
1161                 vdirty(0, lines);
1162                 if (sig)
1163                         vrepaint(cursor);
1164         }       
1165 }
1166 #endif
1167 
1168 unsigned char *nextchr(cursor)
1169 unsigned char *cursor;
1170 {
1171 
1172         wchar_t wchar;
1173         int length;
1174         length = mbtowc(&wchar, (char *)cursor, MULTI_BYTE_MAX);
1175         if(length <= 0)
1176                 return(++cursor);
1177         return(cursor + length);
1178 }
1179 
1180 unsigned char *lastchr(linebuf, cursor)
1181 unsigned char *linebuf, *cursor;
1182 {
1183         wchar_t wchar;
1184         int length;
1185         unsigned char *ccursor, *ocursor;
1186         if(cursor == linebuf)
1187                 return(linebuf - 1);
1188         ccursor = ocursor = linebuf;
1189         while(ccursor < cursor) {
1190                 length = mbtowc(&wchar, (char *)ccursor, MULTI_BYTE_MAX);
1191                 ocursor =  ccursor;
1192                 if(length <= 0)
1193                         ccursor++;
1194                 else
1195                         ccursor += length;
1196         }
1197         return(ocursor);
1198 }                       
1199 
1200 int
1201 ixlatctl(int flag)
1202 {
1203         static struct strioctl sb = {0, 0, 0, 0};
1204 
1205         if (!(MULTI_BYTE_MAX > 1))
1206                 return (0);
1207 
1208         switch (flag) {
1209         case 0:
1210                 sb.ic_cmd = EUC_MSAVE;
1211                 sb.ic_len = 0;
1212                 sb.ic_dp = 0;
1213                 if (ioctl(0, I_STR, &sb) < 0)
1214                         return (-1);
1215                 return (0);
1216         case 1:
1217                 sb.ic_cmd = EUC_MREST;
1218                 sb.ic_len = 0;
1219                 sb.ic_dp = 0;
1220                 if (ioctl(0, I_STR, &sb) < 0)
1221                         return (-1);
1222                 return (0);
1223         case 11:
1224                 return (0);
1225         default:
1226                 return (-1);
1227         }
1228 }
1229 #ifndef PRESUNEUC
1230 
1231 /* locale specific initialization */
1232 void
1233 localize(void)
1234 {
1235         wchar_t fillerchar;
1236         extern int      wdchkind();
1237         extern int      wdbindf();
1238         extern wchar_t  *wddelim();
1239         extern wchar_t  mcfiller();
1240 
1241         wdwc = wdchkind;
1242         wdbdg = wdbindf;
1243         wddlm = wddelim;
1244         mcfllr = mcfiller;
1245         mc_wrap = 1;
1246         fillerchar = mcfiller();
1247         mc_filler = isascii(fillerchar) ? (fillerchar & 0x7f) : '~';
1248 }
1249 #endif /* PRESUNEUC */