sed1.c (16599B)
1 /* from Unix 7th Edition sed */ 2 /* Sccsid @(#)sed1.c 1.42 (gritter) 2/6/05> */ 3 /* 4 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * Redistributions of source code and documentation must retain the 10 * above copyright notice, this list of conditions and the following 11 * disclaimer. 12 * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed or owned by Caldera 18 * International, Inc. 19 * Neither the name of Caldera International, Inc. nor the names of 20 * other contributors may be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 24 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE 28 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 31 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 33 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 34 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <fcntl.h> 40 #include <unistd.h> 41 #include <stdlib.h> 42 #include <ctype.h> 43 #include <wchar.h> 44 #include <wctype.h> 45 #include "sed.h" 46 47 #if !defined (SUS) && !defined (SU3) && !defined(S42) 48 #define INIT extern char *cp, *badp; \ 49 register char *sp = cp; 50 #define GETC() (*sp++) 51 #define PEEKC() (*sp) 52 #define UNGETC(c) (--sp) 53 #define RETURN(c) { cp = sp; return ep; } 54 #define ERROR(c) { cp = sp; return badp; } 55 56 #define regexp_h_malloc(n) smalloc(n) 57 #include <regexp.h> 58 #endif /* !SUS && !SU3 && !S42 */ 59 60 #ifndef CCEOF 61 #ifdef CEOF 62 #define CCEOF CEOF 63 #else /* !CEOF */ 64 #define CCEOF 22 65 #endif /* !CEOF */ 66 #endif /* !CCEOF */ 67 68 int ceof = CCEOF; 69 70 #if !defined (SUS) && !defined (SU3) 71 static const char *trans[] = { 72 "\\00", 73 "\\01", 74 "\\02", 75 "\\03", 76 "\\04", 77 "\\05", 78 "\\06", 79 "\\07", 80 "-<", 81 "->", 82 "\n", 83 "\\13", 84 "\\14", 85 "\\15", 86 "\\16", 87 "\\17", 88 "\\20", 89 "\\21", 90 "\\22", 91 "\\23", 92 "\\24", 93 "\\25", 94 "\\26", 95 "\\27", 96 "\\30", 97 "\\31", 98 "\\32", 99 "\\33", 100 "\\34", 101 "\\35", 102 "\\36", 103 "\\37" 104 }; 105 #endif /* !SUS, !SU3 */ 106 107 static char *cbp; 108 static char *ebp; 109 static int dolflag; 110 static int sflag; 111 static int jflag; 112 static int delflag; 113 static long long lnum; 114 static char ibuf[512]; 115 static int ibrd; 116 static int mflag; 117 static int f = -1; 118 static int spend; 119 static int genend; 120 static int hspend; 121 122 static void command(struct reptr *); 123 static int match(char *, int, int); 124 static int substitute(struct reptr *); 125 static void dosub(char *); 126 static int place(int, int, int); 127 static int gline(int); 128 static void arout(void); 129 static void lcom(wint_t, int); 130 static void oout(int); 131 static void mout(const char *); 132 static void nout(wint_t); 133 static void wout(wint_t); 134 static void lout(int); 135 136 #if defined (SUS) || defined (SU3) || defined (S42) 137 #define NBRA 9 138 int sed; 139 int nbra; 140 int circf; 141 static char *braslist[NBRA]; 142 static char *braelist[NBRA]; 143 static char *loc1, *loc2, *locs; 144 145 static int 146 step(char *line, char *pattern) 147 { 148 struct re_emu *re = (struct re_emu *)&pattern[-1]; 149 regmatch_t bralist[NBRA+1]; 150 int eflag = 0; 151 int res; 152 int i, nsub; 153 154 if (circf == 2) /* empty pattern */ 155 return 0; 156 if (locs) 157 eflag |= REG_NOTBOL; 158 /* 159 * Don't fetch more match locations than necessary since this 160 * might prevent use of DFA. 161 */ 162 nsub = mflag; 163 if ((res = regexec(&re->r_preg, line, nsub, bralist, eflag)) == 0) { 164 if (nsub > 0) { 165 loc1 = line + bralist[0].rm_so; 166 loc2 = line + bralist[0].rm_eo; 167 for (i = 1; i < nsub; i++) { 168 if (bralist[i].rm_so != -1) { 169 braslist[i-1] = line + bralist[i].rm_so; 170 braelist[i-1] = line + bralist[i].rm_eo; 171 } else 172 braslist[i-1] = braelist[i-1] = NULL; 173 } 174 } 175 } 176 return res == 0; 177 } 178 #endif /* SUS || SU3 || S42 */ 179 180 static int lcomlen; 181 static int Braslist[NBRA]; 182 static int Braelist[NBRA]; 183 static int Loc1, Loc2; 184 185 void 186 execute(const char *file) 187 { 188 register char *p1, *p2; 189 register struct reptr *ipc; 190 int c; 191 int execc; 192 193 if (f >= 0) 194 close(f); 195 if (file) { 196 if ((f = open(file, O_RDONLY)) < 0) { 197 nonfatal("Can't open %s", file); 198 return; 199 } 200 } else 201 f = 0; 202 203 ebp = ibuf; 204 cbp = ibuf; 205 206 if(pending) { 207 ipc = pending; 208 pending = 0; 209 goto yes; 210 } 211 212 for(;;) { 213 if((execc = gline(0)) < 0) { 214 if (f >= 0) { 215 close(f); 216 f = -1; 217 } 218 return; 219 } 220 spend = execc; 221 222 for(ipc = ptrspace; ipc->command; ) { 223 224 p1 = ipc->ad1; 225 p2 = ipc->ad2; 226 227 if(p1) { 228 229 if(ipc->inar) { 230 if(*p2 == CEND) { 231 p1 = 0; 232 } else if(*p2 == CLNUM) { 233 c = glno(&p2[1]); 234 if(lnum > tlno[c]) { 235 ipc->inar = 0; 236 if(ipc->negfl) 237 goto yes; 238 ipc++; 239 continue; 240 } 241 if(lnum == tlno[c]) { 242 ipc->inar = 0; 243 } 244 } else if(match(p2, 0, 0)) { 245 ipc->inar = 0; 246 } 247 } else if(*p1 == CEND) { 248 if(!dolflag) { 249 if(ipc->negfl) 250 goto yes; 251 ipc++; 252 continue; 253 } 254 255 } else if(*p1 == CLNUM) { 256 c = glno(&p1[1]); 257 if(lnum != tlno[c]) { 258 if(ipc->negfl) 259 goto yes; 260 ipc++; 261 continue; 262 } 263 if(p2) { 264 ipc->inar = 1; 265 #if defined (SUS) || defined (SU3) 266 goto ichk; 267 #endif /* SUS, SU3 */ 268 } 269 } else if(match(p1, 0, 0)) { 270 if(p2) { 271 ipc->inar = 1; 272 #if defined (SUS) || defined (SU3) 273 ichk: if (*p2 == CLNUM) { 274 c = glno(&p2[1]); 275 if (lnum >= tlno[c]) 276 ipc->inar = 0; 277 } 278 #endif /* SUS, SU3 */ 279 } 280 } else { 281 if(ipc->negfl) 282 goto yes; 283 ipc++; 284 continue; 285 } 286 } 287 288 if(ipc->negfl) { 289 ipc++; 290 continue; 291 } 292 yes: 293 command(ipc); 294 295 if(delflag) 296 break; 297 298 if(jflag) { 299 jflag = 0; 300 if((ipc = P(ipc->bptr.lb1)) == 0) { 301 ipc = ptrspace; 302 break; 303 } 304 } else 305 ipc++; 306 307 } 308 if(!nflag && !delflag) { 309 for(p1 = linebuf; p1 < &linebuf[spend]; p1++) 310 putc(*p1&0377, stdout); 311 putc('\n', stdout); 312 } 313 314 if(A(aptr) > abuf) { 315 arout(); 316 } 317 318 delflag = 0; 319 320 } 321 } 322 323 static int 324 match(char *expbuf, int gf, int needloc) 325 { 326 register char *p1; 327 int i, val; 328 329 if(gf) { 330 if(*expbuf) return(0); 331 #if defined (SUS) || defined (SU3) || defined (S42) 332 if (loc1 == loc2) { 333 int n; 334 wchar_t wc; 335 if (multibyte && (n = mbtowc(&wc, &linebuf[Loc2], 336 MB_LEN_MAX)) > 0) 337 Loc2 += n; 338 else 339 Loc2++; 340 } 341 #endif 342 locs = p1 = loc2 = &linebuf[Loc2]; 343 } else { 344 p1 = linebuf; 345 locs = 0; 346 } 347 348 mflag = needloc; 349 circf = *expbuf++; 350 val = step(p1, expbuf); 351 for (i = 0; i < NBRA; i++) { 352 Braslist[i] = braslist[i] - linebuf; 353 Braelist[i] = braelist[i] - linebuf; 354 } 355 Loc1 = loc1 - linebuf; 356 Loc2 = loc2 - linebuf; 357 return val; 358 } 359 360 static int 361 substitute(struct reptr *ipc) 362 { 363 int matchcnt = 1; 364 365 if (match(ipc->bptr.re1, 0, ipc->nsub + 1) == 0) 366 return(0); 367 368 sflag = 0; 369 if (ipc->gfl >= -1 && ipc->gfl <= 1) 370 dosub(ipc->rhs); 371 372 if(ipc->gfl != 0) { 373 while(linebuf[Loc2]) { 374 if(match(ipc->bptr.re1, 1, ipc->nsub + 1) == 0) 375 break; 376 matchcnt++; 377 if (ipc->gfl == -1 || ipc->gfl == matchcnt) 378 dosub(ipc->rhs); 379 } 380 } 381 return(1); 382 } 383 384 static void 385 dosub(char *rhsbuf) 386 { 387 register int lc, sc; 388 register char *rp; 389 int c; 390 391 sflag = 1; 392 lc = 0; /*linebuf*/ 393 sc = 0; /*genbuf*/ 394 rp = rhsbuf; 395 while (lc < Loc1) 396 genbuf[sc++] = linebuf[lc++]; 397 while((c = *rp++) != 0) { 398 if (c == '&') { 399 sc = place(sc, Loc1, Loc2); 400 continue; 401 } else if (c == '\\') { 402 c = *rp++; 403 if (c >= '1' && c < NBRA+'1') { 404 sc = place(sc, Braslist[c-'1'], 405 Braelist[c-'1']); 406 continue; 407 } 408 } 409 if (sc >= gbend) 410 growsp("output line too long."); 411 genbuf[sc++] = (char)c; 412 } 413 lc = Loc2; 414 Loc2 = sc; 415 do { 416 if (sc >= gbend) 417 growsp("Output line too long."); 418 } while (genbuf[sc++] = linebuf[lc++], lc <= spend); 419 genend = sc-1; 420 lc = 0; /*linebuf*/ 421 sc = 0; /*genbuf*/ 422 while (linebuf[lc++] = genbuf[sc++], sc <= genend); 423 spend = lc-1; 424 } 425 426 static int 427 place(int asc, int al1, int al2) 428 { 429 register int sc; 430 register int l1, l2; 431 432 sc = asc; 433 l1 = al1; 434 l2 = al2; 435 while (l1 < l2) { 436 if (sc >= gbend) 437 growsp("Output line too long."); 438 genbuf[sc++] = linebuf[l1++]; 439 } 440 return(sc); 441 } 442 443 static void 444 command(struct reptr *ipc) 445 { 446 register int i; 447 wint_t c; 448 register char *p1, *p2; 449 int k1, k2, k3; 450 char *lp; 451 int execc; 452 453 454 switch(ipc->command) { 455 456 case ACOM: 457 *A(aptr) = ipc; 458 aptr_inc(); 459 *A(aptr) = 0; 460 break; 461 462 case CCOM: 463 delflag = 1; 464 if(!ipc->inar || dolflag) { 465 for(p1 = ipc->bptr.re1; *p1; ) { 466 putc(*p1&0377, stdout); 467 p1++; 468 } 469 putc('\n', stdout); 470 } 471 break; 472 case DCOM: 473 delflag++; 474 break; 475 case CDCOM: 476 p1 = p2 = linebuf; 477 478 while(*p1 != '\n') { 479 if(p1++ == &linebuf[spend]) { 480 delflag++; 481 return; 482 } 483 } 484 485 p1++; 486 while(*p2++ = *p1++, p1 <= &linebuf[spend]); 487 spend = p2-1 - linebuf; 488 jflag++; 489 break; 490 491 case EQCOM: 492 fprintf(stdout, "%lld\n", lnum); 493 break; 494 495 case GCOM: 496 p1 = linebuf; 497 p2 = holdsp; 498 while(*p1++ = *p2++, p2 <= &holdsp[hspend]); 499 spend = p1-1 - linebuf; 500 break; 501 502 case CGCOM: 503 linebuf[spend++] = '\n'; 504 k1 = spend; 505 k2 = 0; /*holdsp*/ 506 do { 507 if(k1 >= lbend) 508 growsp(NULL); 509 } while(linebuf[k1++] = holdsp[k2++], k2 <= hspend); 510 spend = k1-1; 511 break; 512 513 case HCOM: 514 p1 = holdsp; 515 p2 = linebuf; 516 while(*p1++ = *p2++, p2 <= &linebuf[spend]); 517 hspend = p1-1 - holdsp; 518 break; 519 520 case CHCOM: 521 holdsp[hspend++] = '\n'; 522 k1 = hspend; 523 k2 = 0; /*linebuf*/ 524 do { 525 if(k1 >= hend) 526 growsp("\1hold space overflow !"); 527 } while(holdsp[k1++] = linebuf[k2++], k2 <= spend); 528 hspend = k1-1; 529 break; 530 531 case ICOM: 532 for(p1 = ipc->bptr.re1; *p1; ) { 533 putc(*p1&0377, stdout); 534 p1++; 535 } 536 putc('\n', stdout); 537 break; 538 539 case BCOM: 540 jflag = 1; 541 break; 542 543 case LCOM: 544 lp = linebuf; 545 lcomlen = 0; 546 while (lp < &linebuf[spend]) { 547 c = fetch(&lp); 548 lcom(c, invchar == 0); 549 } 550 #if defined (SUS) || defined (SU3) 551 putc('$', stdout); 552 #endif /* SUS, SU3 */ 553 putc('\n', stdout); 554 break; 555 556 case NCOM: 557 if(!nflag) { 558 for(p1 = linebuf; p1 < &linebuf[spend]; p1++) 559 putc(*p1&0377, stdout); 560 putc('\n', stdout); 561 } 562 563 if(A(aptr) > abuf) 564 arout(); 565 if((execc = gline(0)) < 0) { 566 pending = ipc; 567 delflag = 1; 568 break; 569 } 570 spend = execc; 571 572 break; 573 case CNCOM: 574 if(A(aptr) > abuf) 575 arout(); 576 linebuf[spend++] = '\n'; 577 if((execc = gline(spend)) < 0) { 578 pending = ipc; 579 delflag = 1; 580 break; 581 } 582 spend = execc; 583 break; 584 585 case PCOM: 586 for(p1 = linebuf; p1 < &linebuf[spend]; p1++) 587 putc(*p1&0377, stdout); 588 putc('\n', stdout); 589 break; 590 case CPCOM: 591 cpcom: 592 for(p1 = linebuf; *p1 != '\n' && p1<&linebuf[spend]; ) { 593 putc(*p1&0377, stdout); 594 p1++; 595 } 596 putc('\n', stdout); 597 break; 598 599 case QCOM: 600 if(!nflag) { 601 for(p1 = linebuf; p1 < &linebuf[spend]; p1++) 602 putc(*p1&0377, stdout); 603 putc('\n', stdout); 604 } 605 if(A(aptr) > abuf) arout(); 606 fclose(stdout); 607 if (ibrd > 0) 608 lseek(f, -ibrd, SEEK_CUR); 609 exit(0); 610 case RCOM: 611 612 *A(aptr) = ipc; 613 aptr_inc(); 614 *A(aptr) = 0; 615 616 break; 617 618 case SCOM: 619 i = substitute(ipc); 620 if(ipc->pfl && i) 621 if(ipc->pfl == 1) { 622 for(p1 = linebuf; p1 < &linebuf[spend]; 623 p1++) 624 putc(*p1&0377, stdout); 625 putc('\n', stdout); 626 } 627 else 628 goto cpcom; 629 if(i && ipc->fcode) 630 goto wcom; 631 break; 632 633 case TCOM: 634 if(sflag == 0) break; 635 sflag = 0; 636 jflag = 1; 637 break; 638 639 wcom: 640 case WCOM: 641 fprintf(ipc->fcode, "%s\n", linebuf); 642 break; 643 case XCOM: 644 p1 = linebuf; 645 p2 = genbuf; 646 while(*p2++ = *p1++, p1 <= &linebuf[spend]); 647 genend = p2-1 - genbuf; 648 p1 = holdsp; 649 p2 = linebuf; 650 while(*p2++ = *p1++, p1 <= &holdsp[hspend]); 651 spend = p2-1 - linebuf; 652 p1 = genbuf; 653 p2 = holdsp; 654 while(*p2++ = *p1++, p1 <= &genbuf[genend]); 655 hspend = p2-1 - holdsp; 656 break; 657 658 case YCOM: 659 if (multibyte) { 660 struct yitem **yt, *yp; 661 662 yt = (struct yitem **)ipc->bptr.re1; 663 k1 = 0; /*linebuf*/ 664 k2 = 0; /*genbuf*/ 665 do { 666 k3 = k1; 667 lp = &linebuf[k1]; 668 c = fetch(&lp); 669 k1 = lp - linebuf; 670 if (invchar == 0 && 671 (yp = ylook(c, yt, 0)) != NULL) { 672 k3 = 0; /*yp->y_mc*/ 673 do { 674 if (k2 >= gbend) 675 growsp("output " 676 "line too " 677 "long."); 678 genbuf[k2] = 679 yp->y_mc[k3++]; 680 } while (genbuf[k2++] != '\0'); 681 k2--; 682 } else { 683 while (k3 < k1) { 684 if (k2 >= gbend) 685 growsp("output " 686 "line too " 687 "long."); 688 genbuf[k2++] = 689 linebuf[k3++]; 690 } 691 } 692 } while (k1 <= spend); 693 genend = k2-1; 694 p1 = linebuf; 695 p2 = genbuf; 696 while (*p1++ = *p2++, p2 <= &genbuf[genend]); 697 spend = p1-1 - linebuf; 698 } else { 699 p1 = linebuf; 700 p2 = ipc->bptr.re1; 701 while((*p1 = p2[*p1 & 0377]) != 0) p1++; 702 } 703 break; 704 case COCOM: 705 case ECOM: 706 case FCOM: 707 case CWCOM: 708 ; 709 } 710 711 } 712 713 static int 714 gline(int addr) 715 { 716 register char *p2; 717 register int c; 718 register int c1; 719 c1 = addr; 720 p2 = cbp; 721 for (;;) { 722 if (p2 >= ebp) { 723 if (f < 0 || (c = read(f, ibuf, sizeof ibuf)) <= 0) { 724 if (c1 > addr && dolflag == 0) { 725 c = 1; 726 ibuf[0] = '\n'; 727 close(f); 728 f = -1; 729 } else 730 return(-1); 731 } else 732 ibrd += c; 733 p2 = ibuf; 734 ebp = ibuf+c; 735 } 736 if ((c = *p2++ & 0377) == '\n') { 737 ibrd--; 738 if(needdol && p2 >= ebp) { 739 if(f<0||(c = read(f, ibuf, sizeof ibuf)) <= 0) { 740 close(f); 741 f = -1; 742 if(eargc == 0) 743 dolflag = 1; 744 } else 745 ibrd += c; 746 747 p2 = ibuf; 748 ebp = ibuf + c; 749 } 750 break; 751 } 752 if(c1 >= lbend) 753 growsp(NULL); 754 linebuf[c1++] = (char)c; 755 ibrd--; 756 } 757 lnum++; 758 if(c1 >= lbend) 759 growsp(NULL); 760 linebuf[c1] = 0; 761 cbp = p2; 762 763 sflag = 0; 764 return(c1); 765 } 766 767 static void 768 arout(void) 769 { 770 register char *p1; 771 struct reptr **a; 772 FILE *fi; 773 char c; 774 int t; 775 776 for (a = abuf; *a; a++) { 777 if((*a)->command == ACOM) { 778 for(p1 = (*a)->bptr.re1; *p1; ) { 779 putc(*p1&0377, stdout); 780 p1++; 781 } 782 putc('\n', stdout); 783 } else { 784 if((fi = fopen((*a)->bptr.re1, "r")) == NULL) 785 continue; 786 while((t = getc(fi)) != EOF) { 787 c = t; 788 putc(c&0377, stdout); 789 } 790 fclose(fi); 791 } 792 } 793 aptr = 1; 794 *A(aptr) = 0; 795 } 796 797 static void 798 lcom(wint_t c, int valid) 799 { 800 if (!valid) { 801 oout(c); 802 return; 803 } 804 #if defined (SUS) || defined (SU3) 805 switch (c) { 806 case '\\': 807 mout("\\\\"); 808 return; 809 case '\a': 810 mout("\\a"); 811 return; 812 case '\b': 813 mout("\\b"); 814 return; 815 case '\f': 816 mout("\\f"); 817 return; 818 case '\r': 819 mout("\\r"); 820 return; 821 case '\t': 822 mout("\\t"); 823 return; 824 case '\v': 825 mout("\\v"); 826 return; 827 } 828 #else /* !SUS, !SU3 */ 829 if (c < 040) { 830 mout(trans[c]); 831 return; 832 } 833 #endif /* !SUS, !SU3 */ 834 if (multibyte) { 835 if (iswprint(c)) 836 wout(c); 837 else 838 nout(c); 839 } else { 840 if (isprint(c)) 841 lout(c); 842 else 843 oout(c); 844 } 845 } 846 847 static void 848 oout(int c) 849 { 850 char lbuf[5], *p; 851 int d; 852 const char *nums = "01234567"; 853 854 p = lbuf; 855 *p++ = '\\'; 856 *p++ = nums[(c & ~077) >> 6]; 857 c &= 077; 858 d = c & 07; 859 *p++ = c > d ? nums[(c-d)>>3] : nums[0]; 860 *p++ = nums[d]; 861 *p = '\0'; 862 mout(lbuf); 863 } 864 865 static void 866 mout(const char *p) 867 { 868 while (*p != '\0') { 869 lout(*p & 0377); 870 p++; 871 } 872 } 873 874 static void 875 nout(wint_t c) 876 { 877 char mb[MB_LEN_MAX+1]; 878 char *p; 879 int i; 880 881 if ((i = wctomb(mb, c)) > 0) { 882 mb[i] = '\0'; 883 for (p = mb; *p; p++) 884 oout(*p & 0377); 885 } 886 } 887 888 static void 889 lout(int c) 890 { 891 if (lcomlen++ > 70) { 892 putc('\\', stdout); 893 putc('\n', stdout); 894 lcomlen = 1; 895 } 896 putc(c, stdout); 897 } 898 899 static void 900 wout(wint_t c) 901 { 902 char mb[MB_LEN_MAX+1], *p; 903 int i, w; 904 905 if ((i = wctomb(mb, c)) > 0) { 906 w = wcwidth(c); 907 if (lcomlen + w > 70) { 908 putc('\\', stdout); 909 putc('\n', stdout); 910 lcomlen = 0; 911 } 912 mb[i] = '\0'; 913 for (p = mb; *p; p++) 914 putc(*p & 0377, stdout); 915 lcomlen += w; 916 } 917 }