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  * When a hangup occurs our actions are similar to a preserve
 928  * command.  If the buffer has not been [Modified], then we do
 929  * nothing but remove the temporary files and exit.
 930  * Otherwise, we sync the temp file and then attempt a preserve.
 931  * If the preserve succeeds, we unlink our temp files.
 932  * If the preserve fails, we leave the temp files as they are
 933  * as they are a backup even without preservation if they
 934  * are not removed.
 935  */
 936 
 937 /*ARGSUSED*/
 938 void
 939 onhup(sig)
 940 int sig;
 941 {
 942 
 943         /*
 944          * USG tty driver can send multiple HUP's!!
 945          */
 946         signal(SIGINT, SIG_IGN);
 947         signal(SIGHUP, SIG_IGN);
 948         if (chng == 0) {
 949                 cleanup(1);
 950                 exit(++errcnt);
 951         }
 952         if (setexit() == 0) {
 953                 if (preserve()) {
 954                         cleanup(1);
 955                         exit(++errcnt);
 956                 }
 957         }
 958         if (kflag)
 959                 crypt_close(perm);
 960         if (xtflag)
 961                 crypt_close(tperm);
 962         exit(++errcnt);
 963 }
 964 
 965 /*
 966  * Similar to onhup.  This happens when any random core dump occurs,
 967  * e.g. a bug in vi.  We preserve the file and then generate a core.
 968  */
 969 void oncore(sig)
 970 int sig;
 971 {
 972         static int timescalled = 0;
 973         char *messagep; /* for message localization */
 974 
 975         /*
 976          * USG tty driver can send multiple HUP's!!
 977          */
 978         signal(SIGINT, SIG_IGN);
 979         signal(SIGHUP, SIG_IGN);
 980         signal(sig, SIG_DFL);   /* Insure that we don't catch it again */
 981         messagep = (char *)gettext("\r\nYour file has been preserved\r\n");
 982         if (timescalled++ == 0 && chng && setexit() == 0) {
 983                 if (inopen)
 984                         vsave();
 985                 (void) preserve();
 986                 write(1, messagep, strlen(messagep));
 987         }
 988         if (timescalled < 2) {
 989                 normal(normf);
 990                 cleanup(2);
 991                 kill(getpid(), sig);    /* Resend ourselves the same signal */
 992                 /* We won't get past here */
 993         }
 994         if (kflag)
 995                 crypt_close(perm);
 996         if (xtflag)
 997                 crypt_close(tperm);
 998         exit(++errcnt);
 999 }
