cleanup: reimplement process_file using foreach_line_in_file

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
This commit is contained in:
David Oberhollenzer 2019-03-08 17:10:47 +01:00
parent b688a39149
commit 4a682b83f1
7 changed files with 159 additions and 229 deletions

View File

@ -1,23 +1,18 @@
#ifndef INPUT_FILE_H
#define INPUT_FILE_H
#include <stdio.h>
typedef struct {
FILE *f;
char *line;
const char *filename;
size_t linenum;
} input_file_t;
#include <stddef.h>
typedef struct {
const char *name;
int (*handle)(input_file_t *f, void *obj);
int (*handle)(char *line, const char *filename,
size_t linenum, void *obj);
} keyword_handler_t;
int process_file(const char *filename, const keyword_handler_t *handlers,
size_t count, void *obj);
void input_file_complain(const input_file_t *f, const char *msg);
void input_file_complain(const char *filename, size_t linenum,
const char *msg);
#endif /* INPUT_FILE_H */

View File

@ -1,122 +1,58 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include "util/input_file.h"
#include "util/util.h"
static int prefetch_line(input_file_t *f)
void input_file_complain(const char *filename, size_t linenum, const char *msg)
{
char *line, *ptr;
ssize_t ret;
size_t n;
retry:
free(f->line);
f->line = NULL;
errno = 0;
line = NULL;
n = 0;
ret = getline(&line, &n, f->f);
if (ret < 0) {
if (errno != 0) {
perror(f->filename);
free(line);
return -1;
}
free(line);
return 1;
}
n = strlen(line);
while (n >0 && isspace(line[n - 1]))
--n;
line[n] = '\0';
f->line = line;
f->linenum += 1;
for (ptr = f->line; isspace(*ptr); ++ptr)
;
if (*ptr == '\0' || *ptr == '#')
goto retry;
if (ptr != f->line)
memmove(f->line, ptr, strlen(ptr) + 1);
ptr = f->line + strlen(f->line);
while (ptr > f->line && isspace(ptr[-1]))
--ptr;
*ptr = '\0';
if (f->line[0] == '\0')
goto retry;
return 0;
fprintf(stderr, "%s: %zu: %s\n", filename, linenum, msg);
}
void input_file_complain(const input_file_t *f, const char *msg)
struct userdata {
const keyword_handler_t *handlers;
size_t count;
void *obj;
};
static int handle_line(void *usr, const char *filename,
size_t linenum, char *line)
{
fprintf(stderr, "%s: %zu: %s\n", f->filename, f->linenum, msg);
struct userdata *u = usr;
size_t i, len;
while (isspace(*line))
++line;
if (*line == '\0' || *line == '#')
return 0;
for (i = 0; i < u->count; ++i) {
len = strlen(u->handlers[i].name);
if (strncmp(line, u->handlers[i].name, len) != 0)
continue;
if (!isspace(line[len]) && line[len] != '\0')
continue;
for (line += len; isspace(*line); ++line)
;
break;
}
if (i == u->count) {
fprintf(stderr, "%s: %zu: unknown keyword\n",
filename, linenum);
return -1;
}
return u->handlers[i].handle(line, filename, linenum, u->obj);
}
int process_file(const char *filename, const keyword_handler_t *handlers,
size_t count, void *obj)
{
input_file_t f;
size_t i, len;
char *ptr;
int ret;
struct userdata u = { handlers, count, obj };
memset(&f, 0, sizeof(f));
f.filename = filename;
f.f = fopen(filename, "r");
if (f.f == NULL) {
perror(f.filename);
return -1;
}
for (;;) {
ret = prefetch_line(&f);
if (ret < 0)
goto fail;
if (ret > 0)
break;
ptr = f.line;
for (i = 0; i < count; ++i) {
len = strlen(handlers[i].name);
if (strncmp(ptr, handlers[i].name, len) != 0)
continue;
if (!isspace(ptr[len]) && ptr[len] != '\0')
continue;
for (ptr += len; isspace(*ptr); ++ptr)
;
memmove(f.line, ptr, strlen(ptr) + 1);
break;
}
if (i == count) {
fprintf(stderr, "%s: %zu: unknown keyword\n",
f.filename, f.linenum);
goto fail;
}
if (handlers[i].handle(&f, obj))
goto fail;
}
fclose(f.f);
free(f.line);
return 0;
fail:
fclose(f.f);
free(f.line);
return -1;
return foreach_line_in_file(filename, &u, handle_line);
}

