1228753Smm/*- 2228753Smm * Copyright (c) 2008 Tim Kientzle 3232153Smm * Copyright (c) 2010 Joerg Sonnenberger 4228753Smm * All rights reserved. 5228753Smm * 6228753Smm * Redistribution and use in source and binary forms, with or without 7228753Smm * modification, are permitted provided that the following conditions 8228753Smm * are met: 9228753Smm * 1. Redistributions of source code must retain the above copyright 10228753Smm * notice, this list of conditions and the following disclaimer 11228753Smm * in this position and unchanged. 12228753Smm * 2. Redistributions in binary form must reproduce the above copyright 13228753Smm * notice, this list of conditions and the following disclaimer in the 14228753Smm * documentation and/or other materials provided with the distribution. 15228753Smm * 16228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26228753Smm */ 27228753Smm 28228753Smm#include "lafe_platform.h" 29228753Smm__FBSDID("$FreeBSD: stable/11/contrib/libarchive/libarchive_fe/line_reader.c 349524 2019-06-28 22:33:44Z mm $"); 30228753Smm 31228753Smm#include <errno.h> 32228753Smm#include <stdio.h> 33228753Smm#include <stdlib.h> 34228753Smm#include <string.h> 35228753Smm 36228753Smm#include "err.h" 37228753Smm#include "line_reader.h" 38228753Smm 39228753Smm#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) 40228753Smm#define strdup _strdup 41228753Smm#endif 42228753Smm 43228753Smm/* 44228753Smm * Read lines from file and do something with each one. If option_null 45228753Smm * is set, lines are terminated with zero bytes; otherwise, they're 46228753Smm * terminated with newlines. 47228753Smm * 48228753Smm * This uses a self-sizing buffer to handle arbitrarily-long lines. 49228753Smm */ 50228753Smmstruct lafe_line_reader { 51228753Smm FILE *f; 52349524Smm char *buff, *buff_end, *line_start, *line_end; 53228753Smm char *pathname; 54228753Smm size_t buff_length; 55228753Smm int nullSeparator; /* Lines separated by null, not CR/CRLF/etc. */ 56228753Smm}; 57228753Smm 58228753Smmstruct lafe_line_reader * 59228753Smmlafe_line_reader(const char *pathname, int nullSeparator) 60228753Smm{ 61228753Smm struct lafe_line_reader *lr; 62228753Smm 63228753Smm lr = calloc(1, sizeof(*lr)); 64228753Smm if (lr == NULL) 65228753Smm lafe_errc(1, ENOMEM, "Can't open %s", pathname); 66228753Smm 67228753Smm lr->nullSeparator = nullSeparator; 68228753Smm lr->pathname = strdup(pathname); 69228753Smm 70228753Smm if (strcmp(pathname, "-") == 0) 71228753Smm lr->f = stdin; 72228753Smm else 73228753Smm lr->f = fopen(pathname, "r"); 74228753Smm if (lr->f == NULL) 75228753Smm lafe_errc(1, errno, "Couldn't open %s", pathname); 76228753Smm lr->buff_length = 8192; 77232153Smm lr->line_start = lr->line_end = lr->buff_end = lr->buff = NULL; 78228753Smm 79228753Smm return (lr); 80228753Smm} 81228753Smm 82232153Smmstatic void 83232153Smmlafe_line_reader_find_eol(struct lafe_line_reader *lr) 84232153Smm{ 85232153Smm 86232153Smm lr->line_end += strcspn(lr->line_end, 87232153Smm lr->nullSeparator ? "" : "\x0d\x0a"); 88232153Smm *lr->line_end = '\0'; /* Noop if line_end == buff_end */ 89232153Smm} 90232153Smm 91228753Smmconst char * 92228753Smmlafe_line_reader_next(struct lafe_line_reader *lr) 93228753Smm{ 94228753Smm size_t bytes_wanted, bytes_read, new_buff_size; 95228753Smm char *line_start, *p; 96228753Smm 97228753Smm for (;;) { 98228753Smm /* If there's a line in the buffer, return it immediately. */ 99228753Smm while (lr->line_end < lr->buff_end) { 100232153Smm line_start = lr->line_start; 101232153Smm lr->line_start = ++lr->line_end; 102232153Smm lafe_line_reader_find_eol(lr); 103232153Smm 104232153Smm if (lr->nullSeparator || line_start[0] != '\0') 105232153Smm return (line_start); 106228753Smm } 107228753Smm 108228753Smm /* If we're at end-of-file, process the final data. */ 109228753Smm if (lr->f == NULL) { 110232153Smm if (lr->line_start == lr->buff_end) 111232153Smm return (NULL); /* No more text */ 112232153Smm line_start = lr->line_start; 113232153Smm lr->line_start = lr->buff_end; 114232153Smm return (line_start); 115228753Smm } 116228753Smm 117228753Smm /* Buffer only has part of a line. */ 118228753Smm if (lr->line_start > lr->buff) { 119228753Smm /* Move a leftover fractional line to the beginning. */ 120228753Smm memmove(lr->buff, lr->line_start, 121228753Smm lr->buff_end - lr->line_start); 122228753Smm lr->buff_end -= lr->line_start - lr->buff; 123228753Smm lr->line_end -= lr->line_start - lr->buff; 124228753Smm lr->line_start = lr->buff; 125228753Smm } else { 126228753Smm /* Line is too big; enlarge the buffer. */ 127228753Smm new_buff_size = lr->buff_length * 2; 128228753Smm if (new_buff_size <= lr->buff_length) 129228753Smm lafe_errc(1, ENOMEM, 130228753Smm "Line too long in %s", lr->pathname); 131228753Smm lr->buff_length = new_buff_size; 132232153Smm /* 133232153Smm * Allocate one extra byte to allow terminating 134232153Smm * the buffer. 135232153Smm */ 136232153Smm p = realloc(lr->buff, new_buff_size + 1); 137228753Smm if (p == NULL) 138228753Smm lafe_errc(1, ENOMEM, 139228753Smm "Line too long in %s", lr->pathname); 140228753Smm lr->buff_end = p + (lr->buff_end - lr->buff); 141228753Smm lr->line_end = p + (lr->line_end - lr->buff); 142228753Smm lr->line_start = lr->buff = p; 143228753Smm } 144228753Smm 145228753Smm /* Get some more data into the buffer. */ 146228753Smm bytes_wanted = lr->buff + lr->buff_length - lr->buff_end; 147228753Smm bytes_read = fread(lr->buff_end, 1, bytes_wanted, lr->f); 148228753Smm lr->buff_end += bytes_read; 149232153Smm *lr->buff_end = '\0'; /* Always terminate buffer */ 150232153Smm lafe_line_reader_find_eol(lr); 151228753Smm 152228753Smm if (ferror(lr->f)) 153228753Smm lafe_errc(1, errno, "Can't read %s", lr->pathname); 154228753Smm if (feof(lr->f)) { 155228753Smm if (lr->f != stdin) 156228753Smm fclose(lr->f); 157228753Smm lr->f = NULL; 158228753Smm } 159228753Smm } 160228753Smm} 161228753Smm 162228753Smmvoid 163228753Smmlafe_line_reader_free(struct lafe_line_reader *lr) 164228753Smm{ 165228753Smm free(lr->buff); 166228753Smm free(lr->pathname); 167228753Smm free(lr); 168228753Smm} 169