diff options
Diffstat (limited to 'old-extension/fileop.c')
-rw-r--r-- | old-extension/fileop.c | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/old-extension/fileop.c b/old-extension/fileop.c new file mode 100644 index 00000000..86f62576 --- /dev/null +++ b/old-extension/fileop.c @@ -0,0 +1,394 @@ +/* + * fileop.c -- Builtin functions for binary I/O and other interfaces to + * the filesystem. + */ + +/* + * Copyright (C) 2012 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Programming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "awk.h" + +int plugin_is_GPL_compatible; + +typedef struct file_struct { + struct file_struct *next; + FILE *fp; + int flags; + char path[1]; +} file_t; + +static file_t *files; +static file_t *file_open(const char *builtin_name, int nargs, int do_open); +static int mode2flags(const char *mode); + +/* do_fread --- read from file */ + +static NODE * +do_fread(int nargs) +{ + NODE *arg; + size_t rlen, count; + file_t *f; + char *rbuf; + + f = file_open("fread", nargs, true); + + arg = get_scalar_argument(2, false); + force_number(arg); + rlen = get_number_ui(arg); + + emalloc(rbuf, char *, rlen + 2, "do_fread"); + if ((count = fread(rbuf, 1, rlen, f->fp)) < rlen) { + if (! feof(f->fp)) + update_ERRNO_int(errno); + } + return make_str_node(rbuf, count, ALREADY_MALLOCED); +} + +/* do_fwrite --- write to file */ + +static NODE * +do_fwrite(int nargs) +{ + NODE *arg; + file_t *f; + size_t count = 0; + + f = file_open("fwrite", nargs, true); + + arg = get_scalar_argument(2, false); + force_string(arg); + if (arg->stlen > 0) { + count = fwrite(arg->stptr, 1, arg->stlen, f->fp); + if (count < arg->stlen) + update_ERRNO_int(errno); + } + return make_number(count); +} + +/* do_fseek --- set the file position indicator */ + +static NODE * +do_fseek(int nargs) +{ + NODE *arg; + long offset; + file_t *f; + int whence = 0, ret = 0; + + f = file_open("fseek", nargs, true); + + arg = get_scalar_argument(2, false); + force_number(arg); + offset = get_number_si(arg); + + arg = get_scalar_argument(3, false); + force_string(arg); + if (strcasecmp(arg->stptr, "SEEK_SET") == 0) + whence = SEEK_SET; + else if (strcasecmp(arg->stptr, "SEEK_CUR") == 0) + whence = SEEK_CUR; + else if (strcasecmp(arg->stptr, "SEEK_END") == 0) + whence = SEEK_END; + else + fatal(_("fseek: `%.*s' is not a valid 4th argument"), + (int) arg->stlen, arg->stptr); + + if (fseek(f->fp, offset, whence) < 0) { + update_ERRNO_int(errno); + ret = -1; + } + return make_number(ret); +} + +/* do_ftruncate --- truncate the file to a specified length */ + +static NODE * +do_ftruncate(int nargs) +{ + NODE *arg; + file_t *f; + off_t len; + int ret = 0; + + f = file_open("ftruncate", nargs, true); + arg = get_scalar_argument(2, false); + force_number(arg); + len = (off_t) get_number_si(arg); + if (ftruncate(fileno(f->fp), len) < 0) { + update_ERRNO_int(errno); + ret = -1; + } + return make_number(ret); +} + +/* do_unlink --- delete the name from the filesystem */ + +static NODE * +do_unlink(int nargs) +{ + NODE *file; + int ret = 0; + + file = get_scalar_argument(0, false); + force_string(file); + if (file->stlen == 0) + fatal(_("unlink: filename has empty string value")); + if (unlink(file->stptr) < 0) { + update_ERRNO_int(errno); + ret = -1; + } + return make_number(ret); +} + +/* do_flush --- flush buffered data to file */ + +static NODE * +do_flush(int nargs) +{ + file_t *f; + int status = -1; + + f = file_open("flush", nargs, false); + if (f != NULL) { + status = fflush(f->fp); + if (status != 0) + update_ERRNO_int(errno); + } + return make_number(status); +} + +/* do_fclose --- close an open file */ + +static NODE * +do_fclose(int nargs) +{ + file_t *f; + int status = -1; + + f = file_open("fclose", nargs, false); + if (f != NULL) { + status = fclose(f->fp); + if (status != 0) + update_ERRNO_int(errno); + assert(files == f); + files = f->next; + efree(f); + } + return make_number(status); +} + +/* do_filesize --- return the size of the file */ + +static NODE * +do_filesize(int nargs) +{ + NODE *file; + struct stat sbuf; + AWKNUM d = -1.0; + + file = get_scalar_argument(0, false); + force_string(file); + if (file->stlen == 0) + fatal(_("filesize: filename has empty string value")); + + if (stat(file->stptr, & sbuf) < 0) { + update_ERRNO_int(errno); + goto ferror; + } + if ((sbuf.st_mode & S_IFMT) != S_IFREG) { + errno = EINVAL; + update_ERRNO_int(errno); + goto ferror; + } + d = sbuf.st_size; + +ferror: + return make_number(d); +} + +/* do_file_exists --- check if path exists in the filesystem */ + +static NODE * +do_file_exists(int nargs) +{ + NODE *file; + struct stat sbuf; + int ret = 1; + + file = get_scalar_argument(0, false); + force_string(file); + if (file->stlen == 0) + fatal(_("file_exists: filename has empty string value")); + + if (stat(file->stptr, & sbuf) < 0) { + if (errno != ENOENT) + update_ERRNO_int(errno); + ret = 0; + } + return make_number(ret); +} + + +/* file_open --- open a file or find an already opened file */ + +static file_t * +file_open(const char *builtin_name, int nargs, int do_open) +{ + NODE *file, *mode; + file_t *f, *prev; + FILE *fp; + int flags; + char *path; + + if (nargs < 2) + cant_happen(); + + file = get_scalar_argument(0, false); + force_string(file); + mode = get_scalar_argument(1, true); + force_string(mode); + + if (file->stlen == 0) + fatal(_("%s: filename has empty string value"), builtin_name); + if (mode->stlen == 0) + fatal(_("%s: mode has empty string value"), builtin_name); + + flags = mode2flags(mode->stptr); + if (flags < 0) + fatal(_("%s: invalid mode `%.*s'"), builtin_name, + (int) mode->stlen, mode->stptr); + + path = file->stptr; + for (prev = NULL, f = files; f != NULL; prev = f, f = f->next) { + if (strcmp(f->path, path) == 0 && f->flags == flags) { + /* Move to the head of the list */ + if (prev != NULL) { + prev->next = f->next; + f->next = files; + files = f; + } + return f; + } + } + + if (! do_open) { + if (do_lint) + lintwarn(_("%s: `%.*s' is not an open file"), + builtin_name, (int) file->stlen, file->stptr); + return NULL; + } + + fp = fopen(path, mode->stptr); + if (fp == NULL) + fatal(_("%s: cannot open file `%.*s'"), + builtin_name, (int) file->stlen, file->stptr); + + os_close_on_exec(fileno(fp), path, "", ""); + + emalloc(f, file_t *, sizeof(file_t) + file->stlen + 1, "file_open"); + memcpy(f->path, path, file->stlen + 1); + f->fp = fp; + f->flags = flags; + f->next = files; + files = f; + return f; +} + + +/* + * mode2flags --- convert a string mode to an integer flag; + * modified from str2mode in io.c. + */ + +static int +mode2flags(const char *mode) +{ + int ret = -1; + const char *second; + + if (mode == NULL || mode[0] == '\0') + return -1; + + second = & mode[1]; + + if (*second == 'b') + second++; + + switch(mode[0]) { + case 'r': + ret = O_RDONLY; + if (*second == '+' || *second == 'w') + ret = O_RDWR; + break; + + case 'w': + ret = O_WRONLY|O_CREAT|O_TRUNC; + if (*second == '+' || *second == 'r') + ret = O_RDWR|O_CREAT|O_TRUNC; + break; + + case 'a': + ret = O_WRONLY|O_APPEND|O_CREAT; + if (*second == '+') + ret = O_RDWR|O_APPEND|O_CREAT; + break; + + default: + ret = -1; + } + if (ret != -1 && strchr(mode, 'b') != NULL) + ret |= O_BINARY; + return ret; +} + + +/* dlload --- load new builtins in this library */ + +NODE * +dlload(NODE *tree, void *dl) +{ + make_old_builtin("fseek", do_fseek, 4); + make_old_builtin("fread", do_fread, 3); + make_old_builtin("fwrite", do_fwrite, 3); + make_old_builtin("flush", do_flush, 2); + make_old_builtin("filesize", do_filesize, 1); + make_old_builtin("file_exists", do_file_exists, 1); + make_old_builtin("fclose", do_fclose, 2); + make_old_builtin("ftruncate", do_ftruncate, 3); + make_old_builtin("unlink", do_unlink, 1); + return make_number((AWKNUM) 0); +} + + +/* dlunload --- routine called when exiting */ + +void +dlunload() +{ + file_t *f; + for (f = files; f != NULL; f = f->next) { + if (f->fp != NULL) { + fclose(f->fp); + f->fp = NULL; + } + } +} |