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