/* * Copyright (c) 2012, Jonathan Schleifer <js@webkeks.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <string.h> #include <limits.h> #include <fcntl.h> #include <unistd.h> #include "stream.h" #include "file.h" #ifndef O_BINARY # define O_BINARY 0 #endif #ifndef S_IRGRP # define S_IRGRP 0 #endif #ifndef S_IROTH # define S_IROTH 0 #endif #ifndef S_IWGRP # define S_IWGRP 0 #endif #ifndef S_IWOTH # define S_IWOTH 0 #endif #define DEFAULT_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH struct CFWFile { CFWStream stream; int fd; bool eof; }; static int parse_mode(const char *mode) { if (!strcmp(mode, "r")) return O_RDONLY; if (!strcmp(mode, "rb")) return O_RDONLY | O_BINARY; if (!strcmp(mode, "r+")) return O_RDWR; if (!strcmp(mode, "rb+") || !strcmp(mode, "r+b")) return O_RDWR | O_BINARY; if (!strcmp(mode, "w")) return O_WRONLY | O_CREAT | O_TRUNC; if (!strcmp(mode, "wb")) return O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; if (!strcmp(mode, "w+")) return O_RDWR | O_CREAT | O_TRUNC; if (!strcmp(mode, "wb+") || !strcmp(mode, "w+b")) return O_RDWR | O_CREAT | O_TRUNC | O_BINARY; if (!strcmp(mode, "a")) return O_WRONLY | O_CREAT | O_APPEND; if (!strcmp(mode, "ab")) return O_WRONLY | O_CREAT | O_APPEND | O_BINARY; if (!strcmp(mode, "a+")) return O_RDWR | O_CREAT | O_APPEND; if (!strcmp(mode, "ab+") || !strcmp(mode, "a+b")) return O_RDWR | O_CREAT | O_APPEND | O_BINARY; return -1; } static ssize_t file_read(void *ptr, void *buf, size_t len) { CFWFile *file = ptr; ssize_t ret; if ((ret = read(file->fd, buf, len)) == 0) file->eof = true; return ret; } static bool file_write(void *ptr, const void *buf, size_t len) { CFWFile *file = ptr; ssize_t ret; if ((ret = write(file->fd, buf, len)) < len) return false; return true; } static bool file_eof(void *ptr) { CFWFile *file = ptr; return file->eof; } static void file_close(void *ptr) { CFWFile *file = ptr; close(file->fd); } static struct cfw_stream_ops stream_ops = { .read = file_read, .write = file_write, .eof = file_eof, .close = file_close }; static bool ctor(void *ptr, va_list args) { CFWFile *file = ptr; const char *path = va_arg(args, const char*); const char *mode = va_arg(args, const char*); int flags; /* Make sure we have a valid file in case we error out */ cfw_stream->ctor(ptr, args); file->eof = false; if ((flags = parse_mode(mode)) == -1) return false; if ((file->fd = open(path, flags, DEFAULT_MODE)) == -1) return false; file->stream.ops = &stream_ops; return true; } static void dtor(void *ptr) { cfw_stream->dtor(ptr); } static CFWClass class = { .name = "CFWFile", .size = sizeof(CFWFile), .ctor = ctor, .dtor = dtor }; CFWClass *cfw_file = &class; static CFWFile cfw_stdin_ = { .stream = { .obj = { .cls = &class, .ref_cnt = INT_MAX }, .ops = &stream_ops }, .fd = 0, .eof = false }; static CFWFile cfw_stdout_ = { .stream = { .obj = { .cls = &class, .ref_cnt = INT_MAX }, .ops = &stream_ops }, .fd = 1, .eof = false }; static CFWFile cfw_stderr_ = { .stream = { .obj = { .cls = &class, .ref_cnt = INT_MAX }, .ops = &stream_ops }, .fd = 2, .eof = false }; CFWFile *cfw_stdin = &cfw_stdin_; CFWFile *cfw_stdout = &cfw_stdout_; CFWFile *cfw_stderr = &cfw_stderr_;