X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Ftextfile.c;h=42c995396381fd20a40623a31d434582ce4782df;hb=e0c9e124bb3603ce4677efc137850d17f51b53fc;hp=8c6efbe3386e2afddb162b67e796b4f341ed4df1;hpb=3071e89c11d1be71cf45b694432e5908e0c4ded9;p=wimlib diff --git a/src/textfile.c b/src/textfile.c index 8c6efbe3..42c99539 100644 --- a/src/textfile.c +++ b/src/textfile.c @@ -16,20 +16,13 @@ * details. * * You should have received a copy of the GNU Lesser General Public License - * along with this file; if not, see http://www.gnu.org/licenses/. + * along with this file; if not, see https://www.gnu.org/licenses/. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include "wimlib/assert.h" -#include "wimlib/encoding.h" -#include "wimlib/error.h" -#include "wimlib/file_io.h" -#include "wimlib/textfile.h" -#include "wimlib/util.h" - #include #include #include @@ -37,6 +30,44 @@ #include #include +#include "wimlib/encoding.h" +#include "wimlib/error.h" +#include "wimlib/file_io.h" +#include "wimlib/textfile.h" +#include "wimlib/util.h" + +static int +stdin_get_contents(void **buf_ret, size_t *bufsize_ret) +{ + char *buf = NULL; + size_t filled = 0; + size_t capacity = 0; + + do { + size_t new_capacity = (capacity * 2) + 256; + char *new_buf; + + if (new_capacity <= capacity || + !(new_buf = REALLOC(buf, new_capacity))) { + ERROR("Too much data sent on stdin!"); + FREE(buf); + return WIMLIB_ERR_INVALID_PARAM; + } + buf = new_buf; + capacity = new_capacity; + filled += fread(&buf[filled], 1, capacity - filled, stdin); + } while (filled == capacity); + + if (!feof(stdin)) { + ERROR_WITH_ERRNO("Error reading stdin"); + FREE(buf); + return WIMLIB_ERR_READ; + } + *buf_ret = buf; + *bufsize_ret = filled; + return 0; +} + static int read_file_contents(const tchar *path, void **buf_ret, size_t *bufsize_ret) { @@ -47,9 +78,6 @@ read_file_contents(const tchar *path, void **buf_ret, size_t *bufsize_ret) int ret; int errno_save; - if (!path || !*path) - return WIMLIB_ERR_INVALID_PARAM; - raw_fd = topen(path, O_RDONLY | O_BINARY); if (raw_fd < 0) { ERROR_WITH_ERRNO("Can't open \"%"TS"\"", path); @@ -142,23 +170,23 @@ translate_text_buffer(const u8 *buf_raw, size_t bufsize_raw, } static int -string_set_append(struct string_set *set, tchar *str) +string_list_append(struct string_list *list, tchar *str) { - size_t num_alloc_strings = set->num_alloc_strings; + size_t num_alloc_strings = list->num_alloc_strings; - if (set->num_strings == num_alloc_strings) { + if (list->num_strings == num_alloc_strings) { tchar **new_strings; num_alloc_strings = max(num_alloc_strings * 3 / 2, num_alloc_strings + 4); - new_strings = REALLOC(set->strings, - sizeof(set->strings[0]) * num_alloc_strings); + new_strings = REALLOC(list->strings, + sizeof(list->strings[0]) * num_alloc_strings); if (!new_strings) return WIMLIB_ERR_NOMEM; - set->strings = new_strings; - set->num_alloc_strings = num_alloc_strings; + list->strings = new_strings; + list->num_alloc_strings = num_alloc_strings; } - set->strings[set->num_strings++] = str; + list->strings[list->num_strings++] = str; return 0; } @@ -265,8 +293,8 @@ parse_text_file(const tchar *path, tchar *buf, size_t buflen, return ret; } - ret = string_set_append(pos_sections[current_section].strings, - line_begin); + ret = string_list_append(pos_sections[current_section].strings, + line_begin); if (ret) return ret; } @@ -274,13 +302,14 @@ parse_text_file(const tchar *path, tchar *buf, size_t buflen, } /** - * do_load_text_file - + * load_text_file - * - * Read and parse lines from a text file from an on-disk file or a buffer. - * The file may contain sections, like in an INI file. + * Read and parse lines from a text file given as an on-disk file, standard + * input, or a buffer. The file may contain sections, like in an INI file. * * @path - * Path to the file on disk to read, or a dummy name for the buffer. + * If @buf is NULL, then either the path to the file on-disk to read, or + * NULL to read from standard input. Else, a dummy name for the buffer. * @buf * If NULL, the data will be read from the @path file. Otherwise the data * will be read from this buffer. @@ -294,12 +323,11 @@ parse_text_file(const tchar *path, tchar *buf, size_t buflen, * consists of the name of the section (e.g. [ExclusionList], like in the * INI file format), along with a pointer to the list of lines parsed for * that section. Use an empty name to indicate the destination of lines - * not in any section. Each list must be initialized to an empty string - * set. + * not in any section. Each list must be initialized to empty. * @num_pos_sections * Number of entries in the @pos_sections array. * @flags - * Flags: LOAD_TEXT_FILE_REMOVE_QUOTES, LOAD_TEXT_FILE_NO_WARNINGS. + * Flags: LOAD_TEXT_FILE_* flags. * @mangle_line * Optional callback to validate and/or modify each line being read. * @@ -309,34 +337,40 @@ parse_text_file(const tchar *path, tchar *buf, size_t buflen, * LOAD_TEXT_FILE_NO_WARNINGS is specified. */ int -do_load_text_file(const tchar *path, - const void *buf, size_t bufsize, - void **mem_ret, - const struct text_file_section *pos_sections, - int num_pos_sections, - int flags, - line_mangle_t mangle_line) +load_text_file(const tchar *path, const void *buf, size_t bufsize, + void **mem_ret, + const struct text_file_section *pos_sections, + int num_pos_sections, + int flags, line_mangle_t mangle_line) { int ret; - bool pathmode = (buf == NULL); + bool is_filemode = (buf == NULL); + bool is_stdin = (is_filemode && path == NULL); tchar *tstr; size_t tstr_nchars; - if (pathmode) { - ret = read_file_contents(path, (void **)&buf, &bufsize); + if (is_stdin && !(flags & LOAD_TEXT_FILE_ALLOW_STDIN)) + return WIMLIB_ERR_INVALID_PARAM; + + if (is_filemode) { + if (is_stdin) + ret = stdin_get_contents((void **)&buf, &bufsize); + else + ret = read_file_contents(path, (void **)&buf, &bufsize); if (ret) return ret; } ret = translate_text_buffer(buf, bufsize, &tstr, &tstr_nchars); - if (pathmode) + if (is_filemode) FREE((void *)buf); if (ret) return ret; tstr[tstr_nchars++] = T('\n'); - ret = parse_text_file(path, tstr, tstr_nchars, pos_sections, + ret = parse_text_file(is_stdin ? T("") : path, + tstr, tstr_nchars, pos_sections, num_pos_sections, flags, mangle_line); if (ret) { for (int i = 0; i < num_pos_sections; i++)