ArchWizard

DGD/

source navigation ]
diff markup ]
identifier search ]
file search ]
Version: [ 1.0.a0 ] [ 1.1 ] [ 1.2 ] [ 1.2p1 ] [ 1.2p2 ] [ 1.2p3 ] [ 1.2p4 ] [ 1.2.151 ]

  1 # define INCLUDE_FILE_IO
  2 # define INCLUDE_CTYPE
  3 # include "dgd.h"
  4 # include "str.h"
  5 # include "array.h"
  6 # include "object.h"
  7 # include "interpret.h"
  8 # include "data.h"
  9 
 10 typedef struct _objplane_ objplane;
 11 
 12 typedef struct _objpatch_ {
 13     short access;                       /* access flags */
 14     objplane *plane;                    /* plane that patch is on */
 15     struct _objpatch_ *prev;            /* previous patch */
 16     struct _objpatch_ *next;            /* next in linked list */
 17     object obj;                         /* new object value */
 18 } objpatch;
 19 
 20 # define OPCHUNKSZ              32
 21 
 22 typedef struct _opchunk_ {
 23     struct _opchunk_ *next;             /* next in linked list */
 24     objpatch op[OPCHUNKSZ];             /* object patches */
 25 } opchunk;
 26 
 27 typedef struct {
 28     opchunk *chunk;                     /* object patch chunk */
 29     unsigned short chunksz;             /* size of object patch chunk */
 30     objpatch *flist;                    /* free list of object patches */
 31     objpatch *op[OBJPATCHHTABSZ];       /* hash table of object patches */
 32 } optable;
 33 
 34 struct _objplane_ {
 35     hashtab *htab;              /* object name hash table */
 36     optable *optab;             /* object patch table */
 37     unsigned long clean;        /* list of objects to clean */
 38     unsigned long upgrade;      /* list of upgrade objects */
 39     uindex destruct;            /* destructed object list */
 40     uindex free;                /* free object list */
 41     uindex nobjects;            /* number of objects in object table */
 42     uindex nfreeobjs;           /* number of objects in free list */
 43     Uint ocount;                /* object creation count */
 44     struct _objplane_ *prev;    /* previous object plane */
 45 };
 46 
 47 object *otable;                 /* object table */
 48 char *ocmap;                    /* object change map */
 49 bool obase;                     /* object base plane flag */
 50 static uindex otabsize;         /* size of object table */
 51 static objplane baseplane;      /* base object plane */
 52 static objplane *oplane;        /* current object plane */
 53 static object *upgraded;        /* list of upgraded objects */
 54 Uint odcount;                   /* objects destructed count */
 55 
 56 /*
 57  * NAME:        object->init()
 58  * DESCRIPTION: initialize the object tables
 59  */
 60 void o_init(n)
 61 register unsigned int n;
 62 {
 63     otable = ALLOC(object, otabsize = n);
 64     memset(otable, '\0', n * sizeof(object));
 65     ocmap = ALLOC(char, (n + 7) >> 3);
 66     memset(ocmap, '\0', (n + 7) >> 3);
 67     for (n = 4; n < otabsize; n <<= 1) ;
 68     baseplane.htab = ht_new(n >> 2, OBJHASHSZ);
 69     baseplane.optab = (optable *) NULL;
 70     baseplane.upgrade = baseplane.clean = OBJ_NONE;
 71     baseplane.destruct = baseplane.free = OBJ_NONE;
 72     baseplane.nobjects = 0;
 73     baseplane.nfreeobjs = 0;
 74     oplane = &baseplane;
 75     upgraded = (object *) NULL;
 76     odcount = 1;
 77     obase = TRUE;
 78 }
 79 
 80 
 81 /*
 82  * NAME:        objpatch->init()
 83  * DESCRIPTION: initialize objpatch table
 84  */
 85 static void op_init(plane)
 86 objplane *plane;
 87 {
 88     memset(plane->optab = ALLOC(optable, 1), '\0', sizeof(optable));
 89 }
 90 
 91 /*
 92  * NAME:        objpatch->clean()
 93  * DESCRIPTION: free objpatch table
 94  */
 95 static void op_clean(plane)
 96 objplane *plane;
 97 {
 98     register opchunk *c, *f;
 99 
100     c = plane->optab->chunk;
101     while (c != (opchunk *) NULL) {
102         f = c;
103         c = c->next;
104         FREE(f);
105     }
106 
107     FREE(plane->optab);
108     plane->optab = (optable *) NULL;
109 }
110 
111 /*
112  * NAME:        objpatch->new()
113  * DESCRIPTION: create a new object patch
114  */
115 static objpatch *op_new(plane, o, prev, obj, access)
116 objplane *plane;
117 objpatch **o, *prev;
118 object *obj;
119 int access;
120 {
121     register optable *tab;
122     register objpatch *op;
123 
124     /* allocate */
125     tab = plane->optab;
126     if (tab->flist != (objpatch *) NULL) {
127         /* from free list */
128         op = tab->flist;
129         tab->flist = op->next;
130     } else {
131         /* newly allocated */
132         if (tab->chunk == (opchunk *) NULL || tab->chunksz == OPCHUNKSZ) {
133             register opchunk *cc;
134 
135             /* create new chunk */
136             cc = ALLOC(opchunk, 1);
137             cc->next = tab->chunk;
138             tab->chunk = cc;
139             tab->chunksz = 0;
140         }
141 
142         op = &tab->chunk->op[tab->chunksz++];
143     }
144 
145     /* initialize */
146     op->access = access;
147     op->plane = plane;
148     op->prev = prev;
149     op->obj = *obj;
150 
151     /* add to hash table */
152     op->next = *o;
153     return *o = op;
154 }
155 
156 /*
157  * NAME:        objpatch->del()
158  * DESCRIPTION: delete an object patch
159  */
160 static void op_del(plane, o)
161 objplane *plane;
162 register objpatch **o;
163 {
164     register objpatch *op;
165     optable *tab;
166 
167     /* remove from hash table */
168     op = *o;
169     *o = op->next;
170 
171     /* add to free list */
172     tab = plane->optab;
173     op->next = tab->flist;
174     tab->flist = op;
175 }
176 
177 
178 /*
179  * NAME:        object->oaccess()
180  * DESCRIPTION: access to object from atomic code
181  */
182 static object *o_oaccess(index, access)
183 register unsigned int index;
184 int access;
185 {
186     register objpatch *o, **oo;
187     register object *obj;
188 
189     if (BTST(ocmap, index)) {
190         /*
191          * object already patched
192          */
193         oo = &oplane->optab->op[index % OBJPATCHHTABSZ];
194         for (o = *oo; o->obj.index != index; o = o->next) ;
195         if (access == OACC_READ) {
196             return &o->obj;
197         }
198         if (o->plane == oplane) {
199             o->access |= access;
200             return &o->obj;
201         }
202 
203         /* create new patch on current plane */
204         return &op_new(oplane, oo, o, &o->obj, access)->obj;
205     } else {
206         /*
207          * first patch for object
208          */
209         BSET(ocmap, index);
210         if (oplane->optab == (optable *) NULL) {
211             op_init(oplane);
212         }
213         oo = &oplane->optab->op[index % OBJPATCHHTABSZ];
214         obj = &op_new(oplane, oo, (objpatch *) NULL, OBJ(index), access)->obj;
215         if (obj->chain.name != (char *) NULL) {
216             char *name;
217             hte **h;
218 
219             /* copy object name to higher plane */
220             strcpy(name = ALLOC(char, strlen(obj->chain.name) + 1),
221                    obj->chain.name);
222             obj->chain.name = name;
223             if (obj->count != 0) {
224                 if (oplane->htab == (hashtab *) NULL) {
225                     oplane->htab = ht_new(OBJPATCHHTABSZ, OBJHASHSZ);
226                 }
227                 h = ht_lookup(oplane->htab, name, FALSE);
228                 obj->chain.next = *h;
229                 *h = (hte *) obj;
230             }
231         }
232         return obj;
233     }
234 }
235 
236 /*
237  * NAME:        object->oread()
238  * DESCRIPTION: read access to object in patch table
239  */
240 object *o_oread(index)
241 unsigned int index;
242 {
243     return o_oaccess(index, OACC_READ);
244 }
245 
246 /*
247  * NAME:        object->owrite()
248  * DESCRIPTION: write access to object in atomic code
249  */
250 object *o_owrite(index)
251 unsigned int index;
252 {
253     return o_oaccess(index, OACC_MODIFY);
254 }
255 
256 /*
257  * NAME:        object->space()
258  * DESCRIPTION: check if there's space for another object
259  */
260 bool o_space()
261 {
262     return (oplane->free != OBJ_NONE) ? TRUE : (oplane->nobjects != otabsize);
263 }
264 
265 /*
266  * NAME:        object->alloc()
267  * DESCRIPTION: allocate a new object
268  */
269 static object *o_alloc()
270 {
271     register uindex n;
272     register object *obj;
273 
274     if (oplane->free != OBJ_NONE) {
275         /* get space from free object list */
276         n = oplane->free;
277         obj = OBJW(n);
278         oplane->free = obj->prev;
279         --oplane->nfreeobjs;
280     } else {
281         /* use new space in object table */
282         if (oplane->nobjects == otabsize) {
283             error("Too many objects");
284         }
285         n = oplane->nobjects++;
286         obj = OBJW(n);
287     }
288 
289     OBJ(n)->index = OBJ_NONE;
290     obj->index = n;
291     obj->ctrl = (control *) NULL;
292     obj->data = (dataspace *) NULL;
293     obj->cfirst = SW_UNUSED;
294     obj->dfirst = SW_UNUSED;
295 
296     return obj;
297 }
298 
299 
300 /*
301  * NAME:        object->new_plane()
302  * DESCRIPTION: create a new object plane
303  */
304 void o_new_plane()
305 {
306     register objplane *p;
307 
308     p = ALLOC(objplane, 1);
309 
310     if (oplane->optab == (optable *) NULL) {
311         p->htab = (hashtab *) NULL;
312         p->optab = (optable *) NULL;
313     } else {
314         p->htab = oplane->htab;
315         p->optab = oplane->optab;
316     }
317     p->clean = oplane->clean;
318     p->upgrade = oplane->upgrade;
319     p->destruct = oplane->destruct;
320     p->free = oplane->free;
321     p->nobjects = oplane->nobjects;
322     p->nfreeobjs = oplane->nfreeobjs;
323     p->ocount = oplane->ocount;
324     p->prev = oplane;
325     oplane = p;
326 
327     obase = FALSE;
328 }
329 
330 /*
331  * NAME:        object->commit_plane()
332  * DESCRIPTION: commit the current object plane
333  */
334 void o_commit_plane()
335 {
336     register objplane *prev;
337     register objpatch **t, **o, *op;
338     register int i;
339     register object *obj;
340 
341 
342     prev = oplane->prev;
343     if (oplane->optab != (optable *) NULL) {
344         for (i = OBJPATCHHTABSZ, t = oplane->optab->op; --i >= 0; t++) {
345             o = t;
346             while (*o != (objpatch *) NULL && (*o)->plane == oplane) {
347                 op = *o;
348                 if (op->prev != (objpatch *) NULL) {
349                     obj = &op->prev->obj;
350                 } else {
351                     obj = OBJ(op->obj.index);
352                 }
353                 if (op->obj.count == 0 && obj->count != 0) {
354                     /* remove object from stackframe above atomic function */
355                     i_odest(cframe, obj);
356                 }
357 
358                 if (prev == &baseplane) {
359                     /*
360                      * commit to base plane
361                      */
362                     if (op->obj.chain.name != (char *) NULL) {
363                         hte **h;
364 
365                         if (obj->chain.name == (char *) NULL) {
366                             char *name;
367 
368                             /*
369                              * make object name static
370                              */
371                             m_static();
372                             name = ALLOC(char, strlen(op->obj.chain.name) + 1);
373                             m_dynamic();
374                             strcpy(name, op->obj.chain.name);
375                             FREE(op->obj.chain.name);
376                             op->obj.chain.name = name;
377                             if (op->obj.count != 0) {
378                                 /* put name in static hash table */
379                                 h = ht_lookup(prev->htab, name, FALSE);
380                                 op->obj.chain.next = *h;
381                                 *h = (hte *) obj;
382                             }
383                         } else {
384                             /*
385                              * same name
386                              */
387                             FREE(op->obj.chain.name);
388                             op->obj.chain.name = obj->chain.name;
389                             if (op->obj.count != 0) {
390                                 /* keep this name */
391                                 op->obj.chain.next = obj->chain.next;
392                             } else if (obj->count != 0) {
393                                 /* remove from hash table */
394                                 h = ht_lookup(prev->htab, obj->chain.name,
395                                               FALSE);
396                                 if (*h != (hte *) obj) {
397                                     /* new object was compiled also */
398                                     h = &(*h)->next;
399                                 }
400                                 *h = obj->chain.next;
401                             }
402                         }
403                     }
404                     if (obj->count != 0) {
405                         op->obj.update = obj->update;
406                     }
407                     BCLR(ocmap, op->obj.index);
408                     *obj = op->obj;
409                     op_del(oplane, o);
410                 } else {
411                     /*
412                      * commit to previous plane
413                      */
414                     if (op->prev == (objpatch *) NULL ||
415                         op->prev->plane != prev) {
416                         /* move to previous plane */
417                         op->plane = prev;
418                         o = &op->next;
419                     } else {
420                         /*
421                          * copy onto previous plane
422                          */
423                         if (op->obj.chain.name != (char *) NULL &&
424                             op->obj.count != 0) {
425                             /* move name to previous plane */
426                             *ht_lookup(oplane->htab, op->obj.chain.name, FALSE)
427                                                                 = (hte *) obj;
428                         }
429                         op->prev->access = op->access;
430                         *obj = op->obj;
431                         op_del(oplane, o);
432                     }
433                 }
434             }
435         }
436 
437         if (prev != &baseplane) {
438             prev->htab = oplane->htab;
439             prev->optab = oplane->optab;
440         } else {
441             if (oplane->htab != (hashtab *) NULL) {
442                 ht_del(oplane->htab);
443             }
444             op_clean(oplane);
445         }
446     }
447 
448     prev->clean = oplane->clean;
449     prev->upgrade = oplane->upgrade;
450     prev->destruct = oplane->destruct;
451     prev->free = oplane->free;
452     prev->nobjects = oplane->nobjects;
453     prev->nfreeobjs = oplane->nfreeobjs;
454     prev->ocount = oplane->ocount;
455     FREE(oplane);
456     oplane = prev;
457 
458     obase = (prev == &baseplane);
459 }
460 
461 /*
462  * NAME:        object->discard_plane()
463  * DESCRIPTION: discard the current object plane without committing it
464  */
465 void o_discard_plane()
466 {
467     register objpatch **o, *op;
468     register int i;
469     register object *obj, *clist;
470     register objplane *p;
471 
472     if (oplane->optab != (optable *) NULL) {
473         clist = (object *) NULL;
474         for (i = OBJPATCHHTABSZ, o = oplane->optab->op; --i >= 0; o++) {
475             while (*o != (objpatch *) NULL && (*o)->plane == oplane) {
476                 op = *o;
477                 if (op->prev != (objpatch *) NULL) {
478                     obj = &op->prev->obj;
479                 } else {
480                     BCLR(ocmap, op->obj.index);
481                     obj = OBJ(op->obj.index);
482                 }
483 
484                 if (op->obj.chain.name != (char *) NULL) {
485                     if (obj->chain.name == (char *) NULL ||
486                         op->prev == (objpatch *) NULL) {
487                         /*
488                          * remove new name
489                          */
490                         if (op->obj.count != 0) {
491                             /* remove from hash table */
492                             *ht_lookup(oplane->htab, op->obj.chain.name, FALSE)
493                                                         = op->obj.chain.next;
494                         }
495                         FREE(op->obj.chain.name);
496                     } else {
497                         hte **h;
498 
499                         if (op->obj.count != 0) {
500                             /*
501                              * move name to previous plane
502                              */
503                             h = ht_lookup(oplane->htab, obj->chain.name, FALSE);
504                             obj->chain.next = op->obj.chain.next;
505                             *h = (hte *) obj;
506                         } else if (obj->count != 0) {
507                             /*
508                              * put name back in hashtable
509                              */
510                             h = ht_lookup(oplane->htab, obj->chain.name, FALSE);
511                             obj->chain.next = *h;
512                             *h = (hte *) obj;
513                         }
514                     }
515                 }
516 
517                 if (obj->index == OBJ_NONE) {
518                     /*
519                      * discard newly created object
520                      */
521                     if ((op->obj.flags & O_MASTER) &&
522                         op->obj.ctrl != (control *) NULL) {
523                         op->obj.chain.next = (hte *) clist;
524                         clist = &op->obj;
525                     }
526                     if (op->obj.data != (dataspace *) NULL) {
527                         /* discard new data block */
528                         d_del_dataspace(op->obj.data);
529                     }
530                 } else {
531                     /* pass on control block and dataspace */
532                     obj->ctrl = op->obj.ctrl;
533                     obj->data = op->obj.data;
534                 }
535                 op_del(oplane, o);
536             }
537         }
538 
539         /* discard new control blocks */
540         while (clist != (object *) NULL) {
541             obj = clist;
542             clist = (object *) obj->chain.next;
543             d_del_control(obj->ctrl);
544         }
545     }
546 
547     p = oplane;
548     oplane = p->prev;
549     if (p->optab != (optable *) NULL) {
550         if (oplane != &baseplane) {
551             oplane->htab = p->htab;
552             oplane->optab = p->optab;
553         } else {
554             if (p->htab != (hashtab *) NULL) {
555                 ht_del(p->htab);
556             }
557             op_clean(p);
558         }
559     }
560     FREE(p);
561 
562     obase = (oplane == &baseplane);
563 }
564 
565 
566 /*
567  * NAME:        object->new()
568  * DESCRIPTION: create a new object
569  */
570 object *o_new(name, ctrl)
571 char *name;
572 register control *ctrl;
573 {
574     register object *o;
575     register dinherit *inh;
576     register int i;
577     hte **h;
578 
579     /* allocate object */
580     o = o_alloc();
581 
582     /* put object in object name hash table */
583     if (obase) {
584         m_static();
585     }
586     strcpy(o->chain.name = ALLOC(char, strlen(name) + 1), name);
587     if (obase) {
588         m_dynamic();
589     } else if (oplane->htab == (hashtab *) NULL) {
590         oplane->htab = ht_new(OBJPATCHHTABSZ, OBJHASHSZ);
591     }
592     h = ht_lookup(oplane->htab, name, FALSE);
593     o->chain.next = *h;
594     *h = (hte *) o;
595 
596     o->flags = O_MASTER;
597     o->cref = 0;
598     o->prev = OBJ_NONE;
599     o->count = ++oplane->ocount;
600     o->update = 0;
601     o->ctrl = ctrl;
602     ctrl->inherits[ctrl->ninherits - 1].oindex = ctrl->oindex = o->index;
603 
604     /* add reference to all inherited objects */
605     o->u_ref = 0;       /* increased to 1 in following loop */
606     inh = ctrl->inherits;
607     for (i = ctrl->ninherits, inh = ctrl->inherits; i > 0; --i, inh++) {
608         OBJF(inh->oindex)->u_ref++;
609     }
610 
611     return o;
612 }
613 
614 /*
615  * NAME:        object->clone()
616  * DESCRIPTION: clone an object
617  */
618 object *o_clone(master)
619 register object *master;
620 {
621     register object *o;
622 
623     /* allocate object */
624     o = o_alloc();
625 
626     o->chain.name = (char *) NULL;
627     o->flags = 0;
628     o->count = ++oplane->ocount;
629     o->update = master->update;
630     o->u_master = master->index;
631     o->ctrl = (control *) NULL;
632     o->data = d_new_dataspace(o);       /* clones always have a dataspace */
633 
634     /* add reference to master object */
635     master->cref++;
636     master->u_ref++;
637 
638     return o;
639 }
640 
641 /*
642  * NAME:        object->delete()
643  * DESCRIPTION: the last reference to a master object was removed
644  */
645 static void o_delete(o, f)
646 register object *o;
647 register frame *f;
648 {
649     register control *ctrl;
650     register dinherit *inh;
651     register int i;
652 
653     ctrl = (O_UPGRADING(o)) ? OBJR(o->prev)->ctrl : o_control(o);
654 
655     /* put in deleted list */
656     o->cref = oplane->destruct;
657     oplane->destruct = o->index;
658 
659     /* callback to the system */
660     PUSH_STRVAL(f, str_new(NULL, strlen(o->chain.name) + 1L));
661     f->sp->u.string->text[0] = '/';
662     strcpy(f->sp->u.string->text + 1, o->chain.name);
663     PUSH_INTVAL(f, ctrl->compiled);
664     PUSH_INTVAL(f, o->index);
665     if (i_call_critical(f, "remove_program", 3, TRUE)) {
666         i_del_value(f->sp++);
667     }
668 
669     /* remove references to inherited objects too */
670     for (i = ctrl->ninherits, inh = ctrl->inherits; --i > 0; inh++) {
671         o = OBJF(inh->oindex);
672         if (--(o->u_ref) == 0) {
673             o_delete(OBJW(inh->oindex), f);
674         }
675     }
676 }
677 
678 /*
679  * NAME:        object->upgrade()
680  * DESCRIPTION: upgrade an object to a new program
681  */
682 void o_upgrade(obj, ctrl, f)
683 register object *obj;
684 control *ctrl;
685 register frame *f;
686 {
687     register object *tmpl;
688     register dinherit *inh;
689     register int i;
690 
691     /* allocate upgrade object */
692     tmpl = o_alloc();
693     tmpl->chain.name = (char *) NULL;
694     tmpl->flags = O_MASTER;
695     tmpl->count = 0;
696     tmpl->update = obj->update;
697     tmpl->ctrl = ctrl;
698     ctrl->inherits[ctrl->ninherits - 1].oindex = tmpl->dfirst = obj->index;
699 
700     /* add reference to inherited objects */
701     for (i = ctrl->ninherits, inh = ctrl->inherits; --i > 0; inh++) {
702         OBJF(inh->oindex)->u_ref++;
703     }
704 
705     /* add to upgrades list */
706     tmpl->chain.next = (hte *) oplane->upgrade;
707     oplane->upgrade = tmpl->index;
708 
709     /* mark as upgrading */
710     obj->cref += 2;
711     tmpl->prev = obj->prev;
712     obj->prev = tmpl->index;
713 
714     /* remove references to old inherited objects */
715     ctrl = o_control(obj);
716     for (i = ctrl->ninherits, inh = ctrl->inherits; --i > 0; inh++) {
717         obj = OBJF(inh->oindex);
718         if (--(obj->u_ref) == 0) {
719             o_delete(OBJW(inh->oindex), f);
720         }
721     }
722 }
723 
724 /*
725  * NAME:        object->upgraded()
726  * DESCRIPTION: an object has been upgraded
727  */
728 void o_upgraded(tmpl, new)
729 register object *tmpl, *new;
730 {
731 # ifdef DEBUG
732     if (new->count == 0) {
733         fatal("upgrading destructed object");
734     }
735 # endif
736     if (!(new->flags & O_MASTER)) {
737         new->update = OBJ(new->u_master)->update;
738     }
739     if (tmpl->count == 0) {
740         tmpl->chain.next = (hte *) upgraded;
741         upgraded = tmpl;
742     }
743     tmpl->count++;
744 }
745 
746 /*
747  * NAME:        object->del()
748  * DESCRIPTION: delete an object
749  */
750 void o_del(obj, f)
751 register object *obj;
752 frame *f;
753 {
754     if (obj->count == 0) {
755         /* can happen if object selfdestructs in close()-on-destruct */
756         error("Destructing destructed object");
757     }
758     i_odest(f, obj);    /* wipe out occurrances on the stack */
759     obj->count = 0;
760     odcount++;
761 
762     if (obj->flags & O_MASTER) {
763         /* remove from object name hash table */
764         *ht_lookup(oplane->htab, obj->chain.name, FALSE) = obj->chain.next;
765 
766         if (--(obj->u_ref) == 0) {
767             o_delete(obj, f);
768         }
769     } else {
770         object *master;
771 
772         master = OBJF(obj->u_master);
773         master->cref--;
774         if (--(master->u_ref) == 0) {
775             o_delete(OBJW(master->index), f);
776         }
777     }
778 
779     /* put in clean list */
780     obj->chain.next = (hte *) oplane->clean;
781     oplane->clean = obj->index;
782 }
783 
784 
785 /*
786  * NAME:        object->name()
787  * DESCRIPTION: return the name of an object
788  */
789 char *o_name(name, o)
790 char *name;
791 register object *o;
792 {
793     if (o->chain.name != (char *) NULL) {
794         return o->chain.name;
795     } else {
796         char num[12];
797         register char *p;
798         register uindex n;
799 
800         /*
801          * return the name of the master object with the index appended
802          */
803         n = o->index;
804         p = num + 11;
805         *p = '\0';
806         do {
807             *--p = '' + n % 10;
808             n /= 10;
809         } while (n != 0);
810         *--p = '#';
811 
812         strcpy(name, OBJR(o->u_master)->chain.name);
813         strcat(name, p);
814         return name;
815     }
816 }
817 
818 /*
819  * NAME:        object->find()
820  * DESCRIPTION: find an object by name
821  */
822 object *o_find(name, access)
823 char *name;
824 int access;
825 {
826     register object *o;
827     register unsigned long number;
828     char *hash;
829 
830     hash = strchr(name, '#');
831     if (hash != (char *) NULL) {
832         register char *p;
833         object *m;
834 
835         /*
836          * Look for a cloned object, which cannot be found directly in the
837          * object name hash table.
838          * The name must be of the form filename#1234, where 1234 is the
839          * decimal representation of the index in the object table.
840          */
841         p = hash + 1;
842         if (*p == '\0' || (p[0] == '' && p[1] != '\0')) {
843             /* don't accept "filename#" or "filename#01" */
844             return (object *) NULL;
845         }
846 
847         /* convert the string to a number */
848         number = 0;
849         do {
850             if (!isdigit(*p)) {
851                 return (object *) NULL;
852             }
853             number = number * 10 + *p++ - '';
854             if (number >= oplane->nobjects) {
855                 return (object *) NULL;
856             }
857         } while (*p != '\0');
858 
859         o = OBJR(number);
860         if (o->count == 0 || (o->flags & O_MASTER) ||
861             strncmp(name, (m=OBJR(o->u_master))->chain.name, hash-name) != 0 ||
862             m->chain.name[hash - name] != '\0') {
863             /*
864              * no entry, not a clone, or object name doesn't match
865              */
866             return (object *) NULL;
867         }
868     } else {
869         /* look it up in the hash table */
870         if (oplane->htab == (hashtab *) NULL ||
871             (o = (object *) *ht_lookup(oplane->htab, name, TRUE)) ==
872                                                             (object *) NULL) {
873             if (oplane != &baseplane) {
874                 o = (object *) *ht_lookup(baseplane.htab, name, FALSE);
875                 if (o != (object *) NULL) {
876                     number = o->index;
877                     switch (access) {
878                     case OACC_READ:
879                         o = OBJR(number);
880                         break;
881 
882                     case OACC_REFCHANGE:
883                         o = OBJF(number);
884                         break;
885 
886                     case OACC_MODIFY:
887                         o = OBJW(number);
888                         break;
889                     }
890                     if (o->count != 0) {
891                         return o;
892                     }
893                 }
894             }
895             return (object *) NULL;
896         }
897         number = o->index;
898     }
899 
900     switch (access) {
901     case OACC_READ:
902         return o;
903 
904     case OACC_REFCHANGE:
905         return OBJF(number);
906 
907     case OACC_MODIFY:
908         return OBJW(number);
909     }
910 }
911 
912 /*
913  * NAME:        object->control()
914  * DESCRIPTION: return the control block for an object
915  */
916 control *o_control(obj)
917 object *obj;
918 {
919     register object *o;
920 
921     o = obj;
922     if (!(o->flags & O_MASTER)) {
923         /* get control block of master object */
924         o = OBJR(o->u_master);
925     }
926     if (o->ctrl == (control *) NULL) {
927         o->ctrl = d_load_control(o);    /* reload */
928     } else {
929         d_ref_control(o->ctrl);
930     }
931     return obj->ctrl = o->ctrl;
932 }
933 
934 /*
935  * NAME:        object->dataspace()
936  * DESCRIPTION: return the dataspace block for an object
937  */
938 dataspace *o_dataspace(o)
939 register object *o;
940 {
941     if (o->data == (dataspace *) NULL) {
942         if (o->dfirst == SW_UNUSED) {
943             /* create new dataspace block */
944             o->data = d_new_dataspace(o);
945         } else {
946             /* load dataspace block */
947             o->data = d_load_dataspace(o);
948         }
949     } else {
950         d_ref_dataspace(o->data);
951     }
952     return o->data;
953 }
954 
955 /*
956  * NAME:        object->clean_upgrades()
957  * DESCRIPTION: clean up upgrade templates
958  */
959 static void o_clean_upgrades()
960 {
961     register object *o, *next;
962     register Uint count;
963 
964     while ((next=upgraded) != (object *) NULL) {
965         upgraded = (object *) next->chain.next;
966 
967         count = next->count;
968         next->count = 0;
969         do {
970             o = next;
971             next = OBJ(o->cref);
972             o->ref -= count;
973             if (o->ref == 0) {
974 # ifdef DEBUG
975                 if (o->prev != OBJ_NONE) {
976                     fatal("removing issue in middle of list");
977                 }
978 # endif
979                 /* remove from template list */
980                 if (next->prev == o->index) {
981                     next->prev = OBJ_NONE;
982                 } else {
983                     OBJ(next->prev)->prev = OBJ_NONE;
984                 }
985 
986                 /* put in delete list */
987                 o->cref = baseplane.destruct;
988                 baseplane.destruct = o->index;
989             }
990         } while (o->dfirst != next->index);
991     }
992 }
993 
994 /*
995  * NAME:        object->clean()
996  * DESCRIPTION: clean up the object table
997  */
998 void o_clean()
999 {
1000     register object *o;
1001 
1002     while (baseplane.clean != OBJ_NONE) {
1003         o = OBJ(baseplane.clean);
1004         baseplane.clean = (unsigned long) o->chain.next;
1005 
1006         /* free dataspace block (if it exists) */
1007         if (o->data == (dataspace *) NULL && o->dfirst != SW_UNUSED) {
1008             /* reload dataspace block (sectors are needed) */
1009             o->data = d_load_dataspace(o);
1010         }
1011         if (o->data != (dataspace *) NULL) {
1012             d_del_dataspace(o->data);
1013         }
1014 
1015         if (!(o->flags & O_MASTER)) {
1016             register object *tmpl;
1017 
1018             /* check if clone still had to be upgraded */
1019             tmpl = OBJF(o->u_master);
1020             if (tmpl->update != o->update) {
1021                 /* non-upgraded clone of old issue */
1022                 do {
1023                     tmpl = OBJF(tmpl->prev);
1024                 } while (tmpl->update != o->update);
1025 
1026                 if (tmpl->count == 0) {
1027                     tmpl->chain.next = (hte *) upgraded;
1028                     upgraded = tmpl;
1029                 }
1030                 tmpl->count++;
1031             }
1032 
1033             /* put clone in free list */
1034             o->prev = baseplane.free;
1035             baseplane.free = o->index;
1036             baseplane.nfreeobjs++;
1037         }
1038     }
1039 
1040     o_clean_upgrades();         /* 1st time */
1041 
1042     while (baseplane.upgrade != OBJ_NONE) {
1043         register object *up;
1044         register control *ctrl;
1045 
1046         o = OBJ(baseplane.upgrade);
1047         baseplane.upgrade = (unsigned long) o->chain.next;
1048 
1049         up = OBJ(o->dfirst);
1050         if (up->u_ref == 0) {
1051             /* no more instances of object around */
1052             o->cref = baseplane.destruct;
1053             baseplane.destruct = o->index;
1054         } else {
1055             /* upgrade objects */
1056             up->flags &= ~O_COMPILED;
1057             up->cref -= 2;
1058             o->u_ref = up->cref;
1059             if (up->count != 0 &&
1060                 (up->data != (dataspace *) NULL || up->dfirst != SW_UNUSED)) {
1061                 o->u_ref++;
1062             }
1063             ctrl = up->ctrl;
1064 
1065             if (ctrl->vmapsize != 0 && o->u_ref != 0) {
1066                 /*
1067                  * upgrade variables
1068                  */
1069                 o->cref = up->index;
1070                 if (o->prev != OBJ_NONE) {
1071                     OBJ(o->prev)->cref = o->index;
1072                 }
1073 
1074                 up->update++;
1075                 if (up->count != 0 && up->data == (dataspace *) NULL &&
1076                     up->dfirst != SW_UNUSED) {
1077                     /* load dataspace (with old control block) */
1078                     up->data = d_load_dataspace(up);
1079                 }
1080             } else {
1081                 /* no variable upgrading */
1082                 up->prev = o->prev;
1083                 o->cref = baseplane.destruct;
1084                 baseplane.destruct = o->index;
1085             }
1086 
1087             /* swap control blocks */
1088             up->ctrl = o->ctrl;
1089             up->ctrl->oindex = up->index;
1090             o->ctrl = ctrl;
1091             ctrl->oindex = o->index;
1092             o->cfirst = up->cfirst;
1093             up->cfirst = SW_UNUSED;
1094 
1095             if (ctrl->ndata != 0) {
1096                 /* upgrade all dataspaces in memory */
1097                 d_upgrade_all(o, up);
1098             }
1099         }
1100     }
1101 
1102     o_clean_upgrades();         /* 2nd time */
1103 
1104     while (baseplane.destruct != OBJ_NONE) {
1105         o = OBJ(baseplane.destruct);
1106         baseplane.destruct = o->cref;
1107 
1108         /* free control block */
1109         d_del_control(o_control(o));
1110 
1111         if (o->chain.name != (char *) NULL) {
1112             /* free object name */
1113             FREE(o->chain.name);
1114             o->chain.name = (char *) NULL;
1115         }
1116         o->u_ref = 0;
1117 
1118         /* put object in free list */
1119         o->prev = baseplane.free;
1120         baseplane.free = o->index;
1121         baseplane.nfreeobjs++;
1122     }
1123 }
1124 
1125 /*
1126  * NAME:        object->count()
1127  * DESCRIPTION: return the number of objects in use
1128  */
1129 uindex o_count()
1130 {
1131     return oplane->nobjects - oplane->nfreeobjs;
1132 }
1133 
1134 
1135 typedef struct {
1136     uindex free;        /* free object list */
1137     uindex nobjects;    /* # objects */
1138     uindex nfreeobjs;   /* # free objects */
1139     Uint onamelen;      /* length of all object names */
1140 } dump_header;
1141 
1142 static char dh_layout[] = "uuui";
1143 
1144 # define CHUNKSZ        16384
1145 
1146 /*
1147  * NAME:        object->dump()
1148  * DESCRIPTION: dump the object table
1149  */
1150 bool o_dump(fd)
1151 int fd;
1152 {
1153     register uindex i;
1154     register object *o;
1155     register unsigned int len, buflen;
1156     dump_header dh;
1157     char buffer[CHUNKSZ];
1158 
1159     /* prepare header */
1160     dh.free = baseplane.free;
1161     dh.nobjects = baseplane.nobjects;
1162     dh.nfreeobjs = baseplane.nfreeobjs;
1163     dh.onamelen = 0;
1164     for (i = baseplane.nobjects, o = otable; i > 0; --i, o++) {
1165         if (o->chain.name != (char *) NULL) {
1166             dh.onamelen += strlen(o->chain.name) + 1;
1167         }
1168     }
1169 
1170     /* write header and objects */
1171     if (P_write(fd, (char *) &dh, sizeof(dump_header)) < 0 ||
1172         P_write(fd, (char *) otable, baseplane.nobjects * sizeof(object)) < 0) {
1173         return FALSE;
1174     }
1175 
1176     /* write object names */
1177     buflen = 0;
1178     for (i = baseplane.nobjects, o = otable; i > 0; --i, o++) {
1179         if (o->chain.name != (char *) NULL) {
1180             len = strlen(o->chain.name) + 1;
1181             if (buflen + len > CHUNKSZ) {
1182                 if (P_write(fd, buffer, buflen) < 0) {
1183                     return FALSE;
1184                 }
1185                 buflen = 0;
1186             }
1187             memcpy(buffer + buflen, o->chain.name, len);
1188             buflen += len;
1189         }
1190     }
1191     return (buflen == 0 || P_write(fd, buffer, buflen) >= 0);
1192 }
1193 
1194 /*
1195  * NAME:        object->restore()
1196  * DESCRIPTION: restore the object table
1197  */
1198 void o_restore(fd)
1199 int fd;
1200 {
1201     register uindex i;
1202     register object *o;
1203     register unsigned int len, buflen;
1204     register char *p;
1205     dump_header dh;
1206     char buffer[CHUNKSZ];
1207 
1208     /*
1209      * Free object names of precompiled objects.
1210      */
1211     for (i = baseplane.nobjects, o = otable; i > 0; --i, o++) {
1212         *ht_lookup(baseplane.htab, o->chain.name, FALSE) = o->chain.next;
1213         FREE(o->chain.name);
1214     }
1215 
1216     /* read header and object table */
1217     conf_dread(fd, (char *) &dh, dh_layout, (Uint) 1);
1218     if (dh.nobjects > otabsize) {
1219         error("Too many objects in restore file");
1220     }
1221     conf_dread(fd, (char *) otable, OBJ_LAYOUT, (Uint) dh.nobjects);
1222     baseplane.free = dh.free;
1223     baseplane.nobjects = dh.nobjects;
1224     baseplane.nfreeobjs = dh.nfreeobjs;
1225 
1226     /* read object names, and patch all objects and control blocks */
1227     buflen = 0;
1228     for (i = 0, o = otable; i < baseplane.nobjects; i++, o++) {
1229         if (o->chain.name != (char *) NULL) {
1230             /*
1231              * restore name
1232              */
1233             if (buflen == 0 ||
1234                 (char *) memchr(p, '\0', buflen) == (char *) NULL) {
1235                 /* move remainder to beginning, and refill buffer */
1236                 if (buflen != 0) {
1237                     memcpy(buffer, p, buflen);
1238                 }
1239                 len = (dh.onamelen > CHUNKSZ - buflen) ?
1240                        CHUNKSZ - buflen : dh.onamelen;
1241                 if (P_read(fd, buffer + buflen, len) != len) {
1242                     fatal("cannot restore object names");
1243                 }
1244                 dh.onamelen -= len;
1245                 buflen += len;
1246                 p = buffer;
1247             }
1248             m_static();
1249             strcpy(o->chain.name = ALLOC(char, len = strlen(p) + 1), p);
1250             m_dynamic();
1251 
1252             if (o->count != 0) {
1253                 register hte **h;
1254 
1255                 h = ht_lookup(baseplane.htab, p, FALSE);
1256                 o->chain.next = *h;
1257                 *h = (hte *) o;
1258             }
1259             p += len;
1260             buflen -= len;
1261         }
1262 
1263         if (o->count != 0) {
1264             /* there are no user or editor objects after a restore */
1265             if ((o->flags & O_SPECIAL) != O_SPECIAL) {
1266                 o->flags &= ~O_SPECIAL;
1267             }
1268             o->flags &= ~O_PENDIO;
1269         }
1270 
1271         /* check memory */
1272         if (!m_check()) {
1273             m_purge();
1274         }
1275     }
1276 }
1277 
1278 static int cmp P((cvoid*, cvoid*));
1279 
1280 /*
1281  * NAME:        cmp()
1282  * DESCRIPTION: compare two objects
1283  */
1284 static int cmp(cv1, cv2)
1285 cvoid *cv1, *cv2;
1286 {
1287     register object *o1, *o2;
1288 
1289     /* non-objects first, then objects sorted by count */
1290     o1 = OBJ(*((Uint *) cv1));
1291     o2 = OBJ(*((Uint *) cv2));
1292     if (o1->count == 0) {
1293         if (o2->count == 0) {
1294             return (o1 <= o2) ? (o1 < o2) ? -1 : 0 : 1;
1295         }
1296         return -1;
1297     } else if (o2->count == 0) {
1298         return 1;
1299     } else {
1300         return (o1->count <= o2->count) ? (o1->count < o2->count) ? -1 : 0 : 1;
1301     }
1302 }
1303 
1304 /*
1305  * NAME:        object->conv()
1306  * DESCRIPTION: convert all objects, creating a new swap file
1307  */
1308 void o_conv()
1309 {
1310     register Uint *counts, *sorted;
1311     register uindex i;
1312     register object *o;
1313 
1314     if (baseplane.nobjects != 0) {
1315         /*
1316          * create new object count table
1317          */
1318         counts = ALLOCA(Uint, baseplane.nobjects);
1319         sorted = ALLOCA(Uint, baseplane.nobjects) + baseplane.nobjects;
1320         i = baseplane.nobjects;
1321         while (i != 0) {
1322             *--sorted = --i;
1323         }
1324         /* sort by count */
1325         qsort(sorted, baseplane.nobjects, sizeof(Uint), cmp);
1326         /* skip destructed objects */
1327         for (i = 0; i < baseplane.nobjects; i++) {
1328             if (OBJ(*sorted)->count != 0) {
1329                 break;
1330             }
1331             sorted++;
1332         }
1333         /* fill in counts table */
1334         while (i < baseplane.nobjects) {
1335             counts[*sorted++] = ++i + 1;
1336         }
1337         AFREE(sorted - i);
1338         baseplane.ocount = i + 1;
1339 
1340         /*
1341          * convert all control blocks
1342          */
1343         for (i = baseplane.nobjects, o = otable; i > 0; --i, o++) {
1344             if ((o->count != 0 || ((o->flags & O_MASTER) && o->u_ref != 0)) &&
1345                 o->cfirst != SW_UNUSED) {
1346                 d_conv_control(o->index);
1347             }
1348         }
1349 
1350         /*
1351          * convert all data blocks
1352          */
1353         for (i = baseplane.nobjects, o = otable; i > 0; --i, o++) {
1354             if (o->count != 0 && o->dfirst != SW_UNUSED) {
1355                 d_conv_dataspace(o, counts);
1356                 o_clean_upgrades();
1357                 d_swapout(1);
1358             }
1359         }
1360         o_clean();
1361 
1362         /*
1363          * last pass over all objects:
1364          * fix count and update fields, handle special objects
1365          */
1366         for (i = baseplane.nobjects, o = otable; i > 0; --i, o++, counts++) {
1367             if (o->count != 0) {
1368                 o->count = *counts;
1369             }
1370             o->update = 0;
1371             if ((o->flags & O_SPECIAL) == O_SPECIAL &&
1372                 ext_restore != (void (*) P((object*))) NULL) {
1373                 (*ext_restore)(o);
1374                 d_swapout(1);
1375             }
1376         }
1377         AFREE(counts - baseplane.nobjects);
1378     }
1379 }
1380 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.