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