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