/* * This file is part of rasdaman community. * * Rasdaman community 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 3 of the License, or * (at your option) any later version. * * Rasdaman community 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 rasdaman community. If not, see . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . / /** * PURPOSE: * * The label manager class is used to lookup label:value pairs * stored in a text file. The constructor reads in the file whose * name is passed to it and sorts the non-empty, non-commentary * lines (commentary lines have a '#' as the first non-white * character in a line) in ascending order to make binary searching * possible. The binary search is performed by the lookup member * function. * * COMMENTS: None */ #include #include #include "iostream.h" #include "labelManager.hh" /* * Load the resource file, parse and sort it. */ labelManager::labelManager(const char *resourceFile) { FILE *fp; size_t filesize; int i; char c, *b, *upper; buffer = NULL; lineTable = NULL; lines = 0; strncpy(badSymbol, "???", 4); if ((fp = fopen(resourceFile, "r")) == NULL) { cerr << "Unable to open resource file " << resourceFile << endl; return; } // Position to end of file to determine its length. fseek(fp, 0, SEEK_END); filesize = ftell(fp); if ((buffer = new char[filesize+1]) == NULL) { cerr << "Not enough memory for buffer!" << endl; } fseek(fp, 0, SEEK_SET); // Read in the file and make sure it's terminated by a newline char. fread((void*)buffer, 1, filesize, fp); buffer[filesize] = '\n'; fclose(fp); upper = buffer + filesize; b = buffer; // Pass 1: calculate how much memory is needed for the lineTable. do { // for (i=0; b[i] != '\n'; i++) {cout << b[i];} cout << endl; // Ignore leading whitespace do {c = *b++;} while ((c == ' ') || (c == '\t')); // Commentary line? if (c == '#') { do {c = *b++;} while (c != '\n'); } // Line not empty? else if (c != '\n') { lines++; i = 0; i = (b - buffer) - 1; // Make sure it contains a colon! do {c = *b++; if (c == ':') {i = -1;}} while (c != '\n'); if (i >= 0) { cerr << "Bad line format (missing colon): "; while (buffer[i] != '\n') {cout << buffer[i]; i++;} cout << endl; delete [] buffer; buffer = NULL; lines = 0; return; } } } while (b < upper); if ((lineTable = new char*[lines]) == NULL) { cerr << "Not enough memory for lineTable!" << endl; delete [] buffer; buffer = NULL; lines = 0; return; } b = buffer; i = 0; // Pass 2: fill in lineTable do { do {c = *b++;} while ((c == ' ') || (c == '\t')); if (c == '#') { do {c = *b++;} while (c != '\n'); } else if (c != '\n') { lineTable[i++] = b-1; do {c = *b++;} while (c != '\n'); // terminate all non-empty lines with '\0' *(b-1) = '\0'; } } while (b < upper); if ((unsigned int)i != lines) { cerr << "Fatal error: passes incompatible!" << endl; } sortResources(0, lines-1); /*cout << lines << " label definitions found." << endl; for (i=0; i second string can at best be =, not < if (*l == ':') continue; // If end of second idf was reached the second string is <. Otherwise check chars. if ((*m == ':') || (*m < *l)) { j++; swap = lineTable[j]; lineTable[j] = lineTable[i]; lineTable[i] = swap; } } swap = lineTable[from]; lineTable[from] = lineTable[j]; lineTable[j] = swap; // Select cheaper recursion branch if ((j - from) < (to - j)) { sortResources(from, j-1); from = j+1; } else { sortResources(j+1, to); to = j-1; } } } /* * Destructor: just frees all dynamically allocated memory. */ labelManager::~labelManager(void) { if (lineTable != NULL) delete [] lineTable; if (buffer != NULL) delete [] buffer; } /* * Look up a symbol and return a read-only pointer to the symbol value. If * this symbol doesn't exist it returns a pointer to the badSymbol-member. */ char *labelManager::lookup(const char *symbol) { int at, step, iter; char *s, *l; if (lines == 0) return badSymbol; at = (lines+1)/2; step = (at+1)/2; iter = lines << 1; if (at >= (int)lines) at = lines-1; // Do a binary search over the sorted items while (iter != 0) { // The symbol may be terminated by a colon or any character <= 32 s = (char*)symbol; l = lineTable[at]; while ((*s == *l) && (*l != ':')) {s++; l++;} // Was the symbol's end reached? if (((unsigned char)(*s) <= 32) || (*s == ':')) { // Both read to the end. Success. if (*l == ':') return (l+1); // Symbol's end reached but not label's ==> label >, i.e. step down at -= step; if (at < 0) at = 0; } else { // label's end reached ==> label <, i.e. step up. Otherwise use chars. if ((*l == ':') || (*l < *s)) { at += step; if (at >= (int)lines) at = lines-1; } else { at -= step; if (at < 0) at = 0; } } step = (step+1)/2; iter >>= 1; //cout << at << ", " << step << ", " << iter << ": " << lineTable[at] << endl; } return badSymbol; } /* * Returns the number of label definitions. */ int labelManager::numberOfLabels(void) { return lines; } /* * Returns a read-only pointer to the index-th label in the sorted table. * Normally this shouldn't be used from an outside application, but it * may be handy for debugging. */ char *labelManager::returnLabelNumber(unsigned int index) { if (index >= lines) { return NULL; } return lineTable[index]; } /* TEST int main(int argc, char *argv[]) { int i; char *b; labelManager lman("labels.txt"); for (i=0; i