1000 
1001 /*
1002  * An interrupt occurred.  Drain any output which
1003  * is still in the output buffering pipeline.
1004  * Catch interrupts again.  Unless we are in visual
1005  * reset the output state (out of -nl mode, e.g).
1006  * Then like a normal error (with the \n before Interrupt
1007  * suppressed in visual mode).
1008  */
1009 
1010 /*ARGSUSED*/
1011 void
1012 onintr(sig)
1013 int sig;
1014 {
1015 #ifndef CBREAK
1016         signal(SIGINT, onintr);
1017 #else
1018         signal(SIGINT, inopen ? vintr : onintr);
1019 #endif
1020         cancelalarm();
1021         draino();
1022         if (!inopen) {
1023                 pstop();
1024                 setlastchar('\n');
1025 #ifdef CBREAK
1026         }
1027 #else
1028         } else
1029                 vraw();
1030 #endif
1031         error(gettext("\nInterrupt") + (inopen!=0));
1032 }
1033 
1034 /*
1035  * If we are interruptible, enable interrupts again.
1036  * In some critical sections we turn interrupts off,
1037  * but not very often.
1038  */
1039 void
1040 setrupt(void)
1041 {
1042 
1043         if (ruptible) {
1044 #ifndef CBREAK
1045                 signal(SIGINT, onintr);
1046 #else
1047                 signal(SIGINT, inopen ? vintr : onintr);
1048 #endif
1049 #ifdef SIGTSTP
1050                 if (dosusp)
1051                         signal(SIGTSTP, onsusp);
1052 #endif
1053         }
1054 }
1055 
1056 int
1057 preserve(void)
1058 {
1059 
1060 #ifdef VMUNIX
1061         tflush();
1062 #endif
1063         synctmp();
1064         pid = fork();
1065         if (pid < 0)
1066                 return (0);
1067         if (pid == 0) {
1068                 close(0);
1069                 dup(tfile);
1070                 execlp(EXPRESERVE, "expreserve", (char *) 0);
1071                 exit(++errcnt);
1072         }
1073         waitfor();
1074         if (rpid == pid && status == 0)
1075                 return (1);
1076         return (0);
1077 }
1078 
1079 #ifndef V6
1080 void exit(i)
1081         int i;
1082 {
1083 
1084         extern void _exit(int) __NORETURN;
1085 #ifdef TRACE
1086         if (trace)
1087                 fclose(trace);
1088 #endif
1089         _exit(i);
1090 }
1091 #endif
1092 
1093 #ifdef SIGTSTP
1094 /*
1095  * We have just gotten a susp.  Suspend and prepare to resume.
1096  */
1097 extern void redraw();
1098 
1099 /*ARGSUSED*/
1100 void
1101 onsusp(sig)
1102 int sig;
1103 {
1104         ttymode f;
1105         int savenormtty;
1106 
1107         f = setty(normf);
1108         vnfl();
1109         putpad((unsigned char *)exit_ca_mode);
1110         flush();
1111         resetterm();
1112         savenormtty = normtty;
1113         normtty = 0;
1114 
1115         signal(SIGTSTP, SIG_DFL);
1116         kill(0, SIGTSTP);
1117 
1118         /* the pc stops here */
1119 
1120         signal(SIGTSTP, onsusp);
1121         normtty = savenormtty;
1122         vcontin(0);
1123         flush();
1124         setty(f);
1125         if (!inopen)
1126                 error(0);
1127         else {
1128                 if(vcnt < 0) {
1129                         vcnt = -vcnt;
1130                         if(state == VISUAL)
1131                                 vclear();
1132                         else if(state == CRTOPEN)
1133                                 vcnt = 0;
1134                 }
1135                 vdirty(0, lines);
1136                 if (sig)
1137                         vrepaint(cursor);
1138         }
1139 }
1140 #endif
1141 
1142 unsigned char *nextchr(cursor)
1143 unsigned char *cursor;
1144 {
1145 
1146         wchar_t wchar;
1147         int length;
1148         length = mbtowc(&wchar, (char *)cursor, MULTI_BYTE_MAX);
1149         if(length <= 0)
1150                 return(++cursor);
1151         return(cursor + length);
1152 }
1153 
1154 unsigned char *lastchr(linebuf, cursor)
1155 unsigned char *linebuf, *cursor;
1156 {
1157         wchar_t wchar;
1158         int length;
1159         unsigned char *ccursor, *ocursor;
1160         if(cursor == linebuf)
1161                 return(linebuf - 1);
1162         ccursor = ocursor = linebuf;
1163         while(ccursor < cursor) {
1164                 length = mbtowc(&wchar, (char *)ccursor, MULTI_BYTE_MAX);
1165                 ocursor =  ccursor;
1166                 if(length <= 0)
1167                         ccursor++;
1168                 else
1169                         ccursor += length;
1170         }
1171         return(ocursor);
1172 }
1173 
1174 int
1175 ixlatctl(int flag)
1176 {
1177         static struct strioctl sb = {0, 0, 0, 0};
1178 
1179         if (!(MULTI_BYTE_MAX > 1))
1180                 return (0);
1181 
1182         switch (flag) {
1183         case 0:
1184                 sb.ic_cmd = EUC_MSAVE;
1185                 sb.ic_len = 0;
1186                 sb.ic_dp = 0;
1187                 if (ioctl(0, I_STR, &sb) < 0)
1188                         return (-1);
1189                 return (0);
1190         case 1:
1191                 sb.ic_cmd = EUC_MREST;
1192                 sb.ic_len = 0;
1193                 sb.ic_dp = 0;
1194                 if (ioctl(0, I_STR, &sb) < 0)
1195                         return (-1);
1196                 return (0);
1197         case 11:
1198                 return (0);
1199         default:
1200                 return (-1);
1201         }
1202 }
1203 #ifndef PRESUNEUC
1204 
1205 /* locale specific initialization */
1206 void
1207 localize(void)
1208 {
1209         wchar_t fillerchar;
1210         extern int      wdchkind();
1211         extern int      wdbindf();
1212         extern wchar_t  *wddelim();
1213         extern wchar_t  mcfiller();
1214 
1215         wdwc = wdchkind;
1216         wdbdg = wdbindf;
1217         wddlm = wddelim;
1218         mcfllr = mcfiller;
1219         mc_wrap = 1;
1220         fillerchar = mcfiller();
1221         mc_filler = isascii(fillerchar) ? (fillerchar & 0x7f) : '~';
1222 }
1223 #endif /* PRESUNEUC */