summaryrefslogtreecommitdiff
path: root/pttc/src/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'pttc/src/file.c')
-rw-r--r--pttc/src/file.c320
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;
+}