Get rid of the old texinfo.
[dragonfly.git] / contrib / groff / src / roff / troff / symbol.cc
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 2, or (at your option) any later
10 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 along
18 with groff; see the file COPYING.  If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21
22 #include "troff.h"
23 #include "symbol.h"
24
25 const char **symbol::table = 0;
26 int symbol::table_used = 0;
27 int symbol::table_size = 0;
28 char *symbol::block = 0;
29 int symbol::block_size = 0;
30
31 const symbol NULL_SYMBOL;
32 const symbol EMPTY_SYMBOL("");
33
34 #ifdef BLOCK_SIZE
35 #undef BLOCK_SIZE
36 #endif
37
38 const int BLOCK_SIZE = 1024;
39 // the table will increase in size as necessary
40 // the size will be chosen from the following array
41 // add some more if you want
42 static const unsigned int table_sizes[] = { 
43   101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, 80021,
44   160001, 500009, 1000003, 1500007, 2000003, 0 
45 };
46 const double FULL_MAX = 0.3;    // don't let the table get more than this full
47
48 static unsigned int hash_string(const char *p)
49 {
50   // compute a hash code; this assumes 32-bit unsigned ints
51   // see p436 of  Compilers by Aho, Sethi & Ullman
52   // give special treatment to two-character names
53   unsigned int hc = 0, g;
54   if (*p != 0) {
55     hc = *p++;
56     if (*p != 0) {
57       hc <<= 7;
58       hc += *p++;
59       for (; *p != 0; p++) {
60         hc <<= 4;
61         hc += *p;
62         if ((g = (hc & 0xf0000000)) == 0) {
63           hc ^= g >> 24;
64           hc ^= g;
65         }
66       }
67     }
68   }
69   return hc;
70 }
71
72 // Tell compiler that a variable is intentionally unused.
73 inline void unused(void *) { }
74
75 symbol::symbol(const char *p, int how)
76 {
77   if (p == 0) {
78     s = 0;
79     return;
80   }
81   if (*p == 0) {
82     s = "";
83     return;
84   }
85   if (table == 0) {
86     table_size = table_sizes[0];
87     table = (const char **)new char*[table_size];
88     for (int i = 0; i < table_size; i++)
89       table[i] = 0;
90     table_used = 0;
91   }
92   unsigned int hc = hash_string(p);
93   const char **pp;
94   for (pp = table + hc % table_size; 
95        *pp != 0; 
96        (pp == table ? pp = table + table_size - 1 : --pp))
97     if (strcmp(p, *pp) == 0) {
98       s = *pp;
99       return;
100     }
101   if (how == MUST_ALREADY_EXIST) {
102     s = 0;
103     return;
104   }
105   if (table_used  >= table_size - 1 || table_used >= table_size*FULL_MAX) {
106     const char **old_table = table;
107     unsigned int old_table_size = table_size;
108     int i;
109     for (i = 1; table_sizes[i] <= old_table_size; i++)
110       if (table_sizes[i] == 0)
111         fatal("too many symbols");
112     table_size = table_sizes[i];
113     table_used = 0;
114     table = (const char **)new char*[table_size];
115     for (i = 0; i < table_size; i++)
116       table[i] = 0;
117     for (pp = old_table + old_table_size - 1; 
118          pp >= old_table;
119          --pp) {
120            symbol temp(*pp, 1); /* insert it into the new table */
121            unused(&temp);
122          }
123     a_delete old_table;
124     for (pp = table + hc % table_size;
125          *pp != 0; 
126          (pp == table ? pp = table + table_size - 1 : --pp))
127       ;
128   }
129   ++table_used;
130   if (how == DONT_STORE) {
131     s = *pp = p;
132   }
133   else {
134     int len = strlen(p)+1;
135     if (block == 0 || block_size < len) {
136       block_size = len > BLOCK_SIZE ? len : BLOCK_SIZE;
137       block = new char [block_size];
138     }
139     (void)strcpy(block, p);
140     s = *pp = block;
141     block += len;
142     block_size -= len;
143   }
144 }
145
146 symbol concat(symbol s1, symbol s2)
147 {
148   char *buf = new char [strlen(s1.contents()) + strlen(s2.contents()) + 1];
149   strcpy(buf, s1.contents());
150   strcat(buf, s2.contents());
151   symbol res(buf);
152   a_delete buf;
153   return res;
154 }