/* * $Header$ */ #ifndef lint static char *rcsid_gdb_struct_c = "$Header$"; #endif /************************************************************************/ /* /* gdb_struct.c /* /* GDB - Structured Data Maintenance Routines /* /* Author: Noah Mendelsohn /* Copyright: 1986 MIT Project Athena /* For copying and distribution information, please see /* the file . /* /* These routines implement the following layers of the /* Client Library Specification of the GDB system: /* /* Layer Function /* ----- -------- /* 2 Structured Data Management at a /* Single Site /* /* 4 Memory Management /* /* 5 String Management /* /* Some of the routines specified are actually implemented as /* macros defined in gdb.h. /* /************************************************************************/ #include #include #include #include #include "gdb.h" /************************************************************************/ /* /* MEMORY MANAGEMENT /* /* In anticipation of the day when we may want to do something /* fancy with memory management, all of the gdb routines which /* require dynamic allocation of memory call the routines named /* db_alloc and db_free. For the moment, these are implemented /* as calls to malloc and free. /* /************************************************************************/ /*----------------------------------------------------------*/ /* /* gdb_am /* /* Allocate memory for use by gdb. Current implementation /* just does a malloc. /* /*----------------------------------------------------------*/ char * gdb_am(bytes) int bytes; { return(malloc((unsigned)bytes)); } /*----------------------------------------------------------*/ /* /* gdb_fm /* /* Return allocated memory. Note: the current /* implementation ignores the byte count supplied, /* but future implementations may require that it /* be correct. /* /*----------------------------------------------------------*/ /*ARGSUSED*/ int gdb_fm(ptr, bytes) char *ptr; int bytes; { free(ptr); return; } /************************************************************************/ /* /* STRING MANAGEMENT /* /* To allow dynamic manipulation of strings in gdb without /* excessive memory re-allocation, we define a string as a /* counted byte space. Though this space will frequently be used /* to store a standard null terminated string, that is not /* required. /* /* Current representation for a string is a pointer followed by /* an integer length. A null pointer indicates a null string, in /* which case the length is arbitrary. Any other pointer is to /* memory which was allocated by db_alloc in which must be free'd /* eventually with db_free. /* /************************************************************************/ /*----------------------------------------------------------*/ /* /* string_alloc (string_alloc) /* /* Fills in supplied string descriptor and returns /* pointer to the newly allocated data. /* /*----------------------------------------------------------*/ char * string_alloc(stringp, bytes) STRING *stringp; /* pointer to string */ /* descriptor to be */ /* filled in */ int bytes; /* number of bytes to alloc */ { GDB_INIT_CHECK MAX_STRING_SIZE(*stringp) = bytes; /* put length in returned */ /* string descriptor-- */ /* will be irrelavent if */ /* alloc fails */ STRING_DATA(*stringp) = db_alloc(bytes); /* try to get the data */ return (STRING_DATA(*stringp)); /* return ptr to new string */ /* if any */ } /*----------------------------------------------------------*/ /* /* string_free (string_free) /* /* Releases the data space for a gdb string. Must have /* been allocated with string_alloc. Remember to pass /* in the address of the string descriptor, not the /* descriptor itself! /* /*----------------------------------------------------------*/ int string_free(stringp) STRING *stringp; { GDB_INIT_CHECK if (stringp->ptr == NULL) return; db_free(stringp->ptr, stringp->length); stringp->ptr = NULL; stringp->length = 0; return; } /************************************************************************/ /* /* STRUCTURED DATA MANAGEMENT AT A SINGLE SITE /* /* These routines provide the abstraction of typed, structured /* data at a single site. Tuples are collections of typed fields, /* and they are each described by a tuple descriptor. Relations /* are circularly linked lists of tuples. For completeness, a /* relation also carries a tuple descriptor, which should match /* the descriptor for each of its constituent tuples. This allows /* a null relation to be typed. /* /* Some of the facilities of structured data management are /* defined as macros in gdb.h. In many cases, the routines /* declared below are known by defines of more descriptive /* names, also in gdb.h. /* /************************************************************************/ /************************************************************************/ /* /* TUPLE_DESCRIPTOR MANAGEMENT /* /************************************************************************/ /*----------------------------------------------------------*/ /* /* create_tuple_descriptor (create_tuple_descriptor) /* /* Allocates space for a tuple descriptor and fills /* it in. Gives up if space is not available. /* Should be passed a list of integer coded types /* and a list of string field names. /* /* Tuple descriptors are reference counted, and they are /* not really deleted until the reference count goes /* to zero. It is presumed that all callers use the /* create and delete routines, or otherwise maintain /* the reference count appropriately. /* /*----------------------------------------------------------*/ TUPLE_DESCRIPTOR create_tuple_descriptor(number_of_fields, name_list, type_list) char *name_list[]; FIELD_TYPE type_list[]; int number_of_fields; { register TUPLE_DESCRIPTOR tpd; /* pointer to new descriptor */ register int i; register int data_len; /* length of the actual */ int field_len; /* length of current field */ int align; /* code describing alignment */ /* requirement for this field*/ /* (4 for fullword, 1 for */ /* char, etc.) */ int next_offset; /* byte offset to next field */ int descriptor_length; /* length of the part of */ /* the allocated storage */ /* actually used for the */ /* descriptor.*/ int str_len; /* we also have to retain */ /* the string names for the */ /* fields. These are stored */ /* immediately off the end */ /* of the descriptor, and */ /* all are allocated */ /* together. This is the */ /* length of the string data */ char *next_name; /* place to put the next */ /* copied fieldname*/ GDB_INIT_CHECK /* * Calculate size and allocate descriptor */ descriptor_length = sizeof(struct tupl_desc) + (number_of_fields-1) * sizeof(struct tupld_var); str_len = 0; for (i=0; iid = GDB_DESC_ID; tpd->ref_count = 1; /* whoever asked for creation*/ /* is expected to delete*/ tpd->field_count = number_of_fields; tpd->str_len = str_len; data_len = sizeof(struct tuple_dat) - 1; /* tuple_dat includes the */ /* first byte of data */ next_offset = 0; next_name = ((char *)tpd) + descriptor_length; /* place to put first */ /* field name*/ for (i=0; ivar[i].name = strcpy(next_name, name_list[i]); next_name += strlen(next_name) + 1; /* * Put in the type and the length for the field data */ tpd->var[i].type = type_list[i]; tpd->var[i].length = field_len; /* * Now store the actual offset of this field, and * compute the first byte address we could conceivably * use for the next field. */ next_offset = GDB_ROUNDUP(next_offset, align); tpd->var[i].offset = next_offset; next_offset += field_len; } data_len += next_offset; tpd->data_len = data_len; return tpd; /* return the new descriptor */ } /*----------------------------------------------------------*/ /* /* delete_tuple_descriptor (delete_tuple_descriptor) /* /* Return the space for a tuple descriptor /* /*----------------------------------------------------------*/ int delete_tuple_descriptor(t) TUPLE_DESCRIPTOR t; { int descriptor_length; register int ref_count; /* buffer the reference */ /* count here */ if (t == NULL) return ; GDB_CHECK_TPD(t, "delete_tuple_descriptor") /* * Decrement the reference count. If it's not zero, then just * return. */ if ((ref_count = --(t->ref_count)) >0) return ; if (ref_count <0) GDB_GIVEUP("Tuple descriptor reference count is less than zero") /* * Current representation is to allocate the space for the string * right off the end of the descriptor itself. We therefore have * to add their length into the amount we free. */ descriptor_length = gdb_descriptor_length(t->field_count); db_free((char *)t, descriptor_length+t->str_len); return ; } /*----------------------------------------------------------*/ /* /* field_index (field_index) /* /*----------------------------------------------------------*/ int field_index(tuple_descriptor, field_name) TUPLE_DESCRIPTOR tuple_descriptor; char *field_name; { register int i; register int n; register TUPLE_DESCRIPTOR tpd = tuple_descriptor; /* * Make sure supplied descriptor is valid */ if (tpd == NULL) GDB_GIVEUP("null tuple descriptor passed to field_index function") GDB_CHECK_TPD(tpd, "field_index") n = tpd -> field_count; /* * Loop through each field in descriptor, return index if match */ for(i=0; ivar[i].name) == 0) return i; /* * No match, return -1 */ return (-1); } /************************************************************************/ /* /* TUPLE MANAGEMENT /* /************************************************************************/ /*----------------------------------------------------------*/ /* /* create_tuple (create_tuple) /* /* Allocate space for a new tuple, given its /* descriptor. Giveup if out of memory. /* /*----------------------------------------------------------*/ TUPLE create_tuple(descriptor) TUPLE_DESCRIPTOR descriptor; { register TUPLE t; GDB_CHECK_TPD(descriptor, "create_tuple") t = (TUPLE)db_alloc(descriptor -> data_len); if (t == NULL) GDB_GIVEUP("create_tuple (create_tuple) could not allocate enough memory.\n") t->id = GDB_TUP_ID; t->desc = descriptor; /* fill in descriptor */ /* pointer in new tuple */ REFERENCE_TUPLE_DESCRIPTOR(descriptor); /* bump the reference count */ #ifdef GDB_CHECK /* * Only for the sake of keeping things clean, null out the pointers. * Wastes time, but helps debugging. */ t->next = t->prev = NULL; #endif return t; } /*----------------------------------------------------------*/ /* /* delete_tuple (delete_tuple) /* /* Release the data space occupied by a tuple. /* /*----------------------------------------------------------*/ int delete_tuple(t) TUPLE t; { register TUPLE_DESCRIPTOR tpd; if (t==NULL) GDB_GIVEUP("Delete_tuple called with null tuple") GDB_CHECK_TUP(t, "delete_tuple") tpd = t->desc; db_free((char *)t, t->desc->data_len); delete_tuple_descriptor(tpd); /* does a reference counted */ /* delete*/ } /*----------------------------------------------------------*/ /* /* initialize_tuple (initialize_tuple) /* /* Set each field in tuple to its null value. /* /*----------------------------------------------------------*/ int initialize_tuple(t) TUPLE t; { register char *field_data; /* pointer to first byte */ /* of field data in tuple*/ register TUPLE_DESCRIPTOR tpd; /* pointer to descriptor */ register int i; /* counter of fields */ int num_fields; /* total number of fields */ /* * Return if no tuple at all supplied--perhaps this should be * an error. If supplied, make sure it looks like a tuple. */ if (t == NULL) return; GDB_CHECK_TUP(t, "initialize_tuple") /* * Set up to loop through fields: get tuple descriptor, field count * and pointer to first data byte in the tuple. */ tpd = t->desc; num_fields = tpd->field_count; field_data = t->data; /* address of first byte of */ /* user data */ /* * For each field in the tuple, loop calling its null value * initialization routine. */ for (i=0; ivar[i].type, NULL_PROPERTY) (field_data+tpd->var[i].offset); } } /*----------------------------------------------------------*/ /* /* null_tuple_strings (null_tuple_strings) /* /* Reclaim the space for all fields in the tuple /* whose type is 'string.' /* /*----------------------------------------------------------*/ int null_tuple_strings(t) TUPLE t; { register char *field_data; /* pointer to first byte of */ /* field data in tuple */ register TUPLE_DESCRIPTOR tpd; /* pointer to descriptor */ register int i; /* counter of fields */ int num_fields; /* total number of fields */ /* * Return if no tuple at all supplied--perhaps this should be * an error */ if (t == NULL) return; GDB_CHECK_TUP(t, "null_tuple_strings") /* * Set up to loop through fields: get tuple descriptor, field count * and pointer to first data byte in the tuple. */ tpd = t->desc; num_fields = tpd->field_count; field_data = t->data; /* address of first byte of */ /* user data */ /* * For each field in the tuple, loop calling its null value * initialization routine. */ for (i=0; iid = GDB_REL_ID; r->first = (TUPLE)r; r->last = (TUPLE)r; r->desc = desc; REFERENCE_TUPLE_DESCRIPTOR(desc); /* bump the reference count */ return r; } /*----------------------------------------------------------*/ /* /* delete_relation /* /* Deletes the tuples which comprise a relation. /* For each tuple, it does a null-tuple-strings /* prior to deleting, but it does not yet handle /* any other non-contiguous data. /* /*----------------------------------------------------------*/ int delete_relation(rel) RELATION rel; { register TUPLE t, next; TUPLE_DESCRIPTOR desc; /* * Make sure a proper relation is supplied. */ if (rel == NULL) GDB_GIVEUP("delete_relation called with null relation") GDB_CHECK_REL(rel, "delete_relation") t = FIRST_TUPLE_IN_RELATION(rel); /*----------------------------------------------------------*/ /* /* Free all the tuples /* /*----------------------------------------------------------*/ while (t!=NULL) { null_tuple_strings(t); next = NEXT_TUPLE_IN_RELATION(rel, t); delete_tuple(t); t = next; } /*----------------------------------------------------------*/ /* /* Give back the memory for the relation /* /*----------------------------------------------------------*/ desc = DESCRIPTOR_FROM_RELATION(rel); db_free((char *)rel, sizeof(struct rel_dat)); delete_tuple_descriptor(desc); /* does a reference */ /* counted delete */ } /*----------------------------------------------------------*/ /* /* tuples_in_relation /* /* Returns number of tuples in a relation. /* /* /*----------------------------------------------------------*/ int tuples_in_relation(rel) RELATION rel; { register int count; register RELATION r=rel; register TUPLE t; count = 0; for (t=FIRST_TUPLE_IN_RELATION(r); t != NULL; t=NEXT_TUPLE_IN_RELATION(r,t)) { count++; } return count; }