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 #ifndef INPUT_FILE_H
#define INPUT_FILE_H #define INPUT_FILE_H
#include <stdio.h> #include <stddef.h>
typedef struct {
FILE *f;
char *line;
const char *filename;
size_t linenum;
} input_file_t;
typedef struct { typedef struct {
const char *name; 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; } keyword_handler_t;
int process_file(const char *filename, const keyword_handler_t *handlers, int process_file(const char *filename, const keyword_handler_t *handlers,
size_t count, void *obj); 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 */ #endif /* INPUT_FILE_H */

View File

@ -1,122 +1,58 @@
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include "util/input_file.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; fprintf(stderr, "%s: %zu: %s\n", filename, linenum, msg);
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;
} }
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, int process_file(const char *filename, const keyword_handler_t *handlers,
size_t count, void *obj) size_t count, void *obj)
{ {
input_file_t f; struct userdata u = { handlers, count, obj };
size_t i, len;
char *ptr;
int ret;
memset(&f, 0, sizeof(f)); return foreach_line_in_file(filename, &u, handle_line);
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;
} }

View File

@ -1,65 +1,37 @@
#include "buildstrategy.h" #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) static int foreach_line(const char *filename, line_handler_t cb)
{ {
FILE *f = fopen(filename, "r"); struct userdata u = { cb };
for (;;) { return foreach_line_in_file(filename, &u, handle_line);
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;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -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_provides;
static hash_table_t tbl_sourcepkgs; 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; source_pkg_t *src, *dep;
size_t count; size_t count;
@ -79,8 +52,9 @@ static int handle_depends(const char *sourcepkg, const char *binpkg)
dep = hash_table_lookup(&tbl_provides, binpkg); dep = hash_table_lookup(&tbl_provides, binpkg);
if (dep == NULL) { if (dep == NULL) {
fprintf(stderr, "nothing provides '%s' required by '%s'\n", fprintf(stderr,
binpkg, sourcepkg); "%s: %zu: nothing provides '%s' required by '%s'\n",
filename, linenum, binpkg, sourcepkg);
return -1; return -1;
} }
@ -100,14 +74,16 @@ static int handle_depends(const char *sourcepkg, const char *binpkg)
return 0; 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; source_pkg_t *src = NULL;
src = hash_table_lookup(&tbl_provides, binpkg); src = hash_table_lookup(&tbl_provides, binpkg);
if (src != NULL) { if (src != NULL) {
fprintf(stderr, "%s: package already provided by %s\n", fprintf(stderr,
binpkg, src->name); "%s: %zu: %s: package already provided by %s\n",
filename, linenum, binpkg, src->name);
return -1; return -1;
} }

View File

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

View File

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

View File

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

View File

@ -38,11 +38,14 @@ typedef struct {
char *name; char *name;
} pkg_desc_t; } 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); int filelist_read(const char *filename, image_entry_t **out);