15155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* $OpenBSD: shf.c,v 1.15 2006/04/02 00:48:33 deraadt Exp $ */ 25155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 35155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*- 4c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012 55155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Thorsten Glaser <tg@mirbsd.org> 65155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * 75155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Provided that these terms and disclaimer and all copyright notices 85155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * are retained or reproduced in an accompanying document, permission 95155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * is granted to deal in this work without restriction, including un- 105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * limited rights to use, publicly perform, distribute, sell, modify, 115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * merge, give away, or sublicence. 125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * 135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the utmost extent permitted by applicable law, neither express nor 155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * implied; without malicious intent or gross negligence. In no event 165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * may a licensor, author or contributor be held liable for indirect, 175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * direct, other damage, loss, or other issues arising in any way out 185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of dealing in the work, even if advised of the possibility of such 195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * damage or existence of a defect, except proven that it results out 205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of said person's immediate fault when using the work as intended. 2103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra *- 2203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Use %zX instead of %p and floating point isn't supported at all. 235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "sh.h" 265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 27c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.56 2013/01/01 03:32:44 tg Exp $"); 285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* flags to shf_emptybuf() */ 305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define EB_READSW 0x01 /* about to switch to reading */ 315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define EB_GROW 0x02 /* grow buffer if necessary (STRING+DYNAMIC) */ 325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* 345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Replacement stdio routines. Stdio is too flakey on too many machines 355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * to be useful when you have multiple processes using the same underlying 365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * file descriptors. 375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int shf_fillbuf(struct shf *); 405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int shf_emptybuf(struct shf *, int); 415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 4203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* 4303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Open a file. First three args are for open(), last arg is flags for 445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * this package. Returns NULL if file could not be opened, or if a dup 455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * fails. 465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct shf * 485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_open(const char *name, int oflags, int mode, int sflags) 495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru struct shf *shf; 5103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t bsize = 5203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* at most 512 */ 5303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; 545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru int fd; 555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* Done before open so if alloca fails, fd won't be lost. */ 575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf = alloc(sizeof(struct shf) + bsize, ATEMP); 585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->areap = ATEMP; 595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->buf = (unsigned char *)&shf[1]; 605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->bsize = bsize; 615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags = SHF_ALLOCS; 625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* Rest filled in by reopen. */ 635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru fd = open(name, oflags, mode); 655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (fd < 0) { 665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru afree(shf, shf->areap); 675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (NULL); 685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if ((sflags & SHF_MAPHI) && fd < FDBASE) { 705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru int nfd; 715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru nfd = fcntl(fd, F_DUPFD, FDBASE); 735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru close(fd); 745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (nfd < 0) { 755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru afree(shf, shf->areap); 765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (NULL); 775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru fd = nfd; 795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru sflags &= ~SHF_ACCMODE; 815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD : 825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR : SHF_RDWR); 835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (shf_reopen(fd, sflags, shf)); 855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* helper function for shf_fdopen and shf_reopen */ 8803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic void 8903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_open_hlp(int fd, int *sflagsp, const char *where) 905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 9103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra int sflags = *sflagsp; 925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* use fcntl() to figure out correct read/write flags */ 945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (sflags & SHF_GETFL) { 955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru int flags = fcntl(fd, F_GETFL, 0); 965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (flags < 0) 985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* will get an error on first read/write */ 995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru sflags |= SHF_RDWR; 1005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru else { 1015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru switch (flags & O_ACCMODE) { 1025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case O_RDONLY: 1035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru sflags |= SHF_RD; 1045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 1055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case O_WRONLY: 1065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru sflags |= SHF_WR; 1075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 1085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case O_RDWR: 1095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru sflags |= SHF_RDWR; 1105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 1115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 1125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 11303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra *sflagsp = sflags; 1145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 1155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 1165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(sflags & (SHF_RD | SHF_WR))) 11703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: %s", where, "missing read/write"); 11803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra} 11903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra 12003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* Set up the shf structure for a file descriptor. Doesn't fail. */ 12103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastruct shf * 12203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_fdopen(int fd, int sflags, struct shf *shf) 12303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{ 12403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t bsize = 12503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* at most 512 */ 12603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; 1275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 12803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf_open_hlp(fd, &sflags, "shf_fdopen"); 1295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf) { 1305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (bsize) { 1315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->buf = alloc(bsize, ATEMP); 1325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru sflags |= SHF_ALLOCB; 1335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else 1345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->buf = NULL; 1355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else { 1365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf = alloc(sizeof(struct shf) + bsize, ATEMP); 1375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->buf = (unsigned char *)&shf[1]; 1385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru sflags |= SHF_ALLOCS; 1395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 1405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->areap = ATEMP; 1415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->fd = fd; 1425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rp = shf->wp = shf->buf; 1435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rnleft = 0; 1445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rbsize = bsize; 1455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft = 0; /* force call to shf_emptybuf() */ 1465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; 1475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags = sflags; 14803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->errnosv = 0; 1495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->bsize = bsize; 1505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (sflags & SHF_CLEXEC) 1515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru fcntl(fd, F_SETFD, FD_CLOEXEC); 1525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (shf); 1535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 1545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 1555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Set up an existing shf (and buffer) to use the given fd */ 1565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct shf * 1575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_reopen(int fd, int sflags, struct shf *shf) 1585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 15903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t bsize = 16003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* at most 512 */ 16103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; 1625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 16303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf_open_hlp(fd, &sflags, "shf_reopen"); 1645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!shf || !shf->buf || shf->bsize < bsize) 16503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: %s", "shf_reopen", "bad shf/buf/bsize"); 1665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 1675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* assumes shf->buf and shf->bsize already set up */ 1685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->fd = fd; 1695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rp = shf->wp = shf->buf; 1705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rnleft = 0; 1715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rbsize = bsize; 1725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft = 0; /* force call to shf_emptybuf() */ 1735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; 1745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags; 17503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->errnosv = 0; 1765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (sflags & SHF_CLEXEC) 1775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru fcntl(fd, F_SETFD, FD_CLOEXEC); 1785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (shf); 1795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 1805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 18103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* 18203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Open a string for reading or writing. If reading, bsize is the number 1835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of bytes that can be read. If writing, bsize is the maximum number of 18403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * bytes that can be written. If shf is not NULL, it is filled in and 18503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * returned, if it is NULL, shf is allocated. If writing and buf is NULL 1865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is 1875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * used for the initial size). Doesn't fail. 18803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * When writing, a byte is reserved for a trailing NUL - see shf_sclose(). 1895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 1905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct shf * 19103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_sopen(char *buf, ssize_t bsize, int sflags, struct shf *shf) 1925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 1935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* can't have a read+write string */ 1945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(!(sflags & SHF_RD) ^ !(sflags & SHF_WR))) 19503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: flags 0x%X", "shf_sopen", sflags); 1965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 1975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!shf) { 1985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf = alloc(sizeof(struct shf), ATEMP); 1995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru sflags |= SHF_ALLOCS; 2005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 2015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->areap = ATEMP; 2025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) { 2035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (bsize <= 0) 2045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru bsize = 64; 2055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru sflags |= SHF_ALLOCB; 2065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru buf = alloc(bsize, shf->areap); 2075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 2085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->fd = -1; 2095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->buf = shf->rp = shf->wp = (unsigned char *)buf; 2105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rnleft = bsize; 2115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rbsize = bsize; 2125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft = bsize - 1; /* space for a '\0' */ 2135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wbsize = bsize; 2145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags = sflags | SHF_STRING; 21503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->errnosv = 0; 2165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->bsize = bsize; 2175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 2185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (shf); 2195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 2205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 2215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Flush and close file descriptor, free the shf structure */ 2225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint 2235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_close(struct shf *shf) 2245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 2255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru int ret = 0; 2265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 2275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->fd >= 0) { 2285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ret = shf_flush(shf); 2295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (close(shf->fd) < 0) 2305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ret = EOF; 2315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 2325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_ALLOCS) 2335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru afree(shf, shf->areap); 2345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru else if (shf->flags & SHF_ALLOCB) 2355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru afree(shf->buf, shf->areap); 2365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 2375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (ret); 2385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 2395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 2405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Flush and close file descriptor, don't free file structure */ 2415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint 2425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_fdclose(struct shf *shf) 2435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 2445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru int ret = 0; 2455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 2465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->fd >= 0) { 2475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ret = shf_flush(shf); 2485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (close(shf->fd) < 0) 2495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ret = EOF; 2505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rnleft = 0; 2515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rp = shf->buf; 2525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft = 0; 2535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->fd = -1; 2545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 2555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 2565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (ret); 2575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 2585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 25903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* 26003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Close a string - if it was opened for writing, it is NUL terminated; 2615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * returns a pointer to the string and frees shf if it was allocated 2625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * (does not free string if it was allocated). 2635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 2645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar * 2655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_sclose(struct shf *shf) 2665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 2675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru unsigned char *s = shf->buf; 2685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 26903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* NUL terminate */ 2705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_WR) { 2715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft++; 2725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf_putc('\0', shf); 2735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 2745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_ALLOCS) 2755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru afree(shf, shf->areap); 2765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return ((char *)s); 2775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 2785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 27903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* 28003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Un-read what has been read but not examined, or write what has been 2815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * buffered. Returns 0 for success, EOF for (write) error. 2825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 2835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint 2845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_flush(struct shf *shf) 2855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 2865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_STRING) 2875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return ((shf->flags & SHF_WR) ? EOF : 0); 2885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 2895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->fd < 0) 29003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: %s", "shf_flush", "no fd"); 2915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 2925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_ERROR) { 29303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra errno = shf->errnosv; 2945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 2955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 2965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 2975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_READING) { 2985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags &= ~(SHF_EOF | SHF_READING); 2995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->rnleft > 0) { 3005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru lseek(shf->fd, (off_t)-shf->rnleft, SEEK_CUR); 3015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rnleft = 0; 3025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rp = shf->buf; 3035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 3045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (0); 3055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else if (shf->flags & SHF_WRITING) 3065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (shf_emptybuf(shf, 0)); 3075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 3085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (0); 3095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 3105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 31103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* 31203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Write out any buffered data. If currently reading, flushes the read 3135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * buffer. Returns 0 for success, EOF for (write) error. 3145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 3155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int 3165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_emptybuf(struct shf *shf, int flags) 3175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 3185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru int ret = 0; 3195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 3205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(shf->flags & SHF_STRING) && shf->fd < 0) 32103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: %s", "shf_emptybuf", "no fd"); 3225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 3235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_ERROR) { 32403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra errno = shf->errnosv; 3255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 3265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 3275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 3285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_READING) { 32903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra if (flags & EB_READSW) 33003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* doesn't happen */ 3315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (0); 3325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ret = shf_flush(shf); 3335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags &= ~SHF_READING; 3345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 3355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_STRING) { 3365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru unsigned char *nbuf; 3375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 33803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* 33903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Note that we assume SHF_ALLOCS is not set if 34003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * SHF_ALLOCB is set... (changing the shf pointer could 34103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * cause problems) 3425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 3435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) || 3445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru !(shf->flags & SHF_ALLOCB)) 3455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 3465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* allocate more space for buffer */ 34703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra nbuf = aresize2(shf->buf, 2, shf->wbsize, shf->areap); 3485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rp = nbuf + (shf->rp - shf->buf); 3495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wp = nbuf + (shf->wp - shf->buf); 3505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rbsize += shf->wbsize; 3515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft += shf->wbsize; 35203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->wbsize <<= 1; 3535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->buf = nbuf; 3545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else { 3555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_WRITING) { 35603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t n, ntowrite = shf->wp - shf->buf; 3575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru unsigned char *buf = shf->buf; 3585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 3595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru while (ntowrite > 0) { 3605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru n = write(shf->fd, buf, ntowrite); 3615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (n < 0) { 3625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (errno == EINTR && 3635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru !(shf->flags & SHF_INTERRUPT)) 3645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 3655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags |= SHF_ERROR; 36603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->errnosv = errno; 3675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft = 0; 3685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (buf != shf->buf) { 36903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* 37003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * allow a second flush 37103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * to work 37203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra */ 3735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru memmove(shf->buf, buf, 3745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ntowrite); 3755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wp = shf->buf + ntowrite; 3765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 3775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 3785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 3795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru buf += n; 3805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ntowrite -= n; 3815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 3825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (flags & EB_READSW) { 3835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wp = shf->buf; 3845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft = 0; 3855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags &= ~SHF_WRITING; 3865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (0); 3875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 3885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 3895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wp = shf->buf; 3905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft = shf->wbsize; 3915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 3925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags |= SHF_WRITING; 3935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 3945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (ret); 3955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 3965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 3975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */ 3985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int 3995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_fillbuf(struct shf *shf) 4005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 40103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t n; 40203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra 4035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_STRING) 4045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (0); 4055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 4065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->fd < 0) 40703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: %s", "shf_fillbuf", "no fd"); 4085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 4095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & (SHF_EOF | SHF_ERROR)) { 4105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_ERROR) 41103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra errno = shf->errnosv; 4125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 4135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 4145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 4155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) 4165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 4175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 4185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags |= SHF_READING; 4195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 4205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rp = shf->buf; 42103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra while (/* CONSTCOND */ 1) { 42203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra n = blocking_read(shf->fd, (char *)shf->buf, shf->rbsize); 42303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra if (n < 0 && errno == EINTR && !(shf->flags & SHF_INTERRUPT)) 4245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 4255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 4265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 42703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra if (n < 0) { 42803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->flags |= SHF_ERROR; 42903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->errnosv = errno; 43003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->rnleft = 0; 43103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->rp = shf->buf; 43203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra return (EOF); 4335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 43403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra if ((shf->rnleft = n) == 0) 43503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->flags |= SHF_EOF; 4365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (0); 4375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 4385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 43903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* 44003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Read a buffer from shf. Returns the number of bytes read into buf, if 44103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * no bytes were read, returns 0 if end of file was seen, EOF if a read 44203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * error occurred. 4435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 44403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t 44503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_read(char *buf, ssize_t bsize, struct shf *shf) 4465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 44703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t ncopy, orig_bsize = bsize; 4485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 4495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(shf->flags & SHF_RD)) 45003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: flags 0x%X", "shf_read", shf->flags); 4515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 4525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (bsize <= 0) 45303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: %s %zd", "shf_write", "bsize", bsize); 4545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 4555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru while (bsize > 0) { 4565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->rnleft == 0 && 4575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) 4585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 4595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ncopy = shf->rnleft; 4605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (ncopy > bsize) 4615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ncopy = bsize; 4625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru memcpy(buf, shf->rp, ncopy); 4635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru buf += ncopy; 4645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru bsize -= ncopy; 4655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rp += ncopy; 4665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rnleft -= ncopy; 4675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 4685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* Note: fread(3S) returns 0 for errors - this doesn't */ 4695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (orig_bsize == bsize ? (shf_error(shf) ? EOF : 0) : 4705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru orig_bsize - bsize); 4715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 4725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 47303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* 47403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Read up to a newline or EOF. The newline is put in buf; buf is always 47503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * NUL terminated. Returns NULL on read error or if nothing was read 47603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * before end of file, returns a pointer to the NUL byte in buf 47703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * otherwise. 4785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 4795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar * 48003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_getse(char *buf, ssize_t bsize, struct shf *shf) 4815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 4825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru unsigned char *end; 48303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t ncopy; 4845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru char *orig_buf = buf; 4855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 4865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(shf->flags & SHF_RD)) 48703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: flags 0x%X", "shf_getse", shf->flags); 4885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 4895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (bsize <= 0) 4905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (NULL); 4915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 49203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* save room for NUL */ 493c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser --bsize; 4945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru do { 4955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->rnleft == 0) { 4965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf_fillbuf(shf) == EOF) 4975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (NULL); 4985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->rnleft == 0) { 4995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *buf = '\0'; 5005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (buf == orig_buf ? NULL : buf); 5015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 5025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 50303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra end = (unsigned char *)memchr((char *)shf->rp, '\n', 5045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rnleft); 5055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ncopy = end ? end - shf->rp + 1 : shf->rnleft; 5065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (ncopy > bsize) 5075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ncopy = bsize; 5085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru memcpy(buf, (char *) shf->rp, ncopy); 5095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rp += ncopy; 5105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rnleft -= ncopy; 5115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru buf += ncopy; 5125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru bsize -= ncopy; 5135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } while (!end && bsize); 5145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *buf = '\0'; 5155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (buf); 5165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 5175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 5185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Returns the char read. Returns EOF for error and end of file. */ 5195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint 5205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_getchar(struct shf *shf) 5215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 5225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(shf->flags & SHF_RD)) 52303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: flags 0x%X", "shf_getchar", shf->flags); 5245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 5255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) 5265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 5275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru --shf->rnleft; 5285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (*shf->rp++); 5295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 5305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 53103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* 53203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Put a character back in the input stream. Returns the character if 5335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * successful, EOF if there is no room. 5345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 5355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint 5365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_ungetc(int c, struct shf *shf) 5375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 5385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(shf->flags & SHF_RD)) 53903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: flags 0x%X", "shf_ungetc", shf->flags); 5405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 5415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if ((shf->flags & SHF_ERROR) || c == EOF || 5425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru (shf->rp == shf->buf && shf->rnleft)) 5435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 5445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 5455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) 5465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 5475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 5485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->rp == shf->buf) 5495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rp = shf->buf + shf->rbsize; 5505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_STRING) { 55103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* 55203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Can unget what was read, but not something different; 55303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * we don't want to modify a string. 5545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 555c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser if ((int)(shf->rp[-1]) != c) 5565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 5575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags &= ~SHF_EOF; 5585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rp--; 5595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rnleft++; 5605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (c); 5615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 5625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags &= ~SHF_EOF; 5635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *--(shf->rp) = c; 5645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->rnleft++; 5655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (c); 5665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 5675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 56803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* 56903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Write a character. Returns the character if successful, EOF if the 57003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * char could not be written. 5715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 5725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint 5735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_putchar(int c, struct shf *shf) 5745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 5755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(shf->flags & SHF_WR)) 57603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: flags 0x%X", "shf_putchar", shf->flags); 5775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 5785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (c == EOF) 5795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 5805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 5815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_UNBUF) { 5825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru unsigned char cc = (unsigned char)c; 58303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t n; 5845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 5855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->fd < 0) 58603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: %s", "shf_putchar", "no fd"); 5875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_ERROR) { 58803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra errno = shf->errnosv; 5895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 5905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 5915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru while ((n = write(shf->fd, &cc, 1)) != 1) 5925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (n < 0) { 5935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (errno == EINTR && 5945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru !(shf->flags & SHF_INTERRUPT)) 5955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 5965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags |= SHF_ERROR; 59703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->errnosv = errno; 5985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 5995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 6005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else { 6015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* Flush deals with strings and sticky errors */ 6025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF) 6035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 6045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft--; 6055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *shf->wp++ = c; 6065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 6075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 6085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (c); 6095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 6105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 61103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* 61203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Write a string. Returns the length of the string if successful, EOF 61303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * if the string could not be written. 6145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 61503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t 6165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_puts(const char *s, struct shf *shf) 6175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 6185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!s) 6195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 6205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 6215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (shf_write(s, strlen(s), shf)); 6225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 6235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 6245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Write a buffer. Returns nbytes if successful, EOF if there is an error. */ 62503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t 62603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_write(const char *buf, ssize_t nbytes, struct shf *shf) 6275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 62803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t n, ncopy, orig_nbytes = nbytes; 6295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 6305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(shf->flags & SHF_WR)) 63103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: flags 0x%X", "shf_write", shf->flags); 6325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 6335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (nbytes < 0) 63403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("%s: %s %zd", "shf_write", "nbytes", nbytes); 6355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 6365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* Don't buffer if buffer is empty and we're writting a large amount. */ 6375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if ((ncopy = shf->wnleft) && 6385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru (shf->wp != shf->buf || nbytes < shf->wnleft)) { 6395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (ncopy > nbytes) 6405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ncopy = nbytes; 6415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru memcpy(shf->wp, buf, ncopy); 6425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru nbytes -= ncopy; 6435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru buf += ncopy; 6445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wp += ncopy; 6455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft -= ncopy; 6465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 6475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (nbytes > 0) { 6485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->flags & SHF_STRING) { 6495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* resize buffer until there's enough space left */ 6505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru while (nbytes > shf->wnleft) 6515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf_emptybuf(shf, EB_GROW) == EOF) 6525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 6535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* then write everything into the buffer */ 6545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else { 6555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* flush deals with sticky errors */ 6565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf_emptybuf(shf, EB_GROW) == EOF) 6575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 6585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* write chunks larger than window size directly */ 6595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (nbytes > shf->wbsize) { 6605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ncopy = nbytes; 6615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (shf->wbsize) 6625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ncopy -= nbytes % shf->wbsize; 6635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru nbytes -= ncopy; 6645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru while (ncopy > 0) { 6655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru n = write(shf->fd, buf, ncopy); 6665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (n < 0) { 6675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (errno == EINTR && 6685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru !(shf->flags & SHF_INTERRUPT)) 6695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 6705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->flags |= SHF_ERROR; 67103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra shf->errnosv = errno; 6725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft = 0; 6735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* 6745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Note: fwrite(3) returns 0 6755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * for errors - this doesn't 6765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 6775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (EOF); 6785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 6795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru buf += n; 6805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ncopy -= n; 6815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 6825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 6835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* ... and buffer the rest */ 6845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 6855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (nbytes > 0) { 6865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* write remaining bytes to buffer */ 6875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru memcpy(shf->wp, buf, nbytes); 6885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wp += nbytes; 6895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf->wnleft -= nbytes; 6905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 6915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 6925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 6935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (orig_nbytes); 6945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 6955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 69603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t 6975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_fprintf(struct shf *shf, const char *fmt, ...) 6985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 6995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru va_list args; 70003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t n; 7015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 7025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru va_start(args, fmt); 7035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru n = shf_vfprintf(shf, fmt, args); 7045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru va_end(args); 7055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 7065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (n); 7075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 7085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 70903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t 71003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_snprintf(char *buf, ssize_t bsize, const char *fmt, ...) 7115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 7125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru struct shf shf; 7135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru va_list args; 71403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t n; 7155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 7165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!buf || bsize <= 0) 71703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra internal_errorf("shf_snprintf: buf %zX, bsize %zd", 71803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra (size_t)buf, bsize); 7195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 7205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf_sopen(buf, bsize, SHF_WR, &shf); 7215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru va_start(args, fmt); 7225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru n = shf_vfprintf(&shf, fmt, args); 7235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru va_end(args); 72403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* NUL terminates */ 725c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser shf_sclose(&shf); 7265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (n); 7275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 7285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 7295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar * 7305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_smprintf(const char *fmt, ...) 7315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 7325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru struct shf shf; 7335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru va_list args; 7345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 7355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf); 7365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru va_start(args, fmt); 7375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf_vfprintf(&shf, fmt, args); 7385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru va_end(args); 73903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* NUL terminates */ 74003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra return (shf_sclose(&shf)); 7415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 7425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 7435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define BUF_SIZE 128 7445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 7455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_HASH 0x001 /* '#' seen */ 7465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_PLUS 0x002 /* '+' seen */ 7475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_RIGHT 0x004 /* '-' seen */ 7485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_BLANK 0x008 /* ' ' seen */ 7495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_SHORT 0x010 /* 'h' seen */ 7505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_LONG 0x020 /* 'l' seen */ 7515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_ZERO 0x040 /* '0' seen */ 7525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_DOT 0x080 /* '.' seen */ 7535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_UPPER 0x100 /* format character was uppercase */ 7545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_NUMBER 0x200 /* a number was formated %[douxefg] */ 75503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define FL_SIZET 0x400 /* 'z' seen */ 75603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define FM_SIZES 0x430 /* h/l/z mask */ 7575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 75803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t 7595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_vfprintf(struct shf *shf, const char *fmt, va_list args) 7605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 7615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru const char *s; 7625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru char c, *cp; 76303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra int tmp = 0, flags; 76403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t field, precision, len; 7655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru unsigned long lnum; 7665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* %#o produces the longest output */ 767c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser char numbuf[(8 * sizeof(long) + 2) / 3 + 1 768c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef DEBUG 769c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser /* a NUL for LLVM/Clang scan-build */ 770c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser + 1 771c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 772c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser ]; 7735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* this stuff for dealing with the buffer */ 77403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra ssize_t nwritten = 0; 77503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra 77603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define VA(type) va_arg(args, type) 7775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 7785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!fmt) 7795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (0); 7805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 7815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru while ((c = *fmt++)) { 7825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (c != '%') { 7835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf_putc(c, shf); 7845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru nwritten++; 7855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 7865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 7875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* 78803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * This will accept flags/fields in any order - not just 78903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * the order specified in printf(3), but this is the way 79003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * _doprnt() seems to work (on BSD and SYSV). The only 79103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * restriction is that the format character must come 79203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * last :-). 7935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 79403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra flags = 0; 79503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra field = precision = 0; 7965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru for ( ; (c = *fmt++) ; ) { 7975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru switch (c) { 7985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case '#': 7995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_HASH; 8005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 8015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case '+': 8035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_PLUS; 8045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 8055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case '-': 8075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_RIGHT; 8085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 8095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case ' ': 8115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_BLANK; 8125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 8135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case '0': 8155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(flags & FL_DOT)) 8165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_ZERO; 8175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 8185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case '.': 8205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_DOT; 8215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru precision = 0; 8225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 8235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case '*': 82503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra tmp = VA(int); 8265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (flags & FL_DOT) 8275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru precision = tmp; 8285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru else if ((field = tmp) < 0) { 8295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru field = -field; 8305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_RIGHT; 8315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 8325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 8335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'l': 83503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra flags &= ~FM_SIZES; 8365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_LONG; 8375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 8385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'h': 84003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra flags &= ~FM_SIZES; 8415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_SHORT; 8425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 84303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra 84403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra case 'z': 84503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra flags &= ~FM_SIZES; 84603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra flags |= FL_SIZET; 84703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra continue; 8485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 8495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (ksh_isdigit(c)) { 850c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser bool overflowed = false; 851c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser 8525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru tmp = c - '0'; 853c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser while (c = *fmt++, ksh_isdigit(c)) { 854c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser if (notok2mul(2147483647, tmp, 10)) 855c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser overflowed = true; 8565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru tmp = tmp * 10 + c - '0'; 857c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser } 8585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru --fmt; 859c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser if (overflowed) 8605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru tmp = 0; 8615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (flags & FL_DOT) 8625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru precision = tmp; 8635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru else 8645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru field = tmp; 8655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru continue; 8665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 8675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 8685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 8695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (precision < 0) 8715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru precision = 0; 8725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 87303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra if (!c) 87403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* nasty format */ 8755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 8765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (c >= 'A' && c <= 'Z') { 8785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_UPPER; 8795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru c = ksh_tolower(c); 8805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 8815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 8825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru switch (c) { 8835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'd': 8845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'i': 88503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra if (flags & FL_SIZET) 88603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra lnum = (long)VA(ssize_t); 88703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra else if (flags & FL_LONG) 88803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra lnum = VA(long); 88903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra else if (flags & FL_SHORT) 89003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra lnum = (long)(short)VA(int); 89103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra else 89203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra lnum = (long)VA(int); 89303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra goto integral; 89403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra 8955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'o': 8965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'u': 8975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'x': 89803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra if (flags & FL_SIZET) 89903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra lnum = VA(size_t); 90003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra else if (flags & FL_LONG) 90103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra lnum = VA(unsigned long); 90203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra else if (flags & FL_SHORT) 90303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra lnum = (unsigned long)(unsigned short)VA(int); 90403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra else 90503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra lnum = (unsigned long)VA(unsigned int); 90603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra 90703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra integral: 9085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_NUMBER; 9095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru cp = numbuf + sizeof(numbuf); 910c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef DEBUG 911c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser /* 912c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * this is necessary so Clang 3.2 realises 913c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * utf_skipcols/shf_putc in the output loop 914c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * terminate; these values are always ASCII 915c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * so an out-of-bounds access cannot happen 916c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * but Clang doesn't know that 917c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser */ 918c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser *--cp = '\0'; 919c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 92003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra 9215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru switch (c) { 9225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'd': 9235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'i': 9245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (0 > (long)lnum) { 9255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru lnum = -(long)lnum; 9265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru tmp = 1; 9275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else 9285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru tmp = 0; 9295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* FALLTHROUGH */ 9305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'u': 9315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru do { 9325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *--cp = lnum % 10 + '0'; 9335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru lnum /= 10; 9345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } while (lnum); 9355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 9365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (c != 'u') { 9375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (tmp) 9385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *--cp = '-'; 9395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru else if (flags & FL_PLUS) 9405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *--cp = '+'; 9415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru else if (flags & FL_BLANK) 9425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *--cp = ' '; 9435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 9445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 9455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 9465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'o': 9475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru do { 9485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *--cp = (lnum & 0x7) + '0'; 9495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru lnum >>= 3; 9505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } while (lnum); 9515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 9525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if ((flags & FL_HASH) && *cp != '0') 9535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *--cp = '0'; 9545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 9555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 9565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'x': { 9575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru const char *digits = (flags & FL_UPPER) ? 9585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru digits_uc : digits_lc; 9595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru do { 9605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *--cp = digits[lnum & 0xf]; 9615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru lnum >>= 4; 9625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } while (lnum); 9635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 9645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (flags & FL_HASH) { 9655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *--cp = (flags & FL_UPPER) ? 'X' : 'x'; 9665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *--cp = '0'; 9675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 9685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 9695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 9705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru len = numbuf + sizeof(numbuf) - (s = cp); 971c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef DEBUG 972c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser /* see above comment for Clang 3.2 */ 973c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser --len; 974c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 9755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (flags & FL_DOT) { 9765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (precision > len) { 9775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru field = precision; 9785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags |= FL_ZERO; 9795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else 98003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra /* no loss */ 98103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra precision = len; 9825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 9835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 9845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 9855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 's': 98603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra if ((s = VA(const char *)) == NULL) 9875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru s = "(null)"; 9885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru len = utf_mbswidth(s); 9895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 9905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 9915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case 'c': 9925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru flags &= ~FL_DOT; 993c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser c = (char)(VA(int)); 994c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser /* FALLTHROUGH */ 9955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 9965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru case '%': 9975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru default: 9985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru numbuf[0] = c; 999c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser numbuf[1] = 0; 10005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru s = numbuf; 10015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru len = 1; 10025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru break; 10035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 10045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 10055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* 10065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * At this point s should point to a string that is to be 10075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * formatted, and len should be the length of the string. 10085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */ 10095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(flags & FL_DOT) || len < precision) 10105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru precision = len; 10115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (field > precision) { 10125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru field -= precision; 10135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (!(flags & FL_RIGHT)) { 10145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru field = -field; 10155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru /* skip past sign or 0x when padding with 0 */ 10165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if ((flags & FL_ZERO) && (flags & FL_NUMBER)) { 10175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (*s == '+' || *s == '-' || 10185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *s == ' ') { 10195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf_putc(*s, shf); 10205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru s++; 10215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru precision--; 10225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru nwritten++; 10235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else if (*s == '0') { 10245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf_putc(*s, shf); 10255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru s++; 10265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru nwritten++; 10275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (--precision > 0 && 10285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru (*s | 0x20) == 'x') { 10295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf_putc(*s, shf); 10305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru s++; 10315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru precision--; 10325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru nwritten++; 10335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 10345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 10355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru c = '0'; 10365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else 10375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru c = flags & FL_ZERO ? '0' : ' '; 10385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (field < 0) { 10395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru nwritten += -field; 10405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru for ( ; field < 0 ; field++) 10415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf_putc(c, shf); 10425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 10435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else 10445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru c = ' '; 10455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } else 10465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru field = 0; 10475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 10485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (precision > 0) { 10495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru const char *q; 10505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 10515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru nwritten += precision; 10525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru q = utf_skipcols(s, precision); 10535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru do { 10545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf_putc(*s, shf); 10555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } while (++s < q); 10565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 10575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru if (field > 0) { 10585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru nwritten += field; 10595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru for ( ; field > 0 ; --field) 10605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru shf_putc(c, shf); 10615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 10625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru } 10635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 10645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru return (shf_error(shf) ? EOF : nwritten); 10655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 10665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 1067c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST) 10685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint 10695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_getc(struct shf *shf) 10705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 1071c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return (shf_getc_i(shf)); 10725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 10735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru 10745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint 10755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_putc(int c, struct shf *shf) 10765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{ 1077c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return (shf_putc_i(c, shf)); 1078c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser} 1079c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1080c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser 1081c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef DEBUG 1082c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserconst char * 1083c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasercstrerror(int errnum) 1084c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{ 1085c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#undef strerror 1086c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return (strerror(errnum)); 1087c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define strerror dontuse_strerror /* poisoned */ 1088c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser} 1089c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#elif !HAVE_STRERROR 1090c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser 1091c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if HAVE_SYS_ERRLIST 1092c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if !HAVE_SYS_ERRLIST_DECL 1093c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserextern const int sys_nerr; 1094c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserextern const char * const sys_errlist[]; 1095c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1096c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1097c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser 1098c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserconst char * 1099c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasercstrerror(int errnum) 1100c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{ 1101c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser /* "Unknown error: " + sign + rough estimate + NUL */ 1102c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser static char errbuf[15 + 1 + (8 * sizeof(int) + 2) / 3 + 1]; 1103c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser 1104c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if HAVE_SYS_ERRLIST 1105c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser if (errnum > 0 && errnum < sys_nerr && sys_errlist[errnum]) 1106c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return (sys_errlist[errnum]); 1107c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1108c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser 1109c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser switch (errnum) { 1110c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser case 0: 1111c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return ("Undefined error: 0"); 1112c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef EPERM 1113c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser case EPERM: 1114c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return ("Operation not permitted"); 1115c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1116c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ENOENT 1117c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser case ENOENT: 1118c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return ("No such file or directory"); 1119c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1120c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ESRCH 1121c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser case ESRCH: 1122c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return ("No such process"); 1123c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1124c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef E2BIG 1125c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser case E2BIG: 1126c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return ("Argument list too long"); 1127c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1128c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ENOEXEC 1129c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser case ENOEXEC: 1130c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return ("Exec format error"); 1131c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1132c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ENOMEM 1133c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser case ENOMEM: 1134c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return ("Cannot allocate memory"); 1135c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1136c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef EACCES 1137c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser case EACCES: 1138c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return ("Permission denied"); 1139c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1140c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ENOTDIR 1141c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser case ENOTDIR: 1142c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return ("Not a directory"); 1143c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1144c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef EINVAL 1145c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser case EINVAL: 1146c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return ("Invalid argument"); 1147c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1148c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ELOOP 1149c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser case ELOOP: 1150c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return ("Too many levels of symbolic links"); 1151c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif 1152c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser default: 1153c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser shf_snprintf(errbuf, sizeof(errbuf), 1154c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser "Unknown error: %d", errnum); 1155c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser return (errbuf); 1156c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser } 11575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} 11585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif 1159