/* * PSX-Tools Bundle Pack * Copyright (C) 2002-2005 Nicolas "Pixel" Noble * * 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 */ /* $Id: cd-tool.cpp,v 1.48 2007-07-27 14:29:23 pixel Exp $ */ #define WIP #define VERSION "0.6" #include #include "Input.h" #include "Output.h" #include "Buffer.h" #include "BLua.h" #include "LuaConfigFile.h" #include "LuaRegex.h" #include "cdreader.h" #include "cdutils.h" #include "generic.h" #include "Main.h" #include "cdabstract.h" #include "dvdabstract.h" #include "isobuilder.h" #include "luacd.h" #include "luapsx.h" #include #include #include "cd-tool-hc.h" #ifdef _WIN32 #include #include #include #include #define EXT_PREFIX 0x1f8 #define KEV irec.Event.KeyEvent /* to make life easier */ #define KST irec.Event.KeyEvent.dwControlKeyState static int pending_key = 0; static int pending_count = 0; static int pending_prefix = 0; extern int _rl_last_c_pos; /* imported from display.c */ extern int _rl_last_v_pos; extern int rl_dispatching; /* imported from readline.c */ extern int rl_point; extern int rl_done; extern int rl_visible_prompt_length; extern "C" { extern int haveConsole; /* imported from rltty.c */ extern HANDLE hStdout, hStdin; } int my_getc (FILE * stream) { int key; if ( pending_count ) { --pending_count; if ( pending_prefix && (pending_count & 1) ) return pending_prefix; else return pending_key; } while ( 1 ) { DWORD dummy; if (WaitForSingleObject(hStdin, WAIT_FOR_INPUT) != WAIT_OBJECT_0) { if ( rl_done ) return( 0 ); else continue; } if ( haveConsole & FOR_INPUT ) { INPUT_RECORD irec; ReadConsoleInput(hStdin, &irec, 1, &dummy); switch(irec.EventType) { case KEY_EVENT: if ( KEV.bKeyDown && ((KEV.wVirtualKeyCode < VK_SHIFT) || (KEV.wVirtualKeyCode > VK_MENU)) ) { int mask = 0; key = KEV.uChar.AsciiChar & 0xff; // if ( KST & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) ) // mask=0x100; if ( key ) { /* Ascii direct */ pending_count = KEV.wRepeatCount - 1; pending_key = key; pending_prefix = 0; if ( mask ) key = tolower(key) | mask; } else /* Others prefixed */ { key = EXT_PREFIX; if ( mask ) key |= 4; if (KST & SHIFT_PRESSED) key |= 1; if (KST & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) key |= 2; mask |= EXT_PREFIX; pending_count = (KEV.wRepeatCount << 1) - 1; pending_key = KEV.wVirtualKeyCode; pending_prefix = key; } return key; } break; default: break; } } else { ReadFile(hStdin, &key, 1, &dummy, NULL); return key; } } } #endif bool interactive = false; cdutils * cdutil = 0; isobuilder * build = 0; static int myprint(lua_State * __L) { Lua * L = Lua::find(__L); String t = "From LUA: " + L->tostring() + "\n"; char * tc = t.strdup(); Base::printm(M_STATUS, "%s", tc); free(tc); return 0; } class Luabasecdtool : public LuaObject { public: static void pushstatics(Lua *) throw (GeneralException); }; typedef void basecdtool; enum basecdtool_t { BASECDTOOL_LOAD = 0, }; struct lua_functypes_t basecdtool_functions[] = { { BASECDTOOL_LOAD, "load", 0, 1, { BLUA_STRING | BLUA_OBJECT } }, { -1, 0, 0, 0, 0 } }; class sLua_basecdtool : public Base { public: DECLARE_FUNCTION(basecdtool, BASECDTOOL_LOAD); private: static int basecdtool_proceed_statics(Lua * L, int n, int caller); }; void Luabasecdtool::pushstatics(Lua * L) throw (GeneralException ) { CHECK_FUNCTIONS(basecdtool); PUSH_FUNCTION(basecdtool, BASECDTOOL_LOAD); } int sLua_basecdtool::basecdtool_proceed_statics(Lua * L, int n, int caller) { int r = 0; switch (caller) { case BASECDTOOL_LOAD: if (!n) { L->load(&Input("cd-tool.lua")); } else { if (L->isstring(1)) { L->load(&Input(L->tostring(1))); } else { Handle * t = (Handle *) LuaObject::getme(L, 1); L->load(t); } } } return r; } class Luacdtool : public LuaObject { public: static void pushstatics(Lua *) throw (GeneralException); }; typedef void cdtool; enum cdtool_functions_t { CDTOOL_PRINT = 0, CDTOOL_PRINTN, CDTOOL_QUIT, CDTOOL_EXIT, CDTOOL_INFOS, CDTOOL_PATH, CDTOOL_PRINTDIR, }; struct lua_functypes_t cdtool_functions[] = { { CDTOOL_PRINT, "print", 0, 1, { BLUA_ANY } }, { CDTOOL_PRINTN, "printn", 1, 1, { BLUA_ANY } }, { CDTOOL_QUIT, "quit", 0, 0, 0 }, { CDTOOL_EXIT, "exit", 0, 0, 0 }, { CDTOOL_INFOS, "infos", 0, 1, { BLUA_OBJECT } }, { CDTOOL_PATH, "path", 0, 1, { BLUA_OBJECT } }, { CDTOOL_PRINTDIR, "printdir", 1, 2, { BLUA_STRING, BLUA_OBJECT } }, { -1, 0, 0, 0, 0 } }; class sLua_cdtool : public Base { public: DECLARE_FUNCTION(cdtool, CDTOOL_PRINT); DECLARE_FUNCTION(cdtool, CDTOOL_PRINTN); DECLARE_FUNCTION(cdtool, CDTOOL_QUIT); DECLARE_FUNCTION(cdtool, CDTOOL_EXIT); DECLARE_FUNCTION(cdtool, CDTOOL_INFOS); DECLARE_FUNCTION(cdtool, CDTOOL_PATH); DECLARE_FUNCTION(cdtool, CDTOOL_PRINTDIR); private: static int cdtool_proceed_statics(Lua * L, int n, int caller); }; void Luacdtool::pushstatics(Lua * L) throw (GeneralException ) { CHECK_FUNCTIONS(cdtool); PUSH_FUNCTION(cdtool, CDTOOL_PRINT); PUSH_FUNCTION(cdtool, CDTOOL_PRINTN); PUSH_FUNCTION(cdtool, CDTOOL_QUIT); PUSH_FUNCTION(cdtool, CDTOOL_EXIT); PUSH_FUNCTION(cdtool, CDTOOL_INFOS); PUSH_FUNCTION(cdtool, CDTOOL_PATH); PUSH_FUNCTION(cdtool, CDTOOL_PRINTDIR); } int sLua_cdtool::cdtool_proceed_statics(Lua * L, int n, int caller) { int r = 0; String p; cdutils * cd = cdutil; char * tc; String eol = ""; switch (caller) { case CDTOOL_PRINT: eol = "\n"; case CDTOOL_PRINTN: if (n) { p = L->tostring(1) + eol; } else { p = eol; } tc = p.strdup(); printm(M_BARE, "%s", tc); free(tc); break; case CDTOOL_QUIT: case CDTOOL_EXIT: interactive = false; break; case CDTOOL_INFOS: if (n) cd = (cdutils *) LuaObject::getme(L, 1); if (cd) cd->show_iso_infos(); else L->error("Cdutils object void"); break; case CDTOOL_PATH: if (n) cd = (cdutils *) LuaObject::getme(L, 1); if (cd) cd->show_pt_infos(); else L->error("Cdutils object void"); break; case CDTOOL_PRINTDIR: p = L->tostring(1); if (n == 2) cd = (cdutils *) LuaObject::getme(L, 2); if (cd) { char * f; cdutils::DirEntry dir = cd->find_path(f = p.strdup()); free(f); if (!dir.R) L->error("Path `" + p + "' not found"); if (!(dir.Flags & 2)) L->error("Path `" + p + "' points to a file"); cd->show_head_entry(); cd->show_dir(&dir); } else L->error("Cdutils object void"); break; } return r; } int lga = 0; enum { NO_OPTION = 0, DVD_IN, DVD_OUT, }; int getopt_flag = NO_OPTION; struct option long_options[] = { {"help", 0, NULL, 'h'}, {"verbose", 0, NULL, 'v'}, {"file", 1, NULL, 'f'}, {"write", 0, NULL, 'w'}, {"output", 1, NULL, 'o'}, {"archive", 1, NULL, 'a'}, {"compile", 1, NULL, 'c'}, {"debug", 0, NULL, 'd'}, {"interactive", 0, NULL, 'i'}, {"line", 0, NULL, 'l'}, {"exec", 1, NULL, 'e'}, {"built-in", 0, NULL, 'b'}, {"probe", 0, NULL, 'p'}, {"log", 1, NULL, 'g'}, {"dvd_in", 1, &getopt_flag, DVD_IN}, {"dvd_out", 1, &getopt_flag, DVD_OUT}, {0, 0, NULL, 0 } }; static Uint32 elf_hash(const unsigned char * name) { Uint32 h = 0, g; while (*name) { h = (h << 4) + *name++; if ((g = h & 0xf0000000)) h ^= g >> 24; h &= ~g; } return h; } static int lua_elf_hash(lua_State * __L) { Lua * L = Lua::find(__L); String t = L->tostring(); L->push((lua_Number) elf_hash((unsigned char *) t.to_charp())); return 1; } CODE_BEGINS /* That's the basic lua starter for non interactive mode */ Lua * start_basic_lua(void) { Lua * L = new Lua(); L->open_base(); L->open_math(); L->open_string(); L->open_table(); L->open_dir(); LuaInput::pushconstruct(L); LuaOutput::pushconstruct(L); LuaBuffer::pushconstruct(L); LuaConfigFile::pushstatics(L); LuaRegex::pushstatics(L); CD_PUSHSTATICS(L); Luapsx::pushstatics(L); L->push("print"); L->push(myprint); L->setvar(); L->push("hash"); L->push(lua_elf_hash); L->setvar(); Luabasecdtool::pushstatics(L); return L; } /* That's the extended stuff for interactive mode */ Lua * start_full_lua(void) { Lua * L = start_basic_lua(); Luacdtool::pushstatics(L); return L; } void showbanner() { printm(M_BARE, "CD-Tool version " VERSION " (c) 2003-2007 Nicolas \"Pixel\" Noble\n" LUA_RELEASE " " LUA_COPYRIGHT "\n" #ifdef WIP "Special version Work In Progress, compiled the " __DATE__ " at " __TIME__ "\n" #endif "This is free software with ABSOLUTELY NO WARRANTY.\n" "\n"); } void showhelp(bool longhelp = false) { printm(M_BARE, "Usage:\n" "%s [options] [lua-script1] [lua-script2] ...\n" "\n" "Options:\n" " -v for verbose mode.\n" " -f to load an initial iso file (object cdutil).\n" " -w to open the previous iso file in write mode.\n" " -o to start creating an output iso (object iso).\n" " -a to load an additionnal archive file.\n" " -c to dump the compiled byte code to file.\n" " -d to enable debug mode (ie, do not strip)\n" " -i to start interactive mode.\n" " -l to turn off the exec on end line.\n" " -e to execute this single command in LUA.\n" " -b to force the use of the built-in cd-tool.lua\n" " -p to run a CD device probe.\n" " -g to log into a file.\n" " -h for a help page.\n" " --dvd_in replaces -f with a 2048-bytes iso.\n" " --dvd_out replaces -o with a 2048-bytes iso.\n" , argv[0]); if (longhelp) printm(M_BARE, "\n" "Verbose mode can be somewhat a floody thing.\n" "Options -i/-e and -c are mutually exclusive.\n" "Options -i and -e are NOT mutually exclusive. For example:\n" "\n" " $ %s -i -e \"main()\" somescript.lua\n" "\n" "This will first load the script 'somescript.lua', then execute main, and\n" "afterward, start the interactive mode.\n" "\n" "If a script contains inlined code, it will be run right after loading.\n" , argv[0]); } void probe(void) { std::vector p; if (!cdabstract::canprobe()) { printm(M_ERROR, "Can't probe on this platform.\n"); exit(-1); } p = cdabstract::probe(); printm(M_BARE, "Alvaible devices:\n"); for (std::vector::iterator i = p.begin(); i != p.end(); i++) { printm(M_BARE, *i + "\n"); } } class cd_tool_printer_t : public printer_t { public: cd_tool_printer_t(Handle * h) : log(h) { } virtual bool printm(int level, const char * format, va_list ap) { char tmp[10241]; vsprintf(tmp, format, ap); (*log) << tmp; return true; } private: Handle * log; }; virtual int startup() throw (GeneralException) { char c; bool auto_exec = true, strip = true, todo = false, runit, write = false, builtin = false; char * file = 0, * output = 0, * compile = 0, * exec = 0, * line_read = 0, * dvd_in = 0, * dvd_out = 0; char prompt[10]; Lua * L = 0; Handle * read_iso = 0, * build_iso = 0, * write_iso = 0; Buffer command; String line, endline; int pos; verbosity = M_WARNING; showbanner(); /* Let's start parsing options */ while ((c = getopt_long(argc, argv, "Hhvf:wo:a:c:dile:pbg:", long_options, NULL)) != EOF) { switch (c) { case 'h': case 'H': case '?': showhelp(true); throw Exit(0); case 'v': verbosity = M_INFO; break; case 'f': file = strdup(optarg); break; case 'w': write = true; break; case 'o': output = strdup(optarg); break; case 'a': new Archive(optarg); break; case 'c': compile = strdup(optarg); break; case 'd': strip = false; break; case 'i': interactive = true; todo = true; break; case 'l': auto_exec = false; break; case 'e': exec = strdup(optarg); todo = true; break; case 'p': probe(); throw Exit(0); case 'b': builtin = true; break; case 'g': printer = new cd_tool_printer_t(new Output(optarg)); break; case 0: if (!getopt_flag) { showhelp(); throw Exit(-1); } switch(getopt_flag) { case DVD_IN: dvd_in = strdup(optarg); break; case DVD_OUT: dvd_out = strdup(optarg); break; } getopt_flag = NO_OPTION; break; default: showhelp(); throw Exit(-1); } } if (interactive) L = start_full_lua(); else L = start_basic_lua(); /* Loading cd-tool.lua (only when not compiling) */ if (!compile && !builtin) { try { L->load(&Input("cd-tool.lua")); } catch (GeneralException e) { printm(M_WARNING, "There was an error loading cd-tool.lua, using built-in: %s\n", e.GetMsg()); builtin = true; } } if (!compile && builtin) { Buffer built; built.write(cd_tool_lua, cd_tool_lua_size); try { L->load(&built); } catch (GeneralException e) { printm(M_WARNING, "There was an error loading built-in cd-tool.lua: %s\n", e.GetMsg()); } } /* Loading all the scripts */ while (optind < argc) { todo = true; L->load(&Input(argv[optind++]), !compile); } /* Doh... */ if (!todo) { showhelp(); throw Exit(0); } /* Compilation process will exit from itself right after */ if (compile) { L->dump(&Output(compile), strip); throw Exit(0); } /* Sanity checks */ if (dvd_in && file) throw GeneralException("Error: you can't have both --dvd_in and -f at the same time."); if (dvd_out && output) throw GeneralException("Error: you can't have both --dvd_out and -o at the same time."); /* The basic input (and eventually output) iso file */ if (file) { /* The write mode can't apply on a CD of course... */ if (write) { read_iso = new Input(file); write_iso = new Output(file, 0, 0); } else { read_iso = cdabstract::open_cd(file); } } /* Same as above, but with dvd stuff */ if (dvd_in) { read_iso = new dvdabstract(new Input(dvd_in)); if (write) { write_iso = new dvdabstract(new Output(dvd_in, 0, 0)); } } /* Let's create the cdutils object and push it to the LUA stack. */ if (read_iso) { cdutil = new cdutils(read_iso, write_iso); if (!cdutil->get_iso_infos()) throw Exit(-1); Luacdutils lcdutil(cdutil); L->push("cdutil"); lcdutil.push(L); L->setvar(); } /* The generated iso file */ if (output || dvd_out) { if (output) build_iso = new Output(output); else build_iso = new dvdabstract(new Output(dvd_out)); build = new isobuilder(build_iso); Luaisobuilder lbuild(build); L->push("iso"); lbuild.push(L); L->setvar(); } /* One shot command */ if (exec) { command << exec; L->load(&command); } /* Interactive mode loop */ strcpy(prompt, "> "); #ifdef _WIN32 rl_getc_function = my_getc; #endif rl_bind_key('\t', rl_insert); while (interactive) { /* Basic usage of readline */ if (line_read) free(line_read); line_read = readline(prompt); if (!line_read) { printm(M_BARE, "\n"); break; } if (*line_read) add_history(line_read); line = line_read; line = line.trim(); endline = ""; /* Splitting the line between ;; */ while (line.strlen()) { runit = false; if ((pos = line.strstr(";;")) >= 0) { endline = line.extract(pos + 2); line = line.extract(0, pos); runit = true; } else { endline = ""; } if (line[line.strlen() - 1] == '\\') { line[line.strlen() - 1] = ' '; } else if (auto_exec) { runit = true; } command << line; if (runit) { try { L->load(&command); } catch (LuaException e) { /* If there was an error, ignore it, and free the stack */ while(L->gettop()) L->pop(); printm(M_ERROR, "%s\n", e.GetMsg()); } catch (GeneralException e) { /* A more severe exception... */ while(L->gettop()) L->pop(); printm(M_ERROR, "Aborted. LUA caused the following exception: %s\n", e.GetMsg()); } strcpy(prompt, "> "); } else { strcpy(prompt, "- "); command << "\n"; } line = endline.trim(); } } /* Finishing off the work, cleaning out the dust */ if (output) { delete build; delete build_iso; } if (file) { delete cdutil; } return 0; } CODE_ENDS