1252884aeSStefan Eßer /* 2252884aeSStefan Eßer * ***************************************************************************** 3252884aeSStefan Eßer * 4*3aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5252884aeSStefan Eßer * 6*3aa99676SStefan Eßer * Copyright (c) 2018-2020 Gavin D. Howard and contributors. 7252884aeSStefan Eßer * 8252884aeSStefan Eßer * Redistribution and use in source and binary forms, with or without 9252884aeSStefan Eßer * modification, are permitted provided that the following conditions are met: 10252884aeSStefan Eßer * 11252884aeSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 12252884aeSStefan Eßer * list of conditions and the following disclaimer. 13252884aeSStefan Eßer * 14252884aeSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 15252884aeSStefan Eßer * this list of conditions and the following disclaimer in the documentation 16252884aeSStefan Eßer * and/or other materials provided with the distribution. 17252884aeSStefan Eßer * 18252884aeSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19252884aeSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20252884aeSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21252884aeSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22252884aeSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23252884aeSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24252884aeSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25252884aeSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26252884aeSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27252884aeSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28252884aeSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 29252884aeSStefan Eßer * 30252884aeSStefan Eßer * ***************************************************************************** 31252884aeSStefan Eßer * 32252884aeSStefan Eßer * Code to handle special I/O for bc. 33252884aeSStefan Eßer * 34252884aeSStefan Eßer */ 35252884aeSStefan Eßer 36252884aeSStefan Eßer #include <assert.h> 37252884aeSStefan Eßer #include <ctype.h> 38252884aeSStefan Eßer #include <errno.h> 39252884aeSStefan Eßer #include <stdlib.h> 40252884aeSStefan Eßer #include <string.h> 41252884aeSStefan Eßer 42252884aeSStefan Eßer #include <signal.h> 43252884aeSStefan Eßer 44252884aeSStefan Eßer #include <fcntl.h> 45252884aeSStefan Eßer #include <sys/stat.h> 46252884aeSStefan Eßer #include <unistd.h> 47252884aeSStefan Eßer 48252884aeSStefan Eßer #include <read.h> 49252884aeSStefan Eßer #include <history.h> 50252884aeSStefan Eßer #include <program.h> 51252884aeSStefan Eßer #include <vm.h> 52252884aeSStefan Eßer 53252884aeSStefan Eßer static bool bc_read_binary(const char *buf, size_t size) { 54252884aeSStefan Eßer 55252884aeSStefan Eßer size_t i; 56252884aeSStefan Eßer 57252884aeSStefan Eßer for (i = 0; i < size; ++i) { 58252884aeSStefan Eßer if (BC_ERR(BC_READ_BIN_CHAR(buf[i]))) return true; 59252884aeSStefan Eßer } 60252884aeSStefan Eßer 61252884aeSStefan Eßer return false; 62252884aeSStefan Eßer } 63252884aeSStefan Eßer 64*3aa99676SStefan Eßer bool bc_read_buf(BcVec *vec, char *buf, size_t *buf_len) { 65252884aeSStefan Eßer 66252884aeSStefan Eßer char *nl; 67252884aeSStefan Eßer 68*3aa99676SStefan Eßer if (!*buf_len) return false; 69252884aeSStefan Eßer 70*3aa99676SStefan Eßer nl = strchr(buf, '\n'); 71252884aeSStefan Eßer 72252884aeSStefan Eßer if (nl != NULL) { 73252884aeSStefan Eßer 74*3aa99676SStefan Eßer size_t nllen = (size_t) ((nl + 1) - buf); 75252884aeSStefan Eßer 76*3aa99676SStefan Eßer nllen = *buf_len >= nllen ? nllen : *buf_len; 77252884aeSStefan Eßer 78*3aa99676SStefan Eßer bc_vec_npush(vec, nllen, buf); 79*3aa99676SStefan Eßer *buf_len -= nllen; 80*3aa99676SStefan Eßer memmove(buf, nl + 1, *buf_len + 1); 81252884aeSStefan Eßer 82252884aeSStefan Eßer return true; 83252884aeSStefan Eßer } 84252884aeSStefan Eßer 85*3aa99676SStefan Eßer bc_vec_npush(vec, *buf_len, buf); 86*3aa99676SStefan Eßer *buf_len = 0; 87252884aeSStefan Eßer 88252884aeSStefan Eßer return false; 89252884aeSStefan Eßer } 90252884aeSStefan Eßer 91252884aeSStefan Eßer BcStatus bc_read_chars(BcVec *vec, const char *prompt) { 92252884aeSStefan Eßer 93252884aeSStefan Eßer bool done = false; 94252884aeSStefan Eßer 95252884aeSStefan Eßer assert(vec != NULL && vec->size == sizeof(char)); 96252884aeSStefan Eßer 97252884aeSStefan Eßer BC_SIG_ASSERT_NOT_LOCKED; 98252884aeSStefan Eßer 99252884aeSStefan Eßer bc_vec_npop(vec, vec->len); 100252884aeSStefan Eßer 101252884aeSStefan Eßer #if BC_ENABLE_PROMPT 102252884aeSStefan Eßer if (BC_USE_PROMPT) { 103252884aeSStefan Eßer bc_file_puts(&vm.fout, prompt); 104252884aeSStefan Eßer bc_file_flush(&vm.fout); 105252884aeSStefan Eßer } 106252884aeSStefan Eßer #endif // BC_ENABLE_PROMPT 107252884aeSStefan Eßer 108*3aa99676SStefan Eßer if (bc_read_buf(vec, vm.buf, &vm.buf_len)) { 109252884aeSStefan Eßer bc_vec_pushByte(vec, '\0'); 110252884aeSStefan Eßer return BC_STATUS_SUCCESS; 111252884aeSStefan Eßer } 112252884aeSStefan Eßer 113252884aeSStefan Eßer while (!done) { 114252884aeSStefan Eßer 115252884aeSStefan Eßer ssize_t r; 116252884aeSStefan Eßer 117252884aeSStefan Eßer BC_SIG_LOCK; 118252884aeSStefan Eßer 119252884aeSStefan Eßer r = read(STDIN_FILENO, vm.buf + vm.buf_len, 120252884aeSStefan Eßer BC_VM_STDIN_BUF_SIZE - vm.buf_len); 121252884aeSStefan Eßer 122252884aeSStefan Eßer if (BC_UNLIKELY(r < 0)) { 123252884aeSStefan Eßer 124252884aeSStefan Eßer if (errno == EINTR) { 125252884aeSStefan Eßer 126252884aeSStefan Eßer if (vm.status == (sig_atomic_t) BC_STATUS_QUIT) { 127252884aeSStefan Eßer BC_SIG_UNLOCK; 128252884aeSStefan Eßer return BC_STATUS_QUIT; 129252884aeSStefan Eßer } 130252884aeSStefan Eßer 131252884aeSStefan Eßer assert(vm.sig); 132252884aeSStefan Eßer 133252884aeSStefan Eßer vm.status = (sig_atomic_t) BC_STATUS_SUCCESS; 134252884aeSStefan Eßer #if BC_ENABLE_PROMPT 135252884aeSStefan Eßer if (BC_USE_PROMPT) bc_file_puts(&vm.fout, prompt); 136252884aeSStefan Eßer #endif // BC_ENABLE_PROMPT 137252884aeSStefan Eßer bc_file_flush(&vm.fout); 138252884aeSStefan Eßer 139252884aeSStefan Eßer BC_SIG_UNLOCK; 140252884aeSStefan Eßer 141252884aeSStefan Eßer continue; 142252884aeSStefan Eßer } 143252884aeSStefan Eßer 144252884aeSStefan Eßer BC_SIG_UNLOCK; 145252884aeSStefan Eßer 146252884aeSStefan Eßer bc_vm_err(BC_ERROR_FATAL_IO_ERR); 147252884aeSStefan Eßer } 148252884aeSStefan Eßer 149252884aeSStefan Eßer BC_SIG_UNLOCK; 150252884aeSStefan Eßer 151252884aeSStefan Eßer if (r == 0) { 152252884aeSStefan Eßer bc_vec_pushByte(vec, '\0'); 153252884aeSStefan Eßer return BC_STATUS_EOF; 154252884aeSStefan Eßer } 155252884aeSStefan Eßer 156252884aeSStefan Eßer vm.buf_len += (size_t) r; 157*3aa99676SStefan Eßer vm.buf[vm.buf_len] = '\0'; 158252884aeSStefan Eßer 159*3aa99676SStefan Eßer done = bc_read_buf(vec, vm.buf, &vm.buf_len); 160252884aeSStefan Eßer } 161252884aeSStefan Eßer 162252884aeSStefan Eßer bc_vec_pushByte(vec, '\0'); 163252884aeSStefan Eßer 164252884aeSStefan Eßer return BC_STATUS_SUCCESS; 165252884aeSStefan Eßer } 166252884aeSStefan Eßer 167252884aeSStefan Eßer BcStatus bc_read_line(BcVec *vec, const char *prompt) { 168252884aeSStefan Eßer 169252884aeSStefan Eßer BcStatus s; 170252884aeSStefan Eßer 171252884aeSStefan Eßer #if BC_ENABLE_HISTORY 172252884aeSStefan Eßer if (BC_TTY && !vm.history.badTerm) 173252884aeSStefan Eßer s = bc_history_line(&vm.history, vec, prompt); 174252884aeSStefan Eßer else s = bc_read_chars(vec, prompt); 175252884aeSStefan Eßer #else // BC_ENABLE_HISTORY 176252884aeSStefan Eßer s = bc_read_chars(vec, prompt); 177252884aeSStefan Eßer #endif // BC_ENABLE_HISTORY 178252884aeSStefan Eßer 179252884aeSStefan Eßer if (BC_ERR(bc_read_binary(vec->v, vec->len - 1))) 180252884aeSStefan Eßer bc_vm_verr(BC_ERROR_FATAL_BIN_FILE, bc_program_stdin_name); 181252884aeSStefan Eßer 182252884aeSStefan Eßer return s; 183252884aeSStefan Eßer } 184252884aeSStefan Eßer 185252884aeSStefan Eßer void bc_read_file(const char *path, char **buf) { 186252884aeSStefan Eßer 187252884aeSStefan Eßer BcError e = BC_ERROR_FATAL_IO_ERR; 188252884aeSStefan Eßer size_t size, r; 189252884aeSStefan Eßer struct stat pstat; 190252884aeSStefan Eßer int fd; 191252884aeSStefan Eßer 192252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 193252884aeSStefan Eßer 194252884aeSStefan Eßer assert(path != NULL); 195252884aeSStefan Eßer 196252884aeSStefan Eßer fd = open(path, O_RDONLY); 197252884aeSStefan Eßer if (BC_ERR(fd < 0)) bc_vm_verr(BC_ERROR_FATAL_FILE_ERR, path); 198252884aeSStefan Eßer if (BC_ERR(fstat(fd, &pstat) == -1)) goto malloc_err; 199252884aeSStefan Eßer 200252884aeSStefan Eßer if (BC_ERR(S_ISDIR(pstat.st_mode))) { 201252884aeSStefan Eßer e = BC_ERROR_FATAL_PATH_DIR; 202252884aeSStefan Eßer goto malloc_err; 203252884aeSStefan Eßer } 204252884aeSStefan Eßer 205252884aeSStefan Eßer size = (size_t) pstat.st_size; 206252884aeSStefan Eßer *buf = bc_vm_malloc(size + 1); 207252884aeSStefan Eßer 208252884aeSStefan Eßer r = (size_t) read(fd, *buf, size); 209252884aeSStefan Eßer if (BC_ERR(r != size)) goto read_err; 210252884aeSStefan Eßer 211252884aeSStefan Eßer (*buf)[size] = '\0'; 212252884aeSStefan Eßer 213252884aeSStefan Eßer if (BC_ERR(bc_read_binary(*buf, size))) { 214252884aeSStefan Eßer e = BC_ERROR_FATAL_BIN_FILE; 215252884aeSStefan Eßer goto read_err; 216252884aeSStefan Eßer } 217252884aeSStefan Eßer 218252884aeSStefan Eßer close(fd); 219252884aeSStefan Eßer 220252884aeSStefan Eßer return; 221252884aeSStefan Eßer 222252884aeSStefan Eßer read_err: 223252884aeSStefan Eßer free(*buf); 224252884aeSStefan Eßer malloc_err: 225252884aeSStefan Eßer close(fd); 226252884aeSStefan Eßer bc_vm_verr(e, path); 227252884aeSStefan Eßer } 228