/* * Hack -- Execute a script function */ static void do_cmd_wiz_script(void) { int err; char name[80]; /* Get name of script to execute */ name[0] = '\0'; if (!get_string("Function name: ", name, 80)) return; /* No name, no execute */ if (name[0] == '\0') { msg_print("Cancelled."); return; } /* Execute script */ err = script_execute(name); /* Error */ if (err) { msg_print("Failed."); return; } }
int main(int argc, char *argv[]) { bool daemonize; int ch; int rv; daemonize = false; while ((ch = getopt(argc, argv, "d")) != -1) { switch (ch) { case 'd': daemonize = true; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc != 1) usage(); if (daemonize) { rv = daemon(1, 0); if (rv == -1) err(1, "daemon"); } script_execute(argv[0]); return (0); }
static bool start_script_animation (ply_boot_splash_plugin_t *plugin) { assert (plugin != NULL); plugin->script_state = script_state_new (plugin); plugin->script_image_lib = script_lib_image_setup (plugin->script_state, plugin->image_dir); plugin->script_sprite_lib = script_lib_sprite_setup (plugin->script_state, plugin->displays); plugin->script_plymouth_lib = script_lib_plymouth_setup (plugin->script_state, plugin->mode); plugin->script_math_lib = script_lib_math_setup (plugin->script_state); plugin->script_string_lib = script_lib_string_setup (plugin->script_state); ply_trace ("executing script file"); script_return_t ret = script_execute (plugin->script_state, plugin->script_main_op); script_obj_unref (ret.object); if (plugin->keyboard != NULL) ply_keyboard_add_input_handler (plugin->keyboard, (ply_keyboard_input_handler_t) on_keyboard_input, plugin); on_timeout (plugin); return true; }
static inline void maybe_script_execute (const char *file, char *const argv[], char *const envp[], int xflags) { if (SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15) && (xflags & SPAWN_XFLAGS_TRY_SHELL) && errno == ENOEXEC) script_execute (file, argv, envp); }
script_lib_math_data_t *script_lib_math_setup (script_state_t *state) { script_lib_math_data_t *data = malloc (sizeof (script_lib_math_data_t)); srand ((int) ply_get_timestamp ()); script_obj_t *math_hash = script_obj_hash_get_element (state->global, "Math"); script_add_native_function (math_hash, "Cos", script_lib_math_double_from_double_function, cos, "value", NULL); script_add_native_function (math_hash, "Sin", script_lib_math_double_from_double_function, sin, "value", NULL); script_add_native_function (math_hash, "Tan", script_lib_math_double_from_double_function, tan, "value", NULL); script_add_native_function (math_hash, "ATan2", script_lib_math_double_from_double_double_function, atan2, "value_a", "value_b", NULL); script_add_native_function (math_hash, "Sqrt", script_lib_math_double_from_double_function, sqrt, "value", NULL); script_add_native_function (math_hash, "Int", script_lib_math_double_from_double_function, floor, "value", NULL); script_add_native_function (math_hash, "Random", script_lib_math_random, NULL, NULL); script_obj_unref (math_hash); data->script_main_op = script_parse_string (script_lib_math_string, "script-lib-math.script"); script_return_t ret = script_execute (state, data->script_main_op); script_obj_unref (ret.object); return data; }
static bool start_script_animation (ply_boot_splash_plugin_t *plugin) { ply_list_node_t *node; script_obj_t *target_obj; script_obj_t *value_obj; script_env_var_t *env_var; assert (plugin != NULL); plugin->script_state = script_state_new (plugin); for (node = ply_list_get_first_node (plugin->script_env_vars); node != NULL; node = ply_list_get_next_node (plugin->script_env_vars, node)) { env_var = ply_list_node_get_data (node); target_obj = script_obj_hash_get_element (plugin->script_state->global, env_var->key); value_obj = script_obj_new_string (env_var->value); script_obj_assign (target_obj, value_obj); } plugin->script_image_lib = script_lib_image_setup (plugin->script_state, plugin->image_dir); plugin->script_sprite_lib = script_lib_sprite_setup (plugin->script_state, plugin->displays); plugin->script_plymouth_lib = script_lib_plymouth_setup (plugin->script_state, plugin->mode); plugin->script_math_lib = script_lib_math_setup (plugin->script_state); plugin->script_string_lib = script_lib_string_setup (plugin->script_state); ply_trace ("executing script file"); script_return_t ret = script_execute (plugin->script_state, plugin->script_main_op); script_obj_unref (ret.object); if (plugin->keyboard != NULL) ply_keyboard_add_input_handler (plugin->keyboard, (ply_keyboard_input_handler_t) on_keyboard_input, plugin); on_timeout (plugin); return true; }
script_lib_plymouth_data_t *script_lib_plymouth_setup (script_state_t *state, ply_boot_splash_mode_t mode) { script_lib_plymouth_data_t *data = malloc (sizeof(script_lib_plymouth_data_t)); data->script_refresh_func = script_obj_new_null (); data->script_boot_progress_func = script_obj_new_null (); data->script_root_mounted_func = script_obj_new_null (); data->script_keyboard_input_func = script_obj_new_null (); data->script_update_status_func = script_obj_new_null (); data->script_display_normal_func = script_obj_new_null (); data->script_display_password_func = script_obj_new_null (); data->script_display_question_func = script_obj_new_null (); data->script_display_message_func = script_obj_new_null (); data->script_hide_message_func = script_obj_new_null (); data->script_quit_func = script_obj_new_null (); data->mode = mode; script_obj_t *plymouth_hash = script_obj_hash_get_element (state->global, "Plymouth"); script_add_native_function (plymouth_hash, "SetRefreshFunction", plymouth_set_function, &data->script_refresh_func, "function", NULL); script_add_native_function (plymouth_hash, "SetBootProgressFunction", plymouth_set_function, &data->script_boot_progress_func, "function", NULL); script_add_native_function (plymouth_hash, "SetRootMountedFunction", plymouth_set_function, &data->script_root_mounted_func, "function", NULL); script_add_native_function (plymouth_hash, "SetKeyboardInputFunction", plymouth_set_function, &data->script_keyboard_input_func, "function", NULL); script_add_native_function (plymouth_hash, "SetUpdateStatusFunction", plymouth_set_function, &data->script_update_status_func, "function", NULL); script_add_native_function (plymouth_hash, "SetDisplayNormalFunction", plymouth_set_function, &data->script_display_normal_func, "function", NULL); script_add_native_function (plymouth_hash, "SetDisplayPasswordFunction", plymouth_set_function, &data->script_display_password_func, "function", NULL); script_add_native_function (plymouth_hash, "SetDisplayQuestionFunction", plymouth_set_function, &data->script_display_question_func, "function", NULL); script_add_native_function (plymouth_hash, "SetDisplayMessageFunction", plymouth_set_function, &data->script_display_message_func, "function", NULL); script_add_native_function (plymouth_hash, "SetHideMessageFunction", plymouth_set_function, &data->script_hide_message_func, "function", NULL); script_add_native_function (plymouth_hash, "SetQuitFunction", plymouth_set_function, &data->script_quit_func, "function", NULL); script_add_native_function (plymouth_hash, "GetMode", plymouth_get_mode, data, NULL); script_obj_unref (plymouth_hash); data->script_main_op = script_parse_string (script_lib_plymouth_string, "script-lib-plymouth.script"); script_return_t ret = script_execute (state, data->script_main_op); script_obj_unref (ret.object); /* Throw anything sent back away */ return data; }
/* Create a new connection, storing it in the list of clients. */ ship_client_t *client_create_connection(int sock, int version, int type, struct client_queue *clients, ship_t *ship, block_t *block, struct sockaddr *ip, socklen_t size) { ship_client_t *rv = (ship_client_t *)malloc(sizeof(ship_client_t)); uint32_t client_seed_dc, server_seed_dc; uint8_t client_seed_bb[48], server_seed_bb[48]; int i; pthread_mutexattr_t attr; struct mt19937_state *rng; if(!rv) { perror("malloc"); return NULL; } memset(rv, 0, sizeof(ship_client_t)); if(type == CLIENT_TYPE_BLOCK) { rv->pl = (player_t *)malloc(sizeof(player_t)); if(!rv->pl) { perror("malloc"); free(rv); close(sock); return NULL; } memset(rv->pl, 0, sizeof(player_t)); if(!(rv->enemy_kills = (uint32_t *)malloc(sizeof(uint32_t) * 0x60))) { perror("malloc"); free(rv->pl); free(rv); close(sock); return NULL; } if(version == CLIENT_VERSION_BB) { rv->bb_pl = (sylverant_bb_db_char_t *)malloc(sizeof(sylverant_bb_db_char_t)); if(!rv->bb_pl) { perror("malloc"); free(rv->pl); free(rv); close(sock); return NULL; } rv->bb_opts = (sylverant_bb_db_opts_t *)malloc(sizeof(sylverant_bb_db_opts_t)); if(!rv->bb_opts) { perror("malloc"); free(rv->bb_pl); free(rv->pl); free(rv); close(sock); return NULL; } memset(rv->bb_pl, 0, sizeof(sylverant_bb_db_char_t)); memset(rv->bb_opts, 0, sizeof(sylverant_bb_db_opts_t)); } } /* Store basic parameters in the client structure. */ rv->sock = sock; rv->version = version; rv->cur_block = block; rv->arrow = 1; rv->last_message = rv->login_time = time(NULL); rv->hdr_size = 4; /* Create the mutex */ pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&rv->mutex, &attr); pthread_mutexattr_destroy(&attr); memcpy(&rv->ip_addr, ip, size); if(ip->sa_family == AF_INET6) { rv->flags |= CLIENT_FLAG_IPV6; } /* Make sure any packets sent early bail... */ rv->ckey.type = 0xFF; rv->skey.type = 0xFF; if(type == CLIENT_TYPE_SHIP) { rv->flags |= CLIENT_FLAG_TYPE_SHIP; rng = &ship->rng; } else { rng = &block->rng; } #ifdef HAVE_PYTHON rv->pyobj = client_pyobj_create(rv); if(!rv->pyobj) { goto err; } if(type == CLIENT_TYPE_SHIP) { script_execute(ScriptActionClientShipLogin, rv->pyobj, NULL); } else { script_execute(ScriptActionClientBlockLogin, rv->pyobj, NULL); } #endif switch(version) { case CLIENT_VERSION_DCV1: case CLIENT_VERSION_DCV2: case CLIENT_VERSION_PC: /* Generate the encryption keys for the client and server. */ client_seed_dc = mt19937_genrand_int32(rng); server_seed_dc = mt19937_genrand_int32(rng); CRYPT_CreateKeys(&rv->skey, &server_seed_dc, CRYPT_PC); CRYPT_CreateKeys(&rv->ckey, &client_seed_dc, CRYPT_PC); /* Send the client the welcome packet, or die trying. */ if(send_dc_welcome(rv, server_seed_dc, client_seed_dc)) { goto err; } break; case CLIENT_VERSION_GC: case CLIENT_VERSION_EP3: /* Generate the encryption keys for the client and server. */ client_seed_dc = mt19937_genrand_int32(rng); server_seed_dc = mt19937_genrand_int32(rng); CRYPT_CreateKeys(&rv->skey, &server_seed_dc, CRYPT_GAMECUBE); CRYPT_CreateKeys(&rv->ckey, &client_seed_dc, CRYPT_GAMECUBE); /* Send the client the welcome packet, or die trying. */ if(send_dc_welcome(rv, server_seed_dc, client_seed_dc)) { goto err; } break; case CLIENT_VERSION_BB: /* Generate the encryption keys for the client and server. */ for(i = 0; i < 48; i += 4) { client_seed_dc = mt19937_genrand_int32(rng); server_seed_dc = mt19937_genrand_int32(rng); client_seed_bb[i + 0] = (uint8_t)(client_seed_dc >> 0); client_seed_bb[i + 1] = (uint8_t)(client_seed_dc >> 8); client_seed_bb[i + 2] = (uint8_t)(client_seed_dc >> 16); client_seed_bb[i + 3] = (uint8_t)(client_seed_dc >> 24); server_seed_bb[i + 0] = (uint8_t)(server_seed_dc >> 0); server_seed_bb[i + 1] = (uint8_t)(server_seed_dc >> 8); server_seed_bb[i + 2] = (uint8_t)(server_seed_dc >> 16); server_seed_bb[i + 3] = (uint8_t)(server_seed_dc >> 24); } CRYPT_CreateKeys(&rv->skey, server_seed_bb, CRYPT_BLUEBURST); CRYPT_CreateKeys(&rv->ckey, client_seed_bb, CRYPT_BLUEBURST); rv->hdr_size = 8; /* Send the client the welcome packet, or die trying. */ if(send_bb_welcome(rv, server_seed_bb, client_seed_bb)) { goto err; } break; } /* Insert it at the end of our list, and we're done. */ if(type == CLIENT_TYPE_BLOCK) { pthread_rwlock_wrlock(&block->lock); TAILQ_INSERT_TAIL(clients, rv, qentry); ++block->num_clients; pthread_rwlock_unlock(&block->lock); } else { TAILQ_INSERT_TAIL(clients, rv, qentry); } ship_inc_clients(ship); return rv; err: close(sock); if(type == CLIENT_TYPE_BLOCK) { free(rv->enemy_kills); free(rv->pl); } #ifdef HAVE_PYTHON client_pyobj_invalidate(rv); Py_XDECREF(rv->pyobj); #endif pthread_mutex_destroy(&rv->mutex); free(rv); return NULL; }
/* Destroy a connection, closing the socket and removing it from the list. This must always be called with the appropriate lock held for the list! */ void client_destroy_connection(ship_client_t *c, struct client_queue *clients) { time_t now = time(NULL); char tstr[26]; TAILQ_REMOVE(clients, c, qentry); /* If the client was on Blue Burst, update their db character */ if(c->version == CLIENT_VERSION_BB && !(c->flags & CLIENT_FLAG_TYPE_SHIP)) { c->bb_pl->character.play_time += now - c->login_time; shipgate_send_cdata(&ship->sg, c->guildcard, c->sec_data.slot, c->bb_pl, sizeof(sylverant_bb_db_char_t), c->cur_block->b); shipgate_send_bb_opts(&ship->sg, c); } #ifdef HAVE_PYTHON if(c->flags & CLIENT_FLAG_TYPE_SHIP) { script_execute(ScriptActionClientShipLogout, c->pyobj, NULL); } else { script_execute(ScriptActionClientBlockLogout, c->pyobj, NULL); } #endif /* If the user was on a block, notify the shipgate */ if(c->version != CLIENT_VERSION_BB && c->pl && c->pl->v1.name[0]) { shipgate_send_block_login(&ship->sg, 0, c->guildcard, c->cur_block->b, c->pl->v1.name); } else if(c->version == CLIENT_VERSION_BB && c->bb_pl) { shipgate_send_block_login_bb(&ship->sg, 0, c->guildcard, c->cur_block->b, c->bb_pl->character.name); } ship_dec_clients(ship); /* If the client has a lobby sitting around that was created but not added to the list of lobbies, destroy it */ if(c->create_lobby) { lobby_destroy_noremove(c->create_lobby); } /* If we were logging the user, close the file */ if(c->logfile) { ctime_r(&now, tstr); tstr[strlen(tstr) - 1] = 0; fprintf(c->logfile, "[%s] Connection closed\n", tstr); fclose(c->logfile); } if(c->sock >= 0) { close(c->sock); } if(c->recvbuf) { free(c->recvbuf); } if(c->sendbuf) { free(c->sendbuf); } if(c->autoreply) { free(c->autoreply); } if(c->enemy_kills) { free(c->enemy_kills); } if(c->pl) { free(c->pl); } if(c->bb_pl) { free(c->bb_pl); } if(c->bb_opts) { free(c->bb_opts); } if(c->next_maps) { free(c->next_maps); } pthread_mutex_destroy(&c->mutex); #ifdef HAVE_PYTHON client_pyobj_invalidate(c); Py_XDECREF(c->pyobj); #endif free(c); }
/* Spawn a new process executing PATH with the attributes describes in *ATTRP. Before running the process perform the actions described in FILE-ACTIONS. */ int __spawni (pid_t *pid, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[], int use_path) { pid_t new_pid; char *path, *p, *name; size_t len; size_t pathlen; /* Do this once. */ short int flags = attrp == NULL ? 0 : attrp->_flags; /* Avoid gcc warning "variable 'flags' might be clobbered by 'longjmp' or 'vfork'" */ (void) &flags; /* Generate the new process. */ #if HAVE_VFORK if ((flags & POSIX_SPAWN_USEVFORK) != 0 /* If no major work is done, allow using vfork. Note that we might perform the path searching. But this would be done by a call to execvp(), too, and such a call must be OK according to POSIX. */ || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0 && file_actions == NULL)) new_pid = vfork (); else #endif new_pid = fork (); if (new_pid != 0) { if (new_pid < 0) return errno; /* The call was successful. Store the PID if necessary. */ if (pid != NULL) *pid = new_pid; return 0; } /* Set signal mask. */ if ((flags & POSIX_SPAWN_SETSIGMASK) != 0 && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0) _exit (SPAWN_ERROR); /* Set signal default action. */ if ((flags & POSIX_SPAWN_SETSIGDEF) != 0) { /* We have to iterate over all signals. This could possibly be done better but it requires system specific solutions since the sigset_t data type can be very different on different architectures. */ int sig; struct sigaction sa; memset (&sa, '\0', sizeof (sa)); sa.sa_handler = SIG_DFL; for (sig = 1; sig <= NSIG; ++sig) if (sigismember (&attrp->_sd, sig) != 0 && sigaction (sig, &sa, NULL) != 0) _exit (SPAWN_ERROR); } #if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER) /* Set the scheduling algorithm and parameters. */ if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER)) == POSIX_SPAWN_SETSCHEDPARAM) { if (sched_setparam (0, &attrp->_sp) == -1) _exit (SPAWN_ERROR); } else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0) { if (sched_setscheduler (0, attrp->_policy, (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0 ? &attrp->_sp : NULL) == -1) _exit (SPAWN_ERROR); } #endif /* Set the process group ID. */ if ((flags & POSIX_SPAWN_SETPGROUP) != 0 && setpgid (0, attrp->_pgrp) != 0) _exit (SPAWN_ERROR); /* Set the effective user and group IDs. */ if ((flags & POSIX_SPAWN_RESETIDS) != 0 && (local_seteuid (getuid ()) != 0 || local_setegid (getgid ()) != 0)) _exit (SPAWN_ERROR); /* Execute the file actions. */ if (file_actions != NULL) { int cnt; for (cnt = 0; cnt < file_actions->_used; ++cnt) { struct __spawn_action *action = &file_actions->_actions[cnt]; switch (action->tag) { case spawn_do_close: if (close_not_cancel (action->action.close_action.fd) != 0) /* Signal the error. */ _exit (SPAWN_ERROR); break; case spawn_do_open: { int new_fd = open_not_cancel (action->action.open_action.path, action->action.open_action.oflag | O_LARGEFILE, action->action.open_action.mode); if (new_fd == -1) /* The `open' call failed. */ _exit (SPAWN_ERROR); /* Make sure the desired file descriptor is used. */ if (new_fd != action->action.open_action.fd) { if (dup2 (new_fd, action->action.open_action.fd) != action->action.open_action.fd) /* The `dup2' call failed. */ _exit (SPAWN_ERROR); if (close_not_cancel (new_fd) != 0) /* The `close' call failed. */ _exit (SPAWN_ERROR); } } break; case spawn_do_dup2: if (dup2 (action->action.dup2_action.fd, action->action.dup2_action.newfd) != action->action.dup2_action.newfd) /* The `dup2' call failed. */ _exit (SPAWN_ERROR); break; } } } if (! use_path || strchr (file, '/') != NULL) { /* The FILE parameter is actually a path. */ execve (file, argv, envp); if (errno == ENOEXEC) script_execute (file, argv, envp); /* Oh, oh. `execve' returns. This is bad. */ _exit (SPAWN_ERROR); } /* We have to search for FILE on the path. */ path = getenv ("PATH"); if (path == NULL) { #if HAVE_CONFSTR /* There is no `PATH' in the environment. The default search path is the current directory followed by the path `confstr' returns for `_CS_PATH'. */ len = confstr (_CS_PATH, (char *) NULL, 0); path = (char *) alloca (1 + len); path[0] = ':'; (void) confstr (_CS_PATH, path + 1, len); #else /* Pretend that the PATH contains only the current directory. */ path = ""; #endif } len = strlen (file) + 1; pathlen = strlen (path); name = alloca (pathlen + len + 1); /* Copy the file name at the top. */ name = (char *) memcpy (name + pathlen + 1, file, len); /* And add the slash. */ *--name = '/'; p = path; do { char *startp; path = p; p = strchrnul (path, ':'); if (p == path) /* Two adjacent colons, or a colon at the beginning or the end of `PATH' means to search the current directory. */ startp = name + 1; else startp = (char *) memcpy (name - (p - path), path, p - path); /* Try to execute this name. If it works, execv will not return. */ execve (startp, argv, envp); if (errno == ENOEXEC) script_execute (startp, argv, envp); switch (errno) { case EACCES: case ENOENT: case ESTALE: case ENOTDIR: /* Those errors indicate the file is missing or not executable by us, in which case we want to just try the next path directory. */ break; default: /* Some other error means we found an executable file, but something went wrong executing it; return the error to our caller. */ _exit (SPAWN_ERROR); } } while (*p++ != '\0'); /* Return with an error. */ _exit (SPAWN_ERROR); }
static bool zendan(struct program_config *c) { //script test run { static const wgChar *functionname[] = { wgT("cpu_erase"), wgT("ppu_erase"), wgT("erase_wait"), wgT("program_main") }; HSQUIRRELVM v = qr_open(&c->log); int i; for(i = 0; i < sizeof(functionname)/sizeof(wgChar *); i++){ qr_function_register_global(v, functionname[i], script_nop); } qr_function_register_global(v, _SC("cpu_write"), cpu_write_check); qr_function_register_global(v, _SC("cpu_command"), cpu_command); qr_function_register_global(v, _SC("cpu_program"), cpu_program_count); qr_function_register_global(v, _SC("ppu_program"), ppu_program_count); qr_function_register_global(v, _SC("ppu_command"), ppu_command); qr_function_register_global(v, _SC("vram_mirrorfind"), vram_mirrorfind); if(script_execute(v, wgT("testrun"), c) == false){ qr_close(v); return false; } qr_close(v); assert(c->cpu.memory.size != 0); if(c->cpu.programming.count % c->cpu.memory.size != 0){ c->log.append(c->log.object, wgT("logical error: cpu_programsize is not connected 0x%06x/0x%06x\n"), (int) c->cpu.programming.count, (int) c->cpu.memory.size); return false; } if(c->ppu.memory.size != 0){ if(c->ppu.programming.count % c->ppu.memory.size != 0){ c->log.append(c->log.object, wgT("logical error: ppu_programsize is not connected 0x%06x/0x%06x\n"), (int) c->ppu.programming.count, (int) c->ppu.memory.size); return false; } } } //script execute //SQBool ret; c->cpu.command_change = true; gauge_init(&c->cpu); c->ppu.command_change = true; gauge_init(&c->ppu); { HSQUIRRELVM v = qr_open(&c->log); qr_function_register_global(v, _SC("cpu_write"), cpu_write); qr_function_register_global(v, _SC("cpu_erase"), cpu_erase); qr_function_register_global(v, _SC("cpu_program"), cpu_program_memory); qr_function_register_global(v, _SC("cpu_command"), cpu_command); qr_function_register_global(v, _SC("ppu_erase"), ppu_erase); qr_function_register_global(v, _SC("ppu_program"), ppu_program_memory); qr_function_register_global(v, _SC("ppu_command"), ppu_command); qr_function_register_global(v, _SC("program_main"), program_main); qr_function_register_global(v, _SC("erase_wait"), erase_wait); qr_function_register_global(v, _SC("vram_mirrorfind"), script_nop); script_execute(v, wgT("program"), c); //assert(sq_gettype(v, -2) == OT_BOOL); //sq_getbool(v, -1, &ret); qr_close(v); } return true; //ret == SQTrue ? true : false; }