1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
5
6 This file is part of groff.
7
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with groff; see the file COPYING. If not, write to the Free Software
20 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
21
22 #include "lib.h"
23
24 #include "stringclass.h"
25
26 static char *salloc(int len, int *sizep);
27 static void sfree(char *ptr, int size);
28 static char *sfree_alloc(char *ptr, int size, int len, int *sizep);
29 static char *srealloc(char *ptr, int size, int oldlen, int newlen, int *sizep);
30
salloc(int len,int * sizep)31 static char *salloc(int len, int *sizep)
32 {
33 if (len == 0) {
34 *sizep = 0;
35 return 0;
36 }
37 else
38 return new char[*sizep = len*2];
39 }
40
sfree(char * ptr,int)41 static void sfree(char *ptr, int)
42 {
43 a_delete ptr;
44 }
45
sfree_alloc(char * ptr,int oldsz,int len,int * sizep)46 static char *sfree_alloc(char *ptr, int oldsz, int len, int *sizep)
47 {
48 if (oldsz >= len) {
49 *sizep = oldsz;
50 return ptr;
51 }
52 a_delete ptr;
53 if (len == 0) {
54 *sizep = 0;
55 return 0;
56 }
57 else
58 return new char[*sizep = len*2];
59 }
60
srealloc(char * ptr,int oldsz,int oldlen,int newlen,int * sizep)61 static char *srealloc(char *ptr, int oldsz, int oldlen, int newlen, int *sizep)
62 {
63 if (oldsz >= newlen) {
64 *sizep = oldsz;
65 return ptr;
66 }
67 if (newlen == 0) {
68 a_delete ptr;
69 *sizep = 0;
70 return 0;
71 }
72 else {
73 char *p = new char[*sizep = newlen*2];
74 if (oldlen < newlen && oldlen != 0)
75 memcpy(p, ptr, oldlen);
76 a_delete ptr;
77 return p;
78 }
79 }
80
string()81 string::string() : ptr(0), len(0), sz(0)
82 {
83 }
84
string(const char * p,int n)85 string::string(const char *p, int n) : len(n)
86 {
87 assert(n >= 0);
88 ptr = salloc(n, &sz);
89 if (n != 0)
90 memcpy(ptr, p, n);
91 }
92
string(const char * p)93 string::string(const char *p)
94 {
95 if (p == 0) {
96 len = 0;
97 ptr = 0;
98 sz = 0;
99 }
100 else {
101 len = strlen(p);
102 ptr = salloc(len, &sz);
103 memcpy(ptr, p, len);
104 }
105 }
106
string(char c)107 string::string(char c) : len(1)
108 {
109 ptr = salloc(1, &sz);
110 *ptr = c;
111 }
112
string(const string & s)113 string::string(const string &s) : len(s.len)
114 {
115 ptr = salloc(len, &sz);
116 if (len != 0)
117 memcpy(ptr, s.ptr, len);
118 }
119
~string()120 string::~string()
121 {
122 sfree(ptr, sz);
123 }
124
operator =(const string & s)125 string &string::operator=(const string &s)
126 {
127 ptr = sfree_alloc(ptr, sz, s.len, &sz);
128 len = s.len;
129 if (len != 0)
130 memcpy(ptr, s.ptr, len);
131 return *this;
132 }
133
operator =(const char * p)134 string &string::operator=(const char *p)
135 {
136 if (p == 0) {
137 sfree(ptr, len);
138 len = 0;
139 ptr = 0;
140 sz = 0;
141 }
142 else {
143 int slen = strlen(p);
144 ptr = sfree_alloc(ptr, sz, slen, &sz);
145 len = slen;
146 memcpy(ptr, p, len);
147 }
148 return *this;
149 }
150
operator =(char c)151 string &string::operator=(char c)
152 {
153 ptr = sfree_alloc(ptr, sz, 1, &sz);
154 len = 1;
155 *ptr = c;
156 return *this;
157 }
158
move(string & s)159 void string::move(string &s)
160 {
161 sfree(ptr, sz);
162 ptr = s.ptr;
163 len = s.len;
164 sz = s.sz;
165 s.ptr = 0;
166 s.len = 0;
167 s.sz = 0;
168 }
169
grow1()170 void string::grow1()
171 {
172 ptr = srealloc(ptr, sz, len, len + 1, &sz);
173 }
174
operator +=(const char * p)175 string &string::operator+=(const char *p)
176 {
177 if (p != 0) {
178 int n = strlen(p);
179 int newlen = len + n;
180 if (newlen > sz)
181 ptr = srealloc(ptr, sz, len, newlen, &sz);
182 memcpy(ptr + len, p, n);
183 len = newlen;
184 }
185 return *this;
186 }
187
operator +=(const string & s)188 string &string::operator+=(const string &s)
189 {
190 if (s.len != 0) {
191 int newlen = len + s.len;
192 if (newlen > sz)
193 ptr = srealloc(ptr, sz, len, newlen, &sz);
194 memcpy(ptr + len, s.ptr, s.len);
195 len = newlen;
196 }
197 return *this;
198 }
199
append(const char * p,int n)200 void string::append(const char *p, int n)
201 {
202 if (n > 0) {
203 int newlen = len + n;
204 if (newlen > sz)
205 ptr = srealloc(ptr, sz, len, newlen, &sz);
206 memcpy(ptr + len, p, n);
207 len = newlen;
208 }
209 }
210
string(const char * s1,int n1,const char * s2,int n2)211 string::string(const char *s1, int n1, const char *s2, int n2)
212 {
213 assert(n1 >= 0 && n2 >= 0);
214 len = n1 + n2;
215 if (len == 0) {
216 sz = 0;
217 ptr = 0;
218 }
219 else {
220 ptr = salloc(len, &sz);
221 if (n1 == 0)
222 memcpy(ptr, s2, n2);
223 else {
224 memcpy(ptr, s1, n1);
225 if (n2 != 0)
226 memcpy(ptr + n1, s2, n2);
227 }
228 }
229 }
230
operator <=(const string & s1,const string & s2)231 int operator<=(const string &s1, const string &s2)
232 {
233 return (s1.len <= s2.len
234 ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0
235 : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0);
236 }
237
operator <(const string & s1,const string & s2)238 int operator<(const string &s1, const string &s2)
239 {
240 return (s1.len < s2.len
241 ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0
242 : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0);
243 }
244
operator >=(const string & s1,const string & s2)245 int operator>=(const string &s1, const string &s2)
246 {
247 return (s1.len >= s2.len
248 ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0
249 : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0);
250 }
251
operator >(const string & s1,const string & s2)252 int operator>(const string &s1, const string &s2)
253 {
254 return (s1.len > s2.len
255 ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0
256 : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0);
257 }
258
set_length(int i)259 void string::set_length(int i)
260 {
261 assert(i >= 0);
262 if (i > sz)
263 ptr = srealloc(ptr, sz, len, i, &sz);
264 len = i;
265 }
266
clear()267 void string::clear()
268 {
269 len = 0;
270 }
271
search(char c) const272 int string::search(char c) const
273 {
274 char *p = ptr ? (char *)memchr(ptr, c, len) : NULL;
275 return p ? p - ptr : -1;
276 }
277
278 // we silently strip nuls
279
extract() const280 char *string::extract() const
281 {
282 char *p = ptr;
283 int n = len;
284 int nnuls = 0;
285 int i;
286 for (i = 0; i < n; i++)
287 if (p[i] == '\0')
288 nnuls++;
289 char *q = new char[n + 1 - nnuls];
290 char *r = q;
291 for (i = 0; i < n; i++)
292 if (p[i] != '\0')
293 *r++ = p[i];
294 *r = '\0';
295 return q;
296 }
297
remove_spaces()298 void string::remove_spaces()
299 {
300 int l = len - 1;
301 while (l >= 0 && ptr[l] == ' ')
302 l--;
303 char *p = ptr;
304 if (l > 0)
305 while (*p == ' ') {
306 p++;
307 l--;
308 }
309 if (len - 1 != l) {
310 if (l >= 0) {
311 len = l + 1;
312 char *tmp = new char[len];
313 memcpy(tmp, p, len);
314 a_delete ptr;
315 ptr = tmp;
316 }
317 else {
318 len = 0;
319 if (ptr) {
320 a_delete ptr;
321 ptr = 0;
322 }
323 }
324 }
325 }
326
put_string(const string & s,FILE * fp)327 void put_string(const string &s, FILE *fp)
328 {
329 int len = s.length();
330 const char *ptr = s.contents();
331 for (int i = 0; i < len; i++)
332 putc(ptr[i], fp);
333 }
334
as_string(int i)335 string as_string(int i)
336 {
337 static char buf[INT_DIGITS + 2];
338 sprintf(buf, "%d", i);
339 return string(buf);
340 }
341
342