/* * Copyright (c) 1995, 1996 Gunther Schadow. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "pg_config.h" IDENT("@(#) odbm-block.cc (Gunther Schadow) 12/19/96"); #include "odbm.h" #include #include #include #include /******************************************************************* * Data Block * */ /* The data block is has the following layout: * * 1. Scalar Section -- the fixed size scalars, directly followed by the * 2. String Section -- the fix number of null terminated strings */ /* * build a data block: * This method is "const" even though it modifies the data datum. * It is still a problem that NULLs are mapped to empty strings. */ void odbm::build_data() const { // force the "const" errors to shut up odbm *that = (odbm *)this; // check if a new data block is needed register int i; if(data.dptr != NULL) { register bool all_strings_in_block = TRUE; register char *dptr = data.dptr; register char *eptr = data.dptr + data.dsize; for(i = 0; i < nostrings; i++) { all_strings_in_block = all_strings_in_block && (dptr <= strings[i] && strings[i] < eptr); } // is is assumed that the last string does not exceed the string block if(all_strings_in_block) // do not build new block, { // but copy the scalars memcpy(that->data.dptr, scalars.dptr, scalars.dsize); return; // and we are ready! } } // determine length of new data block to allocate register size_t size = scalars.dsize; for(i = 0; i < nostrings; i++) { if(strings[i] != NULL) size += strlen(strings[i]); else size++; // NULLs are mapped to "" strings, see below ... size++; } // remember the old data block char *old_data = that->data.dptr; // allocate a new data block that->data.dptr = new char[size]; that->data.dsize = size; // copy the scalar data memcpy(that->data.dptr, scalars.dptr, scalars.dsize); // copy the string data char *p = &that->data.dptr[scalars.dsize]; for(i = 0; i < nostrings; i++) { if(strings[i] != NULL) for(char *q = strings[i]; *q != '\0'; q++) *p++ = *q; *p++ = '\0'; // put a "" in place of a NULL anyway } // delete the old data block if(old_data != NULL) delete [] old_data; } /* * parse a data block: * the data block is immediately deleted after the scalars and strings * are copyied out of it. * * THIS IS WRONG: ``Unfortunately we cannot just leave the strings * where they are, because we still have to delete the strings separately, * which would result in ``general havoc'' (see free(3)).'' * * No! This is not true: If we do not allow the strings to be deleted nor * modified (appended) in place (const char*), then we can still keep * them together as a block. Thus, the user of odbm does have to care * about the strings only if he/she copies them out but not when he just * reads them from an odbm output! */ void odbm::parse_data() { // copy the scalar data memcpy(scalars.dptr, data.dptr, scalars.dsize); // copy the strings register char *p = &data.dptr[scalars.dsize]; int i; for(i = 0; i < nostrings - 1; i++) { strings[i] = p; while(*p++ != '\0'); // go to end of string } strings[i] = p; } /******************************************************************* * Key Block * */ /* The key block has the following layout: * * 1. Tag (one byte) -- identifies the key as a tuple(0) or index(>0) entry * 2. Key (string) -- the key or index value */ datum odbm::build_key(const char *k) const { if(k == NULL) k = ""; // CHECKME! is this correct? datum r; r.dsize = 1 + strlen(k) + 1; r.dptr = new char [r.dsize + 1]; // always leave one extra byte for the index r.dptr[0] = 0; strcpy(&r.dptr[1], k); return r; } /* * This is used to update the actual key in the odbm object */ void odbm::update_key() const { if(*keyp != &key.dptr[1]) //if the key is outdated { odbm *that = (odbm *)this; // force the const warnings to be silent // delete it and build a new key if(key.dptr != NULL) delete [] that->key.dptr; datum new_key = build_key(*keyp); that->key = new_key; *that->keyp = (char *)parse_key(); } }