1 /* $NetBSD: symbol.cpp,v 1.1.1.1 2016/01/13 18:41:48 christos Exp $ */ 2 3 // -*- C++ -*- 4 /* Copyright (C) 1989, 1990, 1991, 1992, 2002, 2004 5 Free Software Foundation, Inc. 6 Written by James Clark (jjc@jclark.com) 7 8 This file is part of groff. 9 10 groff is free software; you can redistribute it and/or modify it under 11 the terms of the GNU General Public License as published by the Free 12 Software Foundation; either version 2, or (at your option) any later 13 version. 14 15 groff is distributed in the hope that it will be useful, but WITHOUT ANY 16 WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 for more details. 19 20 You should have received a copy of the GNU General Public License along 21 with groff; see the file COPYING. If not, write to the Free Software 22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 23 24 #include "lib.h" 25 26 #include "errarg.h" 27 #include "error.h" 28 #include "symbol.h" 29 30 const char **symbol::table = 0; 31 int symbol::table_used = 0; 32 int symbol::table_size = 0; 33 char *symbol::block = 0; 34 int symbol::block_size = 0; 35 36 const symbol NULL_SYMBOL; 37 const symbol EMPTY_SYMBOL(""); 38 39 #ifdef BLOCK_SIZE 40 #undef BLOCK_SIZE 41 #endif 42 43 const int BLOCK_SIZE = 1024; 44 // the table will increase in size as necessary 45 // the size will be chosen from the following array 46 // add some more if you want 47 static const unsigned int table_sizes[] = { 48 101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, 80021, 49 160001, 500009, 1000003, 1500007, 2000003, 0 50 }; 51 const double FULL_MAX = 0.3; // don't let the table get more than this full 52 53 static unsigned int hash_string(const char *p) 54 { 55 // compute a hash code; this assumes 32-bit unsigned ints 56 // see p436 of Compilers by Aho, Sethi & Ullman 57 // give special treatment to two-character names 58 unsigned int hc = 0, g; 59 if (*p != 0) { 60 hc = *p++; 61 if (*p != 0) { 62 hc <<= 7; 63 hc += *p++; 64 for (; *p != 0; p++) { 65 hc <<= 4; 66 hc += *p; 67 if ((g = (hc & 0xf0000000)) == 0) { 68 hc ^= g >> 24; 69 hc ^= g; 70 } 71 } 72 } 73 } 74 return hc; 75 } 76 77 // Tell compiler that a variable is intentionally unused. 78 inline void unused(void *) { } 79 80 symbol::symbol(const char *p, int how) 81 { 82 if (p == 0) { 83 s = 0; 84 return; 85 } 86 if (*p == 0) { 87 s = ""; 88 return; 89 } 90 if (table == 0) { 91 table_size = table_sizes[0]; 92 table = (const char **)new char*[table_size]; 93 for (int i = 0; i < table_size; i++) 94 table[i] = 0; 95 table_used = 0; 96 } 97 unsigned int hc = hash_string(p); 98 const char **pp; 99 for (pp = table + hc % table_size; 100 *pp != 0; 101 (pp == table ? pp = table + table_size - 1 : --pp)) 102 if (strcmp(p, *pp) == 0) { 103 s = *pp; 104 return; 105 } 106 if (how == MUST_ALREADY_EXIST) { 107 s = 0; 108 return; 109 } 110 if (table_used >= table_size - 1 || table_used >= table_size*FULL_MAX) { 111 const char **old_table = table; 112 unsigned int old_table_size = table_size; 113 int i; 114 for (i = 1; table_sizes[i] <= old_table_size; i++) 115 if (table_sizes[i] == 0) 116 fatal("too many symbols"); 117 table_size = table_sizes[i]; 118 table_used = 0; 119 table = (const char **)new char*[table_size]; 120 for (i = 0; i < table_size; i++) 121 table[i] = 0; 122 for (pp = old_table + old_table_size - 1; 123 pp >= old_table; 124 --pp) { 125 symbol temp(*pp, 1); /* insert it into the new table */ 126 unused(&temp); 127 } 128 a_delete old_table; 129 for (pp = table + hc % table_size; 130 *pp != 0; 131 (pp == table ? pp = table + table_size - 1 : --pp)) 132 ; 133 } 134 ++table_used; 135 if (how == DONT_STORE) { 136 s = *pp = p; 137 } 138 else { 139 int len = strlen(p)+1; 140 if (block == 0 || block_size < len) { 141 block_size = len > BLOCK_SIZE ? len : BLOCK_SIZE; 142 block = new char [block_size]; 143 } 144 (void)strcpy(block, p); 145 s = *pp = block; 146 block += len; 147 block_size -= len; 148 } 149 } 150 151 symbol concat(symbol s1, symbol s2) 152 { 153 char *buf = new char [strlen(s1.contents()) + strlen(s2.contents()) + 1]; 154 strcpy(buf, s1.contents()); 155 strcat(buf, s2.contents()); 156 symbol res(buf); 157 a_delete buf; 158 return res; 159 } 160 161 symbol default_symbol("default"); 162