|
|
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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.