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
6This file is part of groff.
7
8groff is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13groff is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License along
19with groff; see the file COPYING.  If not, write to the Free Software
20Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
21
22#include "lib.h"
23
24#include "stringclass.h"
25
26static char *salloc(int len, int *sizep);
27static void sfree(char *ptr, int size);
28static char *sfree_alloc(char *ptr, int size, int len, int *sizep);
29static char *srealloc(char *ptr, int size, int oldlen, int newlen, int *sizep);
30
31static 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
41static void sfree(char *ptr, int)
42{
43  a_delete ptr;
44}
45
46static 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
61static 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
81string::string() : ptr(0), len(0), sz(0)
82{
83}
84
85string::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
93string::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
107string::string(char c) : len(1)
108{
109  ptr = salloc(1, &sz);
110  *ptr = c;
111}
112
113string::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
120string::~string()
121{
122  sfree(ptr, sz);
123}
124
125string &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
134string &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
151string &string::operator=(char c)
152{
153  ptr = sfree_alloc(ptr, sz, 1, &sz);
154  len = 1;
155  *ptr = c;
156  return *this;
157}
158
159void 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
170void string::grow1()
171{
172  ptr = srealloc(ptr, sz, len, len + 1, &sz);
173}
174
175string &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
188string &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
200void 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
211string::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
231int 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
238int 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
245int 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
252int 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
259void 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
267void string::clear()
268{
269  len = 0;
270}
271
272int 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
280char *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
298void 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
327void 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
335string as_string(int i)
336{
337  static char buf[INT_DIGITS + 2];
338  sprintf(buf, "%d", i);
339  return string(buf);
340}
341
342