diff --git a/binding-mruby/binding-mruby.cpp b/binding-mruby/binding-mruby.cpp index 24d5dfe..815ce00 100644 --- a/binding-mruby/binding-mruby.cpp +++ b/binding-mruby/binding-mruby.cpp @@ -65,9 +65,6 @@ ScriptBinding scriptBindingImpl = ScriptBinding *scriptBinding = &scriptBindingImpl; - -void fileBindingInit(mrb_state *); -void timeBindingInit(mrb_state *); void kernelBindingInit(mrb_state *); void tableBindingInit(mrb_state *); @@ -89,8 +86,6 @@ static void mrbBindingInit(mrb_state *mrb) int arena = mrb_gc_arena_save(mrb); /* Init standard classes */ - fileBindingInit(mrb); - timeBindingInit(mrb); kernelBindingInit(mrb); /* Init RGSS classes */ diff --git a/binding-mruby/mrb-ext/file.cpp b/binding-mruby/mrb-ext/file.cpp deleted file mode 100644 index e19ab74..0000000 --- a/binding-mruby/mrb-ext/file.cpp +++ /dev/null @@ -1,605 +0,0 @@ -/* -** file.cpp -** -** This file is part of mkxp. -** -** Copyright (C) 2013 Jonas Kulla -** -** mkxp 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. -** -** mkxp 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 mkxp. If not, see . -*/ - -#include "file.h" - -#include "debugwriter.h" - -#include "../binding-util.h" -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include - -extern mrb_value timeFromSecondsInt(mrb_state *mrb, time_t seconds); - -static void -checkValid(mrb_state *mrb, FileImpl *p, int rwMode = FileImpl::ReadWrite) -{ - MrbData *data = getMrbData(mrb); - - if (p->closed) - mrb_raise(mrb, data->exc[IO], "closed stream"); - - if (!(p->mode & rwMode)) - { - const char *errorMsg = 0; - - switch (rwMode) - { - case FileImpl::Read : - errorMsg = "not openend for reading"; break; - case FileImpl::Write : - errorMsg = "not openend for writing"; break; - default: break; - } - - mrb_raise(mrb, data->exc[IO], errorMsg); - } -} - -extern const mrb_data_type FileType = -{ - "File", - freeInstance -}; - -static int -getOpenMode(const char *mode) -{ -#define STR_CASE(cs, ret) else if (!strcmp(mode, cs)) { return FileImpl:: ret; } - - if (!strcmp(mode, "r")) - return FileImpl::Read; - STR_CASE("rb", Read) - STR_CASE("r+", ReadWrite) - STR_CASE("w", Write) - STR_CASE("wb", Write) - STR_CASE("w+", ReadWrite) - STR_CASE("rw", ReadWrite) - STR_CASE("a", Write) - STR_CASE("a+", ReadWrite) - - Debug() << "getOpenMode failed for:" << mode; - return 0; -} - -static void handleErrno(mrb_state *mrb) -{ - MrbException exc; - const char *msg; - mrb_value arg1; - -#define ENO(_eno, _msg) \ - case _eno: { exc = Errno##_eno; msg = _msg; break; } - - switch (errno) - { - ENO(EACCES, ""); - ENO(EBADF, ""); - ENO(EEXIST, ""); - ENO(EINVAL, ""); - ENO(EMFILE, ""); - ENO(ENOMEM, ""); - ENO(ERANGE, ""); - default: - exc = IO; msg = "Unknown Errno: %S"; - arg1 = mrb_any_to_s(mrb, mrb_fixnum_value(errno)); - } - -#undef ENO - - mrb_raisef(mrb, getMrbData(mrb)->exc[exc], msg, arg1); -} - -#define GUARD_ERRNO(stmnt) \ -{ \ - errno = 0; \ - { stmnt } \ - if (errno != 0) \ - handleErrno(mrb); \ -} - - -static char * -findLastDot(char *str) -{ - char *find = 0; - char *ptr = str; - - /* Dot in front is not considered */ - if (*ptr == '.') - ptr++; - - for (; *ptr; ++ptr) - { - /* Dot in dirpath is not considered */ - if (*ptr == '/') - { - ptr++; - if (*ptr == '.') - ptr++; - } - - if (*ptr == '.') - find = ptr; - } - - return find; -} - -/* File class methods */ -MRB_FUNCTION(fileBasename) -{ - mrb_value filename; - const char *suffix = 0; - - mrb_get_args(mrb, "S|z", &filename, &suffix); - - char *_filename = RSTRING_PTR(filename); - char *base = basename(_filename); - - char *ext = 0; - - if (suffix) - { - ext = findLastDot(base); - if (ext && !strcmp(ext, suffix)) - *ext = '\0'; - } - - mrb_value str = mrb_str_new_cstr(mrb, base); - - /* Restore param string */ - if (ext) - *ext = '.'; - - return str; -} - -MRB_FUNCTION(fileDelete) -{ - mrb_int argc; - mrb_value *argv; - - mrb_get_args(mrb, "*", &argv, &argc); - - for (int i = 0; i < argc; ++i) - { - mrb_value &v = argv[i]; - - if (!mrb_string_p(v)) - continue; - - const char *filename = RSTRING_PTR(v); - GUARD_ERRNO( unlink(filename); ) - } - - return mrb_nil_value(); -} - -MRB_FUNCTION(fileDirname) -{ - mrb_value filename; - mrb_get_args(mrb, "S", &filename); - - char *_filename = RSTRING_PTR(filename); - char *dir = dirname(_filename); - - return mrb_str_new_cstr(mrb, dir); -} - -MRB_FUNCTION(fileExpandPath) -{ - const char *path; - const char *defDir = 0; - - mrb_get_args(mrb, "z|z", &path, &defDir); - - // FIXME No idea how to integrate 'default_dir' right now - if (defDir) - Debug() << "FIXME: File.expand_path: default_dir not implemented"; - - char buffer[PATH_MAX]; - char *unused = realpath(path, buffer); - (void) unused; - - return mrb_str_new_cstr(mrb, buffer); -} - -MRB_FUNCTION(fileExtname) -{ - mrb_value filename; - mrb_get_args(mrb, "S", &filename); - - char *ext = findLastDot(RSTRING_PTR(filename)); - - return mrb_str_new_cstr(mrb, ext); -} - -MRB_FUNCTION(fileOpen) -{ - mrb_value path; - const char *mode = "r"; - mrb_value block = mrb_nil_value(); - - mrb_get_args(mrb, "S|z&", &path, &mode, &block); - - /* We manually check errno because we're supplying the - * filename on ENOENT */ - errno = 0; - FILE *f = fopen(RSTRING_PTR(path), mode); - if (!f) - { - if (errno == ENOENT) - mrb_raisef(mrb, getMrbData(mrb)->exc[ErrnoENOENT], - "No such file or directory - %S", path); - else - handleErrno(mrb); - } - - SDL_RWops *ops = SDL_RWFromFP(f, SDL_TRUE); - FileImpl *p = new FileImpl(ops, getOpenMode(mode)); - - mrb_value obj = wrapObject(mrb, p, FileType); - setProperty(mrb, obj, CSpath, path); - - if (mrb_type(block) == MRB_TT_PROC) - { - // FIXME inquire how GC behaviour works here for obj - mrb_value ret = mrb_yield(mrb, block, obj); - p->close(); - return ret; - } - - return obj; -} - -MRB_FUNCTION(fileRename) -{ - const char *from, *to; - mrb_get_args(mrb, "zz", &from, &to); - - GUARD_ERRNO( rename(from, to); ) - - return mrb_fixnum_value(0); -} - - -MRB_FUNCTION(mrbNoop) -{ - MRB_FUN_UNUSED_PARAM; - - return mrb_nil_value(); -} - -/* File instance methods */ -MRB_METHOD(fileClose) -{ - FileImpl *p = getPrivateData(mrb, self); - checkValid(mrb, p); - - GUARD_ERRNO( p->close(); ) - - return self; -} - -static void -readLine(FILE *f, std::vector &buffer) -{ - buffer.clear(); - - while (true) - { - if (feof(f)) - break; - - int c = fgetc(f); - - if (c == '\n' || c == EOF) - break; - - buffer.push_back(c); - } -} - -MRB_METHOD(fileEachLine) -{ - FileImpl *p = getPrivateData(mrb, self); - checkValid(mrb, p, FileImpl::Read); - FILE *f = p->fp(); - - mrb_value block; - mrb_get_args(mrb, "&", &block); - - (void) f; - std::vector buffer; - - mrb_value str = mrb_str_buf_new(mrb, 0); - - while (feof(f) == 0) - { - GUARD_ERRNO( readLine(f, buffer); ) - - if (buffer.empty() && feof(f) != 0) - break; - - size_t lineLen = buffer.size(); - mrb_str_resize(mrb, str, lineLen); - memcpy(RSTRING_PTR(str), &buffer[0], lineLen); - - mrb_yield(mrb, block, str); - } - - return self; -} - -MRB_METHOD(fileEachByte) -{ - FileImpl *p = getPrivateData(mrb, self); - checkValid(mrb, p, FileImpl::Read); - FILE *f = p->fp(); - - mrb_value block; - mrb_get_args(mrb, "&", &block); - - GUARD_ERRNO( - while (feof(f) == 0) - { - mrb_int byte = fgetc(f); - - if (byte == -1) - break; - - mrb_yield(mrb, block, mrb_fixnum_value(byte)); - }) - - return self; -} - -MRB_METHOD(fileIsEof) -{ - FileImpl *p = getPrivateData(mrb, self); - checkValid(mrb, p); - FILE *f = p->fp(); - - bool isEof; - GUARD_ERRNO( isEof = feof(f) != 0; ) - - return mrb_bool_value(isEof); -} - -MRB_METHOD(fileSetPos) -{ - FileImpl *p = getPrivateData(mrb, self); - checkValid(mrb, p); - FILE *f = p->fp(); - - mrb_int pos; - mrb_get_args(mrb, "i", &pos); - - GUARD_ERRNO( fseek(f, pos, SEEK_SET); ) - - return self; -} - -MRB_METHOD(fileGetPos) -{ - FileImpl *p = getPrivateData(mrb, self); - checkValid(mrb, p); - FILE *f = p->fp(); - - long pos; - GUARD_ERRNO( pos = ftell(f); ) - - return mrb_fixnum_value(pos); -} - -MRB_METHOD(fileRead) -{ - FileImpl *p = getPrivateData(mrb, self); - checkValid(mrb, p, FileImpl::Read); - FILE *f = p->fp(); - - long cur, size; - GUARD_ERRNO( cur = ftell(f); ) - GUARD_ERRNO( fseek(f, 0, SEEK_END); ) - GUARD_ERRNO( size = ftell(f); ) - GUARD_ERRNO( fseek(f, cur, SEEK_SET); ) - - mrb_int length = size - cur; - mrb_get_args(mrb, "|i", &length); - - mrb_value str = mrb_str_new(mrb, 0, 0); - mrb_str_resize(mrb, str, length); - - GUARD_ERRNO( int unused = fread(RSTRING_PTR(str), 1, length, f); (void) unused; ) - - return str; -} - -// FIXME this function always splits on newline right now, -// to make rs fully work, I'll have to use some strrstr magic I guess -MRB_METHOD(fileReadLines) -{ - FileImpl *p = getPrivateData(mrb, self); - checkValid(mrb, p, FileImpl::Read); - FILE *f = p->fp(); - - mrb_value arg; - int argc = mrb_get_args(mrb, "|o", &arg); - - const char *rs = "\n"; (void) rs; - - if (argc > 0) - { - Debug() << "FIXME: File.readlines: rs not implemented"; - - if (mrb_string_p(arg)) - rs = RSTRING_PTR(arg); - else if (mrb_nil_p(arg)) - rs = "\n"; - else - mrb_raise(mrb, getMrbData(mrb)->exc[TypeError], "Expected string or nil"); // FIXME add "got <> instead" remark - } - - mrb_value ary = mrb_ary_new(mrb); - std::vector buffer; - - while (feof(f) == 0) - { - GUARD_ERRNO( readLine(f, buffer); ) - - if (buffer.empty() && feof(f) != 0) - break; - - mrb_value str = mrb_str_new(mrb, &buffer[0], buffer.size()); - mrb_ary_push(mrb, ary, str); - } - - return ary; -} - -MRB_METHOD(fileWrite) -{ - FileImpl *p = getPrivateData(mrb, self); - checkValid(mrb, p, FileImpl::Write); - FILE *f = p->fp(); - - mrb_value str; - mrb_get_args(mrb, "S", &str); - - size_t count; - GUARD_ERRNO( count = fwrite(RSTRING_PTR(str), 1, RSTRING_LEN(str), f); ) - - return mrb_fixnum_value(count); -} - -MRB_METHOD(fileGetPath) -{ - FileImpl *p = getPrivateData(mrb, self); - checkValid(mrb, p); - - return getProperty(mrb, self, CSpath); -} - -static void -getFileStat(mrb_state *mrb, struct stat &fileStat) -{ - const char *filename; - mrb_get_args(mrb, "z", &filename); - - stat(filename, &fileStat); -} - -MRB_METHOD(fileGetMtime) -{ - mrb_value path = getProperty(mrb, self, CSpath); - - struct stat fileStat; - stat(RSTRING_PTR(path), &fileStat); - - return timeFromSecondsInt(mrb, fileStat.st_mtim.tv_sec); -} - -/* FileTest module functions */ -MRB_FUNCTION(fileTestDoesExist) -{ - const char *filename; - mrb_get_args(mrb, "z", &filename); - - int result = access(filename, F_OK); - - return mrb_bool_value(result == 0); -} - -MRB_FUNCTION(fileTestIsFile) -{ - struct stat fileStat; - getFileStat(mrb, fileStat); - - return mrb_bool_value(S_ISREG(fileStat.st_mode)); -} - -MRB_FUNCTION(fileTestIsDirectory) -{ - struct stat fileStat; - getFileStat(mrb, fileStat); - - return mrb_bool_value(S_ISDIR(fileStat.st_mode)); -} - -MRB_FUNCTION(fileTestSize) -{ - struct stat fileStat; - getFileStat(mrb, fileStat); - - return mrb_fixnum_value(fileStat.st_size); -} - -void -fileBindingInit(mrb_state *mrb) -{ - mrb_define_method(mrb, mrb->kernel_module, "open", fileOpen, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1) | MRB_ARGS_BLOCK()); - - RClass *klass = defineClass(mrb, "IO"); - klass = mrb_define_class(mrb, "File", klass); - - mrb_define_class_method(mrb, klass, "basename", fileBasename, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); - mrb_define_class_method(mrb, klass, "delete", fileDelete, MRB_ARGS_REQ(1) | MRB_ARGS_ANY()); - mrb_define_class_method(mrb, klass, "dirname", fileDirname, MRB_ARGS_REQ(1)); - mrb_define_class_method(mrb, klass, "expand_path", fileExpandPath, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); - mrb_define_class_method(mrb, klass, "extname", fileExtname, MRB_ARGS_REQ(1)); - mrb_define_class_method(mrb, klass, "open", fileOpen, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1) | MRB_ARGS_BLOCK()); - mrb_define_class_method(mrb, klass, "rename", fileRename, MRB_ARGS_REQ(2)); - - /* IO */ - mrb_define_method(mrb, klass, "binmode", mrbNoop, MRB_ARGS_NONE()); - mrb_define_method(mrb, klass, "close", fileClose, MRB_ARGS_NONE()); - mrb_define_method(mrb, klass, "each_line", fileEachLine, MRB_ARGS_BLOCK()); - mrb_define_method(mrb, klass, "each_byte", fileEachByte, MRB_ARGS_BLOCK()); - mrb_define_method(mrb, klass, "eof?", fileIsEof, MRB_ARGS_NONE()); - mrb_define_method(mrb, klass, "pos", fileGetPos, MRB_ARGS_NONE()); - mrb_define_method(mrb, klass, "pos=", fileSetPos, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, klass, "read", fileRead, MRB_ARGS_OPT(1)); - mrb_define_method(mrb, klass, "readlines", fileReadLines, MRB_ARGS_OPT(1)); - mrb_define_method(mrb, klass, "write", fileWrite, MRB_ARGS_REQ(1)); - - /* File */ - mrb_define_method(mrb, klass, "mtime", fileGetMtime, MRB_ARGS_NONE()); - mrb_define_method(mrb, klass, "path", fileGetPath, MRB_ARGS_NONE()); - - /* FileTest */ - RClass *module = mrb_define_module(mrb, "MKXPFileTest"); - mrb_define_module_function(mrb, module, "exist?", fileTestDoesExist, MRB_ARGS_REQ(1)); - mrb_define_module_function(mrb, module, "directory?", fileTestIsDirectory, MRB_ARGS_REQ(1)); - mrb_define_module_function(mrb, module, "file?", fileTestIsFile, MRB_ARGS_REQ(1)); - mrb_define_module_function(mrb, module, "size", fileTestSize, MRB_ARGS_REQ(1)); -} diff --git a/binding-mruby/mrb-ext/file.h b/binding-mruby/mrb-ext/file.h deleted file mode 100644 index 42e379e..0000000 --- a/binding-mruby/mrb-ext/file.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -** file.h -** -** This file is part of mkxp. -** -** Copyright (C) 2013 Jonas Kulla -** -** mkxp 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. -** -** mkxp 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 mkxp. If not, see . -*/ - -#ifndef BINDING_FILE_H -#define BINDING_FILE_H - -#include "../binding-util.h" - -#include - -struct FileImpl -{ - SDL_RWops *ops; - bool closed; - - enum OpenMode - { - Read = 1 << 0, - Write = 1 << 1, - ReadWrite = Read | Write - }; - - int mode; - - FileImpl(SDL_RWops *ops, int mode) - : ops(ops), - closed(false), - mode(mode) - {} - - void close() - { - if (closed) - return; - - SDL_RWclose(ops); - closed = true; - } - - FILE *fp() - { - return ops->hidden.stdio.fp; - } - - ~FileImpl() - { - close(); - } -}; - -DECL_TYPE(File); - -#endif // BINDING_FILE_H diff --git a/binding-mruby/mrb-ext/kernel.cpp b/binding-mruby/mrb-ext/kernel.cpp index c0babd8..d192195 100644 --- a/binding-mruby/mrb-ext/kernel.cpp +++ b/binding-mruby/mrb-ext/kernel.cpp @@ -48,126 +48,6 @@ MRB_FUNCTION(kernelEval) return mrb_load_nstring(mrb, exp, expLen); } -static void printP(mrb_state *mrb, - const char *conv, const char *sep) -{ - mrb_int argc; - mrb_value *argv; - mrb_get_args(mrb, "*", &argv, &argc); - - mrb_value buffer = mrb_str_buf_new(mrb, 128); - mrb_value arg; - - for (int i = 0; i < argc; ++i) - { - arg = argv[i]; - arg = mrb_funcall(mrb, arg, conv, 0); - - mrb_str_buf_append(mrb, buffer, arg); - - if (i < argc) - mrb_str_buf_cat(mrb, buffer, sep, strlen(sep)); - } - - shState->eThread().showMessageBox(RSTRING_PTR(buffer), SDL_MESSAGEBOX_INFORMATION); -} - -MRB_FUNCTION(kernelP) -{ - printP(mrb, "inspect", "\n"); - - return mrb_nil_value(); -} - -MRB_FUNCTION(kernelPrint) -{ - printP(mrb, "to_s", ""); - - return mrb_nil_value(); -} - -// FIXME store this in kernel module -static int currentSeed = 1; -bool srandCalled = false; - -static void -srandCurrentTime(int *currentSeed) -{ - timeval tv; - gettimeofday(&tv, 0); - - // FIXME could check how MRI does this - *currentSeed = tv.tv_sec * tv.tv_usec; - - srand(*currentSeed); -} - -MRB_FUNCTION(kernelRand) -{ - if (!srandCalled) - { - srandCurrentTime(¤tSeed); - srandCalled = true; - } - - mrb_value arg; - - mrb_get_args(mrb, "o", &arg); - - if (mrb_fixnum_p(arg) && mrb_fixnum(arg) != 0) - { - return mrb_fixnum_value(rand() % mrb_fixnum(arg)); - } - else if ((mrb_fixnum_p(arg) && mrb_fixnum(arg) == 0) || mrb_nil_p(arg)) - { - return mrb_float_value(mrb, (float) rand() / RAND_MAX); - } - else if (mrb_float_p(arg)) - { - return mrb_float_value(mrb, (float) rand() / RAND_MAX); - } - else - { - mrb_raisef(mrb, E_TYPE_ERROR, "Expected Fixnum or Float, got %S", - mrb_str_new_cstr(mrb, mrb_class_name(mrb, mrb_class(mrb, arg)))); - return mrb_nil_value(); - } -} - -MRB_FUNCTION(kernelSrand) -{ - srandCalled = true; - - mrb_int seed; - int argc = mrb_get_args(mrb, "|i", &seed); - - if (argc == 1) - { - srand(seed); - - int oldSeed = currentSeed; - currentSeed = seed; - - return mrb_fixnum_value(oldSeed); - } - else - { - int oldSeed = currentSeed; - srandCurrentTime(¤tSeed); - - return mrb_fixnum_value(oldSeed); - } -} - -MRB_FUNCTION(kernelExit) -{ - MRB_FUN_UNUSED_PARAM; - - scriptBinding->terminate(); - - return mrb_nil_value(); -} - MRB_FUNCTION(kernelLoadData) { const char *filename; @@ -211,26 +91,11 @@ MRB_FUNCTION(kernelSaveData) return mrb_nil_value(); } -MRB_FUNCTION(kernelInteger) -{ - mrb_value obj; - mrb_get_args(mrb, "o", &obj); - - return mrb_to_int(mrb, obj); -} - void kernelBindingInit(mrb_state *mrb) { RClass *module = mrb->kernel_module; mrb_define_module_function(mrb, module, "eval", kernelEval, MRB_ARGS_REQ(1)); - mrb_define_module_function(mrb, module, "p", kernelP, MRB_ARGS_REQ(1) | MRB_ARGS_REST()); - mrb_define_module_function(mrb, module, "print", kernelPrint, MRB_ARGS_REQ(1) | MRB_ARGS_REST()); - mrb_define_module_function(mrb, module, "rand", kernelRand, MRB_ARGS_REQ(1)); - mrb_define_module_function(mrb, module, "srand", kernelSrand, MRB_ARGS_OPT(1)); - mrb_define_module_function(mrb, module, "exit", kernelExit, MRB_ARGS_NONE()); mrb_define_module_function(mrb, module, "load_data", kernelLoadData, MRB_ARGS_REQ(1)); mrb_define_module_function(mrb, module, "save_data", kernelSaveData, MRB_ARGS_REQ(2)); - mrb_define_module_function(mrb, module, "exit", kernelExit, MRB_ARGS_NONE()); - mrb_define_module_function(mrb, module, "Integer", kernelInteger, MRB_ARGS_REQ(1)); } diff --git a/binding-mruby/mrb-ext/time.cpp b/binding-mruby/mrb-ext/time.cpp deleted file mode 100644 index 9f66d43..0000000 --- a/binding-mruby/mrb-ext/time.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/* -** time.cpp -** -** This file is part of mkxp. -** -** Copyright (C) 2013 Jonas Kulla -** -** mkxp 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. -** -** mkxp 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 mkxp. If not, see . -*/ - -#include "../binding-util.h" - -#include -#include -#include - -#include "time.h" -#include -#include - -struct TimeImpl -{ - struct tm _tm; - struct timeval _tv; -}; - -extern const mrb_data_type TimeType = -{ - "Time", - freeInstance -}; - -extern mrb_value -timeFromSecondsInt(mrb_state *mrb, time_t seconds) -{ - TimeImpl *p = new TimeImpl; - - p->_tv.tv_sec = seconds; - p->_tm = *localtime(&p->_tv.tv_sec); - - mrb_value obj = wrapObject(mrb, p, TimeType); - - return obj; -} - -MRB_FUNCTION(timeAt) -{ - mrb_int seconds; - mrb_get_args(mrb, "i", &seconds); - - return timeFromSecondsInt(mrb, seconds); -} - -MRB_FUNCTION(timeNow) -{ - TimeImpl *p = new TimeImpl; - - gettimeofday(&p->_tv, 0); - p->_tm = *localtime(&p->_tv.tv_sec); - - mrb_value obj = wrapObject(mrb, p, TimeType); - - return obj; -} - -static mrb_value -secondsAdded(mrb_state *mrb, TimeImpl *p, mrb_int seconds) -{ - TimeImpl *newP = new TimeImpl; - *newP = *p; - - newP->_tv.tv_sec += seconds; - p->_tm = *localtime(&p->_tv.tv_sec); - - return wrapObject(mrb, newP, TimeType); -} - -MRB_METHOD(timePlus) -{ - mrb_int seconds; - mrb_get_args(mrb, "i", &seconds); - - TimeImpl *p = getPrivateData(mrb, self); - - TimeImpl *newP = new TimeImpl; - *newP = *p; - - newP->_tv.tv_sec += seconds; - p->_tm = *localtime(&p->_tv.tv_sec); - - return wrapObject(mrb, newP, TimeType); -} - -MRB_METHOD(timeMinus) -{ - mrb_value minuent; - mrb_get_args(mrb, "o", &minuent); - - TimeImpl *p = getPrivateData(mrb, self); - - if (mrb_fixnum_p(minuent)) - { - mrb_int seconds = mrb_fixnum(minuent); - - return secondsAdded(mrb, p, -seconds); - } - else if (mrb_type(minuent) == MRB_TT_OBJECT) - { - TimeImpl *o = getPrivateDataCheck(mrb, minuent, TimeType); - - return mrb_float_value(mrb, p->_tv.tv_sec - o->_tv.tv_sec); - } - else - { - mrb_raisef(mrb, E_TYPE_ERROR, "Expected Fixnum or Time, got %S", - mrb_str_new_cstr(mrb, mrb_class_name(mrb, mrb_class(mrb, minuent)))); - } - - return mrb_nil_value(); -} - -MRB_METHOD(timeCompare) -{ - mrb_value cmpTo; - mrb_get_args(mrb, "o", &cmpTo); - - mrb_int cmpToS = 0; - - if (mrb_fixnum_p(cmpTo)) - { - cmpToS = mrb_fixnum(cmpTo); - } - else if (mrb_type(cmpTo) == MRB_TT_OBJECT) - { - TimeImpl *cmpToP = getPrivateDataCheck(mrb, cmpTo, TimeType); - cmpToS = cmpToP->_tv.tv_sec; - } - else - { - mrb_raisef(mrb, E_TYPE_ERROR, "Expected Fixnum or Time, got %S", - mrb_str_new_cstr(mrb, mrb_class_name(mrb, mrb_class(mrb, cmpTo)))); - } - - TimeImpl *p = getPrivateData(mrb, self); - mrb_int selfS = p->_tv.tv_sec; - - if (selfS < cmpToS) - return mrb_fixnum_value(-1); - else if (selfS == cmpToS) - return mrb_fixnum_value(0); - else - return mrb_fixnum_value(1); -} - -MRB_METHOD(timeStrftime) -{ - const char *format; - mrb_get_args(mrb, "z", &format); - - TimeImpl *p = getPrivateData(mrb, self); - - static char buffer[512]; - strftime(buffer, sizeof(buffer), format, &p->_tm); - - return mrb_str_new_cstr(mrb, buffer); -} - -#define TIME_ATTR(attr) \ - MRB_METHOD(timeGet_##attr) \ - { \ - TimeImpl *p = getPrivateData(mrb, self); \ - return mrb_fixnum_value(p->_tm.tm_##attr); \ - } - -TIME_ATTR(sec) -TIME_ATTR(min) -TIME_ATTR(hour) -TIME_ATTR(mday) -TIME_ATTR(mon) -TIME_ATTR(year) -TIME_ATTR(wday) - -#define TIME_BIND_ATTR(attr) \ - { mrb_define_method(mrb, klass, #attr, timeGet_##attr, MRB_ARGS_NONE()); } - -void -timeBindingInit(mrb_state *mrb) -{ - RClass *klass = defineClass(mrb, "Time"); - mrb_include_module(mrb, klass, mrb_module_get(mrb, "Comparable")); - - mrb_define_class_method(mrb, klass, "now", timeNow, MRB_ARGS_NONE()); - mrb_define_class_method(mrb, klass, "at", timeAt, MRB_ARGS_REQ(1)); - - mrb_define_method(mrb, klass, "+", timePlus, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, klass, "-", timeMinus, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, klass, "<=>", timeCompare, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, klass, "strftime", timeStrftime, MRB_ARGS_REQ(1)); - - TIME_BIND_ATTR(sec); - TIME_BIND_ATTR(min); - TIME_BIND_ATTR(hour); - TIME_BIND_ATTR(mday); - TIME_BIND_ATTR(mon); - TIME_BIND_ATTR(year); - TIME_BIND_ATTR(wday); -}