diff options
Diffstat (limited to 'pttc/src/file.c')
-rw-r--r-- | pttc/src/file.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/pttc/src/file.c b/pttc/src/file.c new file mode 100644 index 0000000000000..7d065661bb144 --- /dev/null +++ b/pttc/src/file.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +#include "errcode.h" +#include "file.h" +#include "util.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +struct text *text_alloc(char *s, size_t n) +{ + size_t i; + char **line; + struct text *t; + + t = calloc(1, sizeof(struct text)); + if (!t) { + free(s); + return NULL; + } + + /* If s is NULL or empty, there is nothing to do. */ + if (!s || *s == '\0') { + free(s); + return t; + } + + /* beginning of s is the first line. */ + t->n = 1; + t->line = calloc(1, sizeof(*t->line)); + if (!t->line) { + free(s); + goto error; + } + + t->line[0] = s; + + /* iterate through all chars and make \r?\n to \0. */ + for (i = 0; i < n; i++) { + if (t->line[0][i] == '\r') { + if (i+1 >= n) { + /* the file ends with \r. */ + t->line[0][i] = '\0'; + break; + } + /* terminate the line string if it's a line end. */ + if (t->line[0][i+1] == '\n') { + t->line[0][i] = '\0'; + continue; + } + } + + if (t->line[0][i] == '\n') { + /* set newline character always to \0. */ + t->line[0][i] = '\0'; + if (i+1 >= n) { + /* the file ends with \n. */ + break; + } + } + + if (t->line[0][i] == '\0') { + /* increase line pointer buffer. */ + line = realloc(t->line, (t->n+1) * sizeof(*t->line)); + if (!line) + goto error; + t->line = line; + /* point to the next character after the + * newline and increment the number of lines. + */ + t->line[t->n++] = &(t->line[0][i+1]); + } + } + + return t; + +error: + text_free(t); + return NULL; +} + +void text_free(struct text *t) +{ + if (!t) + return; + + if (t->line) + free(t->line[0]); + free(t->line); + free(t); +} + +int text_line(const struct text *t, char *dest, size_t destlen, size_t n) +{ + if (bug_on(!t)) + return -err_internal; + + if (bug_on(!dest && destlen)) + return -err_internal; + + if (n >= t->n) + return -err_out_of_range; + + if (!dest) + return 0; + + if (!destlen) + return -err_internal; + + strncpy(dest, t->line[n], destlen); + + /* Make sure the string is terminated. */ + dest[destlen-1] = '\0'; + return 0; +} + +struct file_list *fl_alloc(void) +{ + return calloc(1, sizeof(struct file_list)); +} + +void fl_free(struct file_list *fl) +{ + if (!fl) + return; + + fl_free(fl->next); + text_free(fl->text); + free(fl->filename); + free(fl); +} + +/* Appends the @filename to @fl and stores a pointer to the internal + * text structure in @t. + * + * Returns 0 on success; a negative enum errcode otherwise. + * Returns -err_internal if @fl or @t is the NULL pointer. + * Returns -err_file_stat if @filename could not be found. + * Returns -err_file_open if @filename could not be opened. + * Returns -err_file_read if the content of @filename could not be fully + * read. + */ +static int fl_append(struct file_list *fl, struct text **t, + const char *filename) +{ + int errcode; + FILE *f; + char *s; + long pos; + size_t fsize; + size_t read; + + if (bug_on(!fl)) + return -err_internal; + + if (bug_on(!t)) + return -err_internal; + + if (bug_on(!filename)) + return -err_internal; + + s = NULL; + *t = NULL; + + while (fl->next) + fl = fl->next; + + fl->next = fl_alloc(); + if (!fl->next) { + errcode = -err_no_mem; + goto error; + } + + errcode = duplicate_name(&fl->next->filename, filename, FILENAME_MAX); + if (errcode < 0) + goto error; + + errno = 0; + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "open %s failed: %s\n", + filename, strerror(errno)); + errcode = -err_file_open; + goto error; + } + + errcode = fseek(f, 0, SEEK_END); + if (errcode) { + fprintf(stderr, "%s: failed to seek end: %s\n", + filename, strerror(errno)); + errcode = -err_file_size; + goto error_file; + } + + pos = ftell(f); + if (pos < 0) { + fprintf(stderr, "%s: failed to determine file size: %s\n", + filename, strerror(errno)); + errcode = -err_file_size; + goto error_file; + } + fsize = (size_t) pos; + + errcode = fseek(f, 0, SEEK_SET); + if (errcode) { + fprintf(stderr, "%s: failed to seek begin: %s\n", + filename, strerror(errno)); + errcode = -err_file_size; + goto error_file; + } + + s = calloc(fsize+1, 1); /* size + 1: space for last null byte. */ + if (!s) { + errcode = -err_no_mem; + goto error_file; + } + + read = fread(s, 1, fsize, f); + fclose(f); + if (read != fsize) { + fprintf(stderr, "read %s failed\n", filename); + free(s); + errcode = -err_file_read; + goto error; + } + + *t = text_alloc(s, fsize); + if (!*t) { + errcode = -err_no_mem; + goto error; + } + + fl->next->text = *t; + + return 0; + +error_file: + fclose(f); +error: + /* filename is closed after reading before handling error. */ + fl_free(fl->next); + fl->next = NULL; + text_free(*t); + *t = NULL; + return errcode; +} + +int fl_getline(struct file_list *fl, char *dest, size_t destlen, + const char *filename, size_t n) +{ + int errcode; + const struct text *t; + + if (bug_on(!fl)) + return -err_internal; + + errcode = fl_gettext(fl, &t, filename); + if (errcode < 0) + return errcode; + + return text_line(t, dest, destlen, n); +} + +int fl_gettext(struct file_list *fl, const struct text **t, + const char *filename) +{ + struct text *tmp; + int errcode; + + if (bug_on(!fl)) + return -err_internal; + + if (bug_on(!t)) + return -err_internal; + + if (bug_on(!filename)) + return -err_internal; + + while (fl->next) { + fl = fl->next; + if (strcmp(fl->filename, filename) == 0) { + *t = fl->text; + return 0; + } + } + errcode = fl_append(fl, &tmp, filename); + if (errcode < 0) + return errcode; + + *t = tmp; + return 0; +} |