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