diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:29:19 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:29:19 +0300 |
| commit | 85f60af1bb558bc7248fb64528c5bba92e504adf (patch) | |
| tree | ddb4ab72a5ca33b668b34ecdb09fe284c5644677 /corebinutils/sh/output.c | |
| parent | 96be0a182e0b889a9daf43c04a0b835aa604d280 (diff) | |
| parent | 126b33a9db9b44a56f2c62d18346746ec1330766 (diff) | |
| download | Project-Tick-85f60af1bb558bc7248fb64528c5bba92e504adf.tar.gz Project-Tick-85f60af1bb558bc7248fb64528c5bba92e504adf.zip | |
Add 'corebinutils/sh/' from commit '126b33a9db9b44a56f2c62d18346746ec1330766'
git-subtree-dir: corebinutils/sh
git-subtree-mainline: 96be0a182e0b889a9daf43c04a0b835aa604d280
git-subtree-split: 126b33a9db9b44a56f2c62d18346746ec1330766
Diffstat (limited to 'corebinutils/sh/output.c')
| -rw-r--r-- | corebinutils/sh/output.c | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/corebinutils/sh/output.c b/corebinutils/sh/output.c new file mode 100644 index 0000000000..846af9835a --- /dev/null +++ b/corebinutils/sh/output.c @@ -0,0 +1,380 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2026 Project Tick. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kenneth Almquist. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Shell output routines. We use our own output routines because: + * When a builtin command is interrupted we have to discard + * any pending output. + * When a builtin command appears in back quotes, we want to + * save the output of the command in a region obtained + * via malloc, rather than doing a fork and reading the + * output of the command via a pipe. + */ + +#include <stdio.h> /* defines BUFSIZ */ +#include <string.h> +#include <stdarg.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <wchar.h> +#include <wctype.h> + +#include "shell.h" +#include "syntax.h" +#include "output.h" +#include "memalloc.h" +#include "error.h" +#include "var.h" + + +#define OUTBUFSIZ BUFSIZ +#define MEM_OUT -2 /* output to dynamically allocated memory */ +#define OUTPUT_ERR 01 /* error occurred on output */ + +static FILE *open_output_cookie(struct output *); +static ssize_t doformat_wr(void *, const char *, size_t); + +struct output output = {NULL, NULL, NULL, OUTBUFSIZ, 1, 0}; +struct output errout = {NULL, NULL, NULL, 256, 2, 0}; +struct output memout = {NULL, NULL, NULL, 64, MEM_OUT, 0}; +struct output *out1 = &output; +struct output *out2 = &errout; + +void +outcslow(int c, struct output *file) +{ + outc(c, file); +} + +void +out1str(const char *p) +{ + outstr(p, out1); +} + +void +out1qstr(const char *p) +{ + outqstr(p, out1); +} + +void +out2str(const char *p) +{ + outstr(p, out2); +} + +void +out2qstr(const char *p) +{ + outqstr(p, out2); +} + +void +outstr(const char *p, struct output *file) +{ + outbin(p, strlen(p), file); +} + +static void +byteseq(int ch, struct output *file) +{ + char seq[4]; + + seq[0] = '\\'; + seq[1] = (ch >> 6 & 0x3) + '0'; + seq[2] = (ch >> 3 & 0x7) + '0'; + seq[3] = (ch & 0x7) + '0'; + outbin(seq, 4, file); +} + +static void +outdqstr(const char *p, struct output *file) +{ + const char *end; + mbstate_t mbs; + size_t clen; + wchar_t wc; + + memset(&mbs, '\0', sizeof(mbs)); + end = p + strlen(p); + outstr("$'", file); + while ((clen = mbrtowc(&wc, p, end - p + 1, &mbs)) != 0) { + if (clen == (size_t)-2) { + while (p < end) + byteseq(*p++, file); + break; + } + if (clen == (size_t)-1) { + memset(&mbs, '\0', sizeof(mbs)); + byteseq(*p++, file); + continue; + } + if (wc == L'\n') + outcslow('\n', file), p++; + else if (wc == L'\r') + outstr("\\r", file), p++; + else if (wc == L'\t') + outstr("\\t", file), p++; + else if (!iswprint(wc)) { + for (; clen > 0; clen--) + byteseq(*p++, file); + } else { + if (wc == L'\'' || wc == L'\\') + outcslow('\\', file); + outbin(p, clen, file); + p += clen; + } + } + outcslow('\'', file); +} + +/* Like outstr(), but quote for re-input into the shell. */ +void +outqstr(const char *p, struct output *file) +{ + int i; + + if (p[0] == '\0') { + outstr("''", file); + return; + } + for (i = 0; p[i] != '\0'; i++) { + if ((p[i] > '\0' && p[i] < ' ' && p[i] != '\n') || + (p[i] & 0x80) != 0 || p[i] == '\'') { + outdqstr(p, file); + return; + } + } + + if (p[strcspn(p, "|&;<>()$`\\\" \n*?[~#=")] == '\0' || + strcmp(p, "[") == 0) { + outstr(p, file); + return; + } + + outcslow('\'', file); + outstr(p, file); + outcslow('\'', file); +} + +void +outbin(const void *data, size_t len, struct output *file) +{ + const char *p; + + p = data; + while (len-- > 0) + outc(*p++, file); +} + +void +emptyoutbuf(struct output *dest) +{ + int offset, newsize; + + if (dest->buf == NULL) { + INTOFF; + dest->buf = ckmalloc(dest->bufsize); + dest->nextc = dest->buf; + dest->bufend = dest->buf + dest->bufsize; + INTON; + } else if (dest->fd == MEM_OUT) { + offset = dest->nextc - dest->buf; + newsize = dest->bufsize << 1; + INTOFF; + dest->buf = ckrealloc(dest->buf, newsize); + dest->bufsize = newsize; + dest->bufend = dest->buf + newsize; + dest->nextc = dest->buf + offset; + INTON; + } else { + flushout(dest); + } +} + + +void +flushall(void) +{ + flushout(&output); + flushout(&errout); +} + + +void +flushout(struct output *dest) +{ + + if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) + return; + if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) + dest->flags |= OUTPUT_ERR; + dest->nextc = dest->buf; +} + + +void +freestdout(void) +{ + output.nextc = output.buf; +} + + +int +outiserror(struct output *file) +{ + return (file->flags & OUTPUT_ERR); +} + + +void +outclearerror(struct output *file) +{ + file->flags &= ~OUTPUT_ERR; +} + + +void +outfmt(struct output *file, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + doformat(file, fmt, ap); + va_end(ap); +} + + +void +out1fmt(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + doformat(out1, fmt, ap); + va_end(ap); +} + +void +out2fmt_flush(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + doformat(out2, fmt, ap); + va_end(ap); + flushout(out2); +} + +void +fmtstr(char *outbuf, int length, const char *fmt, ...) +{ + va_list ap; + + INTOFF; + va_start(ap, fmt); + vsnprintf(outbuf, length, fmt, ap); + va_end(ap); + INTON; +} + +static ssize_t +doformat_wr(void *cookie, const char *buf, size_t len) +{ + struct output *o; + + o = (struct output *)cookie; + outbin(buf, len, o); + + return (len); +} + +static FILE * +open_output_cookie(struct output *dest) +{ + cookie_io_functions_t io; + + memset(&io, 0, sizeof(io)); + io.write = doformat_wr; + return (fopencookie(dest, "w", io)); +} + +void +doformat(struct output *dest, const char *f, va_list ap) +{ + FILE *fp; + + if ((fp = open_output_cookie(dest)) != NULL) { + vfprintf(fp, f, ap); + fclose(fp); + } +} + +FILE * +out1fp(void) +{ + return (open_output_cookie(out1)); +} + +/* + * Version of write which resumes after a signal is caught. + */ + +int +xwrite(int fd, const char *buf, int nbytes) +{ + int ntry; + int i; + int n; + + n = nbytes; + ntry = 0; + for (;;) { + i = write(fd, buf, n); + if (i > 0) { + if ((n -= i) <= 0) + return nbytes; + buf += i; + ntry = 0; + } else if (i == 0) { + if (++ntry > 10) + return nbytes - n; + } else if (errno != EINTR) { + return -1; + } + } +} |
