void c_lt() { int i = sp->type; switch (i | (--sp)->type) { case T_NUMBER: sp->u.number = sp->u.number < (sp+1)->u.number; break; case T_REAL: sp->u.number = sp->u.real < (sp+1)->u.real; sp->type = T_NUMBER; break; case T_NUMBER|T_REAL: if (i == T_NUMBER) { sp->type = T_NUMBER; sp->u.number = sp->u.real < (sp+1)->u.number; } else sp->u.number = sp->u.number < (sp+1)->u.real; break; case T_STRING: i = (strcmp((sp - 1)->u.string, sp->u.string) < 0); free_string_svalue(sp+1); free_string_svalue(sp); sp->type = T_NUMBER; sp->u.number = i; break; default: switch ((sp++)->type) { case T_NUMBER: case T_REAL: bad_argument(sp, T_NUMBER | T_REAL, 2, F_LT); case T_STRING: bad_argument(sp, T_STRING, 2, F_LT); default: bad_argument(sp-1, T_NUMBER | T_STRING | T_REAL, 1, F_LT); } } }
void f_pcre_match(void) { array_t *v; int flag = 0; if (st_num_arg > 2) { if (sp->type != T_NUMBER) error("Bad argument 3 to pcre_match()\n"); if ((sp - 2)->type == T_STRING) error("3rd argument illegal for pcre_match(string, string)\n"); flag = (sp--)->u.number; } if ((sp - 1)->type == T_STRING ) { flag = pcre_match_single((sp-1), sp); free_string_svalue(sp--); free_string_svalue(sp); put_number(flag); } else { v = pcre_match((sp - 1)->u.arr, sp, flag); free_string_svalue(sp--); free_array(sp->u.arr); sp->u.arr = v; } }
void f_query_temp () { int idx; object_t *ob; unsigned short type; svalue_t *value; char *src, *dst; mapping_t *map; char *tmpstr; if( st_num_arg==2 ) { ob=sp->u.ob; pop_stack(); } else ob = current_object; idx = find_global_variable(ob->prog, "tmp_dbase", &type, 0); if (idx == -1) { free_string_svalue(sp--); push_undefined(); return; } value = &ob->variables[idx]; if( value->type != T_MAPPING ) { free_string_svalue(sp--); error("(query_temp) %s 物件的资料库变数型态错误。\n", ob->obname); } map = value->u.map; src = (char *)sp->u.string; dst = tmpstr = (char *)DMALLOC(SVALUE_STRLEN(sp) + 1, TAG_STRING, "query_temp"); while (*src) { while (*src != '/' && *src) *dst++ = *src++; if (*src == '/') { while (*++src == '/'); if( dst == tmpstr ) continue; } *dst = '\0'; value = find_string_in_mapping(map, tmpstr); if( value == &const0u ) break; if( value->type != T_MAPPING ) { if(*src) value = &const0u; break; } map = value->u.map; dst = tmpstr; } FREE(tmpstr); free_string_svalue(sp--); push_svalue(value); }
void f_remove_action (void) { long success; success = remove_action((sp - 1)->u.string, sp->u.string); free_string_svalue(sp--); free_string_svalue(sp); put_number(success); }
/* * Execute a command for an object. Copy the command into a * new buffer, because 'parse_command()' can modify the command. * If the object is not current object, static functions will not * be executed. This will prevent forcing users to do illegal things. * * Return cost of the command executed if success (> 0). * When failure, return 0. */ void f_command (void) { long rc = 0; if (current_object && !(current_object->flags & O_DESTRUCTED)) { char buff[1000]; int save_eval_cost = get_eval(); if (SVALUE_STRLEN(sp) > sizeof(buff) - 1) error("Too long command.\n"); strncpy(buff, sp->u.string, sizeof(buff)); buff[sizeof(buff) - 1] = 0; if (parse_command(buff, current_object)) #ifndef WIN32 rc = save_eval_cost - get_eval(); #else rc = 1; #endif } free_string_svalue(sp); put_number(rc); }
void f_add_action (void) { long flag; if (st_num_arg == 3) { flag = (sp--)->u.number; } else flag = 0; if (sp->type == T_ARRAY) { int i, n = sp->u.arr->size; svalue_t *sv = sp->u.arr->item; for (i = 0; i < n; i++) { if (sv[i].type == T_STRING) { add_action(sp-1, sv[i].u.string, flag & 3); } } free_array((sp--)->u.arr); } else { add_action((sp-1), sp->u.string, flag & 3); free_string_svalue(sp--); } pop_stack(); }
void c_rindex() { int i; switch (sp->type) { #ifndef NO_BUFFER_TYPE case T_BUFFER: { if ((sp-1)->type != T_NUMBER) error("Indexing a buffer with an illegal type.\n"); i = sp->u.buf->size - (sp - 1)->u.number; if ((i > sp->u.buf->size) || (i < 0)) error("Buffer index out of bounds.\n"); i = sp->u.buf->item[i]; free_buffer(sp->u.buf); (--sp)->u.number = i; break; } #endif case T_STRING: { int len = SVALUE_STRLEN(sp); if ((sp-1)->type != T_NUMBER) { error("Indexing a string with an illegal type.\n"); } i = len - (sp - 1)->u.number; if ((i > len) || (i < 0)) error("String index out of bounds.\n"); i = (unsigned char) sp->u.string[i]; free_string_svalue(sp); (--sp)->u.number = i; break; } case T_ARRAY: { array_t *vec = sp->u.arr; if ((sp-1)->type != T_NUMBER) error("Indexing an array with an illegal type\n"); i = vec->size - (sp - 1)->u.number; if (i < 0 || i >= vec->size) error("Array index out of bounds.\n"); assign_svalue_no_free(--sp, &vec->item[i]); free_array(vec); break; } default: error("Indexing from the right on illegal type.\n"); } /* * Fetch value of a variable. It is possible that it is a * variable that points to a destructed object. In that case, * it has to be replaced by 0. */ if (sp->type == T_OBJECT && (sp->u.ob->flags & O_DESTRUCTED)) { free_object(sp->u.ob, "F_RINDEX"); *sp = const0u; } }
void f_crypt (void) { const char *res, *p; char salt[SALT_LEN + 1]; const char *choice = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; if (sp->type == T_STRING && SVALUE_STRLEN(sp) >= 2) { p = sp->u.string; } else { int i; for (i = 0; i < SALT_LEN; i++) salt[i] = choice[random_number(strlen(choice))]; salt[SALT_LEN] = 0; p = salt; } res = string_copy(CRYPT((sp-1)->u.string, p), "f_crypt"); pop_stack(); free_string_svalue(sp); sp->subtype = STRING_MALLOC; sp->u.string = res; }
void f_debugmalloc (void) { char *res; res = dump_debugmalloc((sp - 1)->u.string, sp->u.number); free_string_svalue(--sp); sp->subtype = STRING_MALLOC; sp->u.string = res; }
void f_B2G () { int i; char *istr, *ostr; istr = (char *)sp->u.string; i = SVALUE_STRLEN(sp); if(i == 0) { push_number(0); free_string_svalue(sp); return; } ostr = new_string(i, "f_B2G"); Big2GB(istr, ostr, i); free_string_svalue(sp); put_malloced_string(ostr); }
void f_oldcrypt (void) { char *res, salt[3]; const char *choice = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; if (sp->type == T_STRING && SVALUE_STRLEN(sp) >= 2) { salt[0] = sp->u.string[0]; salt[1] = sp->u.string[1]; free_string_svalue(sp--); } else { salt[0] = choice[random_number(strlen(choice))]; salt[1] = choice[random_number(strlen(choice))]; pop_stack(); } salt[2] = 0; res = string_copy(OLDCRYPT(sp->u.string, salt), "f_crypt"); free_string_svalue(sp); sp->subtype = STRING_MALLOC; sp->u.string = res; }
void f_find_player (void) { object_t *ob; ob = find_living_object(sp->u.string, 1); free_string_svalue(sp); /* safe b/c destructed objects have had their living names removed */ if (ob) { put_unrefed_undested_object(ob, "find_living"); } else { *sp = const0; } }
void f_replace_program P2(int, num_arg, int, instruction) { replace_ob_t *tmp; int name_len; char *name, *xname; program_t *new_prog; int var_offset; if (sp->type != T_STRING) bad_arg(1, instruction); #ifdef DEBUG if (d_flag) debug_message("replace_program called\n"); #endif if (!current_object) error("replace_program called with no current object\n"); if (current_object == simul_efun_ob) error("replace_program on simul_efun object\n"); if (current_object->prog->func_ref) error("cannot replace a program with function references.\n"); name_len = strlen(sp->u.string); name = (char *) DMALLOC(name_len + 3, TAG_TEMPORARY, "replace_program"); xname = name; strcpy(name, sp->u.string); if (name[name_len - 2] != '.' || name[name_len - 1] != 'c') strcat(name, ".c"); if (*name == '/') name++; new_prog = search_inherited(name, current_object->prog, &var_offset); FREE(xname); if (!new_prog) { error("program to replace the current with has to be inherited\n"); } if (!(tmp = retrieve_replace_program_entry())) { tmp = ALLOCATE(replace_ob_t, TAG_TEMPORARY, "replace_program"); tmp->ob = current_object; tmp->next = obj_list_replace; obj_list_replace = tmp; } tmp->new_prog = new_prog; tmp->var_offset = var_offset; #ifdef DEBUG if (d_flag) debug_message("replace_program finished\n"); #endif free_string_svalue(sp--); }
void c_ge() { int i = sp->type; switch ((--sp)->type | i) { case T_NUMBER: sp->u.number = sp->u.number >= (sp+1)->u.number; break; case T_REAL: sp->u.number = sp->u.real >= (sp+1)->u.real; sp->type = T_NUMBER; break; case T_NUMBER | T_REAL: if (i == T_NUMBER) { sp->type = T_NUMBER; sp->u.number = sp->u.real >= (sp+1)->u.number; } else sp->u.number = sp->u.number >= (sp+1)->u.real; break; case T_STRING: i = strcmp(sp->u.string, (sp+1)->u.string) >= 0; free_string_svalue(sp + 1); free_string_svalue(sp); sp->type = T_NUMBER; sp->u.number = i; break; default: { switch ((sp++)->type) { case T_NUMBER: case T_REAL: bad_argument(sp, T_NUMBER | T_REAL, 2, F_GE); case T_STRING: bad_argument(sp, T_STRING, 2, F_GE); default: bad_argument(sp - 1, T_NUMBER | T_STRING | T_REAL, 1, F_GE); } } } }
void f_author_stats (void) { mapping_t *m; if (st_num_arg) { m = get_author_stats(sp->u.string); free_string_svalue(sp--); } else { m = get_author_stats(0); } if (!m) { push_number(0); } else { /* ref count is properly decremented by get_author_stats */ push_mapping(m); } }
void c_exit_foreach (void) { IF_DEBUG(stack_in_use_as_temporary--); if (sp->type == T_REF) { if (!(--sp->u.ref->ref) && sp->u.ref->lvalue == 0) FREE(sp->u.ref); } if ((sp-1)->type == T_LVALUE) { /* mapping */ sp -= 3; free_array((sp--)->u.arr); free_mapping((sp--)->u.map); } else { /* array or string */ sp -= 2; if (sp->type == T_STRING) free_string_svalue(sp--); else free_array((sp--)->u.arr); } }
void f_traceprefix (void) { char *old = 0; if (command_giver && command_giver->interactive) { old = command_giver->interactive->trace_prefix; if (sp->type & T_STRING) { const char *p = sp->u.string; if (*p == '/') p++; command_giver->interactive->trace_prefix = make_shared_string(p); free_string_svalue(sp); } else command_giver->interactive->trace_prefix = 0; } if (old) { put_malloced_string(add_slash(old)); free_string(old); } else *sp = const0; }
void f_pcre_assoc(void) { svalue_t *arg; array_t *vec; arg = sp - st_num_arg + 1; if ((arg + 2)->type != T_ARRAY) error("Bad argument 3 to pcre_assoc()\n"); vec = pcre_assoc(arg, (arg+1)->u.arr, (arg+2)->u.arr, st_num_arg > 3 ? (arg+3) : &const0); if (st_num_arg == 4) pop_3_elems(); else pop_2_elems(); free_string_svalue(sp); sp->type = T_ARRAY; sp->u.arr = vec; }
void f_bg5cc () { char *istr, *ostr, *ret; unsigned char s; istr = (char *)sp->u.string; if(SVALUE_STRLEN(sp) == 0) push_number(0); if(!strchr(istr, '\\')) { ret = string_copy(istr, "f_bg5cc"); } else { ostr = ret = new_string(max_string_length, "f_bg5cc"); while(*istr) { *ostr++ = s = *istr++; if(is_B51(s)) { *ostr++ = s = *istr++; if(s == '\\' && *istr != '\\') *ostr++ = s; } } *ostr = '\0'; } free_string_svalue(sp); put_malloced_string(ret); }
void f_set_living_name (void) { set_living_name(current_object, sp->u.string); free_string_svalue(sp--); }
/*-------------------------------------------------------------------------*/ svalue_t * f_get_error_file (svalue_t *sp) /* EFUN get_error_file() * * mixed * get_error_file(string name, int set_forget_flag) * * Return information about the last error which occured for * <name> (where <name> is a valid name from the wiz list). * * Result is an array of four elements: the filename of the * program where the error occured, the linenumber in the * program, the error message (runtime error messages usually * start with a '*'), and a numerical flag (the 'forget flag') if * the error information has been queried already. * * If there is no error stored for the given <name>, 0 is * returned. * * If <set_forget_flag> is non-zero, the 'forget' flag is set * for the error message after it has been returned. */ { string_t *name; int forget; wiz_list_t *wl; vector_t *vec; svalue_t *v; # define FORGET_FLAG 0x4000000 /* 0x80...0 would be the sign! */ /* Get the function arguments */ name = sp[-1].u.str; forget = sp->u.number; wl = find_wiz(name); sp--; free_string_svalue(sp); /* The error_message is used as a flag if there has been any error. */ if (!wl || !wl->error_message) { put_number(sp, 0); return sp; } vec = allocate_array(4); v = vec->item; put_ref_string(v, wl->file_name); put_number(v+1, wl->line_number & ~0x40000000); put_ref_string(v+2, wl->error_message); put_number(v+3, (wl->line_number & 0x40000000) != 0); if (forget) wl->line_number |= 0x40000000; put_array(sp, vec); return sp; # undef FORGET_FLAG } /* f_get_error_file() */
void f_add_a() { const char *str = sp->u.string; char *ret; char *p; char first; int len; int an; while( *str == ' ' ) str++; // If *str is 0, it was only spaces. Return "a ". if( *str == 0 ) { pop_stack(); copy_and_push_string( "a " ); return; } len = strlen( str ); // Don't add anything if it already begins with a or an. if( !strncasecmp( str, "a ", 2 ) || !strncasecmp( str, "an ", 3 ) ) { return; } first = *str; an = 0; // Some special cases. // If it begins with "us", check the following letter. // "a use", "a usurper", "a user", but "an usher". if( !strncasecmp( str, "us", 2 ) ) { first = str[2]; an = 1; } // "hour*" gets "an". if( !strncasecmp( str, "hour", 4 ) ) { first = 'o'; } switch( first ) { case 'a': case 'e': case 'i': case 'o': case 'u': case 'A': case 'E': case 'I': case 'O': case 'U': an = !an; break; default: break; } if( an ) { // Add an. if( len + 3 > max_string_length ) { free_string_svalue( sp ); error( "add_a() exceeded max string length.\n" ); } ret = new_string( len + 3, "f_add_a" ); memcpy( ret, "an ", 3 ); p = ret + 3; } else { // Add a. if( len + 2 > max_string_length ) { free_string_svalue( sp ); error( "add_a() exceeded max string length.\n" ); } ret = new_string( len + 2, "f_add_a" ); memcpy( ret, "a ", 2 ); p = ret + 2; } // Add the rest of the string. memcpy( p, str, len + 1 ); // + 1: get the \0. free_string_svalue( sp ); sp->type = T_STRING; sp->subtype = STRING_MALLOC; sp->u.string = ret; }
void f_set_author (void) { set_author(sp->u.string); free_string_svalue(sp--); }
void f_cwrap () { register int i, j; int width, slen, blanks; register char *istr, *ostr, *ret; if(st_num_arg >= 2) { if(st_num_arg == 3) { blanks = sp->u.number; pop_stack(); if(blanks < 0) blanks = 0; } else blanks = 4; width = sp->u.number; pop_stack(); if(width < 2) width = 64; if(width - blanks < 2) { width = 64; blanks = 4; } } else { blanks = 4; width = 64; } istr = (char *)sp->u.string; slen = SVALUE_STRLEN(sp); if(slen < blanks) blanks = 0; i = blanks; ostr = ret = new_string(slen+slen/width+blanks, "f_cwrap"); while(blanks--) *ostr++ = ' '; while(*istr) { if(*istr == '\n') { istr++; continue; } if(istr[0] == 27 && istr[1] == '[') { j=2; while(istr[j] && (isdigit(istr[j]) || istr[j]==';')) j++; if(istr[j++] == 'm') { while(j--) *ostr++ = *istr++; continue; } } i++; *ostr++ = *istr++; if(is_B51((unsigned char)*(istr-1))) { i++; *ostr++ = *istr++; } else if((unsigned char)*(istr-1) == '\t') i += 4; if(i >= width) { *ostr++ = '\n'; i = 0; } } *ostr = '\0'; ostr = string_copy(ret, "f_cwrap"); FREE_MSTR(ret); free_string_svalue(sp); put_malloced_string(ostr); }
void f_addn_temp () { int i, j; object_t *ob; unsigned short type; mapping_t *map; svalue_t *value; char *src, *dst; char *tmpstr; if( st_num_arg == 3 ) { ob = sp->u.ob; pop_stack(); } else ob = current_object; i = find_global_variable(ob->prog, "tmp_dbase", &type, 0); if (i == -1) { pop_2_elems(); error("(addn_temp) %s 物件未宣告全域映射资料库变数。\n", ob->obname); } value = &ob->variables[i]; if( value->type != T_MAPPING ) { pop_2_elems(); error("(addn_temp) %s 物件的资料库变数型态错误。\n", ob->obname); } map = value->u.map; src = (char *)(sp-1)->u.string; dst = tmpstr = (char *)DMALLOC(SVALUE_STRLEN(sp-1) + 1, TAG_STRING, "addn_temp"); j=0; while (*src) { i=0; if( ++j > 20 ) { pop_2_elems(); error("(addn_temp) %s too deep mapping(20)。\n", ob->obname); } while (*src != '/' && *src) { *(dst+i) = *src++; i++; } if (*src == '/') { while (*++src == '/'); if(!i) continue; } *(dst+i) = '\0'; value = find_string_in_mapping(map, tmpstr); if(!*src) { if( value == &const0u || value->type != T_NUMBER ) { value = insert_in_mapping(map, dst); *value = *sp--; } else value->u.number += (sp--)->u.number; break; } if(value == &const0u || value->type != T_MAPPING) { value = insert_in_mapping(map, dst); value->type = T_MAPPING; value->u.map = allocate_mapping(0); } map = value->u.map; dst = tmpstr; } FREE(tmpstr); free_string_svalue(sp--); push_svalue(value); }
void f_delete_temp () { int i; object_t *ob; svalue_t *value, lv; mapping_t *map; unsigned short type; char *src, *dst; if( st_num_arg == 2 ) { ob = sp->u.ob; pop_stack(); } else ob = current_object; i = find_global_variable(ob->prog, "tmp_dbase", &type, 0); if (i == -1) { free_string_svalue(sp--); error("(delete_temp) %s 物件未宣告全域映射资料库变数。\n", ob->obname); } value = &ob->variables[i]; if( value->type != T_MAPPING ) { free_string_svalue(sp--); error("(delete_temp) %s 物件的资料库变数型态错误。\n", ob->obname); } map = value->u.map; src = (char *)sp->u.string; dst = (char *)DMALLOC(SVALUE_STRLEN(sp)+1, TAG_STRING, "delete_temp"); while(*src) { i = 0; while(*src != '/' && *src) *(dst+(i++)) = *src++; if(*src == '/') { while (*++src == '/'); if(!i) continue; } *(dst+i) = '\0'; value = find_string_in_mapping(map, dst); if( value == &const0u ) break; if(!*src) { lv.type = T_STRING; lv.subtype = STRING_CONSTANT; lv.u.string = dst; mapping_delete(map, &lv); FREE(dst); free_string_svalue(sp--); return; } if( value->type != T_MAPPING ) break; map = value->u.map; } FREE(dst); free_string_svalue(sp--); }
void c_index() { int i; switch (sp->type) { case T_MAPPING: { svalue_t *v; mapping_t *m; v = find_in_mapping(m = sp->u.map, sp - 1); assign_svalue(--sp, v); /* v will always have a * value */ free_mapping(m); break; } #ifndef NO_BUFFER_TYPE case T_BUFFER: { if ((sp-1)->type != T_NUMBER) error("Indexing a buffer with an illegal type.\n"); i = (sp - 1)->u.number; if ((i > sp->u.buf->size) || (i < 0)) error("Buffer index out of bounds.\n"); i = sp->u.buf->item[i]; free_buffer(sp->u.buf); (--sp)->u.number = i; break; } #endif case T_STRING: { if ((sp-1)->type != T_NUMBER) { error("Indexing a string with an illegal type.\n"); } i = (sp - 1)->u.number; if ((i > SVALUE_STRLEN(sp)) || (i < 0)) error("String index out of bounds.\n"); i = (unsigned char) sp->u.string[i]; free_string_svalue(sp); (--sp)->u.number = i; break; } case T_ARRAY: { array_t *arr; if ((sp-1)->type != T_NUMBER) error("Indexing an array with an illegal type\n"); i = (sp - 1)->u.number; if (i<0) error("Negative index passed to array.\n"); arr = sp->u.arr; if (i >= arr->size) error("Array index out of bounds.\n"); assign_svalue_no_free(--sp, &arr->item[i]); free_array(arr); break; } default: error("Indexing on illegal type.\n"); } /* * Fetch value of a variable. It is possible that it is a * variable that points to a destructed object. In that case, * it has to be replaced by 0. */ if (sp->type == T_OBJECT && (sp->u.ob->flags & O_DESTRUCTED)) { free_object(sp->u.ob, "F_INDEX"); *sp = const0u; } }
/*-------------------------------------------------------------------------*/ svalue_t * f_sl_open (svalue_t *sp) /* EFUN sl_open * * int sl_open(string filename) * * Opens the file <filename> for use as a SQLite database. * If the file doesn't exists it will be created. * Only one open file per object is allowed. On success this * function returns 1, otherwise usually an error is thrown. */ { string_t *file; sqlite3 *db; sqlite_dbs_t *tmp; int err; file = check_valid_path(sp->u.str, current_object, STR_SQLITE_OPEN , MY_TRUE); if (!file) errorf("Illegal use of sl_open('%s')\n", get_txt(sp->u.str)); tmp = find_db (current_object); if (tmp) { free_mstring(file); errorf("The current object already has a database open.\n"); } err = sqlite3_open (get_txt(file), &db); free_mstring(file); if (err) { const char* msg = sqlite3_errmsg(db); sqlite3_close(db); errorf("sl_open: %s\n", msg ); /* NOTREACHED */ } /* create a new chain link and hang on the old chain */ tmp = new_db(); if(!tmp) { sqlite3_close(db); errorf("(sl_open) Out of memory: (%lu bytes)\n", (unsigned long) sizeof(*tmp)); } tmp->db = db; tmp->obj = current_object; current_object->open_sqlite_db = MY_TRUE; /* Synchronous is damn slow. Forget it. */ sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, NULL); sqlite3_set_authorizer(db, my_sqlite3_authorizer, NULL); free_string_svalue (sp); put_number (sp, 1); return sp; } /* f_sl_open() */
/************************************************************************* * f_sql_connect( string database, void|string user, void|string pwd ) * * opens a connection to an ODBC database. returns the ID of the * created handle *************************************************************************/ svalue_t * f_sql_connect ( svalue_t * argv, int argc ) { #if ODBC_DEBUG & DEBUG_FUNC printf( "call f_sql_connect ( )\n" ); #endif SQLRETURN ret; SQLCHAR * database, * user, * password; int pos; hDBC * handle; char * err; database = NULL; user = NULL; password = NULL; switch( argc ) { case 3 : TYPE_TESTV3( argv, T_STRING ); password = argv->u.string; case 2 : pos = 2 - argc; TYPE_TESTV2( argv + pos, T_STRING ); user = (argv + pos)->u.string; case 1 : pos = 1 - argc; TYPE_TESTV1( argv + pos, T_STRING ); database = (argv + pos)->u.string; break; default: errorf( "Too many arguments to sql_connect().\n" ); return( NULL ); } if ( !hODBCEnv && (err = init_odbc_environment()) ) { raise_critical_sql_exception( handle, err ); return( NULL ); } handle = allocate_db_connection( hODBCEnv->next_hDBCon_ID++ ); MEM_CHECK( handle ); ret = SQLAllocHandle( SQL_HANDLE_DBC, hODBCEnv->hODBCEnv, &(handle->hDBCon) ); if ( !SQL_SUCCEEDED( ret ) ) { raise_critical_sql_exception( handle, extract_diagnostics_info( SQL_HANDLE_ENV, hODBCEnv->hODBCEnv ) ); return( NULL ); } SQLSetConnectAttr( handle->hDBCon, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0 ); SQLSetConnectAttr( handle->hDBCon, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER *)SQL_AUTOCOMMIT_ON, 0 ); ret = SQLConnect( handle->hDBCon, database, SQL_NTS, (user ? user : (SQLCHAR *)"\0"), SQL_NTS, (password ? password : (SQLCHAR *)"\0"), SQL_NTS); if ( !SQL_SUCCEEDED( ret ) ) { raise_critical_sql_exception( handle, extract_diagnostics_info( SQL_HANDLE_DBC, handle->hDBCon ) ); return( NULL ); } handle->name = string_copy( database ); push_db_connection( handle ); switch( argc ) { case 3: free_string_svalue( argv ); argv--; case 2: free_string_svalue( argv ); argv--; case 1: free_string_svalue( argv ); } put_number( argv, handle->ID ); #if ODBC_DEBUG & DEBUG_FUNC printf( "ret f_sql_connect ( )\n" ); #endif return( argv ); }
/************************************************************************* * f_sql_exec( int handle, string statement ) * * executes an SQL statement *************************************************************************/ svalue_t * f_sql_exec( svalue_t * argv, int argc ) { #if ODBC_DEBUG & DEBUG_FUNC printf( "call f_sql_exec( )\n" ); #endif int id, i; SQLCHAR * statement; hDBC * handle; //SQLSMALLINT cols; SQLRETURN ret; TYPE_TEST2( argv, T_STRING ); statement = string_copy( argv->u.string ); free_string_svalue( argv ); argv--; TYPE_TEST1( argv, T_NUMBER ); id = argv->u.number; free_svalue( argv ); if ( !(handle = get_db_connection_by_id( id )) ) { pfree( statement ); errorf( "Illegal handle for database.\n" ); return( NULL ); } if ( handle->hStmt ) { //printf( "freeing statement\n" ); ret = SQLFreeStmt( handle->hStmt, SQL_UNBIND ); if ( !SQL_SUCCEEDED( ret ) ) { //printf( "SQLFreeStmt( handle->hStmt, SQL_UNBIND ) = %d\n", ret ); pfree( statement ); errorf( extract_diagnostics_info( SQL_HANDLE_STMT, handle->hStmt ) ); return( NULL ); } ret = SQLFreeHandle( SQL_HANDLE_STMT, handle->hStmt ); if ( !SQL_SUCCEEDED( ret ) ) { //printf( "SQLFreeHandle( SQL_HANDLE_STMT, handle->hStmt ) = %d\n", ret ); pfree( statement ); errorf( extract_diagnostics_info( SQL_HANDLE_STMT, handle->hStmt ) ); return( NULL ); } } if ( handle->columns ) { for ( i = 0; i < handle->colcnt; ++i ) { dispose_column_meta_data( handle->columns[ i ] ); } pfree( handle->columns ); handle->columns = NULL; } //printf( "allocating statement \n" ); ret = SQLAllocHandle( SQL_HANDLE_STMT, handle->hDBCon, &handle->hStmt ); if ( !SQL_SUCCEEDED( ret ) ) { pfree( statement ); errorf( extract_diagnostics_info( SQL_HANDLE_DBC, handle->hDBCon ) ); return( NULL ); } handle->colcnt = 0; handle->rowcnt = 0; // printf( "executing\n" ); ret = SQLExecDirect( handle->hStmt, statement, SQL_NTS ); pfree( statement ); if ( !SQL_SUCCEEDED( ret ) ) { //printf( "XXX: %s\n", extract_diagnostics_info( SQL_HANDLE_STMT, handle->hStmt ) ); put_number( argv, 0 ); return( argv ); } /* getting number of columns. */ //ret = SQLNumResultCols( handle->hStmt, &cols ); ret = SQLNumResultCols( handle->hStmt, &handle->colcnt ); if ( !SQL_SUCCEEDED( ret ) ) { put_number( argv, 0 ); return( argv ); } ret = SQLRowCount( handle->hStmt, &handle->rowcnt ); if ( !SQL_SUCCEEDED( ret ) ) { put_number( argv, 0 ); return( argv ); } //handle->colcnt = cols; if ( handle->colcnt ) { handle->columns = pxalloc( handle->colcnt * sizeof( COL_META_DATA* ) ); MEM_CHECK( handle->columns ); } /* fetching meta data */ COL_META_DATA * tmp; SQLCHAR dColname[ 100 ]; SQLSMALLINT dColnameLen; SQLSMALLINT dType; SQLSMALLINT dDDigits; SQLSMALLINT dNullable; SQLUINTEGER dColSize; for ( i = 1; i <= handle->colcnt; ++i ) { ret = SQLDescribeCol( handle->hStmt, i, dColname, sizeof( dColname ), &dColnameLen, &dType, &dColSize, &dDDigits, &dNullable ); if ( !SQL_SUCCEEDED( ret ) ) { put_number( argv, 0 ); return( argv ); } tmp = allocate_column_meta_data(); MEM_CHECK( tmp ); tmp->nr = i; tmp->name = string_copy( dColname ); tmp->type = map_column_type( dType, dDDigits ); // printf( "[%s] dColSize=%d dDDigits=%d\n", dColname, dColSize, dDDigits ); SQLLEN len; switch( tmp->type ) { case T_NUMBER: tmp->data.number_v = pxalloc( sizeof( SQL_C_LONG ) ); *tmp->data.number_v = 0; SQLBindCol( handle->hStmt, i, SQL_C_LONG, tmp->data.number_v, 100, &len ); break; case T_FLOAT: tmp->data.double_v = pxalloc( sizeof( SQL_C_DOUBLE ) ); *tmp->data.double_v = 0; SQLBindCol( handle->hStmt, i, SQL_C_DOUBLE, tmp->data.double_v, 100, &len ); break; default: tmp->data.string_v = pxalloc( (dColSize + 1) * sizeof( SQLCHAR ) ); SQLBindCol( handle->hStmt, i, SQL_C_CHAR, tmp->data.string_v, (dColSize + 1), &len ); } handle->columns[ i-1 ] = tmp; } put_number( argv, id ); #if ODBC_DEBUG & DEBUG_FUNC printf( "ret f_sql_exec( )\n" ); #endif return( argv ); }