Skip to content

Commit

Permalink
Tidied up b6b_file and increased test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
dimkr committed Jan 22, 2018
1 parent e76e644 commit 5d0e853
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 94 deletions.
149 changes: 56 additions & 93 deletions src/b6b_file.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of b6b.
*
* Copyright 2017 Dima Krasner
* Copyright 2017, 2018 Dima Krasner
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,7 +24,12 @@

#include <b6b.h>

#define B6B_FILE_DEF_FMODE "r"
struct b6b_file_mode {
const char *mode;
const char *fmode;
const struct b6b_strm_ops *ops;
int bmode;
};

static const struct b6b_strm_ops b6b_ro_file_ops = {
.peeksz = b6b_stdio_peeksz,
Expand All @@ -47,6 +52,34 @@ static const struct b6b_strm_ops b6b_rw_file_ops = {
.close = b6b_stdio_close
};

static const struct b6b_file_mode b6b_file_modes[] = {
{"r", "r", &b6b_ro_file_ops, _IOLBF},
{"w", "w", &b6b_wo_file_ops, _IOLBF},
{"a", "a", &b6b_wo_file_ops, _IOLBF},

{"rb", "r", &b6b_ro_file_ops, _IOFBF},
{"wb", "w", &b6b_wo_file_ops, _IOFBF},
{"ab", "a", &b6b_wo_file_ops, _IOFBF},

{"ru", "r", &b6b_ro_file_ops, _IONBF},
{"wu", "w", &b6b_wo_file_ops, _IONBF},
{"au", "a", &b6b_wo_file_ops, _IONBF},

{"r+", "r+", &b6b_wo_file_ops, _IOLBF},
{"w+", "w+", &b6b_wo_file_ops, _IOLBF},
{"a+", "a+", &b6b_wo_file_ops, _IOLBF},

{"r+b", "r+", &b6b_wo_file_ops, _IOFBF},
{"w+b", "w+", &b6b_wo_file_ops, _IOFBF},
{"a+b", "a+", &b6b_wo_file_ops, _IOFBF},

{"r+u", "r+", &b6b_wo_file_ops, _IONBF},
{"w+u", "w+", &b6b_wo_file_ops, _IONBF},
{"a+u", "a+", &b6b_wo_file_ops, _IONBF}
};

#define b6b_file_def_mode b6b_file_modes[0]

static struct b6b_obj *b6b_file_new(struct b6b_interp *interp,
FILE *fp,
const int fd,
Expand All @@ -71,111 +104,39 @@ static struct b6b_obj *b6b_file_new(struct b6b_interp *interp,
return NULL;
}

if (bmode == _IOFBF) {
if (bmode == _IONBF)
setbuf(fp, NULL);
else {
s->buf = malloc(B6B_STRM_BUFSIZ);
if (!b6b_allocated(s->buf)) {
b6b_destroy(o);
return NULL;
}

if (setvbuf(fp, s->buf, _IOFBF, B6B_STRM_BUFSIZ) != 0) {
if (setvbuf(fp, s->buf, bmode, B6B_STRM_BUFSIZ) != 0) {
b6b_destroy(o);
return NULL;
}
} else if (bmode == _IONBF)
setbuf(fp, NULL);
}

return o;
}

static const char *b6b_file_mode(const char *mode,
int *bmode,
const struct b6b_strm_ops **ops)
static const struct b6b_file_mode *b6b_file_mode(const char *mode)
{
if (strcmp("r", mode) == 0) {
*bmode = _IOLBF;
*ops = &b6b_ro_file_ops;
return mode;
}
else if ((strcmp("w", mode) == 0) || (strcmp("a", mode) == 0)) {
*bmode = _IOLBF;
*ops = &b6b_wo_file_ops;
return mode;
}
else if (strcmp("rb", mode) == 0) {
*bmode = _IOFBF;
*ops = &b6b_ro_file_ops;
return "r";
}
else if (strcmp("wb", mode) == 0) {
*bmode = _IOFBF;
*ops = &b6b_wo_file_ops;
return "w";
}
else if (strcmp("ab", mode) == 0) {
*bmode = _IOFBF;
*ops = &b6b_wo_file_ops;
return "a";
}
else if (strcmp("ru", mode) == 0) {
*bmode = _IONBF;
*ops = &b6b_ro_file_ops;
return "r";
}
else if (strcmp("wu", mode) == 0) {
*bmode = _IONBF;
*ops = &b6b_wo_file_ops;
return "w";
}
else if (strcmp("au", mode) == 0) {
*bmode = _IONBF;
*ops = &b6b_wo_file_ops;
return "a";
}
else if ((strcmp("r+", mode) == 0) ||
(strcmp("w+", mode) == 0) ||
(strcmp("a+", mode) == 0)) {
*bmode = _IOLBF;
*ops = &b6b_rw_file_ops;
return mode;
}
else if (strcmp("r+b", mode) == 0) {
*bmode = _IOFBF;
*ops = &b6b_rw_file_ops;
return "r+";
}
else if (strcmp("w+b", mode) == 0) {
*bmode = _IOFBF;
*ops = &b6b_rw_file_ops;
return "w+";
}
else if (strcmp("a+b", mode) == 0) {
*bmode = _IOFBF;
*ops = &b6b_rw_file_ops;
return "a+";
}
else if (strcmp("r+u", mode) == 0) {
*bmode = _IONBF;
*ops = &b6b_rw_file_ops;
return "r+";
}
else if (strcmp("w+u", mode) == 0) {
*bmode = _IONBF;
*ops = &b6b_rw_file_ops;
return "w+";
}
else if (strcmp("a+u", mode) == 0) {
*bmode = _IONBF;
*ops = &b6b_rw_file_ops;
return "a+";
unsigned int i;

for (i = 0; i < sizeof(b6b_file_modes) / sizeof(b6b_file_modes[0]); ++i) {
if (strcmp(b6b_file_modes[i].mode, mode) == 0)
return &b6b_file_modes[i];
}

return NULL;
}

struct b6b_file_fopen_data {
char *path;
const char *mode;
const char *fmode;
FILE *fp;
int rerrno;
};
Expand All @@ -184,7 +145,7 @@ static void b6b_file_do_fopen(void *arg)
{
struct b6b_file_fopen_data *data = (struct b6b_file_fopen_data *)arg;

data->fp = fopen(data->path, data->mode);
data->fp = fopen(data->path, data->fmode);
if (!data->fp)
data->rerrno = errno;
}
Expand All @@ -195,21 +156,23 @@ static enum b6b_res b6b_file_proc_open(struct b6b_interp *interp,
{
struct b6b_file_fopen_data data = {
.fp = NULL,
.mode = B6B_FILE_DEF_FMODE
.fmode = b6b_file_def_mode.fmode
};
const struct b6b_file_mode *fmode = &b6b_file_def_mode;
struct b6b_obj *path, *mode, *f;
int err, fd, bmode = _IONBF;
const struct b6b_strm_ops *ops = &b6b_ro_file_ops;
int err, fd;

switch (b6b_proc_get_args(interp, args, "os|s", NULL, &path, &mode)) {
case 3:
if (!b6b_as_str(mode))
return B6B_ERR;

data.mode = b6b_file_mode(mode->s, &bmode, &ops);
if (!data.mode)
fmode = b6b_file_mode(mode->s);
if (!fmode)
return b6b_return_strerror(interp, EINVAL);

data.fmode = fmode->fmode;

case 2:
/* path->s may be freed during context switch, while b6b_offload()
* blocks */
Expand All @@ -236,7 +199,7 @@ static enum b6b_res b6b_file_proc_open(struct b6b_interp *interp,
return b6b_return_strerror(interp, err);
}

f = b6b_file_new(interp, data.fp, fd, bmode, ops);
f = b6b_file_new(interp, data.fp, fd, fmode->bmode, fmode->ops);
if (!f) {
b6b_offload(interp, b6b_stdio_do_fclose, data.fp);
return B6B_ERR;
Expand Down
4 changes: 3 additions & 1 deletion src/b6b_stdio.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of b6b.
*
* Copyright 2017 Dima Krasner
* Copyright 2017, 2018 Dima Krasner
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -126,6 +126,7 @@ ssize_t b6b_stdio_read(struct b6b_interp *interp,

if (data.ret < len) {
if (ferror(s->fp)) {
clearerr(s->fp);
b6b_return_strerror(interp, data.rerrno);
return -1;
}
Expand Down Expand Up @@ -181,6 +182,7 @@ ssize_t b6b_stdio_write(struct b6b_interp *interp,

if (data.ret == 0) {
if (ferror(s->fp)) {
clearerr(s->fp);
free(copy);
b6b_return_strerror(interp, data.rerrno);
return -1;
Expand Down
55 changes: 55 additions & 0 deletions tests/b6b_test_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ static void teardown(const char *buf, const ssize_t len)
int main()
{
struct b6b_interp interp;
struct stat stbuf;
size_t i;

assert(b6b_interp_new_argv(&interp, 0, NULL, B6B_OPT_TRACE));
Expand Down Expand Up @@ -210,5 +211,59 @@ int main()
b6b_interp_destroy(&interp);
#endif

/* written data to line-buffered files should be flushed upon \n */
setup("", 0);
assert(b6b_interp_new_argv(&interp, 0, NULL, B6B_OPT_TRACE));
assert(b6b_call_copy(&interp,
"{$global f [$open /tmp/.file w]}",
32) == B6B_OK);
assert(b6b_call_copy(&interp, "{$f write abc}", 14) == B6B_OK);
assert(b6b_as_float(interp.fg->_));
assert(interp.fg->_->f == 3);
assert(stat("/tmp/.file", &stbuf) == 0);
assert(stbuf.st_size == 0);
assert(b6b_call_copy(&interp, "{$f write {d\ne}}", 16) == B6B_OK);
assert(b6b_as_float(interp.fg->_));
assert(interp.fg->_->f == 3);
teardown("abcd\n", 5);
b6b_interp_destroy(&interp);

/* data written to block-buffered files should be flushed after each chunk
* of B6B_STRM_BUFSIZ bytes */
setup("", 0);
assert(b6b_interp_new_argv(&interp, 0, NULL, B6B_OPT_TRACE));
assert(b6b_call_copy(&interp,
"{$global f [$open /tmp/.file wb]}",
33) == B6B_OK);
for (i = 0; i < B6B_STRM_BUFSIZ; i += 4096) {
assert(b6b_call_copy(&interp,
"{$f write [[$open /dev/zero ru] read 4096]}",
43) == B6B_OK);
assert(b6b_as_float(interp.fg->_));
assert(interp.fg->_->f == 4096);
assert(stat("/tmp/.file", &stbuf) == 0);
assert(stbuf.st_size == 0);
}
assert(b6b_call_copy(&interp,
"{$f write a}",
12) == B6B_OK);
assert(b6b_as_float(interp.fg->_));
assert(interp.fg->_->f == 1);
assert(stat("/tmp/.file", &stbuf) == 0);
assert(stbuf.st_size == B6B_STRM_BUFSIZ);
b6b_interp_destroy(&interp);

/* written data to unbuffered files should be written immediately */
setup("", 0);
assert(b6b_interp_new_argv(&interp, 0, NULL, B6B_OPT_TRACE));
assert(b6b_call_copy(&interp,
"{$global f [$open /tmp/.file wu]}",
33) == B6B_OK);
assert(b6b_call_copy(&interp, "{$f write abc}", 14) == B6B_OK);
assert(b6b_as_float(interp.fg->_));
assert(interp.fg->_->f == 3);
teardown("abc", 3);
b6b_interp_destroy(&interp);

return EXIT_SUCCESS;
}

0 comments on commit 5d0e853

Please sign in to comment.