Home | History | Annotate | Download | only in src
      1 /*	$OpenBSD: shf.c,v 1.16 2013/04/19 17:36:09 millert Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
      5  *		 2012, 2013, 2015, 2016, 2017, 2018
      6  *	mirabilos <m (at) mirbsd.org>
      7  * Copyright (c) 2015
      8  *	Daniel Richard G. <skunk (at) iSKUNK.ORG>
      9  *
     10  * Provided that these terms and disclaimer and all copyright notices
     11  * are retained or reproduced in an accompanying document, permission
     12  * is granted to deal in this work without restriction, including un-
     13  * limited rights to use, publicly perform, distribute, sell, modify,
     14  * merge, give away, or sublicence.
     15  *
     16  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
     17  * the utmost extent permitted by applicable law, neither express nor
     18  * implied; without malicious intent or gross negligence. In no event
     19  * may a licensor, author or contributor be held liable for indirect,
     20  * direct, other damage, loss, or other issues arising in any way out
     21  * of dealing in the work, even if advised of the possibility of such
     22  * damage or existence of a defect, except proven that it results out
     23  * of said person's immediate fault when using the work as intended.
     24  *-
     25  * Use %zX instead of %p and floating point isn't supported at all.
     26  */
     27 
     28 #include "sh.h"
     29 
     30 __RCSID("$MirOS: src/bin/mksh/shf.c,v 1.97 2018/01/14 01:28:16 tg Exp $");
     31 
     32 /* flags to shf_emptybuf() */
     33 #define EB_READSW	0x01	/* about to switch to reading */
     34 #define EB_GROW		0x02	/* grow buffer if necessary (STRING+DYNAMIC) */
     35 
     36 /*
     37  * Replacement stdio routines. Stdio is too flakey on too many machines
     38  * to be useful when you have multiple processes using the same underlying
     39  * file descriptors.
     40  */
     41 
     42 static int shf_fillbuf(struct shf *);
     43 static int shf_emptybuf(struct shf *, int);
     44 
     45 /*
     46  * Open a file. First three args are for open(), last arg is flags for
     47  * this package. Returns NULL if file could not be opened, or if a dup
     48  * fails.
     49  */
     50 struct shf *
     51 shf_open(const char *name, int oflags, int mode, int sflags)
     52 {
     53 	struct shf *shf;
     54 	ssize_t bsize =
     55 	    /* at most 512 */
     56 	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
     57 	int fd, eno;
     58 
     59 	/* Done before open so if alloca fails, fd won't be lost. */
     60 	shf = alloc(sizeof(struct shf) + bsize, ATEMP);
     61 	shf->areap = ATEMP;
     62 	shf->buf = (unsigned char *)&shf[1];
     63 	shf->bsize = bsize;
     64 	shf->flags = SHF_ALLOCS;
     65 	/* Rest filled in by reopen. */
     66 
     67 	fd = binopen3(name, oflags, mode);
     68 	if (fd < 0) {
     69 		eno = errno;
     70 		afree(shf, shf->areap);
     71 		errno = eno;
     72 		return (NULL);
     73 	}
     74 	if ((sflags & SHF_MAPHI) && fd < FDBASE) {
     75 		int nfd;
     76 
     77 		nfd = fcntl(fd, F_DUPFD, FDBASE);
     78 		eno = errno;
     79 		close(fd);
     80 		if (nfd < 0) {
     81 			afree(shf, shf->areap);
     82 			errno = eno;
     83 			return (NULL);
     84 		}
     85 		fd = nfd;
     86 	}
     87 	sflags &= ~SHF_ACCMODE;
     88 	sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD :
     89 	    ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR : SHF_RDWR);
     90 
     91 	return (shf_reopen(fd, sflags, shf));
     92 }
     93 
     94 /* helper function for shf_fdopen and shf_reopen */
     95 static void
     96 shf_open_hlp(int fd, int *sflagsp, const char *where)
     97 {
     98 	int sflags = *sflagsp;
     99 
    100 	/* use fcntl() to figure out correct read/write flags */
    101 	if (sflags & SHF_GETFL) {
    102 		int flags = fcntl(fd, F_GETFL, 0);
    103 
    104 		if (flags < 0)
    105 			/* will get an error on first read/write */
    106 			sflags |= SHF_RDWR;
    107 		else {
    108 			switch (flags & O_ACCMODE) {
    109 			case O_RDONLY:
    110 				sflags |= SHF_RD;
    111 				break;
    112 			case O_WRONLY:
    113 				sflags |= SHF_WR;
    114 				break;
    115 			case O_RDWR:
    116 				sflags |= SHF_RDWR;
    117 				break;
    118 			}
    119 		}
    120 		*sflagsp = sflags;
    121 	}
    122 
    123 	if (!(sflags & (SHF_RD | SHF_WR)))
    124 		internal_errorf(Tf_sD_s, where, "missing read/write");
    125 }
    126 
    127 /* Set up the shf structure for a file descriptor. Doesn't fail. */
    128 struct shf *
    129 shf_fdopen(int fd, int sflags, struct shf *shf)
    130 {
    131 	ssize_t bsize =
    132 	    /* at most 512 */
    133 	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
    134 
    135 	shf_open_hlp(fd, &sflags, "shf_fdopen");
    136 	if (shf) {
    137 		if (bsize) {
    138 			shf->buf = alloc(bsize, ATEMP);
    139 			sflags |= SHF_ALLOCB;
    140 		} else
    141 			shf->buf = NULL;
    142 	} else {
    143 		shf = alloc(sizeof(struct shf) + bsize, ATEMP);
    144 		shf->buf = (unsigned char *)&shf[1];
    145 		sflags |= SHF_ALLOCS;
    146 	}
    147 	shf->areap = ATEMP;
    148 	shf->fd = fd;
    149 	shf->rp = shf->wp = shf->buf;
    150 	shf->rnleft = 0;
    151 	shf->rbsize = bsize;
    152 	shf->wnleft = 0; /* force call to shf_emptybuf() */
    153 	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
    154 	shf->flags = sflags;
    155 	shf->errnosv = 0;
    156 	shf->bsize = bsize;
    157 	if (sflags & SHF_CLEXEC)
    158 		fcntl(fd, F_SETFD, FD_CLOEXEC);
    159 	return (shf);
    160 }
    161 
    162 /* Set up an existing shf (and buffer) to use the given fd */
    163 struct shf *
    164 shf_reopen(int fd, int sflags, struct shf *shf)
    165 {
    166 	ssize_t bsize =
    167 	    /* at most 512 */
    168 	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
    169 
    170 	shf_open_hlp(fd, &sflags, "shf_reopen");
    171 	if (!shf || !shf->buf || shf->bsize < bsize)
    172 		internal_errorf(Tf_sD_s, "shf_reopen", Tbad_bsize);
    173 
    174 	/* assumes shf->buf and shf->bsize already set up */
    175 	shf->fd = fd;
    176 	shf->rp = shf->wp = shf->buf;
    177 	shf->rnleft = 0;
    178 	shf->rbsize = bsize;
    179 	shf->wnleft = 0; /* force call to shf_emptybuf() */
    180 	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
    181 	shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags;
    182 	shf->errnosv = 0;
    183 	if (sflags & SHF_CLEXEC)
    184 		fcntl(fd, F_SETFD, FD_CLOEXEC);
    185 	return (shf);
    186 }
    187 
    188 /*
    189  * Open a string for reading or writing. If reading, bsize is the number
    190  * of bytes that can be read. If writing, bsize is the maximum number of
    191  * bytes that can be written. If shf is not NULL, it is filled in and
    192  * returned, if it is NULL, shf is allocated. If writing and buf is NULL
    193  * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is
    194  * used for the initial size). Doesn't fail.
    195  * When writing, a byte is reserved for a trailing NUL - see shf_sclose().
    196  */
    197 struct shf *
    198 shf_sopen(char *buf, ssize_t bsize, int sflags, struct shf *shf)
    199 {
    200 	/* can't have a read+write string */
    201 	if (!(!(sflags & SHF_RD) ^ !(sflags & SHF_WR)))
    202 		internal_errorf(Tf_flags, "shf_sopen",
    203 		    (unsigned int)sflags);
    204 
    205 	if (!shf) {
    206 		shf = alloc(sizeof(struct shf), ATEMP);
    207 		sflags |= SHF_ALLOCS;
    208 	}
    209 	shf->areap = ATEMP;
    210 	if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) {
    211 		if (bsize <= 0)
    212 			bsize = 64;
    213 		sflags |= SHF_ALLOCB;
    214 		buf = alloc(bsize, shf->areap);
    215 	}
    216 	shf->fd = -1;
    217 	shf->buf = shf->rp = shf->wp = (unsigned char *)buf;
    218 	shf->rnleft = bsize;
    219 	shf->rbsize = bsize;
    220 	shf->wnleft = bsize - 1;	/* space for a '\0' */
    221 	shf->wbsize = bsize;
    222 	shf->flags = sflags | SHF_STRING;
    223 	shf->errnosv = 0;
    224 	shf->bsize = bsize;
    225 
    226 	return (shf);
    227 }
    228 
    229 /* Flush and close file descriptor, free the shf structure */
    230 int
    231 shf_close(struct shf *shf)
    232 {
    233 	int ret = 0;
    234 
    235 	if (shf->fd >= 0) {
    236 		ret = shf_flush(shf);
    237 		if (close(shf->fd) < 0)
    238 			ret = -1;
    239 	}
    240 	if (shf->flags & SHF_ALLOCS)
    241 		afree(shf, shf->areap);
    242 	else if (shf->flags & SHF_ALLOCB)
    243 		afree(shf->buf, shf->areap);
    244 
    245 	return (ret);
    246 }
    247 
    248 /* Flush and close file descriptor, don't free file structure */
    249 int
    250 shf_fdclose(struct shf *shf)
    251 {
    252 	int ret = 0;
    253 
    254 	if (shf->fd >= 0) {
    255 		ret = shf_flush(shf);
    256 		if (close(shf->fd) < 0)
    257 			ret = -1;
    258 		shf->rnleft = 0;
    259 		shf->rp = shf->buf;
    260 		shf->wnleft = 0;
    261 		shf->fd = -1;
    262 	}
    263 
    264 	return (ret);
    265 }
    266 
    267 /*
    268  * Close a string - if it was opened for writing, it is NUL terminated;
    269  * returns a pointer to the string and frees shf if it was allocated
    270  * (does not free string if it was allocated).
    271  */
    272 char *
    273 shf_sclose(struct shf *shf)
    274 {
    275 	unsigned char *s = shf->buf;
    276 
    277 	/* NUL terminate */
    278 	if (shf->flags & SHF_WR) {
    279 		shf->wnleft++;
    280 		shf_putc('\0', shf);
    281 	}
    282 	if (shf->flags & SHF_ALLOCS)
    283 		afree(shf, shf->areap);
    284 	return ((char *)s);
    285 }
    286 
    287 /*
    288  * Un-read what has been read but not examined, or write what has been
    289  * buffered. Returns 0 for success, -1 for (write) error.
    290  */
    291 int
    292 shf_flush(struct shf *shf)
    293 {
    294 	int rv = 0;
    295 
    296 	if (shf->flags & SHF_STRING)
    297 		rv = (shf->flags & SHF_WR) ? -1 : 0;
    298 	else if (shf->fd < 0)
    299 		internal_errorf(Tf_sD_s, "shf_flush", "no fd");
    300 	else if (shf->flags & SHF_ERROR) {
    301 		errno = shf->errnosv;
    302 		rv = -1;
    303 	} else if (shf->flags & SHF_READING) {
    304 		shf->flags &= ~(SHF_EOF | SHF_READING);
    305 		if (shf->rnleft > 0) {
    306 			if (lseek(shf->fd, (off_t)-shf->rnleft,
    307 			    SEEK_CUR) == -1) {
    308 				shf->flags |= SHF_ERROR;
    309 				shf->errnosv = errno;
    310 				rv = -1;
    311 			}
    312 			shf->rnleft = 0;
    313 			shf->rp = shf->buf;
    314 		}
    315 	} else if (shf->flags & SHF_WRITING)
    316 		rv = shf_emptybuf(shf, 0);
    317 
    318 	return (rv);
    319 }
    320 
    321 /*
    322  * Write out any buffered data. If currently reading, flushes the read
    323  * buffer. Returns 0 for success, -1 for (write) error.
    324  */
    325 static int
    326 shf_emptybuf(struct shf *shf, int flags)
    327 {
    328 	int ret = 0;
    329 
    330 	if (!(shf->flags & SHF_STRING) && shf->fd < 0)
    331 		internal_errorf(Tf_sD_s, "shf_emptybuf", "no fd");
    332 
    333 	if (shf->flags & SHF_ERROR) {
    334 		errno = shf->errnosv;
    335 		return (-1);
    336 	}
    337 
    338 	if (shf->flags & SHF_READING) {
    339 		if (flags & EB_READSW)
    340 			/* doesn't happen */
    341 			return (0);
    342 		ret = shf_flush(shf);
    343 		shf->flags &= ~SHF_READING;
    344 	}
    345 	if (shf->flags & SHF_STRING) {
    346 		unsigned char *nbuf;
    347 
    348 		/*
    349 		 * Note that we assume SHF_ALLOCS is not set if
    350 		 * SHF_ALLOCB is set... (changing the shf pointer could
    351 		 * cause problems)
    352 		 */
    353 		if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) ||
    354 		    !(shf->flags & SHF_ALLOCB))
    355 			return (-1);
    356 		/* allocate more space for buffer */
    357 		nbuf = aresize2(shf->buf, 2, shf->wbsize, shf->areap);
    358 		shf->rp = nbuf + (shf->rp - shf->buf);
    359 		shf->wp = nbuf + (shf->wp - shf->buf);
    360 		shf->rbsize += shf->wbsize;
    361 		shf->wnleft += shf->wbsize;
    362 		shf->wbsize <<= 1;
    363 		shf->buf = nbuf;
    364 	} else {
    365 		if (shf->flags & SHF_WRITING) {
    366 			ssize_t n, ntowrite = shf->wp - shf->buf;
    367 			unsigned char *buf = shf->buf;
    368 
    369 			while (ntowrite > 0) {
    370 				n = write(shf->fd, buf, ntowrite);
    371 				if (n < 0) {
    372 					if (errno == EINTR &&
    373 					    !(shf->flags & SHF_INTERRUPT))
    374 						continue;
    375 					shf->flags |= SHF_ERROR;
    376 					shf->errnosv = errno;
    377 					shf->wnleft = 0;
    378 					if (buf != shf->buf) {
    379 						/*
    380 						 * allow a second flush
    381 						 * to work
    382 						 */
    383 						memmove(shf->buf, buf,
    384 						    ntowrite);
    385 						shf->wp = shf->buf + ntowrite;
    386 					}
    387 					return (-1);
    388 				}
    389 				buf += n;
    390 				ntowrite -= n;
    391 			}
    392 			if (flags & EB_READSW) {
    393 				shf->wp = shf->buf;
    394 				shf->wnleft = 0;
    395 				shf->flags &= ~SHF_WRITING;
    396 				return (0);
    397 			}
    398 		}
    399 		shf->wp = shf->buf;
    400 		shf->wnleft = shf->wbsize;
    401 	}
    402 	shf->flags |= SHF_WRITING;
    403 
    404 	return (ret);
    405 }
    406 
    407 /* Fill up a read buffer. Returns -1 for a read error, 0 otherwise. */
    408 static int
    409 shf_fillbuf(struct shf *shf)
    410 {
    411 	ssize_t n;
    412 
    413 	if (shf->flags & SHF_STRING)
    414 		return (0);
    415 
    416 	if (shf->fd < 0)
    417 		internal_errorf(Tf_sD_s, "shf_fillbuf", "no fd");
    418 
    419 	if (shf->flags & (SHF_EOF | SHF_ERROR)) {
    420 		if (shf->flags & SHF_ERROR)
    421 			errno = shf->errnosv;
    422 		return (-1);
    423 	}
    424 
    425 	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1)
    426 		return (-1);
    427 
    428 	shf->flags |= SHF_READING;
    429 
    430 	shf->rp = shf->buf;
    431 	while (/* CONSTCOND */ 1) {
    432 		n = blocking_read(shf->fd, (char *)shf->buf, shf->rbsize);
    433 		if (n < 0 && errno == EINTR && !(shf->flags & SHF_INTERRUPT))
    434 			continue;
    435 		break;
    436 	}
    437 	if (n < 0) {
    438 		shf->flags |= SHF_ERROR;
    439 		shf->errnosv = errno;
    440 		shf->rnleft = 0;
    441 		shf->rp = shf->buf;
    442 		return (-1);
    443 	}
    444 	if ((shf->rnleft = n) == 0)
    445 		shf->flags |= SHF_EOF;
    446 	return (0);
    447 }
    448 
    449 /*
    450  * Read a buffer from shf. Returns the number of bytes read into buf, if
    451  * no bytes were read, returns 0 if end of file was seen, -1 if a read
    452  * error occurred.
    453  */
    454 ssize_t
    455 shf_read(char *buf, ssize_t bsize, struct shf *shf)
    456 {
    457 	ssize_t ncopy, orig_bsize = bsize;
    458 
    459 	if (!(shf->flags & SHF_RD))
    460 		internal_errorf(Tf_flags, Tshf_read,
    461 		    (unsigned int)shf->flags);
    462 
    463 	if (bsize <= 0)
    464 		internal_errorf(Tf_szs, Tshf_read, bsize, Tbsize);
    465 
    466 	while (bsize > 0) {
    467 		if (shf->rnleft == 0 &&
    468 		    (shf_fillbuf(shf) == -1 || shf->rnleft == 0))
    469 			break;
    470 		ncopy = shf->rnleft;
    471 		if (ncopy > bsize)
    472 			ncopy = bsize;
    473 		memcpy(buf, shf->rp, ncopy);
    474 		buf += ncopy;
    475 		bsize -= ncopy;
    476 		shf->rp += ncopy;
    477 		shf->rnleft -= ncopy;
    478 	}
    479 	/* Note: fread(3S) returns 0 for errors - this doesn't */
    480 	return (orig_bsize == bsize ? (shf_error(shf) ? -1 : 0) :
    481 	    orig_bsize - bsize);
    482 }
    483 
    484 /*
    485  * Read up to a newline or -1. The newline is put in buf; buf is always
    486  * NUL terminated. Returns NULL on read error or if nothing was read
    487  * before end of file, returns a pointer to the NUL byte in buf
    488  * otherwise.
    489  */
    490 char *
    491 shf_getse(char *buf, ssize_t bsize, struct shf *shf)
    492 {
    493 	unsigned char *end;
    494 	ssize_t ncopy;
    495 	char *orig_buf = buf;
    496 
    497 	if (!(shf->flags & SHF_RD))
    498 		internal_errorf(Tf_flags, "shf_getse",
    499 		    (unsigned int)shf->flags);
    500 
    501 	if (bsize <= 0)
    502 		return (NULL);
    503 
    504 	/* save room for NUL */
    505 	--bsize;
    506 	do {
    507 		if (shf->rnleft == 0) {
    508 			if (shf_fillbuf(shf) == -1)
    509 				return (NULL);
    510 			if (shf->rnleft == 0) {
    511 				*buf = '\0';
    512 				return (buf == orig_buf ? NULL : buf);
    513 			}
    514 		}
    515 		end = (unsigned char *)memchr((char *)shf->rp, '\n',
    516 		    shf->rnleft);
    517 		ncopy = end ? end - shf->rp + 1 : shf->rnleft;
    518 		if (ncopy > bsize)
    519 			ncopy = bsize;
    520 		memcpy(buf, (char *) shf->rp, ncopy);
    521 		shf->rp += ncopy;
    522 		shf->rnleft -= ncopy;
    523 		buf += ncopy;
    524 		bsize -= ncopy;
    525 #ifdef MKSH_WITH_TEXTMODE
    526 		if (end && buf > orig_buf + 1 && buf[-2] == '\r') {
    527 			buf--;
    528 			bsize++;
    529 			buf[-1] = '\n';
    530 		}
    531 #endif
    532 	} while (!end && bsize);
    533 #ifdef MKSH_WITH_TEXTMODE
    534 	if (!bsize && buf[-1] == '\r') {
    535 		int c = shf_getc(shf);
    536 		if (c == '\n')
    537 			buf[-1] = '\n';
    538 		else if (c != -1)
    539 			shf_ungetc(c, shf);
    540 	}
    541 #endif
    542 	*buf = '\0';
    543 	return (buf);
    544 }
    545 
    546 /* Returns the char read. Returns -1 for error and end of file. */
    547 int
    548 shf_getchar(struct shf *shf)
    549 {
    550 	if (!(shf->flags & SHF_RD))
    551 		internal_errorf(Tf_flags, "shf_getchar",
    552 		    (unsigned int)shf->flags);
    553 
    554 	if (shf->rnleft == 0 && (shf_fillbuf(shf) == -1 || shf->rnleft == 0))
    555 		return (-1);
    556 	--shf->rnleft;
    557 	return (ord(*shf->rp++));
    558 }
    559 
    560 /*
    561  * Put a character back in the input stream. Returns the character if
    562  * successful, -1 if there is no room.
    563  */
    564 int
    565 shf_ungetc(int c, struct shf *shf)
    566 {
    567 	if (!(shf->flags & SHF_RD))
    568 		internal_errorf(Tf_flags, "shf_ungetc",
    569 		    (unsigned int)shf->flags);
    570 
    571 	if ((shf->flags & SHF_ERROR) || c == -1 ||
    572 	    (shf->rp == shf->buf && shf->rnleft))
    573 		return (-1);
    574 
    575 	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1)
    576 		return (-1);
    577 
    578 	if (shf->rp == shf->buf)
    579 		shf->rp = shf->buf + shf->rbsize;
    580 	if (shf->flags & SHF_STRING) {
    581 		/*
    582 		 * Can unget what was read, but not something different;
    583 		 * we don't want to modify a string.
    584 		 */
    585 		if ((int)(shf->rp[-1]) != c)
    586 			return (-1);
    587 		shf->flags &= ~SHF_EOF;
    588 		shf->rp--;
    589 		shf->rnleft++;
    590 		return (c);
    591 	}
    592 	shf->flags &= ~SHF_EOF;
    593 	*--(shf->rp) = c;
    594 	shf->rnleft++;
    595 	return (c);
    596 }
    597 
    598 /*
    599  * Write a character. Returns the character if successful, -1 if the
    600  * char could not be written.
    601  */
    602 int
    603 shf_putchar(int c, struct shf *shf)
    604 {
    605 	if (!(shf->flags & SHF_WR))
    606 		internal_errorf(Tf_flags, "shf_putchar",
    607 		    (unsigned int)shf->flags);
    608 
    609 	if (c == -1)
    610 		return (-1);
    611 
    612 	if (shf->flags & SHF_UNBUF) {
    613 		unsigned char cc = (unsigned char)c;
    614 		ssize_t n;
    615 
    616 		if (shf->fd < 0)
    617 			internal_errorf(Tf_sD_s, "shf_putchar", "no fd");
    618 		if (shf->flags & SHF_ERROR) {
    619 			errno = shf->errnosv;
    620 			return (-1);
    621 		}
    622 		while ((n = write(shf->fd, &cc, 1)) != 1)
    623 			if (n < 0) {
    624 				if (errno == EINTR &&
    625 				    !(shf->flags & SHF_INTERRUPT))
    626 					continue;
    627 				shf->flags |= SHF_ERROR;
    628 				shf->errnosv = errno;
    629 				return (-1);
    630 			}
    631 	} else {
    632 		/* Flush deals with strings and sticky errors */
    633 		if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == -1)
    634 			return (-1);
    635 		shf->wnleft--;
    636 		*shf->wp++ = c;
    637 	}
    638 
    639 	return (c);
    640 }
    641 
    642 /*
    643  * Write a string. Returns the length of the string if successful, -1
    644  * if the string could not be written.
    645  */
    646 ssize_t
    647 shf_puts(const char *s, struct shf *shf)
    648 {
    649 	if (!s)
    650 		return (-1);
    651 
    652 	return (shf_write(s, strlen(s), shf));
    653 }
    654 
    655 /* Write a buffer. Returns nbytes if successful, -1 if there is an error. */
    656 ssize_t
    657 shf_write(const char *buf, ssize_t nbytes, struct shf *shf)
    658 {
    659 	ssize_t n, ncopy, orig_nbytes = nbytes;
    660 
    661 	if (!(shf->flags & SHF_WR))
    662 		internal_errorf(Tf_flags, Tshf_write,
    663 		    (unsigned int)shf->flags);
    664 
    665 	if (nbytes < 0)
    666 		internal_errorf(Tf_szs, Tshf_write, nbytes, Tbytes);
    667 
    668 	/* Don't buffer if buffer is empty and we're writting a large amount. */
    669 	if ((ncopy = shf->wnleft) &&
    670 	    (shf->wp != shf->buf || nbytes < shf->wnleft)) {
    671 		if (ncopy > nbytes)
    672 			ncopy = nbytes;
    673 		memcpy(shf->wp, buf, ncopy);
    674 		nbytes -= ncopy;
    675 		buf += ncopy;
    676 		shf->wp += ncopy;
    677 		shf->wnleft -= ncopy;
    678 	}
    679 	if (nbytes > 0) {
    680 		if (shf->flags & SHF_STRING) {
    681 			/* resize buffer until there's enough space left */
    682 			while (nbytes > shf->wnleft)
    683 				if (shf_emptybuf(shf, EB_GROW) == -1)
    684 					return (-1);
    685 			/* then write everything into the buffer */
    686 		} else {
    687 			/* flush deals with sticky errors */
    688 			if (shf_emptybuf(shf, EB_GROW) == -1)
    689 				return (-1);
    690 			/* write chunks larger than window size directly */
    691 			if (nbytes > shf->wbsize) {
    692 				ncopy = nbytes;
    693 				if (shf->wbsize)
    694 					ncopy -= nbytes % shf->wbsize;
    695 				nbytes -= ncopy;
    696 				while (ncopy > 0) {
    697 					n = write(shf->fd, buf, ncopy);
    698 					if (n < 0) {
    699 						if (errno == EINTR &&
    700 						    !(shf->flags & SHF_INTERRUPT))
    701 							continue;
    702 						shf->flags |= SHF_ERROR;
    703 						shf->errnosv = errno;
    704 						shf->wnleft = 0;
    705 						/*
    706 						 * Note: fwrite(3) returns 0
    707 						 * for errors - this doesn't
    708 						 */
    709 						return (-1);
    710 					}
    711 					buf += n;
    712 					ncopy -= n;
    713 				}
    714 			}
    715 			/* ... and buffer the rest */
    716 		}
    717 		if (nbytes > 0) {
    718 			/* write remaining bytes to buffer */
    719 			memcpy(shf->wp, buf, nbytes);
    720 			shf->wp += nbytes;
    721 			shf->wnleft -= nbytes;
    722 		}
    723 	}
    724 
    725 	return (orig_nbytes);
    726 }
    727 
    728 ssize_t
    729 shf_fprintf(struct shf *shf, const char *fmt, ...)
    730 {
    731 	va_list args;
    732 	ssize_t n;
    733 
    734 	va_start(args, fmt);
    735 	n = shf_vfprintf(shf, fmt, args);
    736 	va_end(args);
    737 
    738 	return (n);
    739 }
    740 
    741 ssize_t
    742 shf_snprintf(char *buf, ssize_t bsize, const char *fmt, ...)
    743 {
    744 	struct shf shf;
    745 	va_list args;
    746 	ssize_t n;
    747 
    748 	if (!buf || bsize <= 0)
    749 		internal_errorf("shf_snprintf: buf %zX, bsize %zd",
    750 		    (size_t)buf, bsize);
    751 
    752 	shf_sopen(buf, bsize, SHF_WR, &shf);
    753 	va_start(args, fmt);
    754 	n = shf_vfprintf(&shf, fmt, args);
    755 	va_end(args);
    756 	/* NUL terminates */
    757 	shf_sclose(&shf);
    758 	return (n);
    759 }
    760 
    761 char *
    762 shf_smprintf(const char *fmt, ...)
    763 {
    764 	struct shf shf;
    765 	va_list args;
    766 
    767 	shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
    768 	va_start(args, fmt);
    769 	shf_vfprintf(&shf, fmt, args);
    770 	va_end(args);
    771 	/* NUL terminates */
    772 	return (shf_sclose(&shf));
    773 }
    774 
    775 #define	FL_HASH		0x001	/* '#' seen */
    776 #define FL_PLUS		0x002	/* '+' seen */
    777 #define FL_RIGHT	0x004	/* '-' seen */
    778 #define FL_BLANK	0x008	/* ' ' seen */
    779 #define FL_SHORT	0x010	/* 'h' seen */
    780 #define FL_LONG		0x020	/* 'l' seen */
    781 #define FL_ZERO		0x040	/* '0' seen */
    782 #define FL_DOT		0x080	/* '.' seen */
    783 #define FL_UPPER	0x100	/* format character was uppercase */
    784 #define FL_NUMBER	0x200	/* a number was formated %[douxefg] */
    785 #define FL_SIZET	0x400	/* 'z' seen */
    786 #define FM_SIZES	0x430	/* h/l/z mask */
    787 
    788 ssize_t
    789 shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
    790 {
    791 	const char *s;
    792 	char c, *cp;
    793 	int tmp = 0, flags;
    794 	size_t field, precision, len;
    795 	unsigned long lnum;
    796 	/* %#o produces the longest output */
    797 	char numbuf[(8 * sizeof(long) + 2) / 3 + 1 + /* NUL */ 1];
    798 	/* this stuff for dealing with the buffer */
    799 	ssize_t nwritten = 0;
    800 
    801 #define VA(type) va_arg(args, type)
    802 
    803 	if (!fmt)
    804 		return (0);
    805 
    806 	while ((c = *fmt++)) {
    807 		if (c != '%') {
    808 			shf_putc(c, shf);
    809 			nwritten++;
    810 			continue;
    811 		}
    812 		/*
    813 		 * This will accept flags/fields in any order - not just
    814 		 * the order specified in printf(3), but this is the way
    815 		 * _doprnt() seems to work (on BSD and SYSV). The only
    816 		 * restriction is that the format character must come
    817 		 * last :-).
    818 		 */
    819 		flags = 0;
    820 		field = precision = 0;
    821 		while ((c = *fmt++)) {
    822 			switch (c) {
    823 			case '#':
    824 				flags |= FL_HASH;
    825 				continue;
    826 
    827 			case '+':
    828 				flags |= FL_PLUS;
    829 				continue;
    830 
    831 			case '-':
    832 				flags |= FL_RIGHT;
    833 				continue;
    834 
    835 			case ' ':
    836 				flags |= FL_BLANK;
    837 				continue;
    838 
    839 			case '0':
    840 				if (!(flags & FL_DOT))
    841 					flags |= FL_ZERO;
    842 				continue;
    843 
    844 			case '.':
    845 				flags |= FL_DOT;
    846 				precision = 0;
    847 				continue;
    848 
    849 			case '*':
    850 				tmp = VA(int);
    851 				if (tmp < 0) {
    852 					if (flags & FL_DOT)
    853 						precision = 0;
    854 					else {
    855 						field = (unsigned int)-tmp;
    856 						flags |= FL_RIGHT;
    857 					}
    858 				} else if (flags & FL_DOT)
    859 					precision = (unsigned int)tmp;
    860 				else
    861 					field = (unsigned int)tmp;
    862 				continue;
    863 
    864 			case 'l':
    865 				flags &= ~FM_SIZES;
    866 				flags |= FL_LONG;
    867 				continue;
    868 
    869 			case 'h':
    870 				flags &= ~FM_SIZES;
    871 				flags |= FL_SHORT;
    872 				continue;
    873 
    874 			case 'z':
    875 				flags &= ~FM_SIZES;
    876 				flags |= FL_SIZET;
    877 				continue;
    878 			}
    879 			if (ctype(c, C_DIGIT)) {
    880 				bool overflowed = false;
    881 
    882 				tmp = ksh_numdig(c);
    883 				while (ctype((c = *fmt++), C_DIGIT))
    884 					if (notok2mul(2147483647, tmp, 10))
    885 						overflowed = true;
    886 					else
    887 						tmp = tmp * 10 + ksh_numdig(c);
    888 				--fmt;
    889 				if (overflowed)
    890 					tmp = 0;
    891 				if (flags & FL_DOT)
    892 					precision = (unsigned int)tmp;
    893 				else
    894 					field = (unsigned int)tmp;
    895 				continue;
    896 			}
    897 			break;
    898 		}
    899 
    900 		if (!c)
    901 			/* nasty format */
    902 			break;
    903 
    904 		if (ctype(c, C_UPPER)) {
    905 			flags |= FL_UPPER;
    906 			c = ksh_tolower(c);
    907 		}
    908 
    909 		switch (c) {
    910 		case 'd':
    911 		case 'i':
    912 			if (flags & FL_SIZET)
    913 				lnum = (long)VA(ssize_t);
    914 			else if (flags & FL_LONG)
    915 				lnum = VA(long);
    916 			else if (flags & FL_SHORT)
    917 				lnum = (long)(short)VA(int);
    918 			else
    919 				lnum = (long)VA(int);
    920 			goto integral;
    921 
    922 		case 'o':
    923 		case 'u':
    924 		case 'x':
    925 			if (flags & FL_SIZET)
    926 				lnum = VA(size_t);
    927 			else if (flags & FL_LONG)
    928 				lnum = VA(unsigned long);
    929 			else if (flags & FL_SHORT)
    930 				lnum = (unsigned long)(unsigned short)VA(int);
    931 			else
    932 				lnum = (unsigned long)VA(unsigned int);
    933 
    934  integral:
    935 			flags |= FL_NUMBER;
    936 			cp = numbuf + sizeof(numbuf);
    937 			*--cp = '\0';
    938 
    939 			switch (c) {
    940 			case 'd':
    941 			case 'i':
    942 				if (0 > (long)lnum) {
    943 					lnum = -(long)lnum;
    944 					tmp = 1;
    945 				} else
    946 					tmp = 0;
    947 				/* FALLTHROUGH */
    948 			case 'u':
    949 				do {
    950 					*--cp = digits_lc[lnum % 10];
    951 					lnum /= 10;
    952 				} while (lnum);
    953 
    954 				if (c != 'u') {
    955 					if (tmp)
    956 						*--cp = '-';
    957 					else if (flags & FL_PLUS)
    958 						*--cp = '+';
    959 					else if (flags & FL_BLANK)
    960 						*--cp = ' ';
    961 				}
    962 				break;
    963 
    964 			case 'o':
    965 				do {
    966 					*--cp = digits_lc[lnum & 0x7];
    967 					lnum >>= 3;
    968 				} while (lnum);
    969 
    970 				if ((flags & FL_HASH) && *cp != '0')
    971 					*--cp = '0';
    972 				break;
    973 
    974 			case 'x': {
    975 				const char *digits = (flags & FL_UPPER) ?
    976 				    digits_uc : digits_lc;
    977 				do {
    978 					*--cp = digits[lnum & 0xF];
    979 					lnum >>= 4;
    980 				} while (lnum);
    981 
    982 				if (flags & FL_HASH) {
    983 					*--cp = (flags & FL_UPPER) ? 'X' : 'x';
    984 					*--cp = '0';
    985 				}
    986 			    }
    987 			}
    988 			len = numbuf + sizeof(numbuf) - 1 - (s = cp);
    989 			if (flags & FL_DOT) {
    990 				if (precision > len) {
    991 					field = precision;
    992 					flags |= FL_ZERO;
    993 				} else
    994 					/* no loss */
    995 					precision = len;
    996 			}
    997 			break;
    998 
    999 		case 's':
   1000 			if ((s = VA(const char *)) == NULL)
   1001 				s = "(null)";
   1002 			else if (flags & FL_HASH) {
   1003 				print_value_quoted(shf, s);
   1004 				continue;
   1005 			}
   1006 			len = utf_mbswidth(s);
   1007 			break;
   1008 
   1009 		case 'c':
   1010 			flags &= ~FL_DOT;
   1011 			c = (char)(VA(int));
   1012 			/* FALLTHROUGH */
   1013 
   1014 		case '%':
   1015 		default:
   1016 			numbuf[0] = c;
   1017 			numbuf[1] = 0;
   1018 			s = numbuf;
   1019 			len = 1;
   1020 			break;
   1021 		}
   1022 
   1023 		/*
   1024 		 * At this point s should point to a string that is to be
   1025 		 * formatted, and len should be the length of the string.
   1026 		 */
   1027 		if (!(flags & FL_DOT) || len < precision)
   1028 			precision = len;
   1029 		if (field > precision) {
   1030 			field -= precision;
   1031 			if (!(flags & FL_RIGHT)) {
   1032 				/* skip past sign or 0x when padding with 0 */
   1033 				if ((flags & FL_ZERO) && (flags & FL_NUMBER)) {
   1034 					if (ctype(*s, C_SPC | C_PLUS | C_MINUS)) {
   1035 						shf_putc(*s, shf);
   1036 						s++;
   1037 						precision--;
   1038 						nwritten++;
   1039 					} else if (*s == '0') {
   1040 						shf_putc(*s, shf);
   1041 						s++;
   1042 						nwritten++;
   1043 						if (--precision &&
   1044 						    ksh_eq(*s, 'X', 'x')) {
   1045 							shf_putc(*s, shf);
   1046 							s++;
   1047 							precision--;
   1048 							nwritten++;
   1049 						}
   1050 					}
   1051 					c = '0';
   1052 				} else
   1053 					c = flags & FL_ZERO ? '0' : ' ';
   1054 				nwritten += field;
   1055 				while (field--)
   1056 					shf_putc(c, shf);
   1057 				field = 0;
   1058 			} else
   1059 				c = ' ';
   1060 		} else
   1061 			field = 0;
   1062 
   1063 		nwritten += precision;
   1064 		precision = utf_skipcols(s, precision, &tmp) - s;
   1065 		while (precision--)
   1066 			shf_putc(*s++, shf);
   1067 
   1068 		nwritten += field;
   1069 		while (field--)
   1070 			shf_putc(c, shf);
   1071 	}
   1072 
   1073 	return (shf_error(shf) ? -1 : nwritten);
   1074 }
   1075 
   1076 #if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
   1077 int
   1078 shf_getc(struct shf *shf)
   1079 {
   1080 	return (shf_getc_i(shf));
   1081 }
   1082 
   1083 int
   1084 shf_putc(int c, struct shf *shf)
   1085 {
   1086 	return (shf_putc_i(c, shf));
   1087 }
   1088 #endif
   1089 
   1090 #ifdef DEBUG
   1091 const char *
   1092 cstrerror(int errnum)
   1093 {
   1094 #undef strerror
   1095 	return (strerror(errnum));
   1096 #define strerror dontuse_strerror /* poisoned */
   1097 }
   1098 #elif !HAVE_STRERROR
   1099 
   1100 #if HAVE_SYS_ERRLIST
   1101 #if !HAVE_SYS_ERRLIST_DECL
   1102 extern const int sys_nerr;
   1103 extern const char * const sys_errlist[];
   1104 #endif
   1105 #endif
   1106 
   1107 const char *
   1108 cstrerror(int errnum)
   1109 {
   1110 	/* "Unknown error: " + sign + rough estimate + NUL */
   1111 	static char errbuf[15 + 1 + (8 * sizeof(int) + 2) / 3 + 1];
   1112 
   1113 #if HAVE_SYS_ERRLIST
   1114 	if (errnum > 0 && errnum < sys_nerr && sys_errlist[errnum])
   1115 		return (sys_errlist[errnum]);
   1116 #endif
   1117 
   1118 	switch (errnum) {
   1119 	case 0:
   1120 		return ("Undefined error: 0");
   1121 	case EPERM:
   1122 		return ("Operation not permitted");
   1123 	case ENOENT:
   1124 		return ("No such file or directory");
   1125 #ifdef ESRCH
   1126 	case ESRCH:
   1127 		return ("No such process");
   1128 #endif
   1129 #ifdef E2BIG
   1130 	case E2BIG:
   1131 		return ("Argument list too long");
   1132 #endif
   1133 	case ENOEXEC:
   1134 		return ("Exec format error");
   1135 	case EBADF:
   1136 		return ("Bad file descriptor");
   1137 #ifdef ENOMEM
   1138 	case ENOMEM:
   1139 		return ("Cannot allocate memory");
   1140 #endif
   1141 	case EACCES:
   1142 		return ("Permission denied");
   1143 	case EEXIST:
   1144 		return ("File exists");
   1145 	case ENOTDIR:
   1146 		return ("Not a directory");
   1147 #ifdef EINVAL
   1148 	case EINVAL:
   1149 		return ("Invalid argument");
   1150 #endif
   1151 #ifdef ELOOP
   1152 	case ELOOP:
   1153 		return ("Too many levels of symbolic links");
   1154 #endif
   1155 	default:
   1156 		shf_snprintf(errbuf, sizeof(errbuf),
   1157 		    "Unknown error: %d", errnum);
   1158 		return (errbuf);
   1159 	}
   1160 }
   1161 #endif
   1162 
   1163 /* fast character classes */
   1164 const uint32_t tpl_ctypes[128] = {
   1165 	/* 0x00 */
   1166 	CiNUL,		CiCNTRL,	CiCNTRL,	CiCNTRL,
   1167 	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
   1168 	CiCNTRL,	CiTAB,		CiNL,		CiSPX,
   1169 	CiSPX,		CiCR,		CiCNTRL,	CiCNTRL,
   1170 	/* 0x10 */
   1171 	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
   1172 	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
   1173 	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
   1174 	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
   1175 	/* 0x20 */
   1176 	CiSP,		CiALIAS | CiVAR1,	CiQC,	CiHASH,
   1177 	CiSS,		CiPERCT,	CiQCL,		CiQC,
   1178 	CiQCL,		CiQCL,		CiQCX | CiVAR1,	CiPLUS,
   1179 	CiALIAS,	CiMINUS,	CiALIAS,	CiQCM,
   1180 	/* 0x30 */
   1181 	CiOCTAL,	CiOCTAL,	CiOCTAL,	CiOCTAL,
   1182 	CiOCTAL,	CiOCTAL,	CiOCTAL,	CiOCTAL,
   1183 	CiDIGIT,	CiDIGIT,	CiCOLON,	CiQCL,
   1184 	CiANGLE,	CiEQUAL,	CiANGLE,	CiQUEST,
   1185 	/* 0x40 */
   1186 	CiALIAS | CiVAR1,	CiUPPER | CiHEXLT,
   1187 	CiUPPER | CiHEXLT,	CiUPPER | CiHEXLT,
   1188 	CiUPPER | CiHEXLT,	CiUPPER | CiHEXLT,
   1189 	CiUPPER | CiHEXLT,	CiUPPER,
   1190 	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
   1191 	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
   1192 	/* 0x50 */
   1193 	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
   1194 	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
   1195 	CiUPPER,	CiUPPER,	CiUPPER,	CiQCX | CiBRACK,
   1196 	CiQCX,		CiBRACK,	CiQCM,		CiUNDER,
   1197 	/* 0x60 */
   1198 	CiGRAVE,		CiLOWER | CiHEXLT,
   1199 	CiLOWER | CiHEXLT,	CiLOWER | CiHEXLT,
   1200 	CiLOWER | CiHEXLT,	CiLOWER | CiHEXLT,
   1201 	CiLOWER | CiHEXLT,	CiLOWER,
   1202 	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
   1203 	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
   1204 	/* 0x70 */
   1205 	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
   1206 	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
   1207 	CiLOWER,	CiLOWER,	CiLOWER,	CiCURLY,
   1208 	CiQCL,		CiCURLY,	CiQCM,		CiCNTRL
   1209 };
   1210 
   1211 void
   1212 set_ifs(const char *s)
   1213 {
   1214 #if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC)
   1215 	int i = 256;
   1216 
   1217 	memset(ksh_ctypes, 0, sizeof(ksh_ctypes));
   1218 	while (i--)
   1219 		if (ebcdic_map[i] < 0x80U)
   1220 			ksh_ctypes[i] = tpl_ctypes[ebcdic_map[i]];
   1221 #else
   1222 	memcpy(ksh_ctypes, tpl_ctypes, sizeof(tpl_ctypes));
   1223 	memset((char *)ksh_ctypes + sizeof(tpl_ctypes), '\0',
   1224 	    sizeof(ksh_ctypes) - sizeof(tpl_ctypes));
   1225 #endif
   1226 	ifs0 = *s;
   1227 	while (*s)
   1228 		ksh_ctypes[ord(*s++)] |= CiIFS;
   1229 }
   1230 
   1231 #if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC)
   1232 #include <locale.h>
   1233 
   1234 /*
   1235  * Many headaches with EBCDIC:
   1236  * 1. There are numerous EBCDIC variants, and it is not feasible for us
   1237  *    to support them all. But we can support the EBCDIC code pages that
   1238  *    contain all (most?) of the characters in ASCII, and these
   1239  *    usually tend to agree on the code points assigned to the ASCII
   1240  *    subset. If you need a representative example, look at EBCDIC 1047,
   1241  *    which is first among equals in the IBM MVS development
   1242  *    environment: https://en.wikipedia.org/wiki/EBCDIC_1047
   1243  *    Unfortunately, the square brackets are not consistently mapped,
   1244  *    and for certain reasons, we need an unambiguous bijective
   1245  *    mapping between EBCDIC and "extended ASCII".
   1246  * 2. Character ranges that are contiguous in ASCII, like the letters
   1247  *    in [A-Z], are broken up into segments (i.e. [A-IJ-RS-Z]), so we
   1248  *    can't implement e.g. islower() as { return c >= 'a' && c <= 'z'; }
   1249  *    because it will also return true for a handful of extraneous
   1250  *    characters (like the plus-minus sign at 0x8F in EBCDIC 1047, a
   1251  *    little after 'i'). But at least '_' is not one of these.
   1252  * 3. The normal [0-9A-Za-z] characters are at codepoints beyond 0x80.
   1253  *    Not only do they require all 8 bits instead of 7, if chars are
   1254  *    signed, they will have negative integer values! Something like
   1255  *    (c - 'A') could actually become (c + 63)! Use the ord() macro to
   1256  *    ensure you're getting a value in [0, 255] (ORD for constants).
   1257  * 4. '\n' is actually NL (0x15, U+0085) instead of LF (0x25, U+000A).
   1258  *    EBCDIC has a proper newline character instead of "emulating" one
   1259  *    with line feeds, although this is mapped to LF for our purposes.
   1260  * 5. Note that it is possible to compile programs in ASCII mode on IBM
   1261  *    mainframe systems, using the -qascii option to the XL C compiler.
   1262  *    We can determine the build mode by looking at __CHARSET_LIB:
   1263  *    0 == EBCDIC, 1 == ASCII
   1264  */
   1265 
   1266 void
   1267 ebcdic_init(void)
   1268 {
   1269 	int i = 256;
   1270 	unsigned char t;
   1271 	bool mapcache[256];
   1272 
   1273 	while (i--)
   1274 		ebcdic_rtt_toascii[i] = i;
   1275 	memset(ebcdic_rtt_fromascii, 0xFF, sizeof(ebcdic_rtt_fromascii));
   1276 	setlocale(LC_ALL, "");
   1277 #ifdef MKSH_EBCDIC
   1278 	if (__etoa_l(ebcdic_rtt_toascii, 256) != 256) {
   1279 		write(2, "mksh: could not map EBCDIC to ASCII\n", 36);
   1280 		exit(255);
   1281 	}
   1282 #endif
   1283 
   1284 	memset(mapcache, 0, sizeof(mapcache));
   1285 	i = 256;
   1286 	while (i--) {
   1287 		t = ebcdic_rtt_toascii[i];
   1288 		/* ensure unique round-trip capable mapping */
   1289 		if (mapcache[t]) {
   1290 			write(2, "mksh: duplicate EBCDIC to ASCII mapping\n", 40);
   1291 			exit(255);
   1292 		}
   1293 		/*
   1294 		 * since there are 256 input octets, this also ensures
   1295 		 * the other mapping direction is completely filled
   1296 		 */
   1297 		mapcache[t] = true;
   1298 		/* fill the complete round-trip map */
   1299 		ebcdic_rtt_fromascii[t] = i;
   1300 		/*
   1301 		 * Only use the converted value if it's in the range
   1302 		 * [0x00; 0x7F], which I checked; the "extended ASCII"
   1303 		 * characters can be any encoding, not just Latin1,
   1304 		 * and the C1 control characters other than NEL are
   1305 		 * hopeless, but we map EBCDIC NEL to ASCII LF so we
   1306 		 * cannot even use C1 NEL.
   1307 		 * If ever we map to Unicode, bump the table width to
   1308 		 * an unsigned int, and or the raw unconverted EBCDIC
   1309 		 * values with 0x01000000 instead.
   1310 		 */
   1311 		if (t < 0x80U)
   1312 			ebcdic_map[i] = (unsigned short)ord(t);
   1313 		else
   1314 			ebcdic_map[i] = (unsigned short)(0x100U | ord(i));
   1315 	}
   1316 	if (ebcdic_rtt_toascii[0] || ebcdic_rtt_fromascii[0] || ebcdic_map[0]) {
   1317 		write(2, "mksh: NUL not at position 0\n", 28);
   1318 		exit(255);
   1319 	}
   1320 }
   1321 #endif
   1322