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