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: releng/11.0/contrib/libarchive/libarchive_fe/line_reader.c 232153 2012-02-25 10:58:02Z 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; 52228753Smm char *buff, *buff_end, *line_start, *line_end, *p; 53228753Smm char *pathname; 54228753Smm size_t buff_length; 55228753Smm int nullSeparator; /* Lines separated by null, not CR/CRLF/etc. */ 56228753Smm int ret; 57228753Smm}; 58228753Smm 59228753Smmstruct lafe_line_reader * 60228753Smmlafe_line_reader(const char *pathname, int nullSeparator) 61228753Smm{ 62228753Smm struct lafe_line_reader *lr; 63228753Smm 64228753Smm lr = calloc(1, sizeof(*lr)); 65228753Smm if (lr == NULL) 66228753Smm lafe_errc(1, ENOMEM, "Can't open %s", pathname); 67228753Smm 68228753Smm lr->nullSeparator = nullSeparator; 69228753Smm lr->pathname = strdup(pathname); 70228753Smm 71228753Smm if (strcmp(pathname, "-") == 0) 72228753Smm lr->f = stdin; 73228753Smm else 74228753Smm lr->f = fopen(pathname, "r"); 75228753Smm if (lr->f == NULL) 76228753Smm lafe_errc(1, errno, "Couldn't open %s", pathname); 77228753Smm lr->buff_length = 8192; 78232153Smm lr->line_start = lr->line_end = lr->buff_end = lr->buff = NULL; 79228753Smm 80228753Smm return (lr); 81228753Smm} 82228753Smm 83232153Smmstatic void 84232153Smmlafe_line_reader_find_eol(struct lafe_line_reader *lr) 85232153Smm{ 86232153Smm 87232153Smm lr->line_end += strcspn(lr->line_end, 88232153Smm lr->nullSeparator ? "" : "\x0d\x0a"); 89232153Smm *lr->line_end = '\0'; /* Noop if line_end == buff_end */ 90232153Smm} 91232153Smm 92228753Smmconst char * 93228753Smmlafe_line_reader_next(struct lafe_line_reader *lr) 94228753Smm{ 95228753Smm size_t bytes_wanted, bytes_read, new_buff_size; 96228753Smm char *line_start, *p; 97228753Smm 98228753Smm for (;;) { 99228753Smm /* If there's a line in the buffer, return it immediately. */ 100228753Smm while (lr->line_end < lr->buff_end) { 101232153Smm line_start = lr->line_start; 102232153Smm lr->line_start = ++lr->line_end; 103232153Smm lafe_line_reader_find_eol(lr); 104232153Smm 105232153Smm if (lr->nullSeparator || line_start[0] != '\0') 106232153Smm return (line_start); 107228753Smm } 108228753Smm 109228753Smm /* If we're at end-of-file, process the final data. */ 110228753Smm if (lr->f == NULL) { 111232153Smm if (lr->line_start == lr->buff_end) 112232153Smm return (NULL); /* No more text */ 113232153Smm line_start = lr->line_start; 114232153Smm lr->line_start = lr->buff_end; 115232153Smm return (line_start); 116228753Smm } 117228753Smm 118228753Smm /* Buffer only has part of a line. */ 119228753Smm if (lr->line_start > lr->buff) { 120228753Smm /* Move a leftover fractional line to the beginning. */ 121228753Smm memmove(lr->buff, lr->line_start, 122228753Smm lr->buff_end - lr->line_start); 123228753Smm lr->buff_end -= lr->line_start - lr->buff; 124228753Smm lr->line_end -= lr->line_start - lr->buff; 125228753Smm lr->line_start = lr->buff; 126228753Smm } else { 127228753Smm /* Line is too big; enlarge the buffer. */ 128228753Smm new_buff_size = lr->buff_length * 2; 129228753Smm if (new_buff_size <= lr->buff_length) 130228753Smm lafe_errc(1, ENOMEM, 131228753Smm "Line too long in %s", lr->pathname); 132228753Smm lr->buff_length = new_buff_size; 133232153Smm /* 134232153Smm * Allocate one extra byte to allow terminating 135232153Smm * the buffer. 136232153Smm */ 137232153Smm p = realloc(lr->buff, new_buff_size + 1); 138228753Smm if (p == NULL) 139228753Smm lafe_errc(1, ENOMEM, 140228753Smm "Line too long in %s", lr->pathname); 141228753Smm lr->buff_end = p + (lr->buff_end - lr->buff); 142228753Smm lr->line_end = p + (lr->line_end - lr->buff); 143228753Smm lr->line_start = lr->buff = p; 144228753Smm } 145228753Smm 146228753Smm /* Get some more data into the buffer. */ 147228753Smm bytes_wanted = lr->buff + lr->buff_length - lr->buff_end; 148228753Smm bytes_read = fread(lr->buff_end, 1, bytes_wanted, lr->f); 149228753Smm lr->buff_end += bytes_read; 150232153Smm *lr->buff_end = '\0'; /* Always terminate buffer */ 151232153Smm lafe_line_reader_find_eol(lr); 152228753Smm 153228753Smm if (ferror(lr->f)) 154228753Smm lafe_errc(1, errno, "Can't read %s", lr->pathname); 155228753Smm if (feof(lr->f)) { 156228753Smm if (lr->f != stdin) 157228753Smm fclose(lr->f); 158228753Smm lr->f = NULL; 159228753Smm } 160228753Smm } 161228753Smm} 162228753Smm 163228753Smmvoid 164228753Smmlafe_line_reader_free(struct lafe_line_reader *lr) 165228753Smm{ 166228753Smm free(lr->buff); 167228753Smm free(lr->pathname); 168228753Smm free(lr); 169228753Smm} 170