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
8This file is part of groff.
9
10groff is free software; you can redistribute it and/or modify it under
11the terms of the GNU General Public License as published by the Free
12Software Foundation; either version 2, or (at your option) any later
13version.
14
15groff is distributed in the hope that it will be useful, but WITHOUT ANY
16WARRANTY; without even the implied warranty of MERCHANTABILITY or
17FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18for more details.
19
20You should have received a copy of the GNU General Public License along
21with groff; see the file COPYING.  If not, write to the Free Software
22Foundation, 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
30const char **symbol::table = 0;
31int symbol::table_used = 0;
32int symbol::table_size = 0;
33char *symbol::block = 0;
34int symbol::block_size = 0;
35
36const symbol NULL_SYMBOL;
37const symbol EMPTY_SYMBOL("");
38
39#ifdef BLOCK_SIZE
40#undef BLOCK_SIZE
41#endif
42
43const 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
47static 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};
51const double FULL_MAX = 0.3;	// don't let the table get more than this full
52
53static 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.
78inline void unused(void *) { }
79
80symbol::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
151symbol 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
161symbol default_symbol("default");
162