blob: a37f4da02ddc4a630ec7a02555ccced9b631df7b [file] [log] [blame]
Thorsten Glaser811a5752013-07-25 14:24:45 +00001/* $OpenBSD: shf.c,v 1.16 2013/04/19 17:36:09 millert Exp $ */
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07002
3/*-
Thorsten Glaser811a5752013-07-25 14:24:45 +00004 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
Elliott Hughesdd4abe02018-02-05 15:55:19 -08005 * 2012, 2013, 2015, 2016, 2017, 2018
Elliott Hughesfc0307d2016-02-02 15:26:47 -08006 * mirabilos <m@mirbsd.org>
Elliott Hughes23925bb2017-09-22 16:04:20 -07007 * Copyright (c) 2015
8 * Daniel Richard G. <skunk@iSKUNK.ORG>
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07009 *
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.
Geremy Condra03ebf062011-10-12 18:17:24 -070024 *-
25 * Use %zX instead of %p and floating point isn't supported at all.
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -070026 */
27
28#include "sh.h"
29
Elliott Hughes47086262019-03-26 12:34:31 -070030__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.98 2018/08/10 02:53:39 tg Exp $");
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -070031
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
42static int shf_fillbuf(struct shf *);
43static int shf_emptybuf(struct shf *, int);
44
Geremy Condra03ebf062011-10-12 18:17:24 -070045/*
46 * Open a file. First three args are for open(), last arg is flags for
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -070047 * this package. Returns NULL if file could not be opened, or if a dup
48 * fails.
49 */
50struct shf *
51shf_open(const char *name, int oflags, int mode, int sflags)
52{
53 struct shf *shf;
Geremy Condra03ebf062011-10-12 18:17:24 -070054 ssize_t bsize =
55 /* at most 512 */
56 sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
Thorsten Glaser811a5752013-07-25 14:24:45 +000057 int fd, eno;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -070058
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
Elliott Hughes96b43632015-07-17 11:39:41 -070067 fd = binopen3(name, oflags, mode);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -070068 if (fd < 0) {
Thorsten Glaser811a5752013-07-25 14:24:45 +000069 eno = errno;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -070070 afree(shf, shf->areap);
Thorsten Glaser811a5752013-07-25 14:24:45 +000071 errno = eno;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -070072 return (NULL);
73 }
74 if ((sflags & SHF_MAPHI) && fd < FDBASE) {
75 int nfd;
76
77 nfd = fcntl(fd, F_DUPFD, FDBASE);
Thorsten Glaser811a5752013-07-25 14:24:45 +000078 eno = errno;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -070079 close(fd);
80 if (nfd < 0) {
81 afree(shf, shf->areap);
Thorsten Glaser811a5752013-07-25 14:24:45 +000082 errno = eno;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -070083 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
Geremy Condra03ebf062011-10-12 18:17:24 -070094/* helper function for shf_fdopen and shf_reopen */
95static void
96shf_open_hlp(int fd, int *sflagsp, const char *where)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -070097{
Geremy Condra03ebf062011-10-12 18:17:24 -070098 int sflags = *sflagsp;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -070099
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 }
Geremy Condra03ebf062011-10-12 18:17:24 -0700120 *sflagsp = sflags;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700121 }
122
123 if (!(sflags & (SHF_RD | SHF_WR)))
Elliott Hughes77740fc2016-08-12 15:06:53 -0700124 internal_errorf(Tf_sD_s, where, "missing read/write");
Geremy Condra03ebf062011-10-12 18:17:24 -0700125}
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700126
Geremy Condra03ebf062011-10-12 18:17:24 -0700127/* Set up the shf structure for a file descriptor. Doesn't fail. */
128struct shf *
129shf_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");
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700136 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;
Geremy Condra03ebf062011-10-12 18:17:24 -0700155 shf->errnosv = 0;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700156 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 */
163struct shf *
164shf_reopen(int fd, int sflags, struct shf *shf)
165{
Geremy Condra03ebf062011-10-12 18:17:24 -0700166 ssize_t bsize =
167 /* at most 512 */
168 sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700169
Geremy Condra03ebf062011-10-12 18:17:24 -0700170 shf_open_hlp(fd, &sflags, "shf_reopen");
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700171 if (!shf || !shf->buf || shf->bsize < bsize)
Elliott Hughes77740fc2016-08-12 15:06:53 -0700172 internal_errorf(Tf_sD_s, "shf_reopen", Tbad_bsize);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700173
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;
Geremy Condra03ebf062011-10-12 18:17:24 -0700182 shf->errnosv = 0;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700183 if (sflags & SHF_CLEXEC)
184 fcntl(fd, F_SETFD, FD_CLOEXEC);
185 return (shf);
186}
187
Geremy Condra03ebf062011-10-12 18:17:24 -0700188/*
189 * Open a string for reading or writing. If reading, bsize is the number
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700190 * of bytes that can be read. If writing, bsize is the maximum number of
Geremy Condra03ebf062011-10-12 18:17:24 -0700191 * 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
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700193 * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is
194 * used for the initial size). Doesn't fail.
Geremy Condra03ebf062011-10-12 18:17:24 -0700195 * When writing, a byte is reserved for a trailing NUL - see shf_sclose().
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700196 */
197struct shf *
Geremy Condra03ebf062011-10-12 18:17:24 -0700198shf_sopen(char *buf, ssize_t bsize, int sflags, struct shf *shf)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700199{
200 /* can't have a read+write string */
201 if (!(!(sflags & SHF_RD) ^ !(sflags & SHF_WR)))
Elliott Hughes77740fc2016-08-12 15:06:53 -0700202 internal_errorf(Tf_flags, "shf_sopen",
203 (unsigned int)sflags);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700204
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;
Geremy Condra03ebf062011-10-12 18:17:24 -0700223 shf->errnosv = 0;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700224 shf->bsize = bsize;
225
226 return (shf);
227}
228
229/* Flush and close file descriptor, free the shf structure */
230int
231shf_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)
Elliott Hughes50012062015-03-10 22:22:24 -0700238 ret = -1;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700239 }
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 */
249int
250shf_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)
Elliott Hughes50012062015-03-10 22:22:24 -0700257 ret = -1;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700258 shf->rnleft = 0;
259 shf->rp = shf->buf;
260 shf->wnleft = 0;
261 shf->fd = -1;
262 }
263
264 return (ret);
265}
266
Geremy Condra03ebf062011-10-12 18:17:24 -0700267/*
268 * Close a string - if it was opened for writing, it is NUL terminated;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700269 * returns a pointer to the string and frees shf if it was allocated
270 * (does not free string if it was allocated).
271 */
272char *
273shf_sclose(struct shf *shf)
274{
275 unsigned char *s = shf->buf;
276
Geremy Condra03ebf062011-10-12 18:17:24 -0700277 /* NUL terminate */
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700278 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
Geremy Condra03ebf062011-10-12 18:17:24 -0700287/*
288 * Un-read what has been read but not examined, or write what has been
Elliott Hughes50012062015-03-10 22:22:24 -0700289 * buffered. Returns 0 for success, -1 for (write) error.
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700290 */
291int
292shf_flush(struct shf *shf)
293{
Elliott Hughesa3c3f962017-04-12 16:52:30 -0700294 int rv = 0;
295
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700296 if (shf->flags & SHF_STRING)
Elliott Hughesa3c3f962017-04-12 16:52:30 -0700297 rv = (shf->flags & SHF_WR) ? -1 : 0;
298 else if (shf->fd < 0)
Elliott Hughes77740fc2016-08-12 15:06:53 -0700299 internal_errorf(Tf_sD_s, "shf_flush", "no fd");
Elliott Hughesa3c3f962017-04-12 16:52:30 -0700300 else if (shf->flags & SHF_ERROR) {
Geremy Condra03ebf062011-10-12 18:17:24 -0700301 errno = shf->errnosv;
Elliott Hughesa3c3f962017-04-12 16:52:30 -0700302 rv = -1;
303 } else if (shf->flags & SHF_READING) {
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700304 shf->flags &= ~(SHF_EOF | SHF_READING);
305 if (shf->rnleft > 0) {
Elliott Hughesa3c3f962017-04-12 16:52:30 -0700306 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 }
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700312 shf->rnleft = 0;
313 shf->rp = shf->buf;
314 }
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700315 } else if (shf->flags & SHF_WRITING)
Elliott Hughesa3c3f962017-04-12 16:52:30 -0700316 rv = shf_emptybuf(shf, 0);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700317
Elliott Hughesa3c3f962017-04-12 16:52:30 -0700318 return (rv);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700319}
320
Geremy Condra03ebf062011-10-12 18:17:24 -0700321/*
322 * Write out any buffered data. If currently reading, flushes the read
Elliott Hughes50012062015-03-10 22:22:24 -0700323 * buffer. Returns 0 for success, -1 for (write) error.
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700324 */
325static int
326shf_emptybuf(struct shf *shf, int flags)
327{
328 int ret = 0;
329
330 if (!(shf->flags & SHF_STRING) && shf->fd < 0)
Elliott Hughes77740fc2016-08-12 15:06:53 -0700331 internal_errorf(Tf_sD_s, "shf_emptybuf", "no fd");
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700332
333 if (shf->flags & SHF_ERROR) {
Geremy Condra03ebf062011-10-12 18:17:24 -0700334 errno = shf->errnosv;
Elliott Hughes50012062015-03-10 22:22:24 -0700335 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700336 }
337
338 if (shf->flags & SHF_READING) {
Geremy Condra03ebf062011-10-12 18:17:24 -0700339 if (flags & EB_READSW)
340 /* doesn't happen */
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700341 return (0);
342 ret = shf_flush(shf);
343 shf->flags &= ~SHF_READING;
344 }
345 if (shf->flags & SHF_STRING) {
346 unsigned char *nbuf;
347
Geremy Condra03ebf062011-10-12 18:17:24 -0700348 /*
349 * Note that we assume SHF_ALLOCS is not set if
350 * SHF_ALLOCB is set... (changing the shf pointer could
351 * cause problems)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700352 */
353 if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) ||
354 !(shf->flags & SHF_ALLOCB))
Elliott Hughes50012062015-03-10 22:22:24 -0700355 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700356 /* allocate more space for buffer */
Geremy Condra03ebf062011-10-12 18:17:24 -0700357 nbuf = aresize2(shf->buf, 2, shf->wbsize, shf->areap);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700358 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;
Geremy Condra03ebf062011-10-12 18:17:24 -0700362 shf->wbsize <<= 1;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700363 shf->buf = nbuf;
364 } else {
365 if (shf->flags & SHF_WRITING) {
Geremy Condra03ebf062011-10-12 18:17:24 -0700366 ssize_t n, ntowrite = shf->wp - shf->buf;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700367 unsigned char *buf = shf->buf;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700368
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;
Geremy Condra03ebf062011-10-12 18:17:24 -0700376 shf->errnosv = errno;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700377 shf->wnleft = 0;
378 if (buf != shf->buf) {
Geremy Condra03ebf062011-10-12 18:17:24 -0700379 /*
380 * allow a second flush
381 * to work
382 */
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700383 memmove(shf->buf, buf,
384 ntowrite);
385 shf->wp = shf->buf + ntowrite;
386 }
Elliott Hughes50012062015-03-10 22:22:24 -0700387 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700388 }
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
Elliott Hughes50012062015-03-10 22:22:24 -0700407/* Fill up a read buffer. Returns -1 for a read error, 0 otherwise. */
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700408static int
409shf_fillbuf(struct shf *shf)
410{
Geremy Condra03ebf062011-10-12 18:17:24 -0700411 ssize_t n;
412
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700413 if (shf->flags & SHF_STRING)
414 return (0);
415
416 if (shf->fd < 0)
Elliott Hughes77740fc2016-08-12 15:06:53 -0700417 internal_errorf(Tf_sD_s, "shf_fillbuf", "no fd");
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700418
419 if (shf->flags & (SHF_EOF | SHF_ERROR)) {
420 if (shf->flags & SHF_ERROR)
Geremy Condra03ebf062011-10-12 18:17:24 -0700421 errno = shf->errnosv;
Elliott Hughes50012062015-03-10 22:22:24 -0700422 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700423 }
424
Elliott Hughes50012062015-03-10 22:22:24 -0700425 if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1)
426 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700427
428 shf->flags |= SHF_READING;
429
430 shf->rp = shf->buf;
Geremy Condra03ebf062011-10-12 18:17:24 -0700431 while (/* CONSTCOND */ 1) {
432 n = blocking_read(shf->fd, (char *)shf->buf, shf->rbsize);
433 if (n < 0 && errno == EINTR && !(shf->flags & SHF_INTERRUPT))
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700434 continue;
435 break;
436 }
Geremy Condra03ebf062011-10-12 18:17:24 -0700437 if (n < 0) {
438 shf->flags |= SHF_ERROR;
439 shf->errnosv = errno;
440 shf->rnleft = 0;
441 shf->rp = shf->buf;
Elliott Hughes50012062015-03-10 22:22:24 -0700442 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700443 }
Geremy Condra03ebf062011-10-12 18:17:24 -0700444 if ((shf->rnleft = n) == 0)
445 shf->flags |= SHF_EOF;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700446 return (0);
447}
448
Geremy Condra03ebf062011-10-12 18:17:24 -0700449/*
450 * Read a buffer from shf. Returns the number of bytes read into buf, if
Elliott Hughes50012062015-03-10 22:22:24 -0700451 * no bytes were read, returns 0 if end of file was seen, -1 if a read
Geremy Condra03ebf062011-10-12 18:17:24 -0700452 * error occurred.
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700453 */
Geremy Condra03ebf062011-10-12 18:17:24 -0700454ssize_t
455shf_read(char *buf, ssize_t bsize, struct shf *shf)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700456{
Geremy Condra03ebf062011-10-12 18:17:24 -0700457 ssize_t ncopy, orig_bsize = bsize;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700458
459 if (!(shf->flags & SHF_RD))
Elliott Hughes77740fc2016-08-12 15:06:53 -0700460 internal_errorf(Tf_flags, Tshf_read,
461 (unsigned int)shf->flags);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700462
463 if (bsize <= 0)
Elliott Hughes77740fc2016-08-12 15:06:53 -0700464 internal_errorf(Tf_szs, Tshf_read, bsize, Tbsize);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700465
466 while (bsize > 0) {
467 if (shf->rnleft == 0 &&
Elliott Hughes50012062015-03-10 22:22:24 -0700468 (shf_fillbuf(shf) == -1 || shf->rnleft == 0))
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700469 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 */
Elliott Hughes50012062015-03-10 22:22:24 -0700480 return (orig_bsize == bsize ? (shf_error(shf) ? -1 : 0) :
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700481 orig_bsize - bsize);
482}
483
Geremy Condra03ebf062011-10-12 18:17:24 -0700484/*
Elliott Hughes50012062015-03-10 22:22:24 -0700485 * Read up to a newline or -1. The newline is put in buf; buf is always
Geremy Condra03ebf062011-10-12 18:17:24 -0700486 * 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.
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700489 */
490char *
Geremy Condra03ebf062011-10-12 18:17:24 -0700491shf_getse(char *buf, ssize_t bsize, struct shf *shf)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700492{
493 unsigned char *end;
Geremy Condra03ebf062011-10-12 18:17:24 -0700494 ssize_t ncopy;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700495 char *orig_buf = buf;
496
497 if (!(shf->flags & SHF_RD))
Elliott Hughes77740fc2016-08-12 15:06:53 -0700498 internal_errorf(Tf_flags, "shf_getse",
499 (unsigned int)shf->flags);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700500
501 if (bsize <= 0)
502 return (NULL);
503
Geremy Condra03ebf062011-10-12 18:17:24 -0700504 /* save room for NUL */
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +0000505 --bsize;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700506 do {
507 if (shf->rnleft == 0) {
Elliott Hughes50012062015-03-10 22:22:24 -0700508 if (shf_fillbuf(shf) == -1)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700509 return (NULL);
510 if (shf->rnleft == 0) {
511 *buf = '\0';
512 return (buf == orig_buf ? NULL : buf);
513 }
514 }
Geremy Condra03ebf062011-10-12 18:17:24 -0700515 end = (unsigned char *)memchr((char *)shf->rp, '\n',
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700516 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;
Elliott Hughesa3c3f962017-04-12 16:52:30 -0700525#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
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700532 } while (!end && bsize);
Elliott Hughesa3c3f962017-04-12 16:52:30 -0700533#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
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700542 *buf = '\0';
543 return (buf);
544}
545
Elliott Hughes50012062015-03-10 22:22:24 -0700546/* Returns the char read. Returns -1 for error and end of file. */
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700547int
548shf_getchar(struct shf *shf)
549{
550 if (!(shf->flags & SHF_RD))
Elliott Hughes77740fc2016-08-12 15:06:53 -0700551 internal_errorf(Tf_flags, "shf_getchar",
552 (unsigned int)shf->flags);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700553
Elliott Hughes50012062015-03-10 22:22:24 -0700554 if (shf->rnleft == 0 && (shf_fillbuf(shf) == -1 || shf->rnleft == 0))
555 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700556 --shf->rnleft;
Elliott Hughesdd4abe02018-02-05 15:55:19 -0800557 return (ord(*shf->rp++));
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700558}
559
Geremy Condra03ebf062011-10-12 18:17:24 -0700560/*
561 * Put a character back in the input stream. Returns the character if
Elliott Hughes50012062015-03-10 22:22:24 -0700562 * successful, -1 if there is no room.
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700563 */
564int
565shf_ungetc(int c, struct shf *shf)
566{
567 if (!(shf->flags & SHF_RD))
Elliott Hughes77740fc2016-08-12 15:06:53 -0700568 internal_errorf(Tf_flags, "shf_ungetc",
569 (unsigned int)shf->flags);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700570
Elliott Hughes50012062015-03-10 22:22:24 -0700571 if ((shf->flags & SHF_ERROR) || c == -1 ||
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700572 (shf->rp == shf->buf && shf->rnleft))
Elliott Hughes50012062015-03-10 22:22:24 -0700573 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700574
Elliott Hughes50012062015-03-10 22:22:24 -0700575 if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1)
576 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700577
578 if (shf->rp == shf->buf)
579 shf->rp = shf->buf + shf->rbsize;
580 if (shf->flags & SHF_STRING) {
Geremy Condra03ebf062011-10-12 18:17:24 -0700581 /*
582 * Can unget what was read, but not something different;
583 * we don't want to modify a string.
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700584 */
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +0000585 if ((int)(shf->rp[-1]) != c)
Elliott Hughes50012062015-03-10 22:22:24 -0700586 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700587 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
Geremy Condra03ebf062011-10-12 18:17:24 -0700598/*
Elliott Hughes50012062015-03-10 22:22:24 -0700599 * Write a character. Returns the character if successful, -1 if the
Geremy Condra03ebf062011-10-12 18:17:24 -0700600 * char could not be written.
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700601 */
602int
603shf_putchar(int c, struct shf *shf)
604{
605 if (!(shf->flags & SHF_WR))
Elliott Hughes77740fc2016-08-12 15:06:53 -0700606 internal_errorf(Tf_flags, "shf_putchar",
607 (unsigned int)shf->flags);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700608
Elliott Hughes50012062015-03-10 22:22:24 -0700609 if (c == -1)
610 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700611
612 if (shf->flags & SHF_UNBUF) {
613 unsigned char cc = (unsigned char)c;
Geremy Condra03ebf062011-10-12 18:17:24 -0700614 ssize_t n;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700615
616 if (shf->fd < 0)
Elliott Hughes77740fc2016-08-12 15:06:53 -0700617 internal_errorf(Tf_sD_s, "shf_putchar", "no fd");
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700618 if (shf->flags & SHF_ERROR) {
Geremy Condra03ebf062011-10-12 18:17:24 -0700619 errno = shf->errnosv;
Elliott Hughes50012062015-03-10 22:22:24 -0700620 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700621 }
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;
Geremy Condra03ebf062011-10-12 18:17:24 -0700628 shf->errnosv = errno;
Elliott Hughes50012062015-03-10 22:22:24 -0700629 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700630 }
631 } else {
632 /* Flush deals with strings and sticky errors */
Elliott Hughes50012062015-03-10 22:22:24 -0700633 if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == -1)
634 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700635 shf->wnleft--;
636 *shf->wp++ = c;
637 }
638
639 return (c);
640}
641
Geremy Condra03ebf062011-10-12 18:17:24 -0700642/*
Elliott Hughes50012062015-03-10 22:22:24 -0700643 * Write a string. Returns the length of the string if successful, -1
Geremy Condra03ebf062011-10-12 18:17:24 -0700644 * if the string could not be written.
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700645 */
Geremy Condra03ebf062011-10-12 18:17:24 -0700646ssize_t
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700647shf_puts(const char *s, struct shf *shf)
648{
649 if (!s)
Elliott Hughes50012062015-03-10 22:22:24 -0700650 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700651
652 return (shf_write(s, strlen(s), shf));
653}
654
Elliott Hughes50012062015-03-10 22:22:24 -0700655/* Write a buffer. Returns nbytes if successful, -1 if there is an error. */
Geremy Condra03ebf062011-10-12 18:17:24 -0700656ssize_t
657shf_write(const char *buf, ssize_t nbytes, struct shf *shf)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700658{
Geremy Condra03ebf062011-10-12 18:17:24 -0700659 ssize_t n, ncopy, orig_nbytes = nbytes;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700660
661 if (!(shf->flags & SHF_WR))
Elliott Hughes77740fc2016-08-12 15:06:53 -0700662 internal_errorf(Tf_flags, Tshf_write,
663 (unsigned int)shf->flags);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700664
665 if (nbytes < 0)
Elliott Hughes77740fc2016-08-12 15:06:53 -0700666 internal_errorf(Tf_szs, Tshf_write, nbytes, Tbytes);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700667
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)
Elliott Hughes50012062015-03-10 22:22:24 -0700683 if (shf_emptybuf(shf, EB_GROW) == -1)
684 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700685 /* then write everything into the buffer */
686 } else {
687 /* flush deals with sticky errors */
Elliott Hughes50012062015-03-10 22:22:24 -0700688 if (shf_emptybuf(shf, EB_GROW) == -1)
689 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700690 /* 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;
Geremy Condra03ebf062011-10-12 18:17:24 -0700703 shf->errnosv = errno;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700704 shf->wnleft = 0;
705 /*
706 * Note: fwrite(3) returns 0
707 * for errors - this doesn't
708 */
Elliott Hughes50012062015-03-10 22:22:24 -0700709 return (-1);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700710 }
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
Geremy Condra03ebf062011-10-12 18:17:24 -0700728ssize_t
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700729shf_fprintf(struct shf *shf, const char *fmt, ...)
730{
731 va_list args;
Geremy Condra03ebf062011-10-12 18:17:24 -0700732 ssize_t n;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700733
734 va_start(args, fmt);
735 n = shf_vfprintf(shf, fmt, args);
736 va_end(args);
737
738 return (n);
739}
740
Geremy Condra03ebf062011-10-12 18:17:24 -0700741ssize_t
742shf_snprintf(char *buf, ssize_t bsize, const char *fmt, ...)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700743{
744 struct shf shf;
745 va_list args;
Geremy Condra03ebf062011-10-12 18:17:24 -0700746 ssize_t n;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700747
748 if (!buf || bsize <= 0)
Geremy Condra03ebf062011-10-12 18:17:24 -0700749 internal_errorf("shf_snprintf: buf %zX, bsize %zd",
750 (size_t)buf, bsize);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700751
752 shf_sopen(buf, bsize, SHF_WR, &shf);
753 va_start(args, fmt);
754 n = shf_vfprintf(&shf, fmt, args);
755 va_end(args);
Geremy Condra03ebf062011-10-12 18:17:24 -0700756 /* NUL terminates */
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +0000757 shf_sclose(&shf);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700758 return (n);
759}
760
761char *
762shf_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);
Geremy Condra03ebf062011-10-12 18:17:24 -0700771 /* NUL terminates */
772 return (shf_sclose(&shf));
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700773}
774
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700775#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] */
Geremy Condra03ebf062011-10-12 18:17:24 -0700785#define FL_SIZET 0x400 /* 'z' seen */
786#define FM_SIZES 0x430 /* h/l/z mask */
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700787
Geremy Condra03ebf062011-10-12 18:17:24 -0700788ssize_t
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700789shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
790{
791 const char *s;
792 char c, *cp;
Geremy Condra03ebf062011-10-12 18:17:24 -0700793 int tmp = 0, flags;
Elliott Hughes77740fc2016-08-12 15:06:53 -0700794 size_t field, precision, len;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700795 unsigned long lnum;
796 /* %#o produces the longest output */
Elliott Hughes77740fc2016-08-12 15:06:53 -0700797 char numbuf[(8 * sizeof(long) + 2) / 3 + 1 + /* NUL */ 1];
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700798 /* this stuff for dealing with the buffer */
Geremy Condra03ebf062011-10-12 18:17:24 -0700799 ssize_t nwritten = 0;
800
801#define VA(type) va_arg(args, type)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700802
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 /*
Geremy Condra03ebf062011-10-12 18:17:24 -0700813 * 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 :-).
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700818 */
Geremy Condra03ebf062011-10-12 18:17:24 -0700819 flags = 0;
820 field = precision = 0;
Elliott Hughes77740fc2016-08-12 15:06:53 -0700821 while ((c = *fmt++)) {
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700822 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 '*':
Geremy Condra03ebf062011-10-12 18:17:24 -0700850 tmp = VA(int);
Elliott Hughes77740fc2016-08-12 15:06:53 -0700851 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;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700862 continue;
863
864 case 'l':
Geremy Condra03ebf062011-10-12 18:17:24 -0700865 flags &= ~FM_SIZES;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700866 flags |= FL_LONG;
867 continue;
868
869 case 'h':
Geremy Condra03ebf062011-10-12 18:17:24 -0700870 flags &= ~FM_SIZES;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700871 flags |= FL_SHORT;
872 continue;
Geremy Condra03ebf062011-10-12 18:17:24 -0700873
874 case 'z':
875 flags &= ~FM_SIZES;
876 flags |= FL_SIZET;
877 continue;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700878 }
Elliott Hughes23925bb2017-09-22 16:04:20 -0700879 if (ctype(c, C_DIGIT)) {
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +0000880 bool overflowed = false;
881
Elliott Hughes96b43632015-07-17 11:39:41 -0700882 tmp = ksh_numdig(c);
Elliott Hughes23925bb2017-09-22 16:04:20 -0700883 while (ctype((c = *fmt++), C_DIGIT))
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +0000884 if (notok2mul(2147483647, tmp, 10))
885 overflowed = true;
Elliott Hughes77740fc2016-08-12 15:06:53 -0700886 else
887 tmp = tmp * 10 + ksh_numdig(c);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700888 --fmt;
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +0000889 if (overflowed)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700890 tmp = 0;
891 if (flags & FL_DOT)
Elliott Hughes77740fc2016-08-12 15:06:53 -0700892 precision = (unsigned int)tmp;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700893 else
Elliott Hughes77740fc2016-08-12 15:06:53 -0700894 field = (unsigned int)tmp;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700895 continue;
896 }
897 break;
898 }
899
Geremy Condra03ebf062011-10-12 18:17:24 -0700900 if (!c)
901 /* nasty format */
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700902 break;
903
Elliott Hughes23925bb2017-09-22 16:04:20 -0700904 if (ctype(c, C_UPPER)) {
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700905 flags |= FL_UPPER;
906 c = ksh_tolower(c);
907 }
908
909 switch (c) {
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700910 case 'd':
911 case 'i':
Geremy Condra03ebf062011-10-12 18:17:24 -0700912 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
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700922 case 'o':
923 case 'u':
924 case 'x':
Geremy Condra03ebf062011-10-12 18:17:24 -0700925 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:
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700935 flags |= FL_NUMBER;
936 cp = numbuf + sizeof(numbuf);
Elliott Hughes77740fc2016-08-12 15:06:53 -0700937 *--cp = '\0';
Geremy Condra03ebf062011-10-12 18:17:24 -0700938
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700939 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 {
Elliott Hughes96b43632015-07-17 11:39:41 -0700950 *--cp = digits_lc[lnum % 10];
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700951 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 {
Elliott Hughes96b43632015-07-17 11:39:41 -0700966 *--cp = digits_lc[lnum & 0x7];
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700967 lnum >>= 3;
968 } while (lnum);
969
970 if ((flags & FL_HASH) && *cp != '0')
971 *--cp = '0';
972 break;
973
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700974 case 'x': {
975 const char *digits = (flags & FL_UPPER) ?
976 digits_uc : digits_lc;
977 do {
Elliott Hughes96b43632015-07-17 11:39:41 -0700978 *--cp = digits[lnum & 0xF];
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700979 lnum >>= 4;
980 } while (lnum);
981
982 if (flags & FL_HASH) {
983 *--cp = (flags & FL_UPPER) ? 'X' : 'x';
984 *--cp = '0';
985 }
Elliott Hughes77740fc2016-08-12 15:06:53 -0700986 }
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700987 }
Elliott Hughes77740fc2016-08-12 15:06:53 -0700988 len = numbuf + sizeof(numbuf) - 1 - (s = cp);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700989 if (flags & FL_DOT) {
990 if (precision > len) {
991 field = precision;
992 flags |= FL_ZERO;
993 } else
Geremy Condra03ebf062011-10-12 18:17:24 -0700994 /* no loss */
995 precision = len;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -0700996 }
997 break;
998
999 case 's':
Geremy Condra03ebf062011-10-12 18:17:24 -07001000 if ((s = VA(const char *)) == NULL)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001001 s = "(null)";
Thorsten Glaser811a5752013-07-25 14:24:45 +00001002 else if (flags & FL_HASH) {
1003 print_value_quoted(shf, s);
1004 continue;
1005 }
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001006 len = utf_mbswidth(s);
1007 break;
1008
1009 case 'c':
1010 flags &= ~FL_DOT;
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001011 c = (char)(VA(int));
1012 /* FALLTHROUGH */
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001013
1014 case '%':
1015 default:
1016 numbuf[0] = c;
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001017 numbuf[1] = 0;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001018 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)) {
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001032 /* skip past sign or 0x when padding with 0 */
1033 if ((flags & FL_ZERO) && (flags & FL_NUMBER)) {
Elliott Hughes23925bb2017-09-22 16:04:20 -07001034 if (ctype(*s, C_SPC | C_PLUS | C_MINUS)) {
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001035 shf_putc(*s, shf);
1036 s++;
1037 precision--;
1038 nwritten++;
1039 } else if (*s == '0') {
1040 shf_putc(*s, shf);
1041 s++;
1042 nwritten++;
Elliott Hughes77740fc2016-08-12 15:06:53 -07001043 if (--precision &&
Elliott Hughes96b43632015-07-17 11:39:41 -07001044 ksh_eq(*s, 'X', 'x')) {
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001045 shf_putc(*s, shf);
1046 s++;
1047 precision--;
1048 nwritten++;
1049 }
1050 }
1051 c = '0';
1052 } else
1053 c = flags & FL_ZERO ? '0' : ' ';
Elliott Hughes77740fc2016-08-12 15:06:53 -07001054 nwritten += field;
1055 while (field--)
1056 shf_putc(c, shf);
1057 field = 0;
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001058 } else
1059 c = ' ';
1060 } else
1061 field = 0;
1062
Elliott Hughes77740fc2016-08-12 15:06:53 -07001063 nwritten += precision;
1064 precision = utf_skipcols(s, precision, &tmp) - s;
1065 while (precision--)
1066 shf_putc(*s++, shf);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001067
Elliott Hughes77740fc2016-08-12 15:06:53 -07001068 nwritten += field;
1069 while (field--)
1070 shf_putc(c, shf);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001071 }
1072
Elliott Hughes50012062015-03-10 22:22:24 -07001073 return (shf_error(shf) ? -1 : nwritten);
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001074}
1075
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001076#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001077int
1078shf_getc(struct shf *shf)
1079{
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001080 return (shf_getc_i(shf));
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001081}
1082
1083int
1084shf_putc(int c, struct shf *shf)
1085{
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001086 return (shf_putc_i(c, shf));
1087}
1088#endif
1089
1090#ifdef DEBUG
1091const char *
1092cstrerror(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
1102extern const int sys_nerr;
1103extern const char * const sys_errlist[];
1104#endif
1105#endif
1106
1107const char *
1108cstrerror(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");
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001121 case EPERM:
1122 return ("Operation not permitted");
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001123 case ENOENT:
1124 return ("No such file or directory");
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001125#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
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001133 case ENOEXEC:
1134 return ("Exec format error");
Elliott Hughesfc0307d2016-02-02 15:26:47 -08001135 case EBADF:
1136 return ("Bad file descriptor");
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001137#ifdef ENOMEM
1138 case ENOMEM:
1139 return ("Cannot allocate memory");
1140#endif
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001141 case EACCES:
1142 return ("Permission denied");
Elliott Hughesfc0307d2016-02-02 15:26:47 -08001143 case EEXIST:
1144 return ("File exists");
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001145 case ENOTDIR:
1146 return ("Not a directory");
Thorsten Glaserc2dc5de2013-02-18 23:02:51 +00001147#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 }
Jean-Baptiste Queru5155f1c2011-06-16 10:05:28 -07001160}
1161#endif
Elliott Hughes23925bb2017-09-22 16:04:20 -07001162
1163/* fast character classes */
1164const 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
1211void
1212set_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
Elliott Hughesdd4abe02018-02-05 15:55:19 -08001256 * ensure you're getting a value in [0, 255] (ORD for constants).
Elliott Hughes23925bb2017-09-22 16:04:20 -07001257 * 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
1266void
1267ebcdic_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.
Elliott Hughes47086262019-03-26 12:34:31 -07001307 * If ever we map to UCS, bump the table width to
Elliott Hughes23925bb2017-09-22 16:04:20 -07001308 * 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