/*-------------------------------------------------------------------------*/ void struct_free_name (struct_name_t *pSName) /* Free the struct name object <pSName> and all referenced data. */ { #ifdef DEBUG if (!pSName) fatal("NULL pointer passed to struct_free_type().\n"); if (pSName->ref != 0) fatal("struct name object with %"PRIdPINT" refs passed to struct_free_type().\n" , pSName->ref); #endif remove_struct_name(pSName); /* In case it was published */ size_struct_type -= STRUCT_NAME_MEMSIZE; free_mstring(pSName->name); free_mstring(pSName->prog_name); xfree(pSName); } /* struct_free_name() */
/*-------------------------------------------------------------------------*/ void save_error (const char *msg, const char *file, int line) /* A runtime error <msg> occured for object <file> in line number <line>. * Store this information in the wizlist so that the mudlib can handle * it later with the efun get_error_file(). * TODO: A proper runtime error handling could put this into the mudlib * TODO:: completely. */ { wiz_list_t *wl; char *copy, *p; string_t *name; size_t len; /* Get the wizard name and the wizlist entry. */ name = get_wiz_name(file); if (!name) return; wl = add_name(name); /* Set the file_name */ if (wl->file_name) free_mstring(wl->file_name); len = strlen(file); copy = alloca(len + 4); /* May add .c plus the null byte, and / */ *copy = '/'; strcpy(copy+1, file); /* If it is a cloned object, we have to find out what the file * name is, and add '.c'. */ if ( NULL != (p = strrchr(copy, '#')) || ((p = copy+len), *p++ != 'c') || p[-2] != '.' ) { p[0] = '.'; p[1] = 'c'; p[2] = '\0'; } wl->file_name = new_mstring(copy); /* Set the error_message */ if (wl->error_message) free_mstring(wl->error_message); wl->error_message = new_mstring(msg); /* Set the line_number */ wl->line_number = line; } /* save_error() */
/*-------------------------------------------------------------------------*/ Bool dumpstat_dest(string_t *fname) /* this function dumps statistics about all destructed objects into the file * $MUDLIB/<fname>. It is called by dump_driver_info(). * Return TRUE on success, FALSE if <fname> can't be written. */ { FILE *f; object_t *ob; fname = check_valid_path(fname, current_object, STR_OBJDUMP, MY_TRUE); if (!fname) return MY_FALSE; f = fopen(get_txt(fname), "w"); if (!f) { free_mstring(fname); return MY_FALSE; } FCOUNT_WRITE(get_txt(fname)); for (ob = newly_destructed_objs; ob; ob = ob->next_all) { #ifdef DEBUG if (!(ob->flags & O_DESTRUCTED)) /* TODO: Can't happen */ continue; #endif fprintf(f, "%-20s ref %2"PRIdPINT" NEW\n" , get_txt(ob->name) , ob->ref ); } for (ob = destructed_objs; ob; ob = ob->next_all) { #ifdef DEBUG if (!(ob->flags & O_DESTRUCTED)) /* TODO: Can't happen */ continue; #endif fprintf(f, "%-20s ref %2"PRIdPINT"\n" , get_txt(ob->name) , ob->ref ); } fclose(f); free_mstring(fname); return MY_TRUE; } /* dumpstat_dest() */
/*-------------------------------------------------------------------------*/ void load_wiz_file (void) /* Load the old wizlist from the wizlist file and add it's data to * the wizlist already in memory. * * This function is called at driver start up. * TODO: Since the wizlist is saved from the mudlib, this function * TODO:: should be implemented on mudlib level, too. */ { char buff[1000]; FILE *f; if (wizlist_name[0] == '\0') return; f = fopen(wizlist_name, "r"); if (f == NULL) return; while (fgets(buff, sizeof buff, f) != NULL) { char *p; uint32 score; p = strchr(buff, ' '); if (p == 0) { fprintf(stderr, "%s Bad WIZLIST file '%s'.\n" , time_stamp(), wizlist_name); break; } *p = '\0'; p++; if (*p == '\0') { fprintf(stderr, "%s Bad WIZLIST file '%s'.\n" , time_stamp(), wizlist_name); break; } score = atoi(p); if (score > 0) { string_t * tmp; tmp = new_mstring(buff); add_name(tmp)->score += score; free_mstring(tmp); } } fclose(f); } /* load_wiz_file() */
/*-------------------------------------------------------------------------*/ void remove_wiz_list (void) /* Remove all memory allocated by the wizlist. * * Called from simulate::shutdowngame(). */ { wiz_list_t *wl, *w; for (w = all_wiz; w; w = wl) { free_mstring(w->name); if (w->file_name) free_mstring(w->file_name); if (w->error_message) free_mstring(w->error_message); wl = w->next; xfree(w); } } /* remove_wiz_list() */
/*-------------------------------------------------------------------------*/ void struct_free_type (struct_type_t *pSType) /* Free the struct typeobject <pSType> and all referenced data. */ { unsigned short num; #ifdef DEBUG if (!pSType) fatal("NULL pointer passed to struct_free_type().\n"); if (pSType->ref != 0) fatal("struct typeobject with %"PRIdPINT" refs passed to struct_free_type().\n" , pSType->ref); #endif num_struct_type--; size_struct_type -= STRUCT_TYPE_MEMSIZE + STRUCT_TYPE_MEMBER_MEMSIZE(pSType->num_members); if(pSType->name->current == pSType) pSType->name->current = NULL; free_struct_name(pSType->name); if (pSType->unique_name) free_mstring(pSType->unique_name); if (pSType->base) free_struct_type(pSType->base); for (num = 0; num < pSType->num_members; num++) { free_struct_member_data(&pSType->member[num]); } if (pSType->member) xfree(pSType->member); xfree(pSType); } /* struct_free_type() */
/*-------------------------------------------------------------------------*/ Bool assert_simul_efun_object (void) /* (Re)load the simul_efun object and extract all information we need. * Result is TRUE if either the simul_efun object could be loaded, or if * master::get_simul_efun() did not return a string/string vector to * name the simul efun object. The result is FALSE if master::get_simul_efun() * specified a simul efun object, which couldn't be found. * * In other words: after calling assert_simul_efun_object(), the caller * still has to check if simul_efun_object is NULL. * * At the time of call, simul_efun_object must be NULL. */ { svalue_t *svp; object_t *ob; program_t *progp; CBool *visible; /* Flag for every function: visible or not */ string_t *name; int i, j, num_fun; invalidate_simul_efuns(); /* Invalidate the simul_efun information */ free_defines(); /* to prevent #defines hideing places for globals */ /* Get the name(s) of the simul_efun object. */ svp = apply_master(STR_GET_SEFUN, 0); /* If a simul_efun_object appears during the GET_SEFUN call, it * might have been due to a recursive get_simul_efun() call which may * have gotten an old backup copy. This can lead to hard-to-debug * variable and function definition inconsistencies. */ if (simul_efun_object) { printf("%s simul_efun object appeared while asking for it.\n", time_stamp()); return MY_TRUE; } if (svp == NULL) { printf("%s No simul_efun\n", time_stamp()); return MY_TRUE; } if (svp->type == T_POINTER) { simul_efun_vector = svp->u.vec; svp->type = T_NUMBER; if (VEC_SIZE(svp->u.vec)) svp = svp->u.vec->item; } if (svp->type != T_STRING) { printf("%s No simul_efun\n", time_stamp()); return MY_TRUE; } /* Make the (primary) simul_efun name */ name = del_slash(svp->u.str); if (simul_efun_file_name) free_mstring(simul_efun_file_name); simul_efun_file_name = make_tabled(name); /* Get the object and load the program */ ob = find_object(simul_efun_file_name); if (ob == NULL) { fprintf(stderr, "%s The simul_efun file %s was not loaded.\n" , time_stamp(), get_txt(simul_efun_file_name)); fprintf(stderr, "%s The function get_simul_efun() in the master must load it.\n" , time_stamp()); return MY_FALSE; } if (O_PROG_SWAPPED(ob) && load_ob_from_swap(ob) < 0) { fprintf(stderr, "%s Out of memory (unswap object '%s') ==> " "No simul_efun\n", time_stamp(), get_txt(ob->name)); return MY_TRUE; } reference_prog( (simul_efun_program = ob->prog), "get_simul_efun"); num_fun = ob->prog->num_function_names; if (num_fun == 0) return MY_TRUE; if (!simul_efunp) { simul_efunp = xalloc(sizeof (function_t) * num_fun); } else num_fun = total_simul_efun; free_defines(); /* to prevent #defines hideing places for globals */ /* locals and defines are freed now. There are still reserved words, * but it is impossible to define a function with the name being * a reserved word, thus, there will be no clashes with higher-priority * shared identifiers. */ progp = ob->prog; visible = alloca((i = ob->prog->num_functions) * sizeof(*visible)); memset(visible, 0, i); i = ob->prog->num_function_names; while (--i >= 0) visible[progp->function_names[i]] = MY_TRUE; /* The functions .num_function_names+1 .. .num_functions are not * visible by definition. */ /* Loop over the functions in the simul_efun object and * copy the salient information. */ for (i = 0; i < ob->prog->num_functions; i++) { int ix; funflag_t flags, flags2; bytecode_p funstart; mp_int fun_ix_offs, var_ix_offs; program_t *inherit_progp; function_t*funheader; if (!visible[i]) continue; ix = i; flags2 = flags = progp->functions[ix]; flags &= ~FUNSTART_MASK; /* Pinpoint the function, resolving inheritance where * necessary. */ fun_ix_offs = ix; var_ix_offs = 0; inherit_progp = progp; while (flags2 & NAME_INHERITED) { inherit_t *inheritp; inheritp = &inherit_progp->inherit[flags2 & INHERIT_MASK]; ix -= inheritp->function_index_offset; var_ix_offs += inheritp->variable_index_offset; inherit_progp = inheritp->prog; flags2 = inherit_progp->functions[ix]; } fun_ix_offs -= ix; funstart = inherit_progp->program + (flags2 & FUNSTART_MASK); funheader = inherit_progp->function_headers + FUNCTION_HEADER_INDEX(funstart); /* Don't stumble over undefined functions */ if (is_undef_function(funstart)) { flags |= NAME_UNDEFINED; } /* If the function is __INIT, pretend it's a private function */ if ( !(flags & (TYPE_MOD_STATIC|TYPE_MOD_PRIVATE|NAME_UNDEFINED)) ) { if (mstreq(funheader->name, STR_VARINIT)) flags |= TYPE_MOD_PRIVATE; } /* If the function is indeed visible, get its information */ if ( !(flags & (TYPE_MOD_STATIC|TYPE_MOD_PROTECTED|TYPE_MOD_PRIVATE|NAME_UNDEFINED)) ) { string_t *function_name; ident_t *p; unsigned char num_arg; function_name = funheader->name; num_arg = funheader->num_arg; /* Find or make the identifier for the function */ p = make_shared_identifier_mstr(function_name, I_TYPE_GLOBAL, 0); if (p->type == I_TYPE_UNKNOWN) { init_global_identifier(p, /* bVariable: */ MY_FALSE); p->next_all = all_simul_efuns; all_simul_efuns = p; } if (flags & TYPE_MOD_VARARGS) num_arg = SIMUL_EFUN_VARARGS; /* Find the proper index in simul_efunp[] */ switch(0) { default: /* TRY... */ /* Try to find a discarded sefun entry with matching * name, number of arguments and XVARARGS flag to reuse. */ if (all_discarded_simul_efun >= 0) { int last; j = all_discarded_simul_efun; while ( (j = simul_efunp[last = j].offset.next_sefun) >= 0) { if (num_arg != simul_efunp[j].num_arg || 0 != ((simul_efunp[j].flags ^ flags) & TYPE_MOD_XVARARGS) ) continue; if (!mstreq(function_name, simul_efunp[j].name)) continue; /* Found one: remove it from the 'discarded' list */ simul_efunp[last].offset.next_sefun = simul_efunp[j].offset.next_sefun; break; } if (j >= 0) break; /* switch */ } /* New simul_efun: make a new entry */ (void)ref_mstring(function_name); j = num_simul_efun++; if (num_simul_efun > num_fun) { num_fun = num_simul_efun + 12; simul_efunp = rexalloc(simul_efunp , sizeof (function_t) * num_fun ); } simul_efunp[j].name = function_name; simul_efunp[j].num_arg = num_arg; } /* switch() */ /* j now indexes the simul_efunp[] entry to use */ p->u.global.sim_efun = j; simul_efunp[j].flags = funheader->flags; simul_efunp[j].type = funheader->type; simul_efunp[j].num_locals = funheader->num_locals; /* If possible, make an entry in the simul_efun table */ if ((size_t)j < SEFUN_TABLE_SIZE) { simul_efun_table[j].funstart = funstart; simul_efun_table[j].program = inherit_progp; simul_efun_table[j].function_index_offset = fun_ix_offs; simul_efun_table[j].variable_index_offset = var_ix_offs; } } /* if (function visible) */ } /* for ( all functions) */ total_simul_efun = num_fun; simul_efun_object = ob; return MY_TRUE; } /* get_simul_efun_object() */
/*-------------------------------------------------------------------------*/ 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() */
char * read_bytes(char *file, int start, size_t len) { struct stat st; char *str; int size; int f; if(len > MAX_BYTE_TRANSFER) return 0; file = check_valid_path(file, current_object, "read_bytes", 0); if (!file) return 0; f = open(file, O_RDONLY); if (f < 0) return 0; #ifdef PURIFY (void)memset(&st, '\0', sizeof(st)); #endif if (fstat(f, &st) == -1) fatal("Could not stat an open file.\n"); size = (int)st.st_size; if(start < 0) start = size + start; if (start >= size) { (void)close(f); return 0; } if ((start+len) > size) len = (size - start); if ((size = (int)lseek(f, (off_t)start, 0)) < 0) { (void)close(f); return 0; } str = allocate_mstring(len); size = read(f, str, len); (void)close(f); if (size <= 0) { free_mstring(str); return 0; } /* We want to allow all characters to pass untouched! for (il = 0; il < size; il++) if (!isprint(str[il]) && !isspace(str[il])) str[il] = ' '; */ /* * The string has to end to '\0'!!! */ str[size] = '\0'; return str; }
/* * Append string to file. Return 0 for failure, otherwise 1. */ int write_file(char *file, char *str) { FILE *f; file = check_valid_path(file, current_object, "write_file", 1); if (!file) return 0; f = fopen(file, "a"); if (f == 0) error("Wrong permissions for opening file %s for append.\n", file); if (s_flag) num_filewrite++; if (fwrite(str, strlen(str), 1, f) != 1) { (void)fclose(f); return 0; } if (fclose(f) == EOF) return 0; return 1; } int read_file_len; /* Side effect from read_file, so we know how many lines we managed to read */ char * read_file(char *file, int start, int len) { struct stat st; FILE *f; char *str, *p, *p2, *end, c; size_t size; read_file_len = len; if (len < 0) return 0; file = check_valid_path(file, current_object, "read_file", 0); if (!file) return 0; f = fopen(file, "r"); if (f == 0) return 0; #ifdef PURIFY (void)memset(&st, '\0', sizeof(st)); #endif if (fstat(fileno(f), &st) == -1) fatal("Could not stat an open file.\n"); size = (int)st.st_size; if (s_flag) num_fileread++; if (size > READ_FILE_MAX_SIZE) { if ( start || len ) size = READ_FILE_MAX_SIZE; else { (void)fclose(f); return 0; } } if (!start) start = 1; if (!len) read_file_len = len = READ_FILE_MAX_SIZE; str = allocate_mstring(size); str[size] = '\0'; do { if (size > (int)st.st_size) size = (int)st.st_size; if (fread(str, size, 1, f) != 1) { (void)fclose(f); free_mstring(str); return 0; } st.st_size -= size; end = str + size; for (p = str; ( p2 = memchr(p, '\n', (size_t)(end - p)) ) && --start; ) p = p2 + 1; } while ( start > 1 ); for (p2 = str; p != end; ) { c = *p++; if (!isprint(c) && !isspace(c)) c = ' '; *p2++ = c; if ( c == '\n' ) if (!--len) break; } if (len && st.st_size) { size -= (p2 - str) ; if (size > (int)st.st_size) size = (int)st.st_size; if (fread(p2, size, 1, f) != 1) { (void)fclose(f); free_mstring(str); return 0; } st.st_size -= size; end = p2 + size; for (; p2 != end; ) { c = *p2; if (!isprint(c) && !isspace(c)) *p2 = ' '; p2++; if (c == '\n') if (!--len) break; } if ( st.st_size && len ) { /* tried to read more than READ_MAX_FILE_SIZE */ (void)fclose(f); free_mstring(str); return 0; } } read_file_len -= len; *p2 = '\0'; (void)fclose(f); return str; }
/*-------------------------------------------------------------------------*/ Bool dumpstat (string_t *fname) /* This function dumps statistics about all listed objects into the file * $MUDLIB/<fname>. It is called from dump_driver_info. * Return TRUE on success, FALSE if <fname> can't be written. */ { FILE *f; object_t *ob; static char *swapstrings[] = {"", "PROG SWAPPED", "VAR SWAPPED", "SWAPPED", }; fname = check_valid_path(fname, current_object, STR_OBJDUMP, MY_TRUE); if (!fname) return MY_FALSE; f = fopen(get_txt(fname), "w"); if (!f) { free_mstring(fname); return MY_FALSE; } FCOUNT_WRITE(get_txt(fname)); for (ob = obj_list; ob; ob = ob->next_all) { mp_int compsize, totalsize, overhead; char timest[21]; struct tm *tm; #ifdef DEBUG if (ob->flags & O_DESTRUCTED) /* TODO: Can't happen */ continue; #endif compsize = data_size(ob, &totalsize); if (!O_PROG_SWAPPED(ob) && (ob->prog->ref == 1 || !(ob->flags & (O_CLONE|O_REPLACED)))) { overhead = ob->prog->total_size; } else { overhead = 0; } overhead += sizeof (object_t); fprintf(f, "%-20s %5"PRIdMPINT" (%5"PRIdMPINT") ref %2"PRIdPINT" %s " , get_txt(ob->name) , compsize + overhead, totalsize + overhead , ob->ref , ob->flags & O_HEART_BEAT ? "HB" : " " ); if (ob->super) fprintf(f, "%s ", get_txt(ob->super->name)); else fprintf(f, "-- "); if (ob->gigaticks) fprintf(f, " (%"PRIuMPINT"%09"PRIuMPINT")", (mp_uint)ob->gigaticks, (mp_uint)ob->ticks); else fprintf(f, " (%"PRIuMPINT")", (mp_uint)ob->ticks); fprintf(f, " %s", swapstrings[(O_PROG_SWAPPED(ob)?1:0) | (O_VAR_SWAPPED(ob)?2:0)] ); tm = localtime((time_t *)&ob->load_time); strftime(timest, sizeof(timest), "%Y.%m.%d-%H:%M:%S", tm); fprintf(f, " %s\n", timest); } fclose(f); free_mstring(fname); return MY_TRUE; } /* dumpstat() */
/*-------------------------------------------------------------------------*/ svalue_t * x_filter_string (svalue_t *sp, int num_arg) /* EFUN: filter() for strings. * * string filter(string arr, string fun, string|object obj, mixed extra, ...) * string filter(string arr, closure cl, mixed extra, ...) * string filter(string arr, mapping map) * * Filter the elements of <arr> through a filter defined by the other * arguments, and return an array of those elements, for which the * filter yields non-zero. * * The filter can be a function call: * * <obj>-><fun>(elem, <extra>...) * * or a mapping query: * * <map>[elem] * * <obj> can both be an object reference or a filename. If omitted, * this_object() is used (this also works if the third argument is * neither a string nor an object). */ { string_t *rc; /* Result string */ string_t *str; /* Argument string */ svalue_t *arg; /* First argument the vm stack */ mp_int slen; /* Argument string length */ char *src, *dest; /* String text work pointers */ char *flags; /* Flag array, one flag for each element of <str> * (in reverse order). */ mp_int res; /* Number of surviving elements */ res = 0; /* Locate the args on the stack, extract the string to filter * and allocate the flags vector. */ arg = sp - num_arg + 1; str = arg->u.str; slen = (mp_int)mstrsize(str); /* Every element in flags is associated by index number with an * element in the vector to filter. The filter function is evaluated * for every string character, and the associated flag is set to 0 * or 1 according to the result. * At the end, all 1-flagged elements are gathered and copied * into the result string. */ if (arg[1].type == T_MAPPING) { mp_int cnt; /* --- Filter by mapping query --- */ mapping_t *m; if (num_arg > 2) { errorf("Too many arguments to filter(array)\n"); } /* Allocate memory for the flag array. Simultaneously an error * handler is pushed onto the stack (after the arguments) for freeing * the buffer in case of runtime errors. */ flags = xalloc_with_error_handler((size_t)slen + 1); if (!flags) { errorf("Out of memory (%zu bytes) for temporary buffer in filter().\n", (size_t)slen + 1); } sp = inter_sp; m = arg[1].u.map; for (src = get_txt(str), cnt = slen; --cnt >= 0; src++) { svalue_t key; put_number(&key, *src); if (get_map_value(m, &key) == &const0) { flags[cnt] = 0; continue; } flags[cnt] = 1; res++; } } else { /* --- Filter by function call --- */ int error_index; callback_t cb; mp_int cnt; assign_eval_cost(); /* setup_efun_callback() will adopt and therefore remove the * arguments from arg+1 on to arg+num_arg from the stack and update * inter_sp. New top-of-stack will be arg. */ error_index = setup_efun_callback(&cb, arg+1, num_arg-1); if (error_index >= 0) { vefun_bad_arg(error_index+2, arg); /* NOTREACHED */ return arg; } /* push the callback structure onto the stack. */ sp = arg + 1; put_callback(sp, &cb); /* Allocate memory for the flag array. Simultaneously an error * handler is pushed onto the stack (after the arguments) for freeing * the buffer in case of runtime errors. */ inter_sp = sp; flags = xalloc_with_error_handler((size_t)slen + 1); if (!flags) { errorf("Out of memory (%"PRIdMPINT" bytes) for temporary buffer " "in filter().\n", slen + 1); } sp = inter_sp; /* Loop over all elements in p and call the filter. * w is the current element filtered. */ for (src = get_txt(str), cnt = slen; --cnt >= 0; src++) { svalue_t *v; flags[cnt] = 0; if (current_object->flags & O_DESTRUCTED) continue; /* Don't call the filter anymore, but fill the * flags array with 0es. */ if (!callback_object(&cb)) { inter_sp = sp; errorf("object used by filter(array) destructed"); } push_number(inter_sp, *src); v = apply_callback(&cb, 1); if (!v || (v->type == T_NUMBER && !v->u.number) ) continue; flags[cnt] = 1; res++; } } /* flags[] holds the filter results, res is the number of * elements to keep. Now create the result vector. */ rc = alloc_mstring(res); if (!rc) { errorf("Out of memory (%"PRIdMPINT" bytes) for result in filter().\n", slen+1); } for (src = get_txt(str), dest = get_txt(rc), flags = &flags[slen] ; res > 0 ; src++) { if (*--flags) { *dest++ = *src; res--; } } /* Cleanup. Arguments for the closure have already been removed. On the * stack are now the string, the mapping or callback structure and the * error handler. (Not using pop_n_elems() for 2 elements for saving loop * and function call overhead.) */ free_svalue(sp--); /* errorhandler, buffer and flags are freed by this. */ free_svalue(sp--); /* mapping or callback structure. */ free_mstring(str); /* string, at arg == sp */ sp->u.str = rc; /* put result here */ return sp; } /* x_filter_string() */
/*-------------------------------------------------------------------------*/ struct_type_t * struct_new_prototype ( string_t *name, string_t *prog_name ) /* Create a new prototype struct typeobject from the given data. * The references from the data are adopted, and the result is the * new typeobject with one reference. * When an error occurs, NULL is returned and the input data is freed. */ { struct_type_t * pSType; struct_name_t * pSName; hash32_t hash = hash2(name, prog_name); pSName = find_by_name(name, prog_name, hash); if (pSName == NULL) { /* No name yet, create one. */ pSName = xalloc(STRUCT_NAME_MEMSIZE); if (pSName == NULL) { free_mstring(name); free_mstring(prog_name); return NULL; } size_struct_type += STRUCT_NAME_MEMSIZE; pSName->hash = hash; pSName->ref = 1; pSName->name = name; pSName->prog_name = prog_name; pSName->lpctype = NULL; pSName->current = NULL; if (!add_struct_name(pSName)) { free_struct_name(pSName); return NULL; } } else { ref_struct_name(pSName); free_mstring(name); free_mstring(prog_name); } pSType = xalloc(STRUCT_TYPE_MEMSIZE); if (pSType != NULL) { pSType->ref = 1; pSType->name = pSName; pSType->unique_name = NULL; pSType->prog_id = 0; pSType->num_members = 0; pSType->member = NULL; pSType->base = NULL; num_struct_type++; size_struct_type += STRUCT_TYPE_MEMSIZE; } else { free_struct_name(pSName); } return pSType; } /* struct_new_prototype() */
/*-------------------------------------------------------------------------*/ void remove_unreferenced_structs (void) /* Free all structs in the table which are not marked as referenced. * This function must be called before freeing all unreferenced strings! */ { size_t num; if (!table || !table_size) return; for (num = 0; num < table_size; num++) { struct_name_t * this, * prev; for (prev = NULL, this = table[num]; this != NULL; ) { if (!test_memory_reference(this)) { prev = this; this = this->next; } else { struct_name_t * next = this->next; if (prev) prev->next = next; else table[num] = next; num_types--; /* Now we deallocate the memory for the struct name * structure. */ size_struct_type -= STRUCT_NAME_MEMSIZE; dprintf2(gcollect_outfd, "struct name %x '%s' was left " "unreferenced, freeing now.\n" , (p_int) this , (p_int) get_txt(this->name) ); /* Reference all strings and free them, to avoid unnecessary * 'string unreferenced' diagnostics. */ count_ref_from_string(this->name); free_mstring(this->name); count_ref_from_string(this->prog_name); free_mstring(this->prog_name); /* Reference the memory (to update its flags) and free it */ note_malloced_block_ref(this); xfree(this); this = next; } } } /* for (num) */ } /* remove_unreferenced_structs() */