Imported Upstream version 1.22.4
[platform/upstream/groff.git] / src / libs / libgroff / string.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 <stdlib.h>
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
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
41 static void sfree(char *ptr, int)
42 {
43   a_delete ptr;
44 }
45
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
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
81 string::string() : ptr(0), len(0), sz(0)
82 {
83 }
84
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
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     if (len != 0)
104       memcpy(ptr, p, len);
105   }
106 }
107
108 string::string(char c) : len(1)
109 {
110   ptr = salloc(1, &sz);
111   *ptr = c;
112 }
113
114 string::string(const string &s) : len(s.len)
115 {
116   ptr = salloc(len, &sz);
117   if (len != 0)
118     memcpy(ptr, s.ptr, len);
119 }
120   
121 string::~string()
122 {
123   sfree(ptr, sz);
124 }
125
126 string &string::operator=(const string &s)
127 {
128   ptr = sfree_alloc(ptr, sz, s.len, &sz);
129   len = s.len;
130   if (len != 0)
131     memcpy(ptr, s.ptr, len);
132   return *this;
133 }
134
135 string &string::operator=(const char *p)
136 {
137   if (p == 0) {
138     sfree(ptr, len);
139     len = 0;
140     ptr = 0;
141     sz = 0;
142   }
143   else {
144     int slen = strlen(p);
145     ptr = sfree_alloc(ptr, sz, slen, &sz);
146     len = slen;
147     if (len != 0)
148       memcpy(ptr, p, len);
149   }
150   return *this;
151 }
152
153 string &string::operator=(char c)
154 {
155   ptr = sfree_alloc(ptr, sz, 1, &sz);
156   len = 1;
157   *ptr = c;
158   return *this;
159 }
160
161 void string::move(string &s)
162 {
163   sfree(ptr, sz);
164   ptr = s.ptr;
165   len = s.len;
166   sz = s.sz;
167   s.ptr = 0;
168   s.len = 0;
169   s.sz = 0;
170 }
171
172 void string::grow1()
173 {
174   ptr = srealloc(ptr, sz, len, len + 1, &sz);
175 }
176
177 string &string::operator+=(const char *p)
178 {
179   if (p != 0) {
180     int n = strlen(p);
181     int newlen = len + n;
182     if (newlen > sz)
183       ptr = srealloc(ptr, sz, len, newlen, &sz);
184     memcpy(ptr + len, p, n);
185     len = newlen;
186   }
187   return *this;
188 }
189
190 string &string::operator+=(const string &s)
191 {
192   if (s.len != 0) {
193     int newlen = len + s.len;
194     if (newlen > sz)
195       ptr = srealloc(ptr, sz, len, newlen, &sz);
196     memcpy(ptr + len, s.ptr, s.len);
197     len = newlen;
198   }
199   return *this;
200 }
201
202 void string::append(const char *p, int n)
203 {
204   if (n > 0) {
205     int newlen = len + n;
206     if (newlen > sz)
207       ptr = srealloc(ptr, sz, len, newlen, &sz);
208     memcpy(ptr + len, p, n);
209     len = newlen;
210   }
211 }
212
213 string::string(const char *s1, int n1, const char *s2, int n2)
214 {
215   assert(n1 >= 0 && n2 >= 0);
216   len = n1 + n2;
217   if (len == 0) {
218     sz = 0;
219     ptr = 0;
220   }
221   else {
222     ptr = salloc(len, &sz);
223     if (n1 == 0)
224       memcpy(ptr, s2, n2);
225     else {
226       memcpy(ptr, s1, n1);
227       if (n2 != 0)
228         memcpy(ptr + n1, s2, n2);
229     }
230   }
231 }
232
233 int operator<=(const string &s1, const string &s2)
234 {
235   return (s1.len <= s2.len
236           ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0
237           : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0);
238 }
239
240 int operator<(const string &s1, const string &s2)
241 {
242   return (s1.len < s2.len
243           ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0
244           : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0);
245 }
246
247 int operator>=(const string &s1, const string &s2)
248 {
249   return (s1.len >= s2.len
250           ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0
251           : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0);
252 }
253
254 int operator>(const string &s1, const string &s2)
255 {
256   return (s1.len > s2.len
257           ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0
258           : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0);
259 }
260
261 void string::set_length(int i)
262 {
263   assert(i >= 0);
264   if (i > sz)
265     ptr = srealloc(ptr, sz, len, i, &sz);
266   len = i;
267 }
268
269 void string::clear()
270 {
271   len = 0;
272 }
273
274 int string::search(char c) const
275 {
276   char *p = ptr ? (char *)memchr(ptr, c, len) : NULL;
277   return p ? p - ptr : -1;
278 }
279
280 // we silently strip nuls
281
282 char *string::extract() const
283 {
284   char *p = ptr;
285   int n = len;
286   int nnuls = 0;
287   int i;
288   for (i = 0; i < n; i++)
289     if (p[i] == '\0')
290       nnuls++;
291   char *q =(char*)malloc(n + 1 - nnuls);
292   char *r = q;
293   for (i = 0; i < n; i++)
294     if (p[i] != '\0')
295       *r++ = p[i];
296   *r = '\0';
297   return q;
298 }
299
300 void string::remove_spaces()
301 {
302   int l = len - 1;
303   while (l >= 0 && ptr[l] == ' ')
304     l--;
305   char *p = ptr;
306   if (l > 0)
307     while (*p == ' ') {
308       p++;
309       l--;
310     }
311   if (len - 1 != l) {
312     if (l >= 0) {
313       len = l + 1;
314       char *tmp = new char[sz];
315       memcpy(tmp, p, len);
316       a_delete ptr;
317       ptr = tmp;
318     }
319     else {
320       len = 0;
321       if (ptr) {
322         a_delete ptr;
323         ptr = 0;
324         sz = 0;
325       }
326     }
327   }
328 }
329
330 void put_string(const string &s, FILE *fp)
331 {
332   int len = s.length();
333   const char *ptr = s.contents();
334   for (int i = 0; i < len; i++)
335     putc(ptr[i], fp);
336 }
337
338 string as_string(int i)
339 {
340   static char buf[INT_DIGITS + 2];
341   sprintf(buf, "%d", i);
342   return string(buf);
343 }
344