1 /*---------------------------------------------------------------------------
2  * Wizard List
3  *
4  *---------------------------------------------------------------------------
5  * The Wizard List ("wizlist") started out as a means to determine a high
6  * score list of the most popular castles. Over the time, this list
7  * was generalized into a simple user-id management with driver-internal
8  * purposes.
9  *
10  * A user-id ("wizard name", "creator") is a unique string, and every object
11  * is associated with a uid through the master-apply get_wiz_name(object-name).
12  * The reverse doesn't hold true: the mudlib can use uids which are not
13  * associated with any object.
14  *
15  * A special uid is the number 0: this is denotes the 'default' wizard,
16  * ie. the system itself. Together with the .extra information feature,
17  * the wizlist entry for uid 0 can be used to store information "on driver
18  * level".
19  *
20  * Every uid represented with a wizlist entry of the following structure.
21  * Object structures even contain a '.user' entry pointing directly
22  * to the associated wizlist entry.
23  *
24  *   struct wiz_list_s {
25  *      wiz_list_t *next;
26  *      string_t *name;
27  *      int32  score;
28  *      int32  cost;
29  *      int32  gigacost;
30  *      int32  total_cost;
31  *      int32  total_gigacost;
32  *      int32  heart_beats;
33  *      mp_int size_array;
34  *      mp_int mapping_total;
35 #ifdef USE_STRUCTS
36  *      mp_int struct_total;
37 #endif
38  *      svalue_t extra;
39  *      int32  last_call_out;
40  *      int32  call_out_cost;
41  *      string_t *file_name;
42  *      string_t *error_message;
43  *      int32 line_number;
44  *  };
45  *
46  * .name is the tabled uid string of this wizlist entry.
47  * .next is the pointer to the next entry in the wizlist.
48  *
49  * .score, .(total_)cost+.(total_)gigacost, .heart_beats, .size_array and
50  * .mapping_total collect statistics about the objects for this uid/wizard.
51  * .score is the number of action functions executed (weighted over time),
52  * .cost+.gigacost the eval ticks spent (weighted over time),
53  * .total_cost+.total_gigacost the eval ticks spent (total), .heart_beats the
54  * number of heart_beat() calls (weighted over time).  .size_array and
55  * .mapping_total give the number of values held in arrays and mappings for
56  * this wizard.
57  *
58  * .extra offer space for one svalue which can be used by the mudlib
59  * for its own purposes. The driver can be instructed to fill the .extra
60  * member every newly created entry with an empty array of a specific
61  * size. Especially the .extra member for uid 0 can be used to store
62  * data persistent to the whole driver run - it even survives reloads
63  * of the master object.
64  *
65  * .last_call_out and .call_out_cost are used to manage the call_out.
66  * .call_out_cost is the collected execution cost of all call_outs
67  * executed for time .last_call_out for this .user. When executing
68  * call_outs, this value is used to prime the eval_cost counter, and
69  * thus prevents call_outs from hogging all the cpu.
70  *
71  * .file_name, .error_message and .line_number are used to communicate
72  * errors from the driver to the mudlib. Bit 30 (0x40000000) in line_number
73  * is the "forget flag": it is set when the mudlib queries the error
74  * information. This way the mudlib can distinguish old from new
75  * errors.
76  *
77  *
78  * Part of the wizard list information is stored in the toplevel file
79  * "WIZLIST". The file is organized in lines, one for every wizard.
80  * Each line must at least contain:
81  *
82  *    <name> <score>
83  *
84  * No leading space, and <name> and <score> must be separated by one or
85  * more spaces. If existing, this information is read by the driver at
86  * startup and added(!) to the already existing wizlist entries.
87  *
88  * The mudlib is free to add more information after the <score> and read
89  * it itself. For the same reason it is the task of the mudlib to write
90  * the WIZLIST file.
91  *---------------------------------------------------------------------------
92  */
93 
94 #include "driver.h"
95 #include "typedefs.h"
96 
97 #include "my-alloca.h"
98 
99 #include <stdio.h>
100 
101 #include "wiz_list.h"
102 #include "../mudlib/sys/wizlist.h"
103 
104 #include "array.h"
105 #include "backend.h"
106 #include "gcollect.h"
107 #include "interpret.h"
108 #include "main.h"
109 #include "mapping.h"
110 #include "mstrings.h"
111 #include "object.h"
112 #include "simulate.h"
113 #include "stdstrings.h"
114 #include "svalue.h"
115 #include "xalloc.h"
116 
117 /*-------------------------------------------------------------------------*/
118 wiz_list_t default_wizlist_entry
119   /* The default wizlist entry which is used for all "system" purposes.
120    */
121   = { NULL          /* next */
122     , NULL          /* name */
123     , 0             /* score */
124     , 0             /* cost */
125     , 0             /* gigacost */
126     , 0             /* total_cost */
127     , 0             /* total_gigacost */
128     , 0             /* heart_beats */
129     , 0             /* size_array */
130     , 0             /* mapping_total */
131 #ifdef USE_STRUCTS
132     , 0             /* struct_total */
133 #endif
134     , { T_NUMBER }  /* extra */
135     , 0             /* last_call_out */
136     , 0             /* call_out_cost */
137     , NULL          /* error file_name */
138     , NULL          /* error_message */
139     , 0             /* error line_number */
140   };
141 
142 wiz_list_t *all_wiz = NULL;
143   /* The list of all wizard entries, sorted by the numeric value
144    * of <name>. If the names are queried equally often, this even yields
145    * an average O(1) complexity.
146    */
147 
148 static int wiz_info_extra_size = -1;
149   /* Default size of the .extra field, -1 if unspecified.
150    */
151 
152 static int number_of_wiz = 0;
153   /* Number of entries in the list.
154    */
155 
156 char wizlist_name[MAXPATHLEN+1] = "";
157   /* Name of the wizlist file, relative to the mudlib directory.
158    */
159 
160 /*-------------------------------------------------------------------------*/
161 void
name_wizlist_file(const char * name)162 name_wizlist_file (const char *name)
163 
164 /* Set the swap file name to a copy of <name>.
165  */
166 
167 {
168     /* Skip leading '/' */
169     while (*name == '/') name++;
170 
171     xstrncpy(wizlist_name, name, sizeof wizlist_name);
172     wizlist_name[sizeof wizlist_name - 1] = '\0';
173 } /* name_wizlist_file()*/
174 
175 /*-------------------------------------------------------------------------*/
176 size_t
wiz_list_size(void)177 wiz_list_size (void)
178 
179 /* Return the allocated size of the wiz_list.
180  */
181 
182 {
183     /* The extra wizinfo has been counted with the arrays */
184     return sizeof(wiz_list_t) * number_of_wiz;
185 } /* wiz_list_size() */
186 
187 /*-------------------------------------------------------------------------*/
188 static wiz_list_t *
find_wiz(string_t * name)189 find_wiz (string_t *name)
190 
191 /* Find the entry for the user 'name' and return it's pointer.
192  * Return NULL if it can't be found.
193  */
194 
195 {
196     wiz_list_t *wl;
197 
198     if ( !( name = find_tabled(name) ) )
199         return NULL;
200 
201     for (wl = all_wiz; wl; wl = wl->next)
202     {
203         int rc = mstrcmp(wl->name, name);
204 
205         if (!rc)
206             return wl;
207         if (rc > 0)
208             break;
209     }
210     return NULL;
211 } /* find_wiz() */
212 
213 /*-------------------------------------------------------------------------*/
214 wiz_list_t *
add_name(string_t * str)215 add_name (string_t * str)
216 
217 /* Check if an entry for wizard <str> exists; add it, if it doesn't.
218  * Return the pointer to the wiz_list entry.
219  * Must not change refcount of <str>.
220  */
221 
222 {
223     wiz_list_t *wl;
224     wiz_list_t *prev, *this;
225 
226     wl = find_wiz(str);
227     if (wl)
228         return wl;
229 
230     number_of_wiz++;
231     wl = xalloc(sizeof (wiz_list_t));
232 
233     str = make_tabled_from(str);
234 
235     wl->next           = NULL;
236     wl->name           = str;
237     wl->score          = 0;
238     wl->cost           = 0;
239     wl->gigacost       = 0;
240     wl->total_cost     = 0;
241     wl->total_gigacost = 0;
242     wl->heart_beats    = 0;
243     wl->size_array     = 0;
244     wl->mapping_total  = 0;
245 #ifdef USE_STRUCTS
246     wl->struct_total   = 0;
247 #endif /* USE_STRUCTS */
248 #if 0
249     wl->quota_allowance = 0;
250     wl->quota_usage   = 0;
251 #endif
252     wl->file_name     = NULL;
253     wl->error_message = NULL;
254     if (wiz_info_extra_size >= 0)
255         put_array(&(wl->extra), allocate_array(wiz_info_extra_size));
256     else
257         wl->extra = const0;
258     wl->last_call_out = 0;
259 
260     /* Find the insertion point and insert the new entry */
261     for ( prev = NULL, this = all_wiz
262         ; this && mstrcmp(this->name, str) < 0
263         ; prev = this, this = this->next
264         )
265     { NOOP; }
266 
267     if (!prev)
268     {
269         wl->next = all_wiz;
270         all_wiz = wl;
271     }
272     else
273     {
274         wl->next = this;
275         prev->next = wl;
276     }
277 
278     return wl;
279 } /* add_name() */
280 
281 /*-------------------------------------------------------------------------*/
282 void
wiz_decay(void)283 wiz_decay (void)
284 
285 /* Called after every complete walkaround of the reset, this 'decays'
286  * the score of every wizard once per hour.
287  * Together with the decay, the wizlist is checked for destructed extra
288  * data.
289  */
290 
291 {
292     wiz_list_t *wl;
293     static int next_time;
294 
295     /* Only once per hour */
296     if (next_time > current_time)
297         return;
298 
299     next_time = current_time + 60 * 60;
300     for (wl = all_wiz; wl; wl = wl->next)
301     {
302         wl->score = wl->score * 99 / 100;
303         wl->cost = wl->cost * .9;
304         wl->gigacost = wl->gigacost * .9;
305         wl->heart_beats = wl->heart_beats * 9 / 10;
306     }
307 
308     check_wizlist_for_destr();
309 } /* wiz_decay() */
310 
311 /*-------------------------------------------------------------------------*/
312 static string_t *
get_wiz_name(const char * file)313 get_wiz_name (const char *file)
314 
315 /* For the filename <file> return the name of the wizard responsible
316  * for it. This actual query is done with a master apply.
317  *
318  * Result is NULL or an uncounted string reference.
319  */
320 
321 {
322     svalue_t *ret;
323 
324     /* Don't call the master if it isn't loaded! */
325     if (!master_ob)
326         return NULL;
327 
328     push_c_string(inter_sp, file);
329     ret = apply_master(STR_GET_WNAME, 1);
330     if (ret == 0 || ret->type != T_STRING)
331         return NULL;
332     return ret->u.str;
333 } /* get_wiz_name() */
334 
335 /*-------------------------------------------------------------------------*/
336 void
load_wiz_file(void)337 load_wiz_file (void)
338 
339 /* Load the old wizlist from the wizlist file and add it's data to
340  * the wizlist already in memory.
341  *
342  * This function is called at driver start up.
343  * TODO: Since the wizlist is saved from the mudlib, this function
344  * TODO:: should be implemented on mudlib level, too.
345  */
346 
347 {
348     char buff[1000];
349     FILE *f;
350 
351     if (wizlist_name[0] == '\0')
352         return;
353 
354     f = fopen(wizlist_name, "r");
355     if (f == NULL)
356         return;
357 
358     while (fgets(buff, sizeof buff, f) != NULL)
359     {
360         char *p;
361         uint32 score;
362 
363         p = strchr(buff, ' ');
364         if (p == 0)
365         {
366             fprintf(stderr, "%s Bad WIZLIST file '%s'.\n"
367                           , time_stamp(), wizlist_name);
368             break;
369         }
370         *p = '\0';
371         p++;
372         if (*p == '\0')
373         {
374             fprintf(stderr, "%s Bad WIZLIST file '%s'.\n"
375                           , time_stamp(), wizlist_name);
376             break;
377         }
378         score = atoi(p);
379         if (score > 0)
380         {
381             string_t * tmp;
382 
383             tmp = new_mstring(buff);
384             add_name(tmp)->score += score;
385             free_mstring(tmp);
386         }
387     }
388     fclose(f);
389 } /* load_wiz_file() */
390 
391 /*-------------------------------------------------------------------------*/
392 void
remove_wiz_list(void)393 remove_wiz_list (void)
394 
395 /* Remove all memory allocated by the wizlist.
396  *
397  * Called from simulate::shutdowngame().
398  */
399 
400 {
401     wiz_list_t *wl, *w;
402 
403     for (w = all_wiz; w; w = wl)
404     {
405         free_mstring(w->name);
406         if (w->file_name)
407             free_mstring(w->file_name);
408         if (w->error_message)
409             free_mstring(w->error_message);
410         wl = w->next;
411         xfree(w);
412     }
413 } /* remove_wiz_list() */
414 
415 /*-------------------------------------------------------------------------*/
416 void
save_error(const char * msg,const char * file,int line)417 save_error (const char *msg, const char *file, int line)
418 
419 /* A runtime error <msg> occured for object <file> in line number <line>.
420  * Store this information in the wizlist so that the mudlib can handle
421  * it later with the efun get_error_file().
422  * TODO: A proper runtime error handling could put this into the mudlib
423  * TODO:: completely.
424  */
425 
426 {
427     wiz_list_t *wl;
428     char *copy, *p;
429     string_t *name;
430     size_t len;
431 
432     /* Get the wizard name and the wizlist entry. */
433     name = get_wiz_name(file);
434     if (!name)
435         return;
436     wl = add_name(name);
437 
438     /* Set the file_name */
439     if (wl->file_name)
440         free_mstring(wl->file_name);
441 
442     len = strlen(file);
443     copy = alloca(len + 4); /* May add .c plus the null byte, and / */
444     *copy = '/';
445     strcpy(copy+1, file);
446 
447     /* If it is a cloned object, we have to find out what the file
448      * name is, and add '.c'.
449      */
450     if ( NULL != (p = strrchr(copy, '#'))
451      || ((p = copy+len), *p++ != 'c') || p[-2] != '.' )
452     {
453         p[0] = '.';
454         p[1] = 'c';
455         p[2] = '\0';
456     }
457     wl->file_name = new_mstring(copy);
458 
459     /* Set the error_message */
460     if (wl->error_message)
461         free_mstring(wl->error_message);
462     wl->error_message = new_mstring(msg);
463 
464     /* Set the line_number */
465     wl->line_number = line;
466 } /* save_error() */
467 
468 /*=========================================================================*/
469 
470 /*                            EFUNS                                        */
471 
472 /*-------------------------------------------------------------------------*/
473 svalue_t *
f_wizlist_info(svalue_t * sp)474 f_wizlist_info (svalue_t *sp)
475 
476 /* EFUN wizlist_info()
477  *
478  *    mixed *wizlist_info()
479  *
480  * Returns an array with the interesting entries of the wizlist.
481  * Raises a privilege_violation (wizlist_info, this_object(), 0).
482  *
483  * The result is an array with one entry for every wizard (uid).
484  * Every entry is an array itself:
485  *
486  *   string w[WL_NAME]        = Name of the wizard.
487  *   int    w[WL_COMMANDS]    = Weighted number of commands execute by objects
488  *                              of this wizard.
489  *   int    w[WL_COST] and  w[WL_GIGACOST] = Weighted sum of eval_costs.
490  *   int    w[WL_TOTAL_COST] and  w[WL_TOTAL_GIGACOST] = Total sum of
491  *                              eval_costs.
492  *   int    w[WL_HEART_BEATS] = Weighted count of heart_beats.
493  *   int    w[WL_CALL_OUT]    = Reserved for call_out() (unused yet).
494  *   int    w[WL_ARRAY_TOTAL] = Total size of arrays in elements.
495  *   int    w[WL_MAPPING_TOTAL] = Total size of mappings in elements.
496 #ifdef USE_STRUCTS
497  *   int    w[WL_STRUCT_TOTAL] = Total size of mappings in elements.
498 #endif
499  *   mixed  w[WL_EXTRA]       = Extra wizlist-info if set.
500  */
501 
502 {
503     vector_t *all, *entry;
504     svalue_t *wsvp, *svp;
505     wiz_list_t *w;
506 
507     if (!privilege_violation(STR_WIZLIST_INFO, &const0, sp))
508     {
509         all = allocate_array(0);
510     }
511     else
512     {
513         all = allocate_array(number_of_wiz);
514         wsvp = all->item;
515         for (w = all_wiz; w; w = w->next)
516         {
517             entry = allocate_array(WL_SIZE);
518             put_array(wsvp, entry);
519             wsvp++;
520             svp = entry->item;
521             put_ref_string(&(svp[WL_NAME]), w->name);
522             put_number(&(svp[WL_COMMANDS]), w->score);
523             put_number(&(svp[WL_COST]), w->cost);
524             put_number(&(svp[WL_GIGACOST]), w->gigacost);
525             put_number(&(svp[WL_TOTAL_COST]), w->total_cost);
526             put_number(&(svp[WL_TOTAL_GIGACOST]), w->total_gigacost);
527             put_number(&(svp[WL_HEART_BEATS]), w->heart_beats);
528             put_number(&(svp[WL_CALL_OUT]), 0); /* TODO: Implement me */
529             put_number(&(svp[WL_ARRAY_TOTAL]), w->size_array);
530             put_number(&(svp[WL_MAPPING_TOTAL]), w->mapping_total);
531 #ifdef USE_STRUCTS
532             put_number(&(svp[WL_STRUCT_TOTAL]), w->struct_total);
533 #else
534             put_number(&(svp[WL_STRUCT_TOTAL]), 0);
535 #endif /* USE_STRUCTS */
536             if (w->extra.type == T_POINTER)
537             {
538                 vector_t *v = w->extra.u.vec;
539                 put_array(&(svp[WL_EXTRA]), slice_array(v, 0, VEC_SIZE(v) - 1));
540             }
541             else
542                 assign_svalue_no_free(&(svp[WL_EXTRA]), &w->extra);
543         } /* end for */
544     } /* end if */
545 
546     push_array(sp, all);
547     return sp;
548 } /* f_wizlist_info() */
549 
550 /*-------------------------------------------------------------------------*/
551 svalue_t *
f_set_extra_wizinfo(svalue_t * sp)552 f_set_extra_wizinfo (svalue_t *sp)
553 
554 /* EFUN set_extra_wizinfo()
555  *
556  *   void set_extra_wizinfo (object wiz, mixed extra)
557  *   void set_extra_wizinfo (string wiz, mixed extra)
558  *   void set_extra_wizinfo (int    wiz, mixed extra)
559  *
560  * Set the value <extra> as the 'extra' information for the wizlist
561  * entry of <wiz>.
562  *
563  * If <wiz> is an object, the entry of its creator (uid) is used.
564  * If <wiz> is a string (a creator aka uid), it names the entry
565  * to use.
566  * If <wiz> is the number 0, the data is set in the default wizlist
567  * entry. It can be used to store data for the lifetime of this
568  * driver run, like the time of the last reboot.
569  *
570  * <extra> can be any value.
571  *
572  * The function causes a privilege violation
573  * ("set_extra_wizinfo", this_object(), <wiz>).
574  */
575 
576 {
577     wiz_list_t *user;
578     short type;
579 
580     if ((type = sp[-1].type) == T_OBJECT)
581     {
582         user = sp[-1].u.ob->user;
583     }
584     else if (type != T_STRING || !(user = find_wiz(sp[-1].u.str)))
585     {
586         if (type == T_NUMBER && sp[-1].u.number == 0)
587             user = NULL;
588         else
589             efun_gen_arg_error(1, sp->type, sp);
590     }
591 
592     if (!privilege_violation(STR_SET_EXTRA_WIZINFO, sp-1, sp))
593         free_svalue(sp);
594     else
595         transfer_svalue(user ? &user->extra : &default_wizlist_entry.extra, sp);
596 
597     free_svalue(sp-1);
598 
599     return sp - 2;
600 } /* f_set_extra_wizinfo() */
601 
602 /*-------------------------------------------------------------------------*/
603 svalue_t *
f_get_extra_wizinfo(svalue_t * sp)604 f_get_extra_wizinfo (svalue_t *sp)
605 
606 /* EFUN get_extra_wizinfo()
607  *
608  *   mixed get_extra_wizinfo (object wiz)
609  *   mixed get_extra_wizinfo (string wiz)
610  *   mixed get_extra_wizinfo (int    wiz)
611  *
612  * Returns the 'extra' information that was set for the given
613  * wizard <wiz> in the wizlist.
614  *
615  * If <wiz> is an object, the entry of its creator (uid) is used.
616  * If <wiz> is a string (a creator aka uid), it names the entry
617  * to use.
618  * If <wiz> is the number 0, the data is get from the default wizlist
619  * entry.
620  *
621  * The function causes a privilege violation
622  * ("get_extra_wizinfo", this_object(), <wiz>).
623  */
624 
625 {
626     wiz_list_t *user;
627     short type;
628 
629     if ((type = sp->type) == T_OBJECT)
630     {
631         user = sp->u.ob->user;
632     }
633     else if (type != T_STRING || !(user = find_wiz(sp->u.str)))
634     {
635         if (type == T_NUMBER && sp->u.number == 0)
636             user = NULL;
637         else
638             errorf("Bad arg 1 to get_extra_wizinfo(): no valid uid given.\n");
639     }
640 
641     if (!privilege_violation(STR_GET_EXTRA_WIZINFO, sp, sp))
642         errorf("Error in get_extra_wizinfo(): privilege violation.\n");
643 
644     assign_svalue(sp, user ? &user->extra : &default_wizlist_entry.extra);
645 
646     return sp;
647 } /* get_extra_wizlist_info() */
648 
649 /*-------------------------------------------------------------------------*/
650 svalue_t *
f_set_extra_wizinfo_size(svalue_t * sp)651 f_set_extra_wizinfo_size (svalue_t *sp)
652 
653 /* EFUN set_extra_wizinfo_size()
654  *
655  *   void set_extra_wizinfo_size(int size)
656  *
657  * Indicate that the wizlist should contain an array of this size
658  * with extra info foreach wizard. A negative size is used to
659  * indicate non-array 'extra' information.
660  *
661  * Causes the privilege violation
662  * ("set_extra_wizinfo_size", this_object(), size).
663  *
664  * The value is only used to allocate a proper empty 'extra' value
665  * for newly created wizlist entries.
666  *
667  * TODO: The extra_wizinfo idea could be applied to single objects
668  * TODO:: and - ta da! - we have driver supported properties.
669  * TODO:: Which then could be used to implement uids/euids etc.
670  */
671 
672 {
673     if (!privilege_violation(STR_SET_EXTRA_WIZINFO_SIZE, &const0, sp))
674         wiz_info_extra_size = sp->u.number;
675 
676     sp--;
677 
678     return sp;
679 } /* f_set_extra_wizinfo_size() */
680 
681 /*-------------------------------------------------------------------------*/
682 svalue_t *
f_get_error_file(svalue_t * sp)683 f_get_error_file (svalue_t *sp)
684 
685 /* EFUN get_error_file()
686  *
687  *   mixed * get_error_file(string name, int set_forget_flag)
688  *
689  * Return information about the last error which occured for
690  * <name> (where <name> is a valid name from the wiz list).
691  *
692  * Result is an array of four elements: the filename of the
693  * program where the error occured, the linenumber in the
694  * program, the error message (runtime error messages usually
695  * start with a '*'), and a numerical flag (the 'forget flag') if
696  * the error information has been queried already.
697  *
698  * If there is no error stored for the given <name>, 0 is
699  * returned.
700  *
701  * If <set_forget_flag> is non-zero, the 'forget' flag is set
702  * for the error message after it has been returned.
703  */
704 
705 {
706     string_t *name;
707     int forget;
708     wiz_list_t *wl;
709     vector_t *vec;
710     svalue_t *v;
711 #   define FORGET_FLAG 0x4000000 /* 0x80...0 would be the sign! */
712 
713     /* Get the function arguments */
714     name = sp[-1].u.str;
715     forget = sp->u.number;
716     wl = find_wiz(name);
717     sp--;
718     free_string_svalue(sp);
719 
720     /* The error_message is used as a flag if there has been any error.
721      */
722     if (!wl || !wl->error_message)
723     {
724         put_number(sp, 0);
725         return sp;
726     }
727 
728     vec = allocate_array(4);
729     v = vec->item;
730     put_ref_string(v, wl->file_name);
731     put_number(v+1, wl->line_number & ~0x40000000);
732     put_ref_string(v+2, wl->error_message);
733     put_number(v+3, (wl->line_number & 0x40000000) != 0);
734 
735     if (forget)
736         wl->line_number |= 0x40000000;
737 
738     put_array(sp, vec);
739     return sp;
740 
741 #   undef FORGET_FLAG
742 } /* f_get_error_file() */
743 
744 /*=========================================================================*/
745 
746 /*-------------------------------------------------------------------------*/
747 void
check_wizlist_for_destr(void)748 check_wizlist_for_destr (void)
749 
750 /* Check the 'extra' info in all wizinfo and remove destructed objects
751  * and closures.
752  */
753 
754 {
755     wiz_list_t *wl;
756 
757     for (wl = &default_wizlist_entry; wl; )
758     {
759         size_t num;
760         svalue_t *item;
761 
762         if (wl->extra.type == T_POINTER)
763         {
764             num = VEC_SIZE(wl->extra.u.vec);
765             item = &(wl->extra.u.vec->item[0]);
766         }
767         else
768         {
769             num = 1;
770             item = &(wl->extra);
771         }
772 
773         for ( ; num != 0 ; item++, num--)
774         {
775             switch(item->type)
776             {
777             case T_POINTER:
778                 check_for_destr(item->u.vec);
779                 break;
780             case T_MAPPING:
781                 check_map_for_destr(item->u.map);
782                 break;
783             case T_OBJECT:
784             case T_CLOSURE:
785                 if (destructed_object_ref(item))
786                     assign_svalue(item, &const0);
787                 break;
788             default:
789                 NOOP;
790                 break;
791             }
792         }
793 
794         if (wl == &default_wizlist_entry)
795             wl = all_wiz;
796         else
797             wl = wl->next;
798     }
799 } /* check_wizlist_for_destr() */
800 
801 /*-------------------------------------------------------------------------*/
802 #ifdef GC_SUPPORT
803 
804 void
clear_ref_from_wiz_list(void)805 clear_ref_from_wiz_list (void)
806 
807 /* GC support: Clear the refs for the wiz_list memory.
808  */
809 
810 {
811     wiz_list_t *w;
812 
813     for (w = all_wiz; w; w = w->next)
814     {
815         clear_ref_in_vector(&w->extra, 1);
816         if(w->file_name)
817             clear_string_ref(w->file_name);
818         if(w->error_message)
819             clear_string_ref(w->error_message);
820     }
821     clear_ref_in_vector(&default_wizlist_entry.extra, 1);
822 } /* clear_ref_from_wiz_list() */
823 
824 /*-------------------------------------------------------------------------*/
825 void
count_ref_from_wiz_list(void)826 count_ref_from_wiz_list (void)
827 
828 /* GC support: Count the refs for the wiz_list memory.
829  */
830 
831 {
832     wiz_list_t *w;
833 
834     for (w = all_wiz; w; w = w->next) {
835         count_ref_from_string(w->name);
836         count_ref_in_vector(&w->extra, 1);
837         if(w->file_name)
838             count_ref_from_string(w->file_name);
839         if (w->error_message)
840             count_ref_from_string(w->error_message);
841         note_malloced_block_ref((char *)w);
842     }
843     count_ref_in_vector(&default_wizlist_entry.extra, 1);
844 } /* count_ref_from_wiz_list() */
845 
846 #endif /* GC_SUPPORT */
847 
848 /*-------------------------------------------------------------------------*/
849 #ifdef DEBUG
850 
851 void
count_extra_ref_from_wiz_list(void)852 count_extra_ref_from_wiz_list (void)
853 
854 /* DEBUG support: Count the extra refs for the wiz_list memory.
855  */
856 
857 {
858     wiz_list_t *w;
859 
860     for (w = all_wiz; w; w = w->next) {
861         count_extra_ref_in_vector(&w->extra, 1);
862     }
863     count_extra_ref_in_vector(&default_wizlist_entry.extra, 1);
864 } /* count_extra_ref_from_wiz_list() */
865 
866 #endif
867 
868 /***************************************************************************/
869 
870