/* debug.c This file keeps the debug() efun. All debug information and debug switches are managed from here. */ #include <varargs.h> #include <stdio.h> #include <setjmp.h> #include <string.h> #include <ctype.h> #include <sys/time.h> #include <sys/types.h> /* sys/types.h and netinet/in.h are here to enable include of comm.h below */ #include <sys/stat.h> /* #include <netinet/in.h> Included in comm.h below */ #include <memory.h> #include "config.h" #include "lint.h" #include "exec.h" #include "interpret.h" #ifdef RUSAGE /* Defined in config.h */ #ifdef SOLARIS #include <sys/times.h> #include <limits.h> #else #include <sys/resource.h> extern int getrusage (int, struct rusage *); #ifdef sun extern int getpagesize(); #endif #ifndef RUSAGE_SELF #define RUSAGE_SELF 0 #endif #endif /* SOLARIS */ static struct vector *make_cpu_array (int,struct program *[]); #endif #include "object.h" #include "instrs.h" #include "patchlevel.h" #include "comm.h" #include "switch.h" #include "mapping.h" #include "mudstat.h" #define DUMP_FILE "OBJECT_DUMP" int call_warnings; extern struct svalue const0, const1; static void make_fun_map (struct program *); /* * The array below is the available subcommands to the debug() efun. * */ /* Name Number Params */ static char *debc[] = { "index", /* 0 */ "malloc", /* 1 */ "status", /* 2 */ "status tables", /* 3 */ "mudstatus", /* 4 on/off eval time */ "functionlist", /* 5 object */ "rusage", /* 6 */ "top_ten_cpu", /* 7 */ "object_cpu", /* 8 object */ "swap", /* 9 object */ "version", /* 10 */ "wizlist", /* 11 wizname */ "trace", /* 12 bitmask */ "traceprefix", /* 13 pathstart */ "call_out_info", /* 14 object */ "inherit_list", /* 15 object */ "load_average", /* 16 */ "shutdown", /* 17 */ "object_info", /* 18 num object */ "function_map", /* 19 OBSOLETE */ "send_udp", /* 20 host, port, msg */ "mud_port", /* 21 */ "udp_port", /* 22 */ "set_wizard", /* 23 player */ "ob_flags", /* 24 ob */ "get_variables", /* 25 ob null/varname */ "get_eval_cost", /* 26 */ "debug malloc", /* 27 */ "getprofile", /* 28 object */ "get_avg_response", /* 29 */ "destruct", /* 30 object */ "destroy", /* 31 object */ "update snoops", /* 32 */ "call_warnings", /* 33 on/off */ "dump_objects", /* 34 */ "query_debug_ob", /* 35 object */ "set_debug_ob", /* 36 object flags */ "set_swap", /* 37 ({min_mem, max_mem, min_time, max_time}) */ "query_swap", /* 38 */ "set_debug_prog", /* 39 object */ "query_debug_prog", /* 40 object flags */ 0 }; extern struct vector *inherit_list (struct object *); struct svalue * debug_command(char *debcmd, int argc, struct svalue *argv) { static struct svalue retval; int dbnum, dbi, il; for (dbi = -1, dbnum = 0; debc[dbnum]; dbnum++) { if (strcmp(debcmd, debc[dbnum]) == 0) dbi = dbnum; } if (dbi < 0) { retval.type = T_NUMBER; retval.u.number = 0; return &retval; } switch (dbi) { case 0: /* index */ retval.type = T_POINTER; retval.u.vec = allocate_array(dbnum); for (il = 0; il < dbnum; il++) { retval.u.vec->item[il].type = T_STRING; retval.u.vec->item[il].string_type = STRING_CONSTANT; retval.u.vec->item[il].u.string = debc[il]; } return &retval; break; case 1: /* malloc */ retval.type = T_STRING; retval.string_type = STRING_MALLOC; retval.u.string = string_copy((char *)dump_malloc_data()); return &retval; break; case 2: /* status */ case 3: /* status tables */ retval.type = T_STRING; retval.string_type = STRING_MALLOC; retval.u.string = (char *)get_gamedriver_info(debc[dbi]); return &retval; break; case 4: /* mudstatus on/off eval_lim time_lim */ if (argc < 3 || argv[0].type != T_STRING || argv[1].type != T_NUMBER || argv[2].type != T_NUMBER) break; if (strcmp(argv[0].u.string, "on") == 0) mudstatus_set(1, argv[1].u.number, argv[2].u.number); else if (strcmp(argv[0].u.string, "off") == 0) mudstatus_set(0, argv[1].u.number, argv[2].u.number); else break; retval.type = T_NUMBER; retval.u.number = 1; return &retval; break; case 5: /* functionlist object */ if (argc < 1 || argv[0].type != T_OBJECT) break; access_program(argv->u.ob->prog); retval.type = T_POINTER; retval.u.vec = allocate_array(argv[0].u.ob->prog->num_functions); for (il = 0; il < (int)argv[0].u.ob->prog->num_functions; il++) { retval.u.vec->item[il].type = T_STRING; retval.u.vec->item[il].string_type = STRING_SHARED; retval.u.vec->item[il].u.string = argv[0].u.ob->prog->functions[il].name; increment_string_ref(argv[0].u.ob->prog->functions[il].name); } access_program(current_prog); return &retval; break; #ifdef RUSAGE /* Only defined if we compile GD with RUSAGE */ case 6: /* rusage */ { char buff[500]; #ifdef SOLARIS struct tms buffer; if (times(&buffer) == -1) buff[0] = 0; else sprintf(buff, "%ld %ld (s/%ld)", buffer.tms_utime, buffer.tms_stime, CLK_TCK); #else struct rusage rus; long utime, stime; int maxrss; if (getrusage(RUSAGE_SELF, &rus) < 0) buff[0] = 0; else { utime = rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000; stime = rus.ru_stime.tv_sec * 1000 + rus.ru_stime.tv_usec / 1000; maxrss = rus.ru_maxrss; #ifdef sun maxrss *= getpagesize() / 1024; #endif sprintf(buff, "%ld %ld %d %d %d %d %d %d %d %d %d %d %d %d %d %d", utime, stime, maxrss, rus.ru_ixrss, rus.ru_idrss, rus.ru_isrss, rus.ru_minflt, rus.ru_majflt, rus.ru_nswap, rus.ru_inblock, rus.ru_oublock, rus.ru_msgsnd, rus.ru_msgrcv, rus.ru_nsignals, rus.ru_nvcsw, rus.ru_nivcsw); } #endif /* SOLARIS */ retval.type = T_STRING; retval.string_type = STRING_MALLOC; retval.u.string = string_copy(buff); return &retval; break; } case 7: /* top_ten_cpu */ { #define NUMBER_OF_TOP_TEN 10 struct program *p[NUMBER_OF_TOP_TEN]; struct object *ob; struct vector *v; int i, j; for(i = 0; i < NUMBER_OF_TOP_TEN; i++) p[i] = (struct program *)0L; ob = obj_list; do { if (!ob->prog) /* That this case exists is just weird /JnA */ continue; for(i = NUMBER_OF_TOP_TEN-1; i >= 0; i--) { if ( p[i] && (ob->prog->cpu <= p[i]->cpu)) break; } if (i < (NUMBER_OF_TOP_TEN - 1)) for (j = 0; j <= i; j++) if (strcmp(p[j]->name,ob->prog->name) == 0) { i = NUMBER_OF_TOP_TEN-1; break; } if (i < (NUMBER_OF_TOP_TEN - 1)) { j = NUMBER_OF_TOP_TEN - 2; while(j > i) { p[j + 1] = p[j]; j--; } p[i + 1] = ob->prog; } } while (obj_list != (ob = ob->next_all)); v = make_cpu_array(NUMBER_OF_TOP_TEN, p); if (v) { retval.type = T_POINTER; retval.u.vec = v; return &retval; } break; #undef NUMBER_OF_TOP_TEN } case 8: /* object_cpu object */ { int c_num; if (argc && (argv[0].type == T_OBJECT)) { long cpu = argv[0].u.ob->prog->cpu; c_num = cpu; } else { #ifdef SOLARIS struct tms buffer; if (times(&buffer) == -1) c_num = -1; else c_num = buffer.tms_utime + buffer.tms_stime; #else struct rusage rus; if (getrusage(RUSAGE_SELF, &rus) < 0) { c_num = -1; } else { c_num = (rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000 + rus.ru_stime.tv_sec * 1000 + rus.ru_stime.tv_usec / 1000); } #endif } retval.type = T_NUMBER; retval.u.number = c_num; return &retval; break; } #else /* RUSAGE */ case 6: case 7: /* rusage, top_ten_cpu and object_cpu */ case 8: retval.type = T_STRING; retval.string_type = STRING_CONSTANT; retval.u.string = "Only valid if GD compiled with RUSAGE flag.\n"; return &retval; break; #endif /* RUSAGE */ case 9: /* swap, object */ #if 0 /* can not swap while executing */ if (argc && (argv[0].type == T_OBJECT)) (void)swap(argv[0].u.ob); #endif retval = const1; return &retval; break; case 10: /* version, */ { char buff[9]; sprintf(buff, "%6.6s%02d", GAME_VERSION, PATCH_LEVEL); retval.type = T_STRING; retval.string_type = STRING_MALLOC; retval.u.string = string_copy(buff); return &retval; break; } case 11: /* wizlist, wizname */ /* * Prints information, will be changed */ retval = const1; return &retval; break; case 12: /* trace, bitmask */ { int ot = -1; if (command_giver && command_giver->interactive) { if (argc && (argv[0].type == T_NUMBER)) { ot = command_giver->interactive->trace_level; command_giver->interactive->trace_level = argv[0].u.number; } } retval.type = T_NUMBER; retval.u.number = ot; return &retval; } break; case 13: /* traceprefix, pathstart */ { char *old = 0; if (command_giver && command_giver->interactive) { struct svalue *arg; if (argc) { old = command_giver->interactive->trace_prefix; if (argv[0].type == T_STRING) { command_giver->interactive->trace_prefix = make_shared_string(argv[0].u.string); } else command_giver->interactive->trace_prefix = 0; } } if (old) { retval.type = T_STRING; retval.string_type = STRING_SHARED; retval.u.string = old; } else retval = const0; return &retval; } break; case 14: /* call_out_info, */ { extern struct vector *get_calls(struct object *); if (argv[0].type != T_OBJECT) break; retval.type = T_POINTER; retval.u.vec = get_calls(argv[0].u.ob); return &retval; break; } case 15: /* inherit_list, object */ { struct vector *vec; if (argc && (argv[0].type == T_OBJECT)) { retval.type = T_POINTER; retval.u.vec = inherit_list(argv[0].u.ob); return &retval; } else { retval = const0; return &retval; } break; } case 16: /* load_average, */ retval.type = T_STRING; retval.string_type = STRING_MALLOC; retval.u.string = string_copy(query_load_av()); return &retval; break; case 17: /* shutdown, */ startshutdowngame(0); retval = const1; return &retval; break; case 18: /* "object_info", num object */ { struct object *ob; char db_buff[1024], tdb[200]; int i; if (argc < 2 || argv[0].type != T_NUMBER || argv[1].type != T_OBJECT) break; if (argv[0].u.number == 0) { int flags; struct object *obj2; if ( argv[1].type != T_OBJECT) break; ob = argv[1].u.ob; flags = ob->flags; sprintf(db_buff,"O_ENABLE_COMMANDS : %s\nO_CLONE : %s\nO_DESTRUCTED : %s\nO_SWAPPED : %s\nO_ONCE_INTERACTIVE: %s\nO_CREATED : %s\n", flags&O_ENABLE_COMMANDS ?"TRUE":"FALSE", flags&O_CLONE ?"TRUE":"FALSE", flags&O_DESTRUCTED ?"TRUE":"FALSE", flags&O_SWAPPED ?"TRUE":"FALSE", flags&O_ONCE_INTERACTIVE?"TRUE":"FALSE", flags&O_CREATED ?"TRUE":"FALSE"); sprintf(tdb,"time_of_ref : %d\n", ob->time_of_ref); strcat(db_buff, tdb); sprintf(tdb,"ref : %d\n", ob->ref); strcat(db_buff, tdb); #ifdef DEBUG sprintf(tdb,"extra_ref : %d\n", ob->extra_ref); strcat(db_buff, tdb); #endif sprintf(tdb,"swap_num : %ld\n", ob->swap_num); strcat(db_buff, tdb); sprintf(tdb,"name : '%s'\n", ob->name); strcat(db_buff, tdb); sprintf(tdb,"next_all : OBJ(%s)\n", ob->next_all?ob->next_all->name:"NULL"); strcat(db_buff, tdb); if (obj_list == ob) { sprintf(tdb,"This object is the head of the object list.\n"); strcat(db_buff, tdb); } obj2 = obj_list; i = 1; do if (obj2->next_all == ob) { sprintf(tdb,"Previous object in object list: OBJ(%s)\n", obj2->name); strcat(db_buff, tdb); sprintf(tdb, "position in object list:%d\n",i); strcat(db_buff, tdb); } while (obj_list != (obj2 = obj2->next_all)); } else if (argv[0].u.number == 1) { if (argv[1].type != T_OBJECT) break; ob = argv[1].u.ob; sprintf(db_buff,"program ref's %d\n", ob->prog->ref); sprintf(tdb,"Name %s\n", ob->prog->name); strcat(db_buff, tdb); sprintf(tdb,"program size %d\n", ob->prog->program_size); strcat(db_buff, tdb); sprintf(tdb,"num func's %d (%d) \n", ob->prog->num_functions ,ob->prog->num_functions * sizeof(struct function)); strcat(db_buff, tdb); sprintf(tdb,"sizeof rodata %d\n", ob->prog->rodata_size); strcat(db_buff, tdb); sprintf(tdb,"num vars %d (%d)\n", ob->prog->num_variables ,ob->prog->num_variables * sizeof(struct variable)); strcat(db_buff, tdb); sprintf(tdb,"num inherits %d (%d)\n", ob->prog->num_inherited ,ob->prog->num_inherited * sizeof(struct inherit)); strcat(db_buff, tdb); sprintf(tdb,"total size %d\n", ob->prog->total_size); strcat(db_buff, tdb); } else { sprintf(db_buff, "Bad number argument to object_info: %d\n", argv[0].u.number); } retval.type = T_STRING; retval.string_type = STRING_MALLOC; retval.u.string = string_copy(db_buff); return &retval; break; } case 19: /* function_map, 19 1 / 0 object */ { /* This is now obsolete, as all functions are hashed */ if (argc < 2 || argv[0].type != T_NUMBER || argv[1].type != T_OBJECT) break; retval = const0; return &retval; } case 20: /* send_udp, 20 host, port, msg */ { int tmp; if (argc < 3 || argv[0].type != T_STRING || argv[1].type != T_NUMBER || argv[2].type != T_STRING) break; tmp = send_udp(argv[0].u.string, argv[1].u.number, argv[2].u.string); if (tmp) retval = const1; else retval = const0; return &retval; } case 21: /* mud_port, 21 */ { extern int port_number; retval.type = T_NUMBER; retval.u.number = port_number; return &retval; } case 22: /* udp_port, 22 */ { #ifdef CATCH_UDP_PORT extern int udp_port; retval.u.number = udp_port; #else retval.u.number = -1; #endif retval.type = T_NUMBER; return &retval; } case 23: /* set_wizard, object */ { if (argc && (argv[0].type == T_OBJECT)) { retval = const1; return &retval; } else { retval = const0; return &retval; } break; } case 24: /* ob_flags, 24 ob */ { if (argc && (argv[0].type == T_OBJECT)) { retval.type = T_NUMBER; retval.u.number = argv[0].u.ob->flags; return &retval; } retval = const0; return &retval; } case 25: /* get_variables, 25 object NULL/string */ { struct svalue get_variables(); struct svalue get_variable(); switch (argc) { case 1: if ( argv[0].type != T_OBJECT) { retval = const0; return &retval; } retval = get_variables(argv[0].u.ob); return &retval; case 2: if ( argv[0].type != T_OBJECT || argv[1].type != T_STRING) { retval = const0; return &retval; } retval = get_variable(argv[0].u.ob, argv[1].u.string); return &retval; case 3: if ( argv[0].type == T_OBJECT && argv[1].type == T_STRING) { retval = get_variable(argv[0].u.ob, argv[1].u.string); return &retval; } if ( argv[0].type == T_OBJECT) { retval = get_variables(argv[0].u.ob); return &retval; } retval = const0; return &retval; default: retval = const0; return &retval; } } case 26: /* get_eval_cost, 26 */ { extern int eval_cost; retval.type = T_NUMBER; retval.u.number = eval_cost; return &retval; } case 27: /* debug malloc, 27 */ { #ifdef DEBUG_MALLOC debug_malloc(); #endif retval = const1; return &retval; } case 28: /* getprofile, 28 object */ { #ifndef PROFILE_FUNS retval.type = T_STRING; retval.string_type = STRING_CONSTANT; retval.u.string = "Only valid if GD compiled with PROFILE_FUNS flag.\n"; return &retval; break; #else if (argc < 1 || argv[0].type != T_OBJECT) break; retval.type = T_POINTER; retval.u.vec = allocate_array(argv[0].u.ob->prog->num_functions); access_program(argv[0].u.ob->prog); for (il = 0; il < argv[0].u.ob->prog->num_functions; il++) { char buff[200]; /* I know longer funnames crashes the GD... */ sprintf(buff, "%09d:%09ld: %s", argv[0].u.ob->prog->functions[il].num_calls, argv[0].u.ob->prog->functions[il].time_spent / 100, argv[0].u.ob->prog->functions[il].name); retval.u.vec->item[il].type = T_STRING; retval.u.vec->item[il].string_type = STRING_MALLOC; retval.u.vec->item[il].u.string = string_copy(buff); } access_program(current_prog); return &retval; break; #endif } case 29: /* get_avg_response, 29 */ { extern int get_msecs_response(); extern int msr_point; int il, sum, num, tmp; if (msr_point >=0) { for (sum = 0, num = 0,il = 0; il < 100; il++) { if ((tmp = get_msecs_response(il)) >=0) { sum += tmp; num++; } } retval.type = T_NUMBER; retval.u.number = (num > 0) ? sum / num : 0; return &retval; } break; } case 30: /* destruct, 30 */ case 31: /* destroy, 31 */ { extern void destruct_object(); if (argc && argv[0].type == T_OBJECT && !(argv[0].u.ob->flags & O_DESTRUCTED)) destruct_object(argv[0].u.ob); break; } case 32: /* update snoops, 31 */ read_snoop_file(); break; case 33: /* call_warnings, int 0 = off, 1 = on */ if (argc && (argv[0].type == T_STRING)) { if (strcmp(argv[0].u.string, "on") == 0) call_warnings++; else call_warnings = call_warnings > 0 ? call_warnings - 1 : 0; retval.type = T_NUMBER; retval.u.number = call_warnings; return &retval; } else { retval.type = T_NUMBER; retval.u.number = -1; return &retval; } break; case 34: /* dump objects */ { FILE *ufile; char *mem_variables(struct object *); struct object *ob, *nob; char line[255]; if ((ufile = fopen(DUMP_FILE, "w")) == NULL) { retval.type = T_NUMBER; retval.u.number = -1; return &retval; } ob = obj_list; do { if (ob) { extern int num_call_outs(struct object *); int num_co, num_inv; struct object *o; num_co = num_call_outs(ob); for (num_inv = 0, o = ob->contains; o; num_inv++, o = o->next_inv) ; sprintf(line, "%s %s in %s callouts %d inventory %d\n", mem_variables(ob), ob->name, ob->super ? ob->super->name : "(void)", num_co, num_inv); } if (fputs(line, ufile) < 0) { fclose(ufile); break; } nob = ob->next_all; } while (obj_list != (ob = nob)); fclose(ufile); break; } case 35: /* query_debug_ob */ if (!argc || argv[0].type != T_OBJECT) break; retval.type = T_NUMBER; retval.u.number = argv[0].u.ob->debug_flags; return &retval; case 36: /* set_debug_ob */ if (!argc || argv[0].type != T_OBJECT || argv[1].type != T_NUMBER) break; retval.type = T_NUMBER; retval.u.number = argv[0].u.ob->debug_flags; argv[0].u.ob->debug_flags = argv[1].u.number; return &retval; case 37: /* set_swap */ { extern int max_swap_memory; extern int min_swap_memory; extern int min_swap_time; extern int max_swap_time; struct vector *v; if (!argc || argv[0].type != T_POINTER || argv[0].u.vec->size != 4) break; v = argv[0].u.vec; if (v->item[0].type != T_NUMBER || v->item[0].u.number < 0) break; /* Too low min_swap_memory */ if (v->item[1].type != T_NUMBER || v->item[1].u.number < v->item[0].u.number) break; if (v->item[2].type != T_NUMBER || v->item[2].u.number < 0) break; if (v->item[3].type != T_NUMBER || v->item[3].u.number < v->item[2].u.number) break; min_swap_memory = v->item[0].u.number; max_swap_memory = v->item[1].u.number; min_swap_time = v->item[2].u.number; max_swap_time = v->item[3].u.number; retval.type = T_NUMBER; retval.u.number = 1; return &retval; } case 38: /* query_swap */ { if (argc == 0 || argv[0].type == T_NUMBER && argv[0].u.number == 0) { extern int max_swap_memory; extern int min_swap_memory; extern int min_swap_time; extern int max_swap_time; struct vector *v; v = allocate_array(4); v->item[0].type = T_NUMBER; v->item[0].u.number = min_swap_memory; v->item[1].type = T_NUMBER; v->item[1].u.number = max_swap_memory; v->item[2].type = T_NUMBER; v->item[2].u.number = min_swap_time; v->item[3].type = T_NUMBER; v->item[3].u.number = max_swap_time; retval.type = T_POINTER; retval.u.vec = v; return &retval; } else if (argv[0].type == T_NUMBER) { extern int used_memory; extern int swap_out_obj_sec, swap_out_obj_min; extern int swap_out_prog_sec, swap_out_prog_min; extern int swap_in_obj_sec, swap_in_obj_min; extern int swap_in_prog_sec, swap_in_prog_min; extern int swap_out_obj_hour, swap_in_obj_hour; extern int swap_out_prog_hour, swap_in_prog_hour; extern struct object *swap_ob; extern struct program *swap_prog; extern int used_memory; switch(argv[0].u.number) { case 1: { struct vector *v, *v0; v = allocate_array(4); v0 = allocate_array(3); v0->item[0].type = T_NUMBER; v0->item[0].u.number = swap_in_obj_sec; v0->item[1].type = T_NUMBER; v0->item[1].u.number = swap_in_obj_min; v0->item[2].type = T_NUMBER; v0->item[2].u.number = swap_in_obj_hour; v->item[0].type = T_POINTER; v->item[0].u.vec = v0; v0 = allocate_array(3); v0->item[0].type = T_NUMBER; v0->item[0].u.number = swap_in_prog_sec; v0->item[1].type = T_NUMBER; v0->item[1].u.number = swap_in_prog_min; v0->item[2].type = T_NUMBER; v0->item[2].u.number = swap_in_prog_hour; v->item[1].type = T_POINTER; v->item[1].u.vec = v0; v0 = allocate_array(3); v0->item[0].type = T_NUMBER; v0->item[0].u.number = swap_out_obj_sec; v0->item[1].type = T_NUMBER; v0->item[1].u.number = swap_out_obj_min; v0->item[2].type = T_NUMBER; v0->item[2].u.number = swap_out_obj_hour; v->item[2].type = T_POINTER; v->item[2].u.vec = v0; v0 = allocate_array(3); v0->item[0].type = T_NUMBER; v0->item[0].u.number = swap_out_prog_sec; v0->item[1].type = T_NUMBER; v0->item[1].u.number = swap_out_prog_min; v0->item[2].type = T_NUMBER; v0->item[2].u.number = swap_out_prog_hour; v->item[3].type = T_POINTER; v->item[3].u.vec = v0; retval.type = T_POINTER; retval.u.vec = v; return &retval; } case 2: retval.type = T_NUMBER; retval.u.number = (swap_prog->time_of_ref < swap_ob->time_of_ref ? swap_prog->time_of_ref : swap_prog->time_of_ref); return &retval; case 3: retval.type = T_NUMBER; retval.u.number = used_memory; return &retval; } } break; } case 39: /* query_debug_prog */ if (!argc || argv[0].type != T_OBJECT) break; retval.type = T_NUMBER; retval.u.number = argv[0].u.ob->prog->debug_flags; return &retval; case 40: /* set_debug_prog */ if (argc < 2 || argv[0].type != T_OBJECT || argv[1].type != T_NUMBER) break; retval.type = T_NUMBER; retval.u.number = argv[0].u.ob->prog->debug_flags; argv[0].u.ob->prog->debug_flags = argv[1].u.number; return &retval; } retval = const0; return &retval; } #ifdef RUSAGE static struct vector * make_cpu_array(int i, struct program *prog[]) { int num; struct vector *ret; char buff[1024]; /* should REALLY be enough */ if (i <= 0) return 0; ret = allocate_array(i); for(num = 0; num < i; num++) { sprintf(buff, "%8.8ld:%s", prog ? prog[num]->cpu : 0L, prog ? prog[num]->name : ""); free_svalue(&ret->item[num]); ret->item[num].type = T_STRING; ret->item[num].string_type = STRING_MALLOC; ret->item[num].u.string = string_copy(buff); } return ret; } #endif struct svalue get_variables(struct object *ob) { int i, j; struct vector *names; struct vector *values; struct svalue res; extern char *make_shared_string(); struct program *prog; int num_var; struct object oob; if (ob->flags & O_DESTRUCTED || !ob->variables) return const0; access_object(ob); num_var = ob->prog->num_variables + ob->prog->inherit[ob->prog->num_inherited - 1] .variable_index_offset; names = allocate_array(num_var); values = allocate_array(num_var); for (j = ob->prog->num_inherited - 1; j >= 0; j--) if (!(ob->prog->inherit[j].type & TYPE_MOD_SECOND) && ob->prog->num_variables > 0) { access_program(ob->prog->inherit[j].prog); for (i = 0; i < (int)ob->prog->inherit[j].prog->num_variables; i++) { if (num_var == 0) error("Wrong number of variables in object.\n"); names->item[--num_var].type = T_STRING; names->item[num_var].string_type = STRING_SHARED; names->item[num_var].u.string = ob->prog->inherit[j].prog-> variable_names[i].name; increment_string_ref(ob->prog->inherit[j].prog-> variable_names[i].name); assign_svalue_no_free(&values->item[num_var], &ob->variables[ob->prog->inherit[j] .variable_index_offset + i]); } } res.type = T_MAPPING; res.u.map = make_mapping(names, values); free_vector(names); free_vector(values); access_object(current_object); access_program(current_prog); return res; } struct svalue get_variable(struct object *ob, char *var_name) { int i; struct svalue res = const0; if (ob->flags & O_DESTRUCTED || !ob->variables) return res; access_object(ob); if ((i = find_status(ob->prog, var_name,0)) != -1) assign_svalue_no_free(&res, &ob->variables[i]); access_object(current_object); return res; } /* Using globals is a bit unclean. I should return and tidy up later */ static int mapping_elem, array_elem, string_size, num_string; static int num_map, num_arr, num_num, num_ob, num_float; void mem_mapping(struct mapping *); void mem_array(struct vector *); INLINE void mem_incr(struct svalue *var) { switch(var->type) { case T_MAPPING: mapping_elem += var->u.map->size; num_map++; mem_mapping(var->u.map); break; case T_POINTER: array_elem += var->u.vec->size; num_arr++; mem_array(var->u.vec); break; case T_STRING: string_size += strlen(var->u.string); num_string++; break; case T_OBJECT: /* Check for destructed objects while we'r at it :) */ if (var->u.ob->flags & O_DESTRUCTED) { num_num++; free_svalue(var); break; } num_ob++; break; case T_FLOAT: num_float++; break; case T_NUMBER: num_num++; break; default: ; } } void mem_mapping(struct mapping *m) { struct apair **p; struct apair **next; int i; int size; if (m->size < 0) return; size = m->size; m->size = -1; for (i = 0 ; i < size ; i++) { for(p = &m->pairs[i]; *p; ) { /* Check for destructed objects while we'r at it :) */ if ((*p)->arg.type == T_OBJECT && (*p)->arg.u.ob->flags & O_DESTRUCTED) { struct apair *f; f = *p; *p = f->next; f->next = 0; free_apairs(f); mapping_elem--; } else { mem_incr(&(*p)->arg); mem_incr(&(*p)->val); p = &(*p)->next; } } } m->size = size; } void mem_array(struct vector *v) { int i; int size; if (v->size < 0) return; size = v->size; v->size = -1; for (i = 0; i < size; i++) mem_incr(&v->item[i]); v->size = size; } char * mem_variables(struct object *ob) { int i, j; struct svalue *var; struct program *prog; int num_var; static char buf[128]; int was_swapped; extern void swap_object(struct object *); if (ob->flags & O_DESTRUCTED || !ob->variables) return "NOT AVAILABLE "; if (ob->flags & O_SWAPPED) { load_ob_from_swap(ob); was_swapped = 1; } else was_swapped = 0; mapping_elem = 0; array_elem = 0; string_size = 0; num_string = 0; num_arr = 0; num_map = 0; num_ob = 0; num_num = 0; num_float = 0; num_var = ob->prog->num_variables + ob->prog->inherit[ob->prog->num_inherited - 1].variable_index_offset; for (i = -1; i < num_var; i++) { mem_incr(&ob->variables[i]); } sprintf(buf, "A %6d %6d M %6d %6d S %6d %6d O %6d N %6d F %6d", num_arr, array_elem, num_map, mapping_elem, num_string, string_size, num_ob, num_num, num_float); if (was_swapped) swap_object(ob); return buf; }