home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / me34src.zip / me3 / mc / oman.c < prev    next >
C/C++ Source or Header  |  1995-01-14  |  26KB  |  1,098 lines

  1. /* oman.c:  object management
  2.  * C Durland  5/91
  3.  */
  4.  
  5. /* Copyright 1990, 1991, 1992 Craig Durland
  6.  *   Distributed under the terms of the GNU General Public License.
  7.  *   Distributed "as is", without warranties of any kind, but comments,
  8.  *     suggestions and bug reports are welcome.
  9.  */
  10.  
  11. #if 0
  12. cc -DTEST -g oman.c -o oman -I$HOME/c/util $HOME/c/util/util.a /d2/lsdmem/usr/local/lib/liblsdmemd.a /d2/lsdmem/usr/local/lib/liblsdtrap.a
  13. #endif
  14.  
  15. static char what[] = "@(#)OMan (Object Manager) v1.0 12/27/91";
  16.  
  17. #if 0
  18. first_pool -> object_pool_1 -> object_pool_2 -> ... -> NULL
  19.  
  20. object_pool:  object_1 -> object_2 -> object_3 -> ... -> NULL
  21.  
  22. Atom objects:  number, unknown
  23. Atom objects with extra storage:  string
  24. other: list
  25.  
  26. string: dstring
  27. list:  list_header -> list_element_1 -> list_element_2 -> ... -> NULL
  28.  
  29. #endif
  30.  
  31. #include <const.h>
  32. #include <dstring.h>
  33. #include "oman.h"
  34.  
  35. extern char *malloc(), *calloc();
  36.  
  37. /* ******************************************************************** */
  38. /* *************************  ************************* */
  39. /* ******************************************************************** */
  40.  
  41. /* Object types I know about: */
  42. #define LIST        9
  43. #define STRING        8
  44. #define NUMBER        3
  45. #define UNKNOWN        4
  46.  
  47. #define MARKED        0x80
  48.  
  49.  
  50.  
  51. ObjectPool *first_pool = NULL;
  52.  
  53. static void free_objects();
  54.  
  55. /* ******************************************************************** */
  56. /* ****************** Garbage Collection ****************************** */
  57. /* ******************************************************************** */
  58.  
  59. static Object *tmp_list;
  60. static ObjectPool *tmp_pool;
  61.  
  62. static void sweep_objects();
  63.  
  64.     /* Garbage collect a object pool.
  65.      * Call the pools object marker routine.  That routine calls
  66.      *   OMgc_mark_object() to mark all objects that are dead or to mark
  67.      *   objects that are live.  Then free all dead objects.
  68.      * Pool not collected if there is no marker routine - assumes all
  69.      *   objects are immortal.
  70.      * The marker routine returns:
  71.      *   0 : Don't collect this pool.
  72.      *   1 : All objects marked are alive.
  73.      *   2 : All objects marked are dead.
  74.      * Input:
  75.      *   pool:  Pool to garbage collect
  76.      *   marked:
  77.      *     0:  Pool not marked, do the normal sweep.
  78.      *     1:  Pool has all live objects marked.
  79.      *     2:  Pool has all dead objects marked.
  80.      */
  81. void OMgc_pool(pool,marked) ObjectPool *pool;
  82. {
  83.   int s;
  84.  
  85.   if (marked != 0) s = marked;
  86.   else
  87.   {
  88.     tmp_list = NULL;
  89.     tmp_pool = pool;
  90.  
  91.     if (!pool->gc_marker) return;        /* Can't collect this pool! */
  92.  
  93.     if (0 == (s = (*pool->gc_marker)())) return;  /* Don't collect this pool */
  94.   }
  95.  
  96.   sweep_objects(pool, (s == 1));
  97. }
  98.  
  99.     /* Mark an object in preparation for the sweep part of the Garbage
  100.      *   Collection.
  101.      * Input:  pointer to an object in the pool current being garbage
  102.      *   collected.
  103.      */
  104. void OMgc_mark_object(object) Object *object;
  105. {
  106.   if (!object) return;    /* Can happen with (uninitialized) object tables */
  107.  
  108.   object->type |= MARKED;
  109. }
  110.  
  111. OMin_pool(pool, object) ObjectPool *pool; Object *object;
  112. {
  113.   Object *ptr;
  114.  
  115.   for (ptr = pool->first_object; ptr; ptr = ptr->next_object)
  116.     if (ptr == object) return TRUE;
  117.  
  118.   return FALSE;
  119. }
  120.  
  121.  
  122.     /* Coalesce all marked objects in a pool.  Remove and free the dead ones.
  123.      */
  124. static void sweep_objects(pool,marked_objects_are_live) ObjectPool *pool;
  125. {
  126. #if 0
  127.   Object *ptr, *qtr, *last_live, foo, *dead;
  128.  
  129.   dead = NULL;
  130.  
  131.   foo.next_object = ptr = pool->first_object;
  132.   last_live = &foo;
  133.  
  134.   for ( ; ptr; ptr = qtr)
  135.   {
  136.     qtr = ptr->next_object;
  137.     if (ptr->type & MARKED)        /* save this object */
  138.     {
  139.       ptr->type &= ~MARKED;
  140.       last_live = ptr;
  141.     }
  142.     else                /* dead object */
  143.     {
  144.       last_live->next_object = qtr;    /* unlink dead object */
  145.     /* !!! should just call free_object(ptr) */
  146.       ptr->next_object = dead;
  147.       dead = ptr;
  148.     }
  149.   }
  150.  
  151.   pool->first_object = foo.next_object;
  152.   free_objects(dead);
  153.  
  154. #else
  155.  
  156.   Object *ptr, *qtr, *marked_list, *unmarked_list;
  157.  
  158.   marked_list = unmarked_list = NULL;
  159.   for (ptr = pool->first_object; ptr; ptr = qtr)
  160.   {
  161.     qtr = ptr->next_object;
  162.     if (ptr->type & MARKED)
  163.     {
  164.       ptr->type &= ~MARKED;
  165.       ptr->next_object = marked_list;
  166.       marked_list = ptr;
  167.     }
  168.     else
  169.     {
  170.       ptr->next_object = unmarked_list;
  171.       unmarked_list = ptr;
  172.     }
  173.   }
  174.  
  175.   if (marked_objects_are_live)
  176.   {
  177.     pool->first_object = marked_list;
  178.     free_objects(unmarked_list);
  179.   }
  180.   else
  181.   {
  182.     pool->first_object = unmarked_list;
  183.     free_objects(marked_list);
  184.   }
  185.  
  186. #endif
  187. }
  188.  
  189.     /* Garbage collect all pools */
  190. void OMgc_the_world()
  191. {
  192.   ObjectPool *pool;
  193.  
  194.   for (pool = first_pool; pool; pool = pool->next_pool) OMgc_pool(pool, 0);
  195. }
  196.  
  197. /* ******************************************************************** */
  198. /* ********************** Object Pool Management ********************** */
  199. /* ******************************************************************** */
  200.  
  201.     /* Allocate an object pool.
  202.      * Returns:
  203.      *   Pointer to a pool
  204.      *   NULL if no memory
  205.      */
  206. ObjectPool *OMcreate_object_pool(gc_marker) pfi gc_marker;
  207. {
  208.   ObjectPool *pool;
  209.  
  210.   if (!(pool = (ObjectPool *)malloc(sizeof(ObjectPool))))
  211.   {
  212.     OMgc_the_world();
  213.     if (!(pool = (ObjectPool *)malloc(sizeof(ObjectPool)))) return NULL;
  214.   }
  215.  
  216.     /* init the pool */
  217.   pool->next_pool = first_pool;
  218.   first_pool = pool;
  219.  
  220.   pool->first_object = NULL;
  221.   pool->gc_marker = gc_marker;
  222.  
  223.   return pool;
  224. }
  225.  
  226.     /* Free a pool and all its objects.
  227.      * WARNING:  If not a valid pool, infinite loop city!
  228.      */
  229. void OMfree_object_pool(op) void *op;
  230. {
  231.   ObjectPool *pool = op, *ptr, *drag;
  232.  
  233.   free_objects(pool->first_object);
  234.  
  235.   for (drag = NULL, ptr = first_pool; ptr; ptr = ptr->next_pool)
  236.   {
  237.     if (ptr == pool) break;
  238.     drag = ptr;
  239.   }
  240.   if (drag == NULL)        /* freeing first pool */
  241.   {
  242.     first_pool = ptr->next_pool;
  243.   }
  244.   else
  245.   {
  246.     drag->next_pool = ptr->next_pool;
  247.   }
  248.   free((char *)pool);
  249. }
  250.  
  251. /* ******************************************************************** */
  252. /* ************************ Object Management ************************* */
  253. /* ******************************************************************** */
  254.  
  255.     /* Allocate an object.
  256.      * Input:
  257.      *   object_pool:  Pointer to object pool object is to be allocated in.
  258.      *     If NULL, the allocated object is not part of any pool and thus
  259.      *     can't be garbage collected unless you add it to a list.
  260.      *   object_type:  Type of object to allocate.  If an unknown type, ???
  261.      *   object_size:  Only used if object_type is unknown.  In that case,
  262.      *     pass in sizeof(YourObject).
  263.      * Returns:
  264.      *   ptr  : Pointer to the object
  265.      *   NULL : No memory
  266.      * Notes:
  267.      *   If malloc() fails, all pools are garbage collected and the malloc()
  268.      *     is retried.
  269.      */
  270. Object *OMcreate_object(object_pool, object_type, object_size)
  271.   ObjectPool *object_pool; int object_type, object_size;
  272. {
  273.   int size;
  274.   Object *ptr;
  275.  
  276.   switch(object_type)
  277.   {
  278.     case NUMBER:  size = sizeof(NumberObject);    break;
  279.     case LIST:    size = sizeof(ListObject);    break;
  280.     case STRING:  size = sizeof(StringObject);    break;
  281.     default:      size = object_size;        break;
  282.   }
  283.  
  284.   if (!(ptr = (Object *)malloc(size)))
  285.   {
  286.     OMgc_the_world();
  287.     if (!(ptr = (Object *)malloc(size))) return NULL;
  288.   }
  289.  
  290.   ptr->type = object_type;
  291.  
  292.   if (object_pool)
  293.   {
  294.     ptr->next_object = object_pool->first_object;
  295.     object_pool->first_object = ptr;
  296.   }
  297.   else ptr->next_object = NULL;        /* no pool, create a loner */
  298.   
  299.  
  300.     /* initialize the new object */
  301.   switch (object_type)
  302.   {
  303.     case STRING:
  304.     {
  305.       dString *ds = &((StringObject *)ptr)->string;
  306.       init_dString(ds);
  307.       break;
  308.     }
  309.     case LIST:
  310.       ((ListObject *)ptr)->elements = NULL;
  311.       break;
  312.     case NUMBER: 
  313.       ((NumberObject *)ptr)->number = 0;
  314.       break;
  315.     default: /* ??? call unknown initer or let caller take care of it? */
  316.       break;
  317.   }
  318.  
  319.   return ptr;
  320. }
  321.  
  322. static void add_object_to_pool(pool, object)
  323.   ObjectPool *pool; Object *object;
  324. {
  325.   if (pool)
  326.   {
  327.     object->next_object = pool->first_object;
  328.     pool->first_object = object;
  329.   }
  330. }
  331.  
  332. static void free_objects(object) Object *object;
  333. {
  334.   Object *ptr, *qtr;
  335.  
  336.   for (ptr = object; ptr; ptr = qtr)
  337.   {
  338.     qtr = ptr->next_object;
  339.     switch(ptr->type)
  340.     {
  341.       case LIST:
  342.         free_objects(((ListObject *)ptr)->elements);
  343.     break;
  344.       case STRING:
  345.       {
  346.     dString *ds = &((StringObject *)ptr)->string;
  347.     free_dString(ds);
  348.         break;
  349.       }
  350.     }
  351.     free((char *)ptr);
  352.   }
  353. }
  354.  
  355.     /* 
  356.      * Input:
  357.      *   object_pool:  The pool to duplicate the object in.  If NULL, the
  358.      *       new object is not stuck in a pool.  Be sure you keep track
  359.      *       of it because it can't be GC'd unless you put it into a pool.
  360.      *   object:  the object to be dulicated.
  361.      * Returns:
  362.      *   Pointer to the duplicated object.  Duplicatation is done by
  363.      *     creating copies.
  364.      *   NULL if run out of memory.
  365.      * Notes:
  366.      *   Does not create garbage ie a GC after this routine will not find
  367.      *     anything to reclaim.
  368.      *   I don't put the new object in to the pool until after I copy all
  369.      *     the data into it.  This makes error recovery easier.
  370.      */
  371. Object *OMdup_object(object_pool, object)
  372.   ObjectPool *object_pool;
  373.   Object *object;
  374. {
  375.   Object *new;
  376.  
  377.   if (!(new = OMcreate_object((ObjectPool *)NULL, object->type, 0)))
  378.     return NULL;
  379.  
  380.     /* copy object */
  381.   switch (object->type)
  382.   {
  383.     case NUMBER:
  384.       ((NumberObject *)new)->number =
  385.      ((NumberObject *)object)->number;
  386.       break;
  387.     case STRING:
  388.     {
  389.       char *ptr =        ((StringObject *)object)->string.string;
  390.       dString *new_ds = &((StringObject *)new)->string;
  391.       if (!set_dString(new_ds, ptr))
  392.       {
  393.     free_objects(new);
  394.     return NULL;
  395.       }
  396.       break;
  397.     }
  398.     case LIST:
  399.     {
  400.       ListObject *list;
  401.       Object new_list, *element, *new_element, *ptr;
  402.  
  403.       list = (ListObject *)object;
  404.       ptr = &new_list;
  405.       for (element = list->elements; element; element = element->next_object)
  406.       {
  407.     if (!(new_element = OMdup_object((ObjectPool *)NULL, element)))
  408.     {
  409.       ptr->next_object = NULL; free_objects(new_list.next_object);
  410.       free_objects(new);
  411.       return NULL;
  412.     }
  413.     ptr->next_object = new_element;
  414.     ptr = new_element;
  415.       }
  416.       ptr->next_object = NULL;
  417.       ((ListObject *)new)->elements = new_list.next_object;
  418.  
  419.       break;
  420.     }
  421.     case UNKNOWN: /* ??? */
  422.       break;
  423.   }
  424.  
  425.   add_object_to_pool(object_pool, new);
  426.  
  427.   return new;
  428. }
  429.  
  430. /* ******************************************************************** */
  431. /* ******************* Object Fiddling ******************************** */
  432. /* ******************************************************************** */
  433.  
  434. #ifdef __STDC__
  435.  
  436. #include <stdarg.h>
  437. #define VA_START va_start
  438.  
  439. #else    /* __STDC__ */
  440.  
  441. #include <varargs.h>
  442. #define VA_START(a,b) va_start(a)
  443.  
  444. #endif
  445.  
  446. #if 0
  447.  
  448. OMget_object(object) Object *object;
  449. {
  450.   switch(object_type)
  451.   {
  452.     case NUMBER:  return ((NumberObject *)object)->number;
  453.     case UNKNOWN: 
  454.     case LIST:
  455.     case STRING:
  456.   }
  457. }
  458. #endif
  459.  
  460.     /* Copy one object into another.
  461.      * Input:
  462.      * Returns:
  463.      * Notes:
  464.      *   If run out of memory, object is likely cleared ie it loses its
  465.      *     orginal contents.  It is still a valid object.
  466.      *   No garbage is generated.
  467.      */
  468. /* ??? would be nice to have a OSTRING and STRING */
  469. /*VARARGS2*/
  470. #ifdef __STDC__
  471. OMset_object(Object *object, int type, ...)
  472. #else
  473. OMset_object(object, type, va_alist) Object *object; int type; va_dcl
  474. #endif
  475. {
  476.   int s = TRUE;
  477.   va_list varptr;
  478.  
  479.   VA_START(varptr,type);
  480.  
  481.   switch(type)
  482.   {
  483.     default:  return FALSE;
  484.     case NUMBER:
  485.       ((NumberObject *)object)->number = va_arg(varptr, long int);
  486.       break;
  487.     case LIST:
  488.     {
  489.       ListObject *list, *new, *data;
  490.  
  491.       list = (ListObject *)object;
  492.       data = va_arg(varptr, ListObject *);
  493.  
  494.       free_objects(list->elements);    /* free garbage-to-be */
  495.  
  496.       new = (ListObject *)OMdup_object((ObjectPool *)NULL, data);
  497.       if (!new) { s = FALSE; break; }
  498.  
  499.       list->elements = new->elements;
  500.  
  501.         /* free garbage */
  502.       new->elements = NULL; free_objects(new);
  503.  
  504.       break;
  505.     }
  506.     case STRING:
  507.     {
  508.       char *ptr;
  509.       dString *ds = &((StringObject *)object)->string;
  510.  
  511.       ptr = va_arg(varptr, char *);
  512.       s = set_dString(ds,ptr);
  513.       break;
  514.     }
  515.   }
  516.  
  517.   va_end(varptr);
  518.  
  519.   return s;
  520. }
  521.  
  522. /* ******************************************************************** */
  523. /* *********************** List/String Fiddling *********************** */
  524. /* ******************************************************************** */
  525.  
  526.     /* 
  527.      * (length-of foo):  number of objects in foo.
  528.      * (length-of []) => 0.
  529.      * ??? if foo is an atom, return sizeof(foo)????
  530.      */
  531. OMlength_of(object) Object *object;
  532. {
  533.   switch(object->type)
  534.   {
  535.     case LIST:
  536.     {
  537.       int n;
  538.       ListObject *list = (ListObject *)object;
  539.       Object *ptr;
  540.  
  541.       for (n = 0, ptr = list->elements; ptr; ptr = ptr->next_object) n++;
  542.       return n;
  543.     }
  544.     case STRING:
  545.     {
  546.       StringObject *string = (StringObject *)object;
  547.  
  548.       return strlen(string->string.string);
  549.     }
  550.   }
  551.   return 0;        /* default */
  552. }
  553.  
  554.  
  555.     /* Insert a copy of an object into a list or string.
  556.      * The first element of a list is 0.
  557.      * To prepend, insert after element -1.
  558.      * If n > (length object), append.
  559.      * object_to_add is duplicated and the duplicate is inserted.
  560.      * Input:
  561.      *   object:  list or string.
  562.      *   n:  object_to_add is inserted AFTER the nth element of object.
  563.      *   object_to_add:  the same type as object.
  564.      * Returns:
  565.      *   TRUE:  Everything went as expected.
  566.      *   FALSE: type mismatch or out of memory.
  567.      */
  568. OMinsert_object(object,n,object_to_add) Object *object, *object_to_add;
  569. {
  570.   switch(object->type)
  571.   {
  572.     default: return FALSE;
  573.     case LIST:
  574.     {
  575.       int a;
  576.       ListObject *list;
  577.       Object *ptr, *drag, *new;
  578.  
  579.       list = (ListObject *)object;
  580.  
  581.         /* find element n */
  582.       if (n < 0) ptr = NULL;        /* prepend */
  583.       else
  584.       {
  585.     for (a = n, drag = NULL, ptr = list->elements; ptr;
  586.          ptr = ptr->next_object)
  587.     {
  588.       if (a-- <= 0) break;
  589.       drag = ptr;
  590.     }
  591.     if (!ptr) ptr = drag;        /* append to object */
  592.       }
  593.  
  594.       new = OMdup_object((ObjectPool *)NULL,object_to_add);
  595.       if (!new) return FALSE;
  596.  
  597.         /* link in new after ptr */
  598.       if (!ptr)
  599.       {
  600.     new->next_object = list->elements;
  601.     list->elements = new;
  602.       }
  603.       else
  604.       {
  605.     new->next_object = ptr->next_object;
  606.     ptr->next_object = new;
  607.       }
  608.  
  609.       break;
  610.     }
  611.     case STRING:
  612.     {
  613.       char *p, *q, *c1, *c2;
  614.       dString *ds;
  615.       int a,b,c,x;
  616.  
  617.       if (object_to_add->type != STRING) return FALSE;
  618.  
  619.       ds = &((StringObject *)object)->string;
  620.  
  621.       p = ds->string;
  622.       q = ((StringObject *)object_to_add)->string.string;
  623.  
  624.       a = strlen(p);
  625.       b = strlen(q);
  626.       x = a + b;
  627.  
  628.       if (!pad_dString(ds,x)) return FALSE;    /* make result big enough */
  629.       p = ds->string;
  630.  
  631.       n = imax(-1,n);
  632.       n = imin(a-1,n);
  633.     /* open hole at p+n, b chars wide */
  634.       c1 = p + a; c2 = p + a + b; c = a - n;    /* copy the '\0' */
  635.       while (c--) *c2-- = *c1--;
  636.       strncpy(p + n +1, q, b);
  637.  
  638.       break;
  639.     }
  640.   }
  641.   /* NOTREACHED */
  642. }
  643.  
  644.     /* 
  645.      * Output:
  646.      *   n in [0, len]
  647.      *   z in [0, len]
  648.      * Notes:
  649.      *   !!! This is not very robust!  All kinds of cases don't work as
  650.      *     expected!
  651.      */
  652. void OMnz_magic(len, pn,pz) int len, *pn, *pz;
  653. {
  654.   int n = *pn, z = *pz;
  655.  
  656.   if (n < 0)   n += len;   if (z < 0)   z += len;
  657.   if (n < 0)   n  = 0;       if (z < 0)   z  = 0;
  658.   if (n > len) n  = len;   if (z > len) z  = len;
  659.  
  660.   *pn = n; *pz = z;
  661. }
  662.  
  663.     /* 
  664.      * Copy elements from a list and use them to create a new list.
  665.      * Restrictions:
  666.      *   Only works for strings or lists.
  667.      * Input:
  668.      *   pool:  where to put the returned object(s).
  669.      *   object:  list/string to copy elements from.
  670.      *   n: first element to copy (0 is the first element of a list).
  671.      *   z: number of objects to copy.
  672.      * Returns:
  673.      *   Pointer to a object that holds the result.  Returned object is of
  674.      *     the same type as object.
  675.      *   NULL if out of memory or wrong object type.
  676.      * Notes:
  677.      *   If (z <= 0) or (n > (length-of object)) or (foo == []), returns [].
  678.      *   If ask for more elements than can get, return as much as can.
  679.      *   (extract-items "123" 1 1) => "2", (n-items "123" 1 2) => "23"
  680.      *   (extract-items [] n z) => []
  681.      */
  682. Object *OMextract_elements(pool,object,n,z) ObjectPool *pool; Object *object;
  683. {
  684.   int len, type;
  685.   Object *result;
  686.  
  687.   type = object->type;
  688.   if (type != STRING && type != LIST) return NULL;
  689.  
  690.   if (!(result = OMcreate_object((ObjectPool *)NULL,type,0))) return NULL;
  691.  
  692.   OMnz_magic(len = OMlength_of(object), &n,&z);
  693.  
  694.   switch(object->type)
  695.   {
  696.     case LIST:
  697.     {
  698.       int a;
  699.       ListObject *list;
  700.       Object *ptr;
  701.  
  702.       list = (ListObject *)object;
  703.  
  704.       if (n == len) break;    /* list not long enough, return empty list */
  705.  
  706.         /* find element n */
  707.       for (a = n, ptr = list->elements; a--; ptr = ptr->next_object)  ;
  708.  
  709.         /* copy and append z elements of object to result */
  710.       a = z;    /* a >= max len of result */
  711.       for (; ptr && z--; ptr = ptr->next_object)
  712.       {
  713.     if (!OMinsert_object(result,a,ptr))    /* append a copy of object */
  714.     {
  715.       free_objects(result);
  716.       return NULL;
  717.     }
  718.       }
  719.  
  720.       break;
  721.     }
  722.     case STRING:            /* substr string pos z */
  723.     {
  724.       char *p, *q;
  725.       dString *ds;
  726.       int x;
  727.       StringObject *string;
  728.  
  729.       string = (StringObject *)object;
  730.       ds = &((StringObject *)result)->string;
  731.  
  732.       x = imin(len - n, z);
  733.  
  734.       if (!pad_dString(ds,x))         /* make result big enough */
  735.       {
  736.     free_objects(result);
  737.     return NULL;
  738.       }
  739.       p = string->string.string;
  740.       q = ds->string;
  741.       strncpy(q, p+n, x);
  742.       q[x] = '\0';
  743.  
  744.       break;
  745.     }
  746.   }
  747.  
  748.   add_object_to_pool(pool, result);
  749.  
  750.   return result;
  751. }
  752.  
  753.     /* Copy an element from a list or string and atomize it.
  754.      * Restrictions:
  755.      *   Only works for strings or lists.
  756.      * Input:
  757.      *   pool:  where to put the returned object.
  758.      *   object:  list/string to copy element from.
  759.      *   n: first element to copy (0 is the first element of a list).
  760.      * Returns:
  761.      *   Pointer to a object that holds the result.
  762.      *   NULL if out of memory or wrong object type.
  763.      * Notes:
  764.      *   No garbage generated.
  765.      */
  766. Object *OMnth_element(pool,object,n) ObjectPool *pool; Object *object;
  767. {
  768.   int len, type, z;
  769.   ListObject *list;
  770.   Object *ptr;
  771.  
  772.   type = object->type;
  773.  
  774.   if (type == STRING) return OMextract_elements(pool,object,n,1);
  775.  
  776.   if (type != LIST) return NULL;
  777.  
  778.   z = 1;
  779.   OMnz_magic(len = OMlength_of(object), &n,&z);
  780.  
  781.     /* we now know we have a list */
  782.  
  783.   if (n == len)        /* list not long enough, return empty list */
  784.     return OMcreate_object(pool,LIST,0);
  785.  
  786.   list = (ListObject *)object;
  787.  
  788.         /* find element n */
  789.   for (ptr = list->elements; n--; ptr = ptr->next_object)  ;
  790.  
  791.   return OMdup_object(pool, ptr);        /* atomize element */
  792. }
  793.  
  794.     /* Remove elements from a list or string.
  795.      * Input:
  796.      *   object:  object to remove stuff from.  Must be string or list.
  797.      *   n: first element to remove.  0 is the first element of a list.
  798.      *   z: number of elements to remove.
  799.      * Returns:
  800.      *   TRUE:  Everything went as expected.
  801.      *   FALSE: type mismatch.
  802.      * Notes:
  803.      *   If (n >= (length object)) no-op
  804.      *   If z goes off the end, stop there.
  805.      *   ???If (z <= 0) no-op
  806.      *   If (z <= 0) remove -z elements from end of list.  ie z == -2 means
  807.      *     remove last 2 elements.
  808.      *   (remove-items [] n [z]):  [].
  809.      *   No garbage generated.
  810.      *   ??? return the removed elements?
  811.      */
  812. int OMremove_items(object,n,z) Object *object;
  813. {
  814.   switch(object->type)
  815.   {
  816.     default:  return FALSE;
  817.     case LIST:
  818.     {
  819.       int a;
  820.       ListObject *list = (ListObject *)object;
  821.       Object *first, *last, *drag, *drag1;
  822.  
  823.     /* !!! This stuff isn't very robust - should use nz_magic() and do a
  824.      * bit more checking.
  825.      */
  826.  
  827.         /* find first element to free */
  828.       drag = NULL;
  829.       for (a = n, first = list->elements; first; first = first->next_object)
  830.       {
  831.         if (a-- == 0) break;
  832.     drag = first;
  833.       }
  834.       if (!first) break;        /* list not long enough */
  835.  
  836.         /* find last element to free */
  837.       for (a = z, last = first; last; last = last->next_object)
  838.       {
  839.     if (--a == 0) break;
  840.     drag1 = last;
  841.       }
  842.       if (last == NULL) last = drag1;
  843.  
  844.         /* link elements out of list */
  845.       if (drag == NULL) list->elements = last->next_object;
  846.       else        drag->next_object = last->next_object;
  847.  
  848.         /* free dead elements: Won't be GCed 'cause not "real" objects */
  849.       last->next_object = NULL;
  850.       free_objects(first);
  851.  
  852.       break;
  853.     }
  854.     case STRING:
  855.     {
  856.       char *p, *q;
  857.       int len, x;
  858.       StringObject *string = (StringObject *)object;
  859.  
  860.       OMnz_magic(len = OMlength_of(object), &n,&z);
  861.  
  862.     /* Calc how many characters need to be moved from the end of the
  863.      *   string (if any) to cover the removed characters.
  864.      */
  865.       x = imin(len, n + z);
  866.  
  867.       p = &string->string.string[n];
  868.       q = &string->string.string[x];
  869.  
  870.       n = len - x;
  871.  
  872.       while (n--) *p++ = *q++;
  873.       *p = '\0';
  874.  
  875.       break;
  876.     }
  877.   }
  878.   return TRUE;
  879. }
  880.  
  881.  
  882. #ifdef TEST
  883. /* ******************************************************************** */
  884. /* ******************************* TEST ******************************* */
  885. /* ******************************************************************** */
  886.  
  887. ObjectPool *pool;
  888. Object *object = NULL, *frotz = NULL, *save[10];
  889.  
  890. int sweeper()
  891. {
  892.   int j;
  893.  
  894.   if (object) OMgc_mark_object(object);
  895.   if (frotz)  OMgc_mark_object(frotz);
  896.   for (j = 10; j--; ) OMgc_mark_object(save[j]);
  897.  
  898.   return TRUE;
  899. }
  900.  
  901. static void print_object(prefix,object) char *prefix; Object *object;
  902. {
  903.   printf("%s",prefix);
  904.   switch(object->type)
  905.   {
  906.     case STRING:
  907.     printf("\"%s\"\n",((StringObject *)object)->string.string); break;
  908.     case NUMBER: printf("%d\n",((NumberObject *)object)->number); break;
  909.     case LIST: printf("LIST\n"); break;
  910.     default: printf("????\n");
  911.   }
  912. }
  913.  
  914.  
  915. pretty_print_object(object) Object *object;
  916. {
  917.   static char buf[100];
  918.   static int level = 0;
  919.  
  920.   buf[level] = '\0';
  921.  
  922.   print_object(buf,object);
  923.  
  924.   level += 2;
  925.   strcat(buf,"  ");
  926.  
  927.   if (object->type == LIST)
  928.   {
  929.     ListObject *list = (ListObject *)object;
  930.     Object *element;
  931.  
  932.     for (element = list->elements; element; element = element->next_object)
  933.       pretty_print_object(element);
  934.   }
  935.  
  936.   level -= 2;
  937. }
  938.  
  939. main()
  940. {
  941.   char buf[100];
  942.  
  943.   if (!(pool = OMcreate_object_pool(sweeper)))
  944.   {
  945.     printf("No memory at all!!\n");
  946.     exit(1);
  947.   }
  948.  
  949.   while (TRUE)
  950.   {
  951.     printf("Command:  Add-to, Create, Extract, Gc, Length, Print, Set, Remove, Quit: ");
  952.     gets(buf);
  953.     switch(*buf)
  954.     {
  955.       case 'q':  goto done;
  956.       case 'D':  if (object) OMdup_object(pool,object); break;
  957.       case '+':            /* jam object to frotz */
  958.         if (!object) { printf("Need a object!\n"); break; }
  959.     frotz = object;
  960.     object = NULL;
  961.     break;
  962.       case 'S':         /* Swap frotz and object */
  963.       {
  964.     Object *tmp;
  965.  
  966.     if (!object || !frotz) { printf("Need frotz and object!\n"); break; }
  967.     tmp = frotz;
  968.     frotz = object;
  969.     object = (Object *)tmp;
  970.     break;
  971.       }
  972.       case '1':
  973.       case '2':
  974.       case '3':
  975.       case '4':
  976.       case '5':
  977.       {
  978.     int n;
  979.  
  980.     n = *buf - '0';
  981.     save[n] = object;
  982.     break;
  983.       }
  984.       case '-':
  985.       {
  986.     int n;
  987.  
  988.     printf("Restore #");
  989.     gets(buf); n = atoi(buf);
  990.     if (n < 0 || n > 5) { printf("Out of range!\n"); break; }
  991.     object = save[n];
  992.     break;
  993.       }
  994.       case 'c':            /* create object */
  995.       {
  996.     int type, t, n = 0;
  997.  
  998.     printf("Object type:  list (%d), string(%d), number(%d): ",
  999.           LIST,STRING,NUMBER);
  1000.     gets(buf); type = atoi(buf);
  1001.     if (type != LIST && type != NUMBER && type != STRING)
  1002.       { printf("Bad type!\n"); break; }
  1003.     if (!(object = OMcreate_object(pool,type,n)))
  1004.     {
  1005.       printf("No memory to create object!\n");
  1006.       break;
  1007.     }
  1008.     break;
  1009.       }
  1010.       case 'a':            /* Add-to */
  1011.       {
  1012.     /* add object to frotz */
  1013.     int n;
  1014.  
  1015.     if (!object || !frotz) { printf("Need a list and a object!\n"); break; }
  1016.     printf("Insert object at n: ");
  1017.     gets(buf); n = atoi(buf);
  1018.     if (!OMinsert_object(frotz,n,object)) printf("Opps\n");
  1019.     break;
  1020.       }
  1021.       case 'g':            /* garbage collect */
  1022.     OMgc_the_world(); break;
  1023.       case 'p':            /* print pool */
  1024.       {
  1025.     int j;
  1026.     Object *ptr;
  1027.  
  1028.     if (frotz)  { printf("frotz:\n");  pretty_print_object(frotz);  }
  1029.     if (object) { printf("object:\n"); pretty_print_object(object); }
  1030.     for (j = 0; j < 10; j++)
  1031.       if (save[j])
  1032.       {
  1033.         printf("Save[%d]:\n",j); pretty_print_object(save[j]);
  1034.       }
  1035.     printf("======== object pool =======\n");
  1036.     for (ptr = pool->first_object; ptr; ptr = ptr->next_object)
  1037.         pretty_print_object(ptr);
  1038.       }
  1039.       break;
  1040.       case 'l':            /* object length */
  1041.         printf("Length of object = %d\n",OMlength_of(object));
  1042.     break;
  1043.       case 's':            /* set object value */
  1044.     switch(object->type)
  1045.     {
  1046.       case LIST: printf("LIST\n"); break;
  1047.       case STRING:
  1048.         printf("string value: "); gets(buf);
  1049.         OMset_object(object, STRING, buf);
  1050.         break;
  1051.       case NUMBER:
  1052.       {
  1053.         long int x;
  1054.  
  1055.         printf("number value: "); gets(buf); x = atol(buf);
  1056.         OMset_object(object, NUMBER, x);
  1057.         break;
  1058.       }
  1059.       default:  printf("unknown type\n"); break;
  1060.     }
  1061.     break;
  1062.       case 'r':            /* remove stuff */
  1063.       {
  1064.     int n,z;
  1065.  
  1066.     printf("First element:  "); gets(buf); n = atoi(buf);
  1067.     printf("Number of elements:  "); gets(buf); z = atoi(buf);
  1068.     OMremove_items(object,n,z);
  1069.       }
  1070.       break;
  1071.       case 'e':            /* extract */
  1072.       {
  1073.     int n,z;
  1074.     Object *foo;
  1075.  
  1076.     if (object->type != LIST && object->type != STRING)
  1077.     {
  1078.       printf("Can't do that.\n");
  1079.       break;
  1080.     }
  1081.  
  1082.     printf("First element:  "); gets(buf); n = atoi(buf);
  1083.     printf("Number of elements:  "); gets(buf); z = atoi(buf);
  1084.     if (!(foo = OMextract_elements(pool,object,n,z)))
  1085.     {
  1086.       printf("Out of memory!\n");
  1087.       break;
  1088.     }
  1089.     object = foo;
  1090.       }
  1091.       break;
  1092.     }
  1093.   }
  1094. done: ;
  1095. }
  1096.  
  1097. #endif        /* TEST */
  1098.