1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980 Regents of the University of California. 11 * All rights reserved. The Berkeley Software License Agreement 12 * specifies the terms and conditions for redistribution. 13 */ 14 15 /* 16 * This module provides with system/library function substitutes for tchar 17 * datatype. This also includes two conversion functions between tchar and 18 * char arrays. 19 * 20 * T. Kurosaka, Palo Alto, California, USA 21 * March 1989 22 * 23 * Implementation Notes: 24 * Many functions defined here use a "char" buffer chbuf[]. In the 25 * first attempt, there used to be only one chbuf defined as static 26 * (private) variable and shared by these functions. csh linked with that 27 * version of this file misbehaved in interpreting "eval `tset ....`". 28 * (in general, builtin function with back-quoted expression). 29 * This bug seemed to be caused by sharing of chbuf 30 * by these functions simultanously (thru vfork() mechanism?). We could not 31 * identify which two functions interfere each other so we decided to 32 * have each of these function its private instance of chbuf. 33 * The size of chbuf[] might be much bigger than necessary for some functions. 34 */ 35 #ifdef DBG 36 #include <stdio.h> /* For <assert.h> needs stderr defined. */ 37 #else /* !DBG */ 38 #define NDEBUG /* Disable assert(). */ 39 #endif /* !DBG */ 40 41 #include <assert.h> 42 #include "sh.h" 43 44 #ifdef MBCHAR 45 #include <widec.h> /* For wcsetno() */ 46 #endif 47 48 #include <sys/param.h> /* MAXPATHLEN */ 49 #include <fcntl.h> 50 #include <unistd.h> 51 52 bool cflg; 53 54 /* 55 * strtots(to, from): convert a char string 'from' into a tchar buffer 'to'. 56 * 'to' is assumed to have the enough size to hold the conversion result. 57 * When 'to' is NOSTR(=(tchar *)0), strtots() attempts to allocate a space 58 * automatically using xalloc(). It is caller's responsibility to 59 * free the space allocated in this way, by calling xfree(ptr). 60 * In either case, strtots() returns the pointer to the conversion 61 * result (i.e. 'to', if 'to' wasn't NOSTR, or the allocated space.). 62 * When a conversion or allocateion failed, NOSTR is returned. 63 */ 64 65 tchar * 66 strtots(tchar *to, char *from) 67 { 68 int i; 69 70 if (to == NOSTR) { /* Need to xalloc(). */ 71 int i; 72 73 i = mbstotcs(NOSTR, from, 0); 74 if (i < 0) { 75 return (NOSTR); 76 } 77 78 /* Allocate space for the resulting tchar array. */ 79 to = (tchar *)xalloc(i * sizeof (tchar)); 80 } 81 i = mbstotcs(to, from, INT_MAX); 82 if (i < 0) { 83 return (NOSTR); 84 } 85 return (to); 86 } 87 88 char * 89 tstostr(char *to, tchar *from) 90 { 91 tchar *ptc; 92 wchar_t wc; 93 char *pmb; 94 int len; 95 96 if (to == (char *)NULL) { /* Need to xalloc(). */ 97 int i; 98 int i1; 99 char junk[MB_LEN_MAX]; 100 101 /* Get sum of byte counts for each char in from. */ 102 i = 0; 103 ptc = from; 104 while (wc = (wchar_t)((*ptc++)&TRIM)) { 105 if ((i1 = wctomb(junk, wc)) <= 0) { 106 i1 = 1; 107 } 108 i += i1; 109 } 110 111 /* Allocate that much. */ 112 to = (char *)xalloc(i + 1); 113 } 114 115 ptc = from; 116 pmb = to; 117 while (wc = (wchar_t)((*ptc++)&TRIM)) { 118 if ((len = wctomb(pmb, wc)) <= 0) { 119 *pmb = (unsigned char)wc; 120 len = 1; 121 } 122 pmb += len; 123 } 124 *pmb = (char)0; 125 return (to); 126 } 127 128 /* 129 * mbstotcs(to, from, tosize) is similar to strtots() except that 130 * this returns # of tchars of the resulting tchar string. 131 * When NULL is give as the destination, no real conversion is carried out, 132 * and the function reports how many tchar characters would be made in 133 * the converted result including the terminating 0. 134 * tchar *to; - Destination buffer, or NULL. 135 * char *from; - Source string. 136 * int tosize; - Size of to, in terms of # of tchars. 137 */ 138 int 139 mbstotcs(tchar *to, char *from, int tosize) 140 { 141 tchar *ptc = to; 142 char *pmb = from; 143 wchar_t wc; 144 int chcnt = 0; 145 int j; 146 147 148 /* Just count how many tchar would be in the result. */ 149 if (to == (tchar *)NULL) { 150 while (*pmb) { 151 if ((j = mbtowc(&wc, pmb, MB_CUR_MAX)) <= 0) { 152 j = 1; 153 } 154 pmb += j; 155 chcnt++; 156 } 157 chcnt++; /* For terminator. */ 158 return (chcnt); /* # of chars including terminating zero. */ 159 } else { /* Do the real conversion. */ 160 while (*pmb) { 161 if ((j = mbtowc(&wc, pmb, MB_CUR_MAX)) <= 0) { 162 wc = (unsigned char)*pmb; 163 j = 1; 164 } 165 pmb += j; 166 *(ptc++) = (tchar)wc; 167 if (++chcnt >= tosize) { 168 break; 169 } 170 } 171 /* Terminate with zero only when space is left. */ 172 if (chcnt < tosize) { 173 *ptc = (tchar)0; 174 ++chcnt; 175 } 176 return (chcnt); /* # of chars including terminating zero. */ 177 } 178 } 179 180 181 /* tchar version of STRING functions. */ 182 183 /* 184 * Returns the number of 185 * non-NULL tchar elements in tchar string argument. 186 */ 187 int 188 strlen_(tchar *s) 189 { 190 int n; 191 192 n = 0; 193 while (*s++) { 194 n++; 195 } 196 return (n); 197 } 198 199 /* 200 * Concatenate tchar string s2 on the end of s1. S1's space must be large 201 * enough. Return s1. 202 */ 203 tchar * 204 strcat_(tchar *s1, tchar *s2) 205 { 206 tchar *os1; 207 208 os1 = s1; 209 while (*s1++) 210 ; 211 --s1; 212 while (*s1++ = *s2++) 213 ; 214 return (os1); 215 } 216 217 /* 218 * Compare tchar strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 219 * BUGS: Comparison between two characters are done by subtracting two chars 220 * after converting each to an unsigned long int value. It might not make 221 * a whole lot of sense to do that if the characters are in represented 222 * as wide characters and the two characters belong to different codesets. 223 * Therefore, this function should be used only to test the equallness. 224 */ 225 int 226 strcmp_(tchar *s1, tchar *s2) 227 { 228 while (*s1 == *s2++) { 229 if (*s1++ == (tchar)0) { 230 return (0); 231 } 232 } 233 return (((unsigned long)*s1) - ((unsigned long)*(--s2))); 234 } 235 236 /* 237 * This is only used in sh.glob.c for sorting purpose. 238 */ 239 int 240 strcoll_(tchar *s1, tchar *s2) 241 { 242 char buf1[BUFSIZ]; 243 char buf2[BUFSIZ]; 244 245 tstostr(buf1, s1); 246 tstostr(buf2, s2); 247 return (strcoll(buf1, buf2)); 248 } 249 250 /* 251 * Copy tchar string s2 to s1. s1 must be large enough. 252 * return s1 253 */ 254 tchar * 255 strcpy_(tchar *s1, tchar *s2) 256 { 257 tchar *os1; 258 259 os1 = s1; 260 while (*s1++ = *s2++) 261 ; 262 return (os1); 263 } 264 265 /* 266 * Return the ptr in sp at which the character c appears; 267 * NULL if not found 268 */ 269 tchar * 270 index_(tchar *sp, tchar c) 271 { 272 273 do { 274 if (*sp == c) { 275 return (sp); 276 } 277 } while (*sp++); 278 return (NULL); 279 } 280 281 /* 282 * Return the ptr in sp at which the character c last 283 * appears; NOSTR if not found 284 */ 285 286 tchar * 287 rindex_(tchar *sp, tchar c) 288 { 289 tchar *r; 290 291 r = NOSTR; 292 do { 293 if (*sp == c) { 294 r = sp; 295 } 296 } while (*sp++); 297 return (r); 298 } 299 300 /* Additional misc functions. */ 301 302 /* Calculate the display width of a string. */ 303 int 304 tswidth(tchar *ts) 305 { 306 #ifdef MBCHAR 307 wchar_t tc; 308 int w = 0; 309 int p_col; 310 311 while (tc = *ts++) { 312 if ((p_col = wcwidth((wchar_t)tc)) > 0) 313 w += p_col; 314 } 315 return (w); 316 #else /* !MBCHAR --- one char always occupies one column. */ 317 return (strlen_(ts)); 318 #endif 319 } 320 321 /* 322 * Two getenv() substitute functions. They differ in the type of arguments. 323 * BUGS: Both returns the pointer to an allocated space where the env var's 324 * values is stored. This space is freed automatically on the successive 325 * call of either function. Therefore the caller must copy the contents 326 * if it needs to access two env vars. There is an arbitary limitation 327 * on the number of chars of a env var name. 328 */ 329 #define LONGEST_ENVVARNAME 256 /* Too big? */ 330 tchar * 331 getenv_(tchar *name_) 332 { 333 char name[LONGEST_ENVVARNAME * MB_LEN_MAX]; 334 335 assert(strlen_(name_) < LONGEST_ENVVARNAME); 336 return (getenvs_(tstostr(name, name_))); 337 } 338 339 tchar * 340 getenvs_(char *name) 341 { 342 static tchar *pbuf = (tchar *)NULL; 343 char *val; 344 345 if (pbuf) { 346 xfree(pbuf); 347 pbuf = NOSTR; 348 } 349 val = getenv(name); 350 if (val == (char *)NULL) { 351 return (NOSTR); 352 } 353 return (pbuf = strtots(NOSTR, val)); 354 } 355 356 /* Followings are the system call interface for tchar strings. */ 357 358 /* 359 * creat() and open() replacement. 360 * BUGS: An unusually long file name could be dangerous. 361 */ 362 int 363 creat_(tchar *name_, int mode) 364 { 365 int fd; 366 char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */ 367 368 tstostr(chbuf, name_); 369 fd = creat((char *)chbuf, mode); 370 if (fd != -1) { 371 setfd(fd); 372 } 373 return (fd); 374 } 375 376 /*VARARGS2*/ 377 int 378 open_(path_, flags, mode) 379 tchar *path_; 380 int flags; 381 int mode; /* May be omitted. */ 382 { 383 char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */ 384 int fd; 385 386 tstostr(chbuf, path_); 387 fd = open((char *)chbuf, flags, mode); 388 if (fd != -1) { 389 setfd(fd); 390 } 391 return (fd); 392 } 393 394 /* 395 * mkstemp replacement 396 */ 397 int 398 mkstemp_(tchar *name_) 399 { 400 int fd; 401 char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */ 402 403 tstostr(chbuf, name_); 404 fd = mkstemp((char *)chbuf); 405 if (fd != -1) { 406 setfd(fd); 407 strtots(name_, chbuf); 408 } 409 return (fd); 410 } 411 412 /* 413 * read() and write() reaplacement. 414 * int d; 415 * tchar *buf; - where the result be stored. Not NULL terminated. 416 * int nchreq; - # of tchars requrested. 417 */ 418 int 419 read_(int d, tchar *buf, int nchreq) 420 { 421 unsigned char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */ 422 #ifdef MBCHAR 423 /* 424 * We would have to read more than tchar bytes 425 * when there are multibyte characters in the file. 426 */ 427 int i, j, fflags; 428 unsigned char *s; /* Byte being scanned for a multibyte char. */ 429 /* Points to the pos where next read() to read the data into. */ 430 unsigned char *p; 431 tchar *t; 432 wchar_t wc; 433 int b_len; 434 int nchread = 0; /* Count how many bytes has been read. */ 435 int nbytread = 0; /* Total # of bytes read. */ 436 /* # of bytes needed to complete the last char just read. */ 437 int delta; 438 unsigned char *q; /* q points to the first invalid byte. */ 439 int mb_cur_max = MB_CUR_MAX; 440 #ifdef DBG 441 tprintf("Entering read_(d=%d, buf=0x%x, nchreq=%d);\n", 442 d, buf, nchreq); 443 #endif /* DBG */ 444 /* 445 * Step 1: We collect the exact number of bytes that make 446 * nchreq characters into chbuf. 447 * We must be careful not to read too many bytes as we 448 * cannot push back such over-read bytes. 449 * The idea we use here is that n multibyte characters are stored 450 * in no less than n but less than n*MB_CUR_MAX bytes. 451 */ 452 assert(nchreq <= BUFSIZ); 453 delta = 0; 454 p = s = chbuf; 455 t = buf; 456 while (nchread < nchreq) { 457 int m; /* # of bytes to try to read this time. */ 458 int k; /* # of bytes successfully read. */ 459 460 retry: 461 /* 462 * Let's say the (N+1)'th byte bN is actually the first 463 * byte of a three-byte character c. 464 * In that case, p, s, q look like this: 465 * 466 * /-- already read--\ /-- not yet read --\ 467 * chbuf[]: b0 b1 ..... bN bN+1 bN+2 bN+2 ... 468 * ^ ^ ^ 469 * | | | 470 * p s q 471 * \----------/ 472 * c hasn't been completed 473 * 474 * Just after the next read(), p and q will be adavanced to: 475 * 476 * /-- already read-----------------------\ /-- not yet - 477 * chbuf[]: b0 b1 ..... bN bN+1 bN+2 bN+2 ... bX bX+1 bX+2... 478 * ^ ^ ^ 479 * | | | 480 * s p q 481 * \----------/ 482 * c has been completed 483 * but hasn't been scanned 484 */ 485 m = nchreq - nchread; 486 assert(p + m < chbuf + sizeof (chbuf)); 487 k = read(d, p, m); 488 /* 489 * when child sets O_NDELAY or O_NONBLOCK on stdin 490 * and exits and we are interactive then turn the modes off 491 * and retry 492 */ 493 if (k == 0) { 494 if ((intty && !onelflg && !cflg) && 495 ((fflags = fcntl(d, F_GETFL, 0)) & O_NDELAY)) { 496 fflags &= ~O_NDELAY; 497 fcntl(d, F_SETFL, fflags); 498 goto retry; 499 } 500 } else if (k < 0) { 501 if (errno == EAGAIN) { 502 fflags = fcntl(d, F_GETFL, 0); 503 fflags &= ~O_NONBLOCK; 504 fcntl(d, F_SETFL, fflags); 505 goto retry; 506 } 507 return (-1); 508 } 509 nbytread += k; 510 q = p + k; 511 delta = 0; 512 513 /* Try scaning characters in s..q-1 */ 514 while (s < q) { 515 /* Convert the collected bytes into tchar array. */ 516 if (*s == 0) { 517 /* NUL is treated as a normal char here. */ 518 *t++ = 0; 519 s++; 520 nchread++; 521 continue; 522 } 523 524 if ((b_len = q - s) > mb_cur_max) { 525 b_len = mb_cur_max; 526 } 527 if ((j = mbtowc(&wc, (char *)s, b_len)) <= 0) { 528 if (mb_cur_max > 1 && b_len < mb_cur_max) { 529 /* 530 * Needs more byte to complete this char 531 * In order to read() more than delta 532 * bytes. 533 */ 534 break; 535 } 536 wc = (unsigned char)*s; 537 j = 1; 538 } 539 540 *t++ = wc; 541 nchread++; 542 s += j; 543 } 544 545 if (k < m) { 546 /* We've read as many bytes as possible. */ 547 while (s < q) { 548 if ((b_len = q - s) > mb_cur_max) { 549 b_len = mb_cur_max; 550 } 551 if ((j = mbtowc(&wc, (char *)s, b_len)) <= 0) { 552 wc = (unsigned char)*s; 553 j = 1; 554 } 555 *t++ = wc; 556 nchread++; 557 s += j; 558 } 559 return (nchread); 560 } 561 562 p = q; 563 } 564 565 if (mb_cur_max == 1 || (delta = q - s) == 0) { 566 return (nchread); 567 } 568 569 /* 570 * We may have (MB_CUR_MAX - 1) unread data in the buffer. 571 * Here, the last converted data was an illegal character which was 572 * treated as one byte character. We don't know at this point 573 * whether or not the remaining data is in legal sequence. 574 * We first attempt to convert the remaining data. 575 */ 576 do { 577 if ((j = mbtowc(&wc, (char *)s, delta)) <= 0) 578 break; 579 *t++ = wc; 580 nchread++; 581 s += j; 582 delta -= j; 583 } while (delta > 0); 584 585 if (delta == 0) 586 return (nchread); 587 588 /* 589 * There seem to be ugly sequence in the buffer. Fill up till 590 * mb_cur_max and see if we can get a right sequence. 591 */ 592 while (delta < mb_cur_max) { 593 assert((q + 1) < (chbuf + sizeof (chbuf))); 594 if (read(d, q, 1) != 1) 595 break; 596 delta++; 597 q++; 598 if (mbtowc(&wc, (char *)s, delta) > 0) { 599 *t = wc; 600 return (nchread + 1); 601 } 602 } 603 604 /* 605 * no luck. we have filled MB_CUR_MAX bytes in the buffer. 606 * Ideally we should return with leaving such data off and 607 * put them into a local buffer for next read, but we don't 608 * have such. 609 * So, stop reading further, and treat them as all single 610 * byte characters. 611 */ 612 while (s < q) { 613 b_len = q - s; 614 if ((j = mbtowc(&wc, (char *)s, b_len)) <= 0) { 615 wc = (unsigned char)*s; 616 j = 1; 617 } 618 *t++ = wc; 619 nchread++; 620 s += j; 621 } 622 return (nchread); 623 624 #else /* !MBCHAR */ 625 /* One byte always represents one tchar. Easy! */ 626 int i; 627 unsigned char *s; 628 tchar *t; 629 int nchread; 630 631 #ifdef DBG 632 tprintf("Entering read_(d=%d, buf=0x%x, nchreq=%d);\n", 633 d, buf, nchreq); 634 #endif /* DBG */ 635 assert(nchreq <= BUFSIZ); 636 retry: 637 nchread = read(d, (char *)chbuf, nchreq); 638 /* 639 * when child sets O_NDELAY or O_NONBLOCK on stdin 640 * and exits and we are interactive then turn the modes off 641 * and retry 642 */ 643 if (nchread == 0) { 644 if ((intty && !onelflg && !cflg) && 645 ((fflags = fcntl(d, F_GETFL, 0)) & O_NDELAY)) { 646 fflags &= ~O_NDELAY; 647 fcntl(d, F_SETFL, fflags); 648 goto retry; 649 } 650 } else if (nchread < 0) { 651 if (errno == EAGAIN) { 652 fflags = fcntl(d, F_GETFL, 0); 653 fflags &= ~O_NONBLOCK; 654 fcntl(d, F_SETFL, fflags); 655 goto retry; 656 } 657 len = 0; 658 } else { 659 for (i = 0, t = buf, s = chbuf; i < nchread; ++i) { 660 *t++ = ((tchar)*s++); 661 } 662 } 663 return (nchread); 664 #endif 665 } 666 667 /* 668 * BUG: write_() returns -1 on failure, or # of BYTEs it has written. 669 * For consistency and symmetry, it should return the number of 670 * characters it has actually written, but that is technically 671 * difficult although not impossible. Anyway, the return 672 * value of write() has never been used by the original csh, 673 * so this bug should be OK. 674 */ 675 int 676 write_(int d, tchar *buf, int nch) 677 { 678 unsigned char chbuf[BUFSIZ*MB_LEN_MAX]; /* General use buffer. */ 679 #ifdef MBCHAR 680 tchar *pt; 681 unsigned char *pc; 682 wchar_t wc; 683 int i, j; 684 685 #ifdef DBG 686 tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n", 687 d, buf, nch); /* Hope printf() doesn't call write_() itself! */ 688 #endif /* DBG */ 689 assert(nch * MB_CUR_MAX < sizeof (chbuf)); 690 i = nch; 691 pt = buf; 692 pc = chbuf; 693 while (i--) { 694 /* 695 * Convert to tchar string. 696 * NUL is treated as normal char here. 697 */ 698 wc = (wchar_t)((*pt++)&TRIM); 699 if (wc == (wchar_t)0) { 700 *pc++ = 0; 701 } else { 702 if ((j = wctomb((char *)pc, wc)) <= 0) { 703 *pc = (unsigned char)wc; 704 j = 1; 705 } 706 pc += j; 707 } 708 } 709 return (write(d, chbuf, pc - chbuf)); 710 #else /* !MBCHAR */ 711 /* One byte always represents one tchar. Easy! */ 712 int i; 713 unsigned char *s; 714 tchar *t; 715 716 #ifdef DBG 717 tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n", 718 d, buf, nch); /* Hope printf() doesn't call write_() itself! */ 719 #endif /* DBG */ 720 assert(nch <= sizeof (chbuf)); 721 for (i = 0, t = buf, s = chbuf; i < nch; ++i) { 722 *s++ = (char)((*t++)&0xff); 723 } 724 return (write(d, (char *)chbuf, nch)); 725 #endif 726 } 727 728 #undef chbuf 729 730 #include <sys/types.h> 731 #include <sys/stat.h> /* satruct stat */ 732 #include <dirent.h> /* DIR */ 733 734 extern DIR *Dirp; 735 736 int 737 stat_(tchar *path, struct stat *buf) 738 { 739 char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */ 740 741 tstostr(chbuf, path); 742 return (stat((char *)chbuf, buf)); 743 } 744 745 int 746 lstat_(tchar *path, struct stat *buf) 747 { 748 char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */ 749 750 tstostr(chbuf, path); 751 return (lstat((char *)chbuf, buf)); 752 } 753 754 int 755 chdir_(tchar *path) 756 { 757 char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */ 758 759 tstostr(chbuf, path); 760 return (chdir((char *)chbuf)); 761 } 762 763 tchar * 764 getwd_(tchar *path) 765 { 766 char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */ 767 int rc; 768 769 rc = (int)getwd((char *)chbuf); 770 if (rc == 0) { 771 return (0); 772 } else { 773 return (strtots(path, chbuf)); 774 } 775 } 776 777 int 778 unlink_(tchar *path) 779 { 780 char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */ 781 782 tstostr(chbuf, path); 783 return (unlink((char *)chbuf)); 784 } 785 786 DIR * 787 opendir_(tchar *dirname) 788 { 789 char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */ 790 791 extern DIR *opendir(); 792 DIR *dir; 793 794 dir = opendir(tstostr(chbuf, dirname)); 795 if (dir != NULL) { 796 setfd(dir->dd_fd); 797 } 798 return (Dirp = dir); 799 } 800 801 int 802 closedir_(DIR *dirp) 803 { 804 int ret; 805 extern int closedir(); 806 807 ret = closedir(dirp); 808 Dirp = NULL; 809 return (ret); 810 } 811 812 int 813 gethostname_(tchar *name, int namelen) 814 { 815 char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */ 816 817 assert(namelen < BUFSIZ); 818 if (gethostname((char *)chbuf, sizeof (chbuf)) != 0) { 819 return (-1); 820 } 821 if (mbstotcs(name, chbuf, namelen) < 0) { 822 return (-1); 823 } 824 return (0); /* Succeeded. */ 825 } 826 827 int 828 readlink_(tchar *path, tchar *buf, int bufsiz) 829 { 830 char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */ 831 char chpath[MAXPATHLEN + 1]; 832 int i; 833 834 tstostr(chpath, path); 835 i = readlink(chpath, (char *)chbuf, sizeof (chbuf)); 836 if (i < 0) { 837 return (-1); 838 } 839 chbuf[i] = (char)0; /* readlink() doesn't put NULL. */ 840 i = mbstotcs(buf, chbuf, bufsiz); 841 if (i < 0) { 842 return (-1); 843 } 844 return (i - 1); /* Return # of tchars EXCLUDING the terminating NULL. */ 845 } 846 847 /* checks that it's a number */ 848 849 int 850 chkalldigit_(tchar *str) 851 { 852 char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */ 853 char *c = chbuf; 854 855 (void) tstostr(chbuf, str); 856 857 while (*c) 858 if (!isdigit(*(c++))) 859 return (-1); 860 861 return (0); 862 } 863 864 int 865 atoi_(tchar *str) 866 { 867 char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */ 868 869 tstostr(chbuf, str); 870 return (atoi((char *)chbuf)); 871 } 872 873 tchar * 874 simple(tchar *s) 875 { 876 tchar *sname = s; 877 878 while (1) { 879 if (any('/', sname)) { 880 while (*sname++ != '/') 881 ; 882 } else { 883 return (sname); 884 } 885 } 886 } 887