|
Packit |
b1f7ae |
/*
|
|
Packit |
b1f7ae |
* Copyright (c) 2013-2017, Intel Corporation
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
b1f7ae |
* modification, are permitted provided that the following conditions are met:
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* * Redistributions of source code must retain the above copyright notice,
|
|
Packit |
b1f7ae |
* this list of conditions and the following disclaimer.
|
|
Packit |
b1f7ae |
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
Packit |
b1f7ae |
* this list of conditions and the following disclaimer in the documentation
|
|
Packit |
b1f7ae |
* and/or other materials provided with the distribution.
|
|
Packit |
b1f7ae |
* * Neither the name of Intel Corporation nor the names of its contributors
|
|
Packit |
b1f7ae |
* may be used to endorse or promote products derived from this software
|
|
Packit |
b1f7ae |
* without specific prior written permission.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
b1f7ae |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
b1f7ae |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
b1f7ae |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
Packit |
b1f7ae |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
Packit |
b1f7ae |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
Packit |
b1f7ae |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
Packit |
b1f7ae |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
Packit |
b1f7ae |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit |
b1f7ae |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
Packit |
b1f7ae |
* POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include "errcode.h"
|
|
Packit |
b1f7ae |
#include "file.h"
|
|
Packit |
b1f7ae |
#include "util.h"
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include <stdio.h>
|
|
Packit |
b1f7ae |
#include <stdlib.h>
|
|
Packit |
b1f7ae |
#include <string.h>
|
|
Packit |
b1f7ae |
#include <errno.h>
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
struct text *text_alloc(const char *s)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
size_t n, i;
|
|
Packit |
b1f7ae |
char **line;
|
|
Packit |
b1f7ae |
struct text *t;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
t = calloc(1, sizeof(struct text));
|
|
Packit |
b1f7ae |
if (!t)
|
|
Packit |
b1f7ae |
return NULL;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* If s is NULL or empty, there is nothing to do. */
|
|
Packit |
b1f7ae |
if (!s || *s == '\0')
|
|
Packit |
b1f7ae |
return t;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* beginning of s is the first line. */
|
|
Packit |
b1f7ae |
t->n = 1;
|
|
Packit |
b1f7ae |
t->line = calloc(1, sizeof(*t->line));
|
|
Packit |
b1f7ae |
if (!t->line)
|
|
Packit |
b1f7ae |
goto error;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
t->line[0] = duplicate_str(s);
|
|
Packit |
b1f7ae |
if (!t->line[0])
|
|
Packit |
b1f7ae |
goto error;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* iterate through all chars and make \r?\n to \0. */
|
|
Packit |
b1f7ae |
n = strlen(t->line[0]);
|
|
Packit |
b1f7ae |
for (i = 0; i < n; i++) {
|
|
Packit |
b1f7ae |
if (t->line[0][i] == '\r') {
|
|
Packit |
b1f7ae |
if (i+1 >= n) {
|
|
Packit |
b1f7ae |
/* the file ends with \r. */
|
|
Packit |
b1f7ae |
t->line[0][i] = '\0';
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
/* terminate the line string if it's a line end. */
|
|
Packit |
b1f7ae |
if (t->line[0][i+1] == '\n')
|
|
Packit |
b1f7ae |
t->line[0][i] = '\0';
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
} else if (t->line[0][i] == '\n') {
|
|
Packit |
b1f7ae |
/* set newline character always to \0. */
|
|
Packit |
b1f7ae |
t->line[0][i] = '\0';
|
|
Packit |
b1f7ae |
if (i+1 >= n) {
|
|
Packit |
b1f7ae |
/* the file ends with \n. */
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
/* increase line pointer buffer. */
|
|
Packit |
b1f7ae |
line = realloc(t->line, (t->n+1) * sizeof(*t->line));
|
|
Packit |
b1f7ae |
if (!line)
|
|
Packit |
b1f7ae |
goto error;
|
|
Packit |
b1f7ae |
t->line = line;
|
|
Packit |
b1f7ae |
/* point to the next character after the
|
|
Packit |
b1f7ae |
* newline and increment the number of lines.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
t->line[t->n++] = &(t->line[0][i+1]);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return t;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
error:
|
|
Packit |
b1f7ae |
text_free(t);
|
|
Packit |
b1f7ae |
return NULL;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
void text_free(struct text *t)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!t)
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (t->line)
|
|
Packit |
b1f7ae |
free(t->line[0]);
|
|
Packit |
b1f7ae |
free(t->line);
|
|
Packit |
b1f7ae |
free(t);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int text_line(const struct text *t, char *dest, size_t destlen, size_t n)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (bug_on(!t))
|
|
Packit |
b1f7ae |
return -err_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (bug_on(!dest && destlen))
|
|
Packit |
b1f7ae |
return -err_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (n >= t->n)
|
|
Packit |
b1f7ae |
return -err_out_of_range;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!dest)
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!destlen)
|
|
Packit |
b1f7ae |
return -err_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
strncpy(dest, t->line[n], destlen);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Make sure the string is terminated. */
|
|
Packit |
b1f7ae |
dest[destlen-1] = '\0';
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
struct file_list *fl_alloc(void)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
return calloc(1, sizeof(struct file_list));
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
void fl_free(struct file_list *fl)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!fl)
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fl_free(fl->next);
|
|
Packit |
b1f7ae |
text_free(fl->text);
|
|
Packit |
b1f7ae |
free(fl->filename);
|
|
Packit |
b1f7ae |
free(fl);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Appends the @filename to @fl and stores a pointer to the internal
|
|
Packit |
b1f7ae |
* text structure in @t.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Returns 0 on success; a negative enum errcode otherwise.
|
|
Packit |
b1f7ae |
* Returns -err_internal if @fl or @t is the NULL pointer.
|
|
Packit |
b1f7ae |
* Returns -err_file_stat if @filename could not be found.
|
|
Packit |
b1f7ae |
* Returns -err_file_open if @filename could not be opened.
|
|
Packit |
b1f7ae |
* Returns -err_file_read if the content of @filename could not be fully
|
|
Packit |
b1f7ae |
* read.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
int fl_append(struct file_list *fl, struct text **t, const char *filename)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
FILE *f;
|
|
Packit |
b1f7ae |
char *s;
|
|
Packit |
b1f7ae |
long pos;
|
|
Packit |
b1f7ae |
size_t fsize;
|
|
Packit |
b1f7ae |
size_t read;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (bug_on(!fl))
|
|
Packit |
b1f7ae |
return -err_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (bug_on(!t))
|
|
Packit |
b1f7ae |
return -err_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (bug_on(!filename))
|
|
Packit |
b1f7ae |
return -err_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
s = NULL;
|
|
Packit |
b1f7ae |
*t = NULL;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
while (fl->next)
|
|
Packit |
b1f7ae |
fl = fl->next;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fl->next = fl_alloc();
|
|
Packit |
b1f7ae |
if (!fl->next) {
|
|
Packit |
b1f7ae |
errcode = -err_no_mem;
|
|
Packit |
b1f7ae |
goto error;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fl->next->filename = duplicate_str(filename);
|
|
Packit |
b1f7ae |
if (!fl->next->filename) {
|
|
Packit |
b1f7ae |
errcode = -err_no_mem;
|
|
Packit |
b1f7ae |
goto error;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errno = 0;
|
|
Packit |
b1f7ae |
f = fopen(filename, "rb");
|
|
Packit |
b1f7ae |
if (!f) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "open %s failed: %s\n",
|
|
Packit |
b1f7ae |
filename, strerror(errno));
|
|
Packit |
b1f7ae |
errcode = -err_file_open;
|
|
Packit |
b1f7ae |
goto error;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = fseek(f, 0, SEEK_END);
|
|
Packit |
b1f7ae |
if (errcode) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to seek end: %s\n",
|
|
Packit |
b1f7ae |
filename, strerror(errno));
|
|
Packit |
b1f7ae |
errcode = -err_file_size;
|
|
Packit |
b1f7ae |
goto error_file;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
pos = ftell(f);
|
|
Packit |
b1f7ae |
if (pos < 0) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to determine file size: %s\n",
|
|
Packit |
b1f7ae |
filename, strerror(errno));
|
|
Packit |
b1f7ae |
errcode = -err_file_size;
|
|
Packit |
b1f7ae |
goto error_file;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
fsize = (size_t) pos;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = fseek(f, 0, SEEK_SET);
|
|
Packit |
b1f7ae |
if (errcode) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to seek begin: %s\n",
|
|
Packit |
b1f7ae |
filename, strerror(errno));
|
|
Packit |
b1f7ae |
errcode = -err_file_size;
|
|
Packit |
b1f7ae |
goto error_file;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
s = calloc(fsize+1, 1); /* size + 1: space for last null byte. */
|
|
Packit |
b1f7ae |
if (!s) {
|
|
Packit |
b1f7ae |
errcode = -err_no_mem;
|
|
Packit |
b1f7ae |
goto error_file;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
read = fread(s, 1, fsize, f);
|
|
Packit |
b1f7ae |
fclose(f);
|
|
Packit |
b1f7ae |
if (read != fsize) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "read %s failed\n", filename);
|
|
Packit |
b1f7ae |
errcode = -err_file_read;
|
|
Packit |
b1f7ae |
goto error;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*t = text_alloc(s);
|
|
Packit |
b1f7ae |
if (!*t) {
|
|
Packit |
b1f7ae |
errcode = -err_no_mem;
|
|
Packit |
b1f7ae |
goto error;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
free(s);
|
|
Packit |
b1f7ae |
fl->next->text = *t;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
error_file:
|
|
Packit |
b1f7ae |
fclose(f);
|
|
Packit |
b1f7ae |
error:
|
|
Packit |
b1f7ae |
/* filename is closed after reading before handling error. */
|
|
Packit |
b1f7ae |
fl_free(fl->next);
|
|
Packit |
b1f7ae |
fl->next = NULL;
|
|
Packit |
b1f7ae |
free(s);
|
|
Packit |
b1f7ae |
text_free(*t);
|
|
Packit |
b1f7ae |
*t = NULL;
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int fl_getline(struct file_list *fl, char *dest, size_t destlen,
|
|
Packit |
b1f7ae |
const char *filename, size_t n)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
const struct text *t;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (bug_on(!fl))
|
|
Packit |
b1f7ae |
return -err_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = fl_gettext(fl, &t, filename);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return text_line(t, dest, destlen, n);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int fl_gettext(struct file_list *fl, const struct text **t,
|
|
Packit |
b1f7ae |
const char *filename)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct text *tmp;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (bug_on(!fl))
|
|
Packit |
b1f7ae |
return -err_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (bug_on(!t))
|
|
Packit |
b1f7ae |
return -err_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (bug_on(!filename))
|
|
Packit |
b1f7ae |
return -err_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
while (fl->next) {
|
|
Packit |
b1f7ae |
fl = fl->next;
|
|
Packit |
b1f7ae |
if (strcmp(fl->filename, filename) == 0) {
|
|
Packit |
b1f7ae |
*t = fl->text;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
errcode = fl_append(fl, &tmp, filename);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*t = tmp;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|