/* * SPL - The SPL Programming Language * Copyright (C) 2004, 2005 Clifford Wolf * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * mod_file.c: Simple file IO library */ /** * This module provides a simple API for reading and writing files */ #include #include #include #include #include #include #include #include #include "spl.h" #include "compat.h" extern void SPL_ABI(spl_mod_file_init)(struct spl_vm *vm, struct spl_module *mod, int restore); extern void SPL_ABI(spl_mod_file_done)(struct spl_vm *vm, struct spl_module *mod); static void do_exception(struct spl_task *task, char *type, char *filename, char *errmsg) { spl_clib_exception(task, "FileEx", "type", SPL_NEW_STRING_DUP(type), "filename", SPL_NEW_STRING_DUP(filename), "errmsg", SPL_NEW_STRING_DUP(strerror(errno)), "description", SPL_NEW_SPL_STRING(spl_string_printf(0, 0, 0, "Can't %s file '%s': %s", type, filename, errmsg ? errmsg : strerror(errno))), NULL); } #define GET_REAL_FILENAME \ char *real_filename; \ if (task->vm->current_dir_name && *filename != '/') { \ int len = 2 + strlen(filename) + \ strlen(task->vm->current_dir_name); \ real_filename = my_alloca(len); \ snprintf(real_filename, len, "%s/%s", \ task->vm->current_dir_name, \ filename); \ } else \ real_filename = filename; /** * This function reads the specified filename and returns the file content. * * If the file is not UTF-8 encoded, the encoding must be specified with a * 2nd parameter. Valid encodings are the same as for the '#encoding' compiler * pragma (see 'SPL Language Reference' for a list). * * A [[FileEx]] exception is thrown on I/O errors. */ // builtin file_read(filename, encoding) static struct spl_node *handler_file_read(struct spl_task *task, void UNUSED(*data)) { char *filename = spl_clib_get_string(task); char *encoding = spl_clib_get_string(task); GET_REAL_FILENAME char *content = spl_malloc_file(real_filename, 0); if ( content ) { if ( *encoding ) { char *old_content = content; content = spl_utf8_import(old_content, encoding); free(old_content); if ( !content ) { char buffer[200]; snprintf(buffer, 200, "Unknown encoding: %s", encoding); do_exception(task, "read", filename, buffer); return 0; } } const char *error_pos = spl_utf8_check(content); if ( error_pos ) { int line_number = 1, byte_number = 1; char buffer[200]; for (char *p = content; pd_name), SPL_CREATE_LOCAL); } closedir(dir); if (0) error: do_exception(task, "list", filename, 0); return ret; } #ifndef USEWIN32API /** * This function returns the type of a specific entry in given directory. * The returned integer value is according the native file type enumeration. * * On NetBSD type 4 is directory and type 8 is regular file. * * A [[FileEx]] exception is thrown on I/O errors. */ // builtin file_type(dirname,filename) static struct spl_node *handler_file_type(struct spl_task *task, void UNUSED(*data)) { char *filename = spl_clib_get_string(task); //directory char *file = spl_clib_get_string(task); //spl_report(SPL_REPORT_RUNTIME|SPL_REPORT_DEBUG, task, "Getting file type for dir %s file %s\n",filename,file); GET_REAL_FILENAME DIR *dir = opendir(real_filename); if (!dir) return SPL_NEW_INT(0); for (struct dirent *ent = readdir(dir); ent; ent = readdir(dir)) { if (strcmp(file,ent->d_name)==0) { closedir(dir); return SPL_NEW_INT(ent->d_type); } } closedir(dir); return SPL_NEW_INT(0); } #endif /** * This function returns true if the file can be accessed in the specified * mode. The mode argument is a string that may contain the characters 'R', * 'W', 'X' and 'F'. */ // builtin file_access(filename, mode) static struct spl_node *handler_file_access(struct spl_task *task, void UNUSED(*data)) { char *filename = spl_clib_get_string(task); char *modestr = spl_clib_get_string(task); int mode = 0; GET_REAL_FILENAME if (strchr(modestr, 'R')) mode |= R_OK; if (strchr(modestr, 'W')) mode |= W_OK; if (strchr(modestr, 'X')) mode |= X_OK; if (strchr(modestr, 'F')) mode |= F_OK; return SPL_NEW_INT(access(real_filename, mode) == 0); } /** * An instance of this object is thrown on file I/O errors. */ // object FileEx /** * Specifies the type of operation which failed: * "write", "read" or "delete" */ // var type; /** * The filename of which the operation should have been performed. */ // var filename; /** * The error message returned by the operating system */ // var errmsg; /** * A full error description including the information from * [[.type]], [[.filename]] and [[.errmsg]]. */ // var description; void SPL_ABI(spl_mod_file_init)(struct spl_vm *vm, struct spl_module *mod, int restore) { if (!restore) spl_eval(vm, 0, strdup(mod->name), "object FileEx { }"); spl_clib_reg(vm, "file_read", handler_file_read, 0); spl_clib_reg(vm, "file_write", handler_file_write, 0); spl_clib_reg(vm, "file_append", handler_file_write, (void*)1); spl_clib_reg(vm, "file_delete", handler_file_delete, 0); spl_clib_reg(vm, "file_list", handler_file_list, 0); #ifndef USEWIN32API spl_clib_reg(vm, "file_type", handler_file_type, 0); #endif spl_clib_reg(vm, "file_access", handler_file_access, 0); } void SPL_ABI(spl_mod_file_done)(struct spl_vm UNUSED(*vm), struct spl_module UNUSED(*mod)) { return; }