View File

@ -1,65 +1,37 @@
#include "buildstrategy.h"
typedef int (*line_handler_t)(const char *lhs, const char *rhs);
typedef int (*line_handler_t)(const char *filename, size_t linenum,
const char *lhs, const char *rhs);
struct userdata {
line_handler_t cb;
};
static int handle_line(void *usr, const char *filename,
size_t linenum, char *line)
{
struct userdata *u = usr;
char *rhs;
rhs = strchr(line, ',');
if (rhs == NULL)
return 0;
*(rhs++) = '\0';
while (isspace(*rhs))
++rhs;
if (*line == '\0' || *rhs == '\0')
return 0;
return u->cb(filename, linenum, line, rhs);
}
static int foreach_line(const char *filename, line_handler_t cb)
{
FILE *f = fopen(filename, "r");
struct userdata u = { cb };
for (;;) {
char *line = NULL, *rhs, *lhs, *ptr;
size_t n = 0;
ssize_t ret;
errno = 0;
ret = getline(&line, &n, f);
if (ret < 0) {
if (errno == 0) {
free(line);
break;
}
perror(filename);
free(line);
fclose(f);
return -1;
}
rhs = strchr(line, ',');
if (rhs == NULL) {
free(line);
continue;
}
*(rhs++) = '\0';
while (isspace(*rhs))
++rhs;
ptr = rhs;
while (*ptr != '\0' && !isspace(*ptr))
++ptr;
*ptr = '\0';
lhs = line;
while (isspace(*lhs))
++lhs;
if (*lhs == '\0' || *rhs == '\0') {
free(line);
continue;
}
if (cb(lhs, rhs)) {
free(line);
fclose(f);
return -1;
}
free(line);
}
fclose(f);
return 0;
return foreach_line_in_file(filename, &u, handle_line);
}
/*****************************************************************************/
@ -67,7 +39,8 @@ static int foreach_line(const char *filename, line_handler_t cb)
static hash_table_t tbl_provides;
static hash_table_t tbl_sourcepkgs;
static int handle_depends(const char *sourcepkg, const char *binpkg)
static int handle_depends(const char *filename, size_t linenum,
const char *sourcepkg, const char *binpkg)
{
source_pkg_t *src, *dep;
size_t count;
@ -79,8 +52,9 @@ static int handle_depends(const char *sourcepkg, const char *binpkg)
dep = hash_table_lookup(&tbl_provides, binpkg);
if (dep == NULL) {
fprintf(stderr, "nothing provides '%s' required by '%s'\n",
binpkg, sourcepkg);
fprintf(stderr,
"%s: %zu: nothing provides '%s' required by '%s'\n",
filename, linenum, binpkg, sourcepkg);
return -1;
}
@ -100,14 +74,16 @@ static int handle_depends(const char *sourcepkg, const char *binpkg)
return 0;
}
static int handle_provides(const char *sourcepkg, const char *binpkg)
static int handle_provides(const char *filename, size_t linenum,
const char *sourcepkg, const char *binpkg)
{
source_pkg_t *src = NULL;
src = hash_table_lookup(&tbl_provides, binpkg);
if (src != NULL) {
fprintf(stderr, "%s: package already provided by %s\n",
binpkg, src->name);
fprintf(stderr,
"%s: %zu: %s: package already provided by %s\n",
filename, linenum, binpkg, src->name);
return -1;
}

View File

@ -9,6 +9,7 @@
#include <errno.h>
#include "command.h"
#include "util/util.h"
#include "util/hashtable.h"
enum {

View File

@ -1,8 +1,9 @@
#include "pack.h"
static int handle_requires(input_file_t *f, void *obj)
static int handle_requires(char *line, const char *filename,
size_t linenum, void *obj)
{
char *ptr = f->line, *end;
char *ptr = line, *end;
pkg_desc_t *desc = obj;
dependency_t *dep;
size_t len;
@ -19,13 +20,14 @@ static int handle_requires(input_file_t *f, void *obj)
break;
if (len > 0xFF) {
input_file_complain(f, "dependency name too long");
input_file_complain(filename, linenum, "dependency name too long");
return -1;
}
dep = calloc(1, sizeof(*dep) + len + 1);
if (dep == NULL) {
input_file_complain(f, "out of memory");
input_file_complain(filename, linenum,
"out of memory");
return -1;
}
@ -40,28 +42,30 @@ static int handle_requires(input_file_t *f, void *obj)
return 0;
}
static int handle_toc_compressor(input_file_t *f, void *obj)
static int handle_toc_compressor(char *line, const char *filename,
size_t linenum, void *obj)
{
pkg_desc_t *desc = obj;
desc->toccmp = compressor_by_name(f->line);
desc->toccmp = compressor_by_name(line);
if (desc->toccmp == NULL) {
input_file_complain(f, "unkown compressor");
input_file_complain(filename, linenum, "unkown compressor");
return -1;
}
return 0;
}
static int handle_data_compressor(input_file_t *f, void *obj)
static int handle_data_compressor(char *line, const char *filename,
size_t linenum, void *obj)
{
pkg_desc_t *desc = obj;
desc->datacmp = compressor_by_name(f->line);
desc->datacmp = compressor_by_name(line);
if (desc->datacmp == NULL) {
input_file_complain(f, "unkown compressor");
input_file_complain(filename, linenum, "unkown compressor");
return -1;
}

View File

@ -7,20 +7,20 @@ static char *skipspace(char *str)
return str;
}
static void oom(input_file_t *f)
static void oom(const char *filename, size_t linenum)
{
input_file_complain(f, "out of memory");
input_file_complain(filename, linenum, "out of memory");
}
static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
static image_entry_t *filelist_mkentry(char *line, const char *filename,
size_t linenum, mode_t filetype)
{
char *line = f->line;
image_entry_t *ent;
size_t i;
ent = calloc(1, sizeof(*ent));
if (ent == NULL) {
oom(f);
oom(filename, linenum);
return NULL;
}
@ -29,29 +29,31 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
;
if (!isspace(line[i])) {
input_file_complain(f, "expected space after file name");
input_file_complain(filename, linenum,
"expected space after file name");
goto fail;
}
ent->name = calloc(1, i + 1);
if (ent->name == NULL) {
oom(f);
oom(filename, linenum);
goto fail;
}
memcpy(ent->name, line, i);
if (canonicalize_name(ent->name)) {
input_file_complain(f, "invalid file name");
input_file_complain(filename, linenum, "invalid file name");
goto fail;
}
if (ent->name[0] == '\0') {
input_file_complain(f, "refusing to add entry for '/'");
input_file_complain(filename, linenum,
"refusing to add entry for '/'");
goto fail;
}
if (strlen(ent->name) > 0xFFFF) {
input_file_complain(f, "name too long");
input_file_complain(filename, linenum, "name too long");
goto fail;
}
@ -59,20 +61,23 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
/* mode */
if (!isdigit(*line)) {
input_file_complain(f, "expected numeric mode after file name");
input_file_complain(filename, linenum,
"expected numeric mode after file name");
goto fail;
}
while (isdigit(*line)) {
if (*line > '7') {
input_file_complain(f, "mode must be octal number");
input_file_complain(filename, linenum,
"mode must be octal number");
goto fail;
}
ent->mode = (ent->mode << 3) | (*(line++) - '0');
}
if (!isspace(*line)) {
input_file_complain(f, "expected space after file mode");
input_file_complain(filename, linenum,
"expected space after file mode");
goto fail;
}
@ -82,7 +87,8 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
/* uid */
if (!isdigit(*line)) {
input_file_complain(f, "expected numeric UID after mode");
input_file_complain(filename, linenum,
"expected numeric UID after mode");
goto fail;
}
@ -90,7 +96,8 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
ent->uid = (ent->uid * 10) + (*(line++) - '0');
if (!isspace(*line)) {
input_file_complain(f, "expected space after UID");
input_file_complain(filename, linenum,
"expected space after UID");
goto fail;
}
@ -98,7 +105,8 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
/* gid */
if (!isdigit(*line)) {
input_file_complain(f, "expected numeric GID after UID");
input_file_complain(filename, linenum,
"expected numeric GID after UID");
goto fail;
}
@ -108,7 +116,7 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
line = skipspace(line);
/* remove processed data */
memmove(f->line, line, strlen(line) + 1);
memmove(line, line, strlen(line) + 1);
return ent;
fail:
free(ent->name);
@ -116,9 +124,10 @@ fail:
return NULL;
}
int filelist_mkdir(input_file_t *f, void *obj)
int filelist_mkdir(char *line, const char *filename,
size_t linenum, void *obj)
{
image_entry_t *ent = filelist_mkentry(f, S_IFDIR);
image_entry_t *ent = filelist_mkentry(line,filename,linenum,S_IFDIR);
image_entry_t **listptr = obj;
if (ent == NULL)
@ -129,22 +138,24 @@ int filelist_mkdir(input_file_t *f, void *obj)
return 0;
}
int filelist_mkslink(input_file_t *f, void *obj)
int filelist_mkslink(char *line, const char *filename,
size_t linenum, void *obj)
{
image_entry_t *ent = filelist_mkentry(f, S_IFLNK);
image_entry_t *ent = filelist_mkentry(line,filename,linenum,S_IFLNK);
image_entry_t **listptr = obj;
if (ent == NULL)
return -1;
ent->data.symlink.target = strdup(f->line);
ent->data.symlink.target = strdup(line);
if (ent->data.symlink.target == NULL) {
oom(f);
oom(filename, linenum);
goto fail;
}
if (strlen(ent->data.symlink.target) > 0xFFFF) {
input_file_complain(f, "symlink target too long");
input_file_complain(filename, linenum,
"symlink target too long");
goto fail;
}
@ -156,9 +167,10 @@ fail:
return -1;
}
int filelist_mkfile(input_file_t *f, void *obj)
int filelist_mkfile(char *line, const char *filename,
size_t linenum, void *obj)
{
image_entry_t *ent = filelist_mkentry(f, S_IFREG);
image_entry_t *ent = filelist_mkentry(line,filename,linenum,S_IFREG);
image_entry_t **listptr = obj;
const char *ptr;
struct stat sb;
@ -166,22 +178,22 @@ int filelist_mkfile(input_file_t *f, void *obj)
if (ent == NULL)
return -1;
if (f->line[0] == '\0') {
ptr = strrchr(f->filename, '/');
if (line[0] == '\0') {
ptr = strrchr(filename, '/');
if (ptr == NULL) {
ent->data.file.location = strdup(ent->name);
} else {
asprintf(&ent->data.file.location, "%.*s/%s",
(int)(ptr - f->filename), f->filename,
(int)(ptr - filename), filename,
ent->name);
}
} else {
ent->data.file.location = strdup(f->line);
ent->data.file.location = strdup(line);
}
if (ent->data.file.location == NULL) {
oom(f);
oom(filename, linenum);
goto fail;
}
@ -192,7 +204,8 @@ int filelist_mkfile(input_file_t *f, void *obj)
if (sizeof(off_t) > sizeof(uint64_t) &&
sb.st_size > (off_t)(~((uint64_t)0))) {
input_file_complain(f, "input file is too big");
input_file_complain(filename, linenum,
"input file is too big");
goto fail;
}
@ -206,17 +219,18 @@ fail:
return -1;
}
static int filelist_mknod(input_file_t *f, void *obj)
static int filelist_mknod(char *line, const char *filename,
size_t linenum, void *obj)
{
image_entry_t **listptr = obj, *ent;
unsigned int maj, min;
char *ptr;
ent = filelist_mkentry(f, S_IFCHR);
ent = filelist_mkentry(line, filename, linenum, S_IFCHR);
if (ent == NULL)
return -1;
switch (f->line[0]) {
switch (line[0]) {
case 'c':
case 'C':
break;
@ -228,10 +242,10 @@ static int filelist_mknod(input_file_t *f, void *obj)
goto fail;
}
if (!isspace(f->line[1]))
if (!isspace(line[1]))
goto fail;
ptr = f->line + 1;
ptr = line + 1;
while (isspace(*ptr))
++ptr;
@ -245,7 +259,8 @@ static int filelist_mknod(input_file_t *f, void *obj)
return 0;
fail:
image_entry_free(ent);
input_file_complain(f, "error in device specification");
input_file_complain(filename, linenum,
"error in device specification");
return -1;
}

View File

@ -38,11 +38,14 @@ typedef struct {
char *name;
} pkg_desc_t;
int filelist_mkdir(input_file_t *f, void *obj);
int filelist_mkdir(char *line, const char *filename,
size_t linenum, void *obj);
int filelist_mkslink(input_file_t *f, void *obj);
int filelist_mkslink(char *line, const char *filename,
size_t linenum, void *obj);
int filelist_mkfile(input_file_t *f, void *obj);
int filelist_mkfile(char *line, const char *filename,
size_t linenum, void *obj);
int filelist_read(const char *filename, image_entry_t **out);