/*** DryOS functions @author Magic Lantern Team @copyright 2014 @license GPL @module dryos */ #include #include #include #include #include #include "lua_common.h" static int luaCB_card_index(lua_State * L); static int luaCB_card_newindex(lua_State * L); static int luaCB_directory_index(lua_State * L); static int luaCB_directory_newindex(lua_State * L); /*** Calls an eventproc (a function from the camera firmware which can be called by name). See Eventprocs. Dangerous - you need to compile Lua yourself in order to enable it. @tparam string function the name of the function to call @param[opt] arg argument to pass to the call @function call */ static int luaCB_dryos_call(lua_State * L) { #if 1 return luaL_error(L, "dryos.call() is disabled for safety reasons.\n" "If you know what you are doing, just remove this message and recompile.\n" ); #endif LUA_PARAM_STRING(function_name, 1); int result = 0; int argc = lua_gettop(L); if(argc <= 1) { result = call(function_name); } else if(lua_isinteger(L, 2)) { int arg = lua_tointeger(L, 2); result = call(function_name, arg); } else if(lua_isnumber(L, 2)) { float arg = lua_tonumber(L, 2); result = call(function_name, arg); } else if(lua_isstring(L, 2)) { const char * arg = lua_tostring(L, 2); result = call(function_name, arg); } lua_pushinteger(L, result); return 1; } const char * lua_dryos_directory_fields[] = { "exists", "create", "children", "files", "parent", NULL }; const char * lua_dryos_card_fields[] = { "cluster_size", "drive_letter", "file_number", "folder_number", "free_space", "type", NULL }; /*** Creates a @{directory} object that is used to get information about a directory This function does not actually create a directory on the file system, it just creates an object that represents a directory. To actually create the directory in the file system call directory:create() @usage local mydir = dryos.directory("mydir") if mydir.exists == false then mydir:create() end for i,v in ipairs(mydir:files()) do print("filename: "..v) end @tparam string path @treturn directory @function directory */ static int luaCB_dryos_directory(lua_State * L) { LUA_PARAM_STRING(path, 1); lua_newtable(L); if (strlen(path) == 0 || !strcmp(path, "/")) { struct card_info * ml_card = get_ml_card(); if (ml_card == NULL) return luaL_error(L, "Could not get ML card"); lua_pushfstring(L, "%s:/", ml_card->drive_letter); } else if (path[strlen(path) - 1] != '/') { lua_pushfstring(L, "%s/", path); } else { lua_pushvalue(L, 1); } lua_setfield(L, -2, "path"); lua_newtable(L); lua_pushcfunction(L, luaCB_directory_index); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, luaCB_directory_newindex); lua_setfield(L, -2, "__newindex"); lua_pushcfunction(L, luaCB_pairs); lua_setfield(L, -2, "__pairs"); lua_pushlightuserdata(L, lua_dryos_directory_fields); lua_setfield(L, -2, "fields"); lua_setmetatable(L, -2); return 1; } /*** Deletes a file from the card. @tparam string filename @treturn bool success @function remove */ static int luaCB_dryos_remove(lua_State * L) { LUA_PARAM_STRING(filename, 1); lua_pushboolean(L, FIO_RemoveFile(filename) == 0); return 1; } static void setfield (lua_State *L, const char *key, int value) { lua_pushinteger(L, value); lua_setfield(L, -2, key); } static void setboolfield (lua_State *L, const char *key, int value) { if (value < 0) /* undefined? */ return; /* does not set field */ lua_pushboolean(L, value); lua_setfield(L, -2, key); } static int luaCB_dryos_index(lua_State * L) { LUA_PARAM_STRING_OPTIONAL(key, 2, ""); /// Get the value of the seconds clock // @tfield int clock if(!strcmp(key, "clock")) lua_pushinteger(L, get_seconds_clock()); /// Get the value of the milliseconds clock // @tfield int ms_clock else if(!strcmp(key, "ms_clock")) lua_pushinteger(L, get_ms_clock_value()); /// Get/Set the image filename prefix // @tfield string prefix else if(!strcmp(key, "prefix")) lua_pushstring(L, get_file_prefix()); /// Get the DCIM directory // @tfield directory dcim_dir else if(!strcmp(key, "dcim_dir")) { lua_pushcfunction(L, luaCB_dryos_directory); lua_pushstring(L, get_dcim_dir()); lua_call(L, 1, 1); } /// Get the ML config directory // @tfield directory config_dir else if(!strcmp(key, "config_dir")) { lua_pushcfunction(L, luaCB_dryos_directory); lua_pushstring(L, get_config_dir()); lua_call(L, 1, 1); } /// Get the card ML started from // @tfield card ml_card else if(!strcmp(key, "ml_card")) { lua_newtable(L); struct card_info * card = get_ml_card(); if(!card) return luaL_error(L, "Error getting ml_card"); lua_pushlightuserdata(L, card); lua_setfield(L, -2, "_card_ptr"); lua_pushfstring(L, "%s:/", card->drive_letter); lua_setfield(L, -2, "path"); lua_newtable(L); lua_pushcfunction(L, luaCB_card_index); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, luaCB_card_newindex); lua_setfield(L, -2, "__newindex"); lua_pushcfunction(L, luaCB_pairs); lua_setfield(L, -2, "__pairs"); lua_pushlightuserdata(L, lua_dryos_card_fields); lua_setfield(L, -2, "fields"); lua_setmetatable(L, -2); } /// Get the shooting card // @tfield card shooting_card else if(!strcmp(key, "shooting_card")) { lua_newtable(L); struct card_info * card = get_shooting_card(); if(!card) return luaL_error(L, "Error getting shooting_card"); lua_pushlightuserdata(L, card); lua_setfield(L, -2, "_card_ptr"); lua_pushfstring(L, "%s:/", card->drive_letter); lua_setfield(L, -2, "path"); lua_newtable(L); lua_pushcfunction(L, luaCB_card_index); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, luaCB_card_newindex); lua_setfield(L, -2, "__newindex"); lua_pushcfunction(L, luaCB_pairs); lua_setfield(L, -2, "__pairs"); lua_pushlightuserdata(L, lua_dryos_card_fields); lua_setfield(L, -2, "fields"); lua_setmetatable(L, -2); } /// Gets a table representing the current date/time // @tfield date date else if(!strcmp(key, "date")) { /// Represents a date/time // @type date struct tm tm; LoadCalendarFromRTC(&tm); lua_newtable(L); /// Second // @tfield int sec setfield(L, "sec", tm.tm_sec); /// Minute // @tfield int min setfield(L, "min", tm.tm_min); /// Hour // @tfield int hour setfield(L, "hour", tm.tm_hour); /// Day // @tfield int day setfield(L, "day", tm.tm_mday); /// Month // @tfield int month setfield(L, "month", tm.tm_mon+1); /// Year // @tfield int year setfield(L, "year", tm.tm_year+1900); /// Day of week // @tfield int wday setfield(L, "wday", tm.tm_wday+1); /// Day of year // @tfield int yday setfield(L, "yday", tm.tm_yday+1); /// Daylight Savings // @tfield bool isdst setboolfield(L, "isdst", tm.tm_isdst); } else lua_rawget(L, 1); return 1; } static int luaCB_dryos_newindex(lua_State * L) { LUA_PARAM_STRING_OPTIONAL(key, 2, ""); if(!strcmp(key, "clock") || !strcmp(key, "ms_clock") || !strcmp(key, "date") || !strcmp(key, "ml_card") || !strcmp(key, "dcim_dir")) { return luaL_error(L, "'%s' is readonly!", key); } else if(!strcmp(key, "prefix")) { static char prefix[8]; LUA_PARAM_STRING(new_prefix, 3); strncpy(prefix, new_prefix, 7); file_prefix_set(prefix); } else { lua_rawset(L, 1); } return 0; } /// Represents a directory // @type directory /*** Creates a directory @treturn bool whether or not the directory was sucessfully created @function create */ static int luaCB_directory_create(lua_State * L) { if(!lua_istable(L, 1)) return luaL_argerror(L, 1, "expected table"); lua_getfield(L, 1, "path"); const char * path = lua_tostring(L, -1); lua_pushinteger(L, FIO_CreateDirectory(path)); return 1; } /*** Get a table (of @{directory} objects) containing this directory's child directories @treturn {directory,...} @function children */ static int luaCB_directory_children(lua_State * L) { if(!lua_istable(L, 1)) return luaL_argerror(L, 1, "expected table"); if(lua_getfield(L, 1, "path") != LUA_TSTRING) return luaL_error(L, "invalid directory path"); const char * path = lua_tostring(L, -1); struct fio_file file; struct fio_dirent * dirent = FIO_FindFirstEx(path, &file); int index = 1; if(!IS_ERROR(dirent)) { lua_newtable(L); do { if (file.mode & ATTR_DIRECTORY) { //call the directory constructor lua_pushcfunction(L, luaCB_dryos_directory); lua_pushfstring(L, "%s%s/", path, file.name); lua_call(L, 1, 1); lua_seti(L, -2, index++); } } while(FIO_FindNextEx(dirent, &file) == 0); FIO_FindClose(dirent); } else { return luaL_error(L, "error reading directory '%s'", path); } return 1; } /*** Get a table (of @{string}s) that are the file names of this directory's files @treturn {string,...} @function files */ static int luaCB_directory_files(lua_State * L) { if(!lua_istable(L, 1)) return luaL_argerror(L, 1, "expected table"); if(lua_getfield(L, 1, "path") != LUA_TSTRING) return luaL_error(L, "invalid directory path"); const char * path = lua_tostring(L, -1); struct fio_file file; struct fio_dirent * dirent = FIO_FindFirstEx(path, &file); int index = 1; if(!IS_ERROR(dirent)) { lua_newtable(L); do { if (!(file.mode & ATTR_DIRECTORY)) { lua_pushfstring(L, "%s%s", path, file.name); lua_seti(L, -2, index++); } } while(FIO_FindNextEx(dirent, &file) == 0); FIO_FindClose(dirent); } else { return luaL_error(L, "error reading directory: '%s'", path); } return 1; } static int luaCB_directory_index(lua_State * L) { if(!lua_istable(L, 1)) return luaL_argerror(L, 1, "expected table"); LUA_PARAM_STRING_OPTIONAL(key, 2, ""); /// Get the full path of the directory // @tfield string path if(!strcmp(key, "path")) return lua_rawget(L, 1); if(lua_getfield(L, 1, "path") != LUA_TSTRING) return luaL_error(L, "invalid directory path"); const char * path = lua_tostring(L, -1); lua_pop(L, 1); /// Get whether or not the directory exists // @tfield bool exists if(!strcmp(key, "exists")) lua_pushboolean(L, is_dir(path)); else if(!strcmp(key, "create")) lua_pushcfunction(L, luaCB_directory_create); else if(!strcmp(key, "children")) lua_pushcfunction(L, luaCB_directory_children); else if(!strcmp(key, "files")) lua_pushcfunction(L, luaCB_directory_files); /// Get a @{directory} object that represents the current directory's parent // @tfield directory parent else if(!strcmp(key, "parent")) { size_t len = strlen(path); if ((len > 3 || ((len == 2 || len == 3) && path[1] != ':')) && path[len - 1] == '/') { char * parent_path = copy_string(path); parent_path[len - 1] = 0x0; char * last = strrchr(parent_path, '/'); if (last) *(last + 1) = 0x0; else parent_path[0] = 0x0; //call the directory constructor lua_pushcfunction(L, luaCB_dryos_directory); lua_pushstring(L, parent_path); lua_call(L, 1, 1); free(parent_path); return 1; } else { return 0; } } else lua_rawget(L, 1); return 1; } static int luaCB_directory_newindex(lua_State * L) { return luaL_error(L, "'directory' type is readonly"); } /// Represents a card (storage media) // Inherits from @{directory} // @type card static int luaCB_card_index(lua_State * L) { if(!lua_istable(L, 1)) return luaL_argerror(L, 1, "expected table"); LUA_PARAM_STRING_OPTIONAL(key, 2, ""); if(lua_getfield(L, 1, "_card_ptr") == LUA_TLIGHTUSERDATA) { struct card_info * card = lua_touserdata(L, -1); /// Get the cluster size // @tfield int cluster_size if(!strcmp(key, "cluster_size")) lua_pushinteger(L, card->cluster_size); /// Get the drive letter // @tfield string drive_letter else if(!strcmp(key, "drive_letter")) lua_pushstring(L, card->drive_letter); /// Get the current Canon file number // @tfield int file_number else if(!strcmp(key, "file_number")) lua_pushinteger(L, card->file_number); /// Get the current Canon folder number // @tfield int folder_number else if(!strcmp(key, "folder_number")) lua_pushinteger(L, card->folder_number); /// Get the current free space (in MiB) // @tfield int free_space else if(!strcmp(key, "free_space")) lua_pushinteger(L, get_free_space_32k(card) * 1024 / 32); /// Get the type of card // @tfield string type else if(!strcmp(key, "type")) lua_pushstring(L, card->type); else return luaCB_directory_index(L); } else { return luaL_error(L, "could not get lightuserdata for card"); } return 1; } static int luaCB_card_newindex(lua_State * L) { return luaL_error(L, "'card' type is readonly"); } static const char * lua_dryos_fields[] = { "clock", "ms_clock", "prefix", "dcim_dir", "config_dir", "ml_card", "shooting_card", "date", NULL }; const luaL_Reg dryoslib[] = { {"call", luaCB_dryos_call}, {"directory", luaCB_dryos_directory}, {"remove", luaCB_dryos_remove}, {NULL, NULL} }; LUA_LIB(dryos)