/*************************************************************************** gbx_subr_misc.c (c) 2000-2017 BenoƮt Minisini 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ***************************************************************************/ #include #include #include "gb_common.h" #include "gbx_subr.h" #include "gbx_class.h" #include "gambas.h" #include "gbx_eval.h" #include "gbx_date.h" #include "gbx_archive.h" #include "gbx_api.h" #include "gbx_c_collection.h" #include "gbx_c_process.h" #include "gbx_debug.h" #include "gbx_watch.h" #include "gbx_math.h" static EVAL_INTERFACE EVAL; static CCOLLECTION *eval_env; static void init_eval() { static bool init = FALSE; if (init) return; COMPONENT_load(COMPONENT_create("gb.eval")); LIBRARY_get_interface_by_name("gb.eval", EVAL_INTERFACE_VERSION, &EVAL); init = TRUE; } void SUBR_error(void) { SP->type = T_BOOLEAN; SP->_boolean.value = EXEC_got_error ? -1 : 0; SP++; } void SUBR_wait(ushort code) { SUBR_ENTER(); code &= 0x1F; EXEC_set_native_error(FALSE); if (code == 0) GB_Wait(0); else if (code == 1) { int delay = (int)(SUBR_get_float(PARAM) * 1000 + 0.5); if (delay < 0) delay = 0; GB_Wait(delay); } else if (code == 2) { NPARAM = 0; GB_Wait(-1); } if (EXEC_has_native_error()) { EXEC_set_native_error(FALSE); PROPAGATE(); } SUBR_LEAVE_VOID(); } void SUBR_sleep(ushort code) { SUBR_ENTER_PARAM(1); switch(code & 0x3F) { case 0: // Sleep { double wait; struct timespec rem; wait = SUBR_get_float(PARAM); rem.tv_sec = (time_t)(int)wait; rem.tv_nsec = (int)(frac(wait) * 1E9); while (nanosleep(&rem, &rem) < 0); break; } case 1: // Use { char *name = SUBR_get_string(PARAM); COMPONENT *comp = COMPONENT_find(name); if (!comp) comp = COMPONENT_create(name); COMPONENT_load(comp); break; } case 2: // CheckExec { CPROCESS_check(PARAM->_object.object); break; } } SUBR_LEAVE(); } static void error_subr_exec(CPROCESS *process) { OBJECT_UNREF(process); } void SUBR_exec(ushort code) { void *cmd; bool wait; int mode; CPROCESS *process; bool ret; bool shell; char *name; CARRAY *env; SUBR_ENTER_PARAM(4); shell = (code & 0x1F) != 0; if (shell) cmd = (void *)SUBR_get_string(PARAM); else { VALUE_conv_object(PARAM, (TYPE)CLASS_StringArray); cmd = (void *)(PARAM->_object.object); } if (!cmd) THROW(E_ARG); if (VALUE_is_null(&PARAM[1])) env = NULL; else { VALUE_conv_object(&PARAM[1], (TYPE)CLASS_StringArray); env = (PARAM[1]._object.object); } VALUE_conv_integer(&PARAM[2]); mode = PARAM[2]._integer.value; wait = mode & PM_WAIT; name = SUBR_get_string(&PARAM[3]); ret = TRUE; // !PCODE_is_void(code); if (shell) mode |= PM_SHELL; //STRING_ref(name); ## This should not be needed process = CPROCESS_create(mode, cmd, name, env); //STRING_unref(&name); if (wait) { OBJECT_REF(process); ON_ERROR_1(error_subr_exec, process) { CPROCESS_wait_for(process, 0); } END_ERROR if (!ret) { OBJECT_UNREF(process); } else if (!process->to_string) { OBJECT_UNREF_KEEP(process); } } if (ret) { if (process->to_string) { char *result = process->result; process->result = NULL; RELEASE_MANY(SP, NPARAM); SP->type = T_STRING; SP->_string.addr = result; SP->_string.start = 0; SP->_string.len = STRING_length(result); SP++; OBJECT_UNREF(process); } else { RETURN->_object.class = CLASS_Process; RETURN->_object.object = process; SUBR_LEAVE(); } } else { SUBR_LEAVE_VOID(); } } static bool get_value(const char *sym, int len, GB_VARIANT *value) { if (eval_env) if (!GB_CollectionGet(eval_env, sym, len, value)) return FALSE; value->type = T_NULL; return TRUE; } void EVAL_string(char *expr) { int len; EXPRESSION *eval; init_eval(); len = strlen(expr); eval_env = NULL; EVAL.New((void **)(void *)&eval, expr, len); if (EVAL.Compile(eval, FALSE)) { GB_Error(eval->error); goto _ERROR; } if (!EVAL.Run(eval, get_value)) goto _ERROR; goto _FREE; _ERROR: EVAL.Free((void **)(void *)&eval); PROPAGATE(); _FREE: EVAL.Free((void **)(void *)&eval); VALUE_to_string(RETURN, &expr, &len); STREAM_write(CSTREAM_TO_STREAM(CFILE_out), expr, len); STREAM_write_eol(CSTREAM_TO_STREAM(CFILE_out)); STREAM_flush(CSTREAM_TO_STREAM(CFILE_out)); } void SUBR_eval(ushort code) { char *expr; int len; EXPRESSION *eval; SUBR_ENTER(); init_eval(); SUBR_get_string_len(PARAM, &expr, &len); if (NPARAM == 2) { VALUE_conv_object(&PARAM[1], (TYPE)CLASS_Collection); eval_env = (CCOLLECTION *)(PARAM[1]._object.object); } else eval_env = NULL; EVAL.New((void **)(void *)&eval, expr, len); if (EVAL.Compile(eval, FALSE)) { GB_Error(eval->error); goto _ERROR; } if (!EVAL.Run(eval, get_value)) goto _ERROR; goto _FREE; _ERROR: EVAL.Free((void **)(void *)&eval); PROPAGATE(); _FREE: EVAL.Free((void **)(void *)&eval); SUBR_LEAVE(); } void SUBR_array(ushort code) { static bool reuse = FALSE; TYPE type; int i, j; CARRAY *array; bool next_reuse; SUBR_ENTER(); next_reuse = code & CODE_CALL_VARIANT; if (reuse) { array = (CARRAY *)(PARAM[-1]._object.object); type = array->type; } else { type = SUBR_check_good_type(PARAM, NPARAM); if (type == T_NULL) type = T_OBJECT; } for (i = 0; i < NPARAM; i++) VALUE_conv(&PARAM[i], type); if (reuse) { j = array->count; CARRAY_resize(array, j + NPARAM); } else { j = 0; GB_ArrayNew(POINTER(&array), type, NPARAM); OBJECT_REF(array); } for (i = 0; i < NPARAM; i++, j++) { GB_Store(type, (GB_VALUE *)&PARAM[i], GB_ArrayGet(array, j)); RELEASE(&PARAM[i]); } if (reuse) { SP = PARAM; } else { PARAM->_object.class = OBJECT_class(array); //CLASS_Array; PARAM->_object.object = array; SP = PARAM + 1; } reuse = next_reuse; } void SUBR_collection(ushort code) { static bool reuse = FALSE; int i; GB_COLLECTION col; char *key; int len; VALUE *vkey, *vval; bool next_reuse; SUBR_ENTER(); next_reuse = code & CODE_CALL_VARIANT; if (reuse) col = (GB_COLLECTION)(PARAM[-1]._object.object); else { GB_CollectionNew(&col, GB_COMP_BINARY); OBJECT_REF(col); } for (i = 0; i < NPARAM; i += 2) { vkey = &PARAM[i]; vval = vkey + 1; SUBR_get_string_len(vkey, &key, &len); VALUE_conv_variant(vval); if (GB_CollectionSet(col, key, len, (GB_VARIANT *)vval)) { OBJECT_UNREF(col); THROW(E_VKEY); } RELEASE_STRING(&PARAM[i]); RELEASE(&PARAM[i + 1]); } if (reuse) { SP = PARAM; } else { PARAM->_object.class = OBJECT_class(col); //CLASS_Array; PARAM->_object.object = col; SP = PARAM + 1; } reuse = next_reuse; }