static char rcsid[] = "$Id: bvar.c,v 1.1 1992/09/05 01:13:32 mike Exp $"; /* $Log: bvar.c,v $ * Revision 1.1 1992/09/05 01:13:32 mike * Initial revision * */ /* * bvar.c : Buffer local variables. * * Buffer local variables are named and typed Mutt variables that are local * to a buffer, ie two buffers can have vars with the same name but * different types or values. Supported Mutt var data types: NUMBER, * OSTRING, LIST. Buffer vars are only useful for Mutt programming (well, * so far anyway). * Buffer vars can only be created - the only way to get rid of them is by * deleting the buffer that contains them. This is because if you need a * buffer var, you need something that will stick around for a while - * otherwise you would just use a Mutt var. Not being able to use a Mutt * var also implies you need variables of the same name and unique values * for more that one buffer. * * ME initialization: Call init_BVars(). * Buffer creation: When a buffer is created, it needs to call * init_buffer_bvars(). * Buffer deletion: When a buffer is freed, it needs to call * free_buffer_bvars(). * * Notes: * Given the long life and shared (multiple buffers with buffer vars of * the same name) nature of buffer vars, it might make sense to pool the * names of the buffer vars globally to cut down on memory used. * Drawbacks include fragmenting the heap and names are never freed * (because it is expected that other buffer will be using them). * The Object Manager is used to maintain the bvars. */ /* Copyright 1990, 1991, 1992 Craig Durland * Distributed under the terms of the GNU General Public License. * Distributed "as is", without warranties of any kind, but comments, * suggestions and bug reports are welcome. */ #include "me2.h" #include "mm.h" #include "oman.h" typedef struct BVar /* generic buffer variable */ { struct BVar *next; char *name; Object *object; } BVar; #define POOL_VARS 1 extern Object *OMcreate_object(); extern ObjectPool *OMcreate_object_pool(); static ObjectPool *bvar_object_pool; int init_bvars() { if (!(bvar_object_pool = OMcreate_object_pool((pfi)NULL))) return FALSE; return TRUE; } /* Initialize the buffers variable list. This needs to be called when a * buffer is created. */ void init_buffer_bvars(bp) register Buffer *bp; { bp->bvars = NULL; } /* Free and GC all the buffer variables in a buffer. This needs to be * called when a buffer is freed. * I only gc a block when the buffer is freed (since bvars live as long * as the buffer does. When a buffer is freed, free up all objects in * that buffer. * Input: * bp: pointer to the buffer to gc. * Notes: * All bvars are in the same object pool reguardless of what buffer * they are in. * Only gc when a buffer is freed because thats the only time there * will be garbage in this pool. So don't GC when run out of memory * or when somebody gc's the world. * I mark all dead objects because thats easy. */ void free_buffer_bvars(bp) Buffer *bp; { BVar *bv, *bv1; if (!(bv = bp->bvars)) return; /* no bvars to free */ for (; bv; bv = bv1) { bv1 = bv->next; /* since pointer is gone after free_bvar() */ #if !POOL_VARS free(bv->name); #endif OMgc_mark_object(bv->object); free((char *)bv); } OMgc_pool(bvar_object_pool, 2); /* dead objects are marked */ bp->bvars = NULL; } /* Check to see if a buffer variable named name has been allocated in the * current buffer. * Returns: * pointer to var. * NULL if var not allocated. * WARNING! You need to type check. */ static BVar *find_bvar(name) char *name; { BVar *bv; for (bv = curbp->bvars; bv; bv = bv->next) if (0 == strcmp(name,bv->name)) return bv; return NULL; } static char *stash_name(); /* Allocate a buffer var in the current buffer. * Input: * name : name of the buffer var. * type : NUMBER, OSTRING or LIST. * Returns: * TRUE : everything went as expected. * FALSE : bad type or no memory. * Notes: * If there is already a buffer var named name, I don't do anything. * What should I do? type check? */ int alloc_bvar(name,type) char *name; int type; { extern char *savestr(); BVar *bv; Object *object; if (type != NUMBER && type != OSTRING && type != LIST) return FALSE; /* ??? what to do if name exists? */ if (find_bvar(name)) return TRUE; if (!(bv = (BVar *)malloc(sizeof(BVar)))) return FALSE; #if POOL_VARS if (!(bv->name = stash_name(name))) #else if (!(bv->name = savestr(name))) #endif { free((char *)bv); return FALSE; } if (!(object = OMcreate_object(bvar_object_pool, type, 0))) { #if !POOL_VARS free(bv->name); #endif free((char *)bv); return FALSE; } bv->object = object; /* link in the new buffer var */ bv->next = curbp->bvars; curbp->bvars = bv; return TRUE; } /* access_bvar: Modify and/or retrieve the contents of a buffer * variable in the current buffer. * Input: * name: name of the bvar to use. * set: TRUE if modify name, FALSE if just retrieve. * RV: External MM variable. If set, it will be used to set bvar. * Output: * RV: Set to the contents of bvar. * Returns: * TRUE if everything went as expected * FALSE: name is not a bvar, there is a type mismatch between name * and RV or no memory. */ int access_bvar(name,set) char *name; { extern MMDatum RV; BVar *bv; Object *object; if (!(bv = find_bvar(name))) return FALSE; object = bv->object; if (set) { int s; switch (RV.type) /* ??? would be nice to pack this in with MM */ { case NUMBER: s = OMset_object(object, NUMBER, (long int)RV.val.num); break; case LIST: s = OMset_object(object, LIST, RV.val.object); break; case STRING: /* string constant */ s = OMset_object(object, OSTRING, RV.val.str); break; case OSTRING: /* string object */ s = OMset_object(object, OSTRING, OBJSTRING(RV.val.object)); break; default: return FALSE; /* invalid type */ } if (!s) return FALSE; } MMconvert_to_datum(object, &RV); return TRUE; } #if POOL_VARS typedef struct BVname { struct BVname *next; char name[1]; } BVname; static BVname *first_name = NULL; static char *stash_name(name) char *name; { BVname *ptr; for (ptr = first_name; ptr; ptr = ptr->next) if (0 == strcmp(name,ptr->name)) return ptr->name; if (!(ptr = (BVname *)malloc(sizeof(BVname) + strlen(name)))) return NULL; ptr->next = first_name; first_name = ptr; strcpy(ptr->name,name); return ptr->name; } #endif