1114402Sru// -*- C++ -*-
2114402Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
3114402Sru   Free Software Foundation, Inc.
4114402Sru     Written by James Clark (jjc@jclark.com)
5114402Sru
6114402SruThis file is part of groff.
7114402Sru
8114402Srugroff is free software; you can redistribute it and/or modify it under
9114402Sruthe terms of the GNU General Public License as published by the Free
10114402SruSoftware Foundation; either version 2, or (at your option) any later
11114402Sruversion.
12114402Sru
13114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
14114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
15114402SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16114402Srufor more details.
17114402Sru
18114402SruYou should have received a copy of the GNU General Public License along
19114402Sruwith groff; see the file COPYING.  If not, write to the Free Software
20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
21114402Sru
22114402Sru#include "lib.h"
23114402Sru
24114402Sru#include "stringclass.h"
25114402Sru
26114402Srustatic char *salloc(int len, int *sizep);
27114402Srustatic void sfree(char *ptr, int size);
28114402Srustatic char *sfree_alloc(char *ptr, int size, int len, int *sizep);
29114402Srustatic char *srealloc(char *ptr, int size, int oldlen, int newlen, int *sizep);
30114402Sru
31114402Srustatic char *salloc(int len, int *sizep)
32114402Sru{
33114402Sru  if (len == 0) {
34114402Sru    *sizep = 0;
35114402Sru    return 0;
36114402Sru  }
37114402Sru  else
38114402Sru    return new char[*sizep = len*2];
39114402Sru}
40114402Sru
41114402Srustatic void sfree(char *ptr, int)
42114402Sru{
43114402Sru  a_delete ptr;
44114402Sru}
45114402Sru
46114402Srustatic char *sfree_alloc(char *ptr, int oldsz, int len, int *sizep)
47114402Sru{
48114402Sru  if (oldsz >= len) {
49114402Sru    *sizep = oldsz;
50114402Sru    return ptr;
51114402Sru  }
52114402Sru  a_delete ptr;
53114402Sru  if (len == 0) {
54114402Sru    *sizep = 0;
55114402Sru    return 0;
56114402Sru  }
57114402Sru  else
58114402Sru    return new char[*sizep = len*2];
59114402Sru}
60114402Sru
61114402Srustatic char *srealloc(char *ptr, int oldsz, int oldlen, int newlen, int *sizep)
62114402Sru{
63114402Sru  if (oldsz >= newlen) {
64114402Sru    *sizep = oldsz;
65114402Sru    return ptr;
66114402Sru  }
67114402Sru  if (newlen == 0) {
68114402Sru    a_delete ptr;
69114402Sru    *sizep = 0;
70114402Sru    return 0;
71114402Sru  }
72114402Sru  else {
73114402Sru    char *p = new char[*sizep = newlen*2];
74114402Sru    if (oldlen < newlen && oldlen != 0)
75114402Sru      memcpy(p, ptr, oldlen);
76114402Sru    a_delete ptr;
77114402Sru    return p;
78114402Sru  }
79114402Sru}
80114402Sru
81114402Srustring::string() : ptr(0), len(0), sz(0)
82114402Sru{
83114402Sru}
84114402Sru
85114402Srustring::string(const char *p, int n) : len(n)
86114402Sru{
87114402Sru  assert(n >= 0);
88114402Sru  ptr = salloc(n, &sz);
89114402Sru  if (n != 0)
90114402Sru    memcpy(ptr, p, n);
91114402Sru}
92114402Sru
93114402Srustring::string(const char *p)
94114402Sru{
95114402Sru  if (p == 0) {
96114402Sru    len = 0;
97114402Sru    ptr = 0;
98114402Sru    sz = 0;
99114402Sru  }
100114402Sru  else {
101114402Sru    len = strlen(p);
102114402Sru    ptr = salloc(len, &sz);
103114402Sru    memcpy(ptr, p, len);
104114402Sru  }
105114402Sru}
106114402Sru
107114402Srustring::string(char c) : len(1)
108114402Sru{
109114402Sru  ptr = salloc(1, &sz);
110114402Sru  *ptr = c;
111114402Sru}
112114402Sru
113114402Srustring::string(const string &s) : len(s.len)
114114402Sru{
115114402Sru  ptr = salloc(len, &sz);
116114402Sru  if (len != 0)
117114402Sru    memcpy(ptr, s.ptr, len);
118114402Sru}
119114402Sru
120114402Srustring::~string()
121114402Sru{
122114402Sru  sfree(ptr, sz);
123114402Sru}
124114402Sru
125114402Srustring &string::operator=(const string &s)
126114402Sru{
127114402Sru  ptr = sfree_alloc(ptr, sz, s.len, &sz);
128114402Sru  len = s.len;
129114402Sru  if (len != 0)
130114402Sru    memcpy(ptr, s.ptr, len);
131114402Sru  return *this;
132114402Sru}
133114402Sru
134114402Srustring &string::operator=(const char *p)
135114402Sru{
136114402Sru  if (p == 0) {
137114402Sru    sfree(ptr, len);
138114402Sru    len = 0;
139114402Sru    ptr = 0;
140114402Sru    sz = 0;
141114402Sru  }
142114402Sru  else {
143114402Sru    int slen = strlen(p);
144114402Sru    ptr = sfree_alloc(ptr, sz, slen, &sz);
145114402Sru    len = slen;
146114402Sru    memcpy(ptr, p, len);
147114402Sru  }
148114402Sru  return *this;
149114402Sru}
150114402Sru
151114402Srustring &string::operator=(char c)
152114402Sru{
153114402Sru  ptr = sfree_alloc(ptr, sz, 1, &sz);
154114402Sru  len = 1;
155114402Sru  *ptr = c;
156114402Sru  return *this;
157114402Sru}
158114402Sru
159114402Sruvoid string::move(string &s)
160114402Sru{
161114402Sru  sfree(ptr, sz);
162114402Sru  ptr = s.ptr;
163114402Sru  len = s.len;
164114402Sru  sz = s.sz;
165114402Sru  s.ptr = 0;
166114402Sru  s.len = 0;
167114402Sru  s.sz = 0;
168114402Sru}
169114402Sru
170114402Sruvoid string::grow1()
171114402Sru{
172114402Sru  ptr = srealloc(ptr, sz, len, len + 1, &sz);
173114402Sru}
174114402Sru
175114402Srustring &string::operator+=(const char *p)
176114402Sru{
177114402Sru  if (p != 0) {
178114402Sru    int n = strlen(p);
179114402Sru    int newlen = len + n;
180114402Sru    if (newlen > sz)
181114402Sru      ptr = srealloc(ptr, sz, len, newlen, &sz);
182114402Sru    memcpy(ptr + len, p, n);
183114402Sru    len = newlen;
184114402Sru  }
185114402Sru  return *this;
186114402Sru}
187114402Sru
188114402Srustring &string::operator+=(const string &s)
189114402Sru{
190114402Sru  if (s.len != 0) {
191114402Sru    int newlen = len + s.len;
192114402Sru    if (newlen > sz)
193114402Sru      ptr = srealloc(ptr, sz, len, newlen, &sz);
194114402Sru    memcpy(ptr + len, s.ptr, s.len);
195114402Sru    len = newlen;
196114402Sru  }
197114402Sru  return *this;
198114402Sru}
199114402Sru
200114402Sruvoid string::append(const char *p, int n)
201114402Sru{
202114402Sru  if (n > 0) {
203114402Sru    int newlen = len + n;
204114402Sru    if (newlen > sz)
205114402Sru      ptr = srealloc(ptr, sz, len, newlen, &sz);
206114402Sru    memcpy(ptr + len, p, n);
207114402Sru    len = newlen;
208114402Sru  }
209114402Sru}
210114402Sru
211114402Srustring::string(const char *s1, int n1, const char *s2, int n2)
212114402Sru{
213114402Sru  assert(n1 >= 0 && n2 >= 0);
214114402Sru  len = n1 + n2;
215114402Sru  if (len == 0) {
216114402Sru    sz = 0;
217114402Sru    ptr = 0;
218114402Sru  }
219114402Sru  else {
220114402Sru    ptr = salloc(len, &sz);
221114402Sru    if (n1 == 0)
222114402Sru      memcpy(ptr, s2, n2);
223114402Sru    else {
224114402Sru      memcpy(ptr, s1, n1);
225114402Sru      if (n2 != 0)
226114402Sru	memcpy(ptr + n1, s2, n2);
227114402Sru    }
228114402Sru  }
229114402Sru}
230114402Sru
231114402Sruint operator<=(const string &s1, const string &s2)
232114402Sru{
233114402Sru  return (s1.len <= s2.len
234114402Sru	  ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0
235114402Sru	  : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0);
236114402Sru}
237114402Sru
238114402Sruint operator<(const string &s1, const string &s2)
239114402Sru{
240114402Sru  return (s1.len < s2.len
241114402Sru	  ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0
242114402Sru	  : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0);
243114402Sru}
244114402Sru
245114402Sruint operator>=(const string &s1, const string &s2)
246114402Sru{
247114402Sru  return (s1.len >= s2.len
248114402Sru	  ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0
249114402Sru	  : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0);
250114402Sru}
251114402Sru
252114402Sruint operator>(const string &s1, const string &s2)
253114402Sru{
254114402Sru  return (s1.len > s2.len
255114402Sru	  ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0
256114402Sru	  : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0);
257114402Sru}
258114402Sru
259114402Sruvoid string::set_length(int i)
260114402Sru{
261114402Sru  assert(i >= 0);
262114402Sru  if (i > sz)
263114402Sru    ptr = srealloc(ptr, sz, len, i, &sz);
264114402Sru  len = i;
265114402Sru}
266114402Sru
267114402Sruvoid string::clear()
268114402Sru{
269114402Sru  len = 0;
270114402Sru}
271114402Sru
272114402Sruint string::search(char c) const
273114402Sru{
274114402Sru  char *p = ptr ? (char *)memchr(ptr, c, len) : NULL;
275114402Sru  return p ? p - ptr : -1;
276114402Sru}
277114402Sru
278114402Sru// we silently strip nuls
279114402Sru
280114402Sruchar *string::extract() const
281114402Sru{
282114402Sru  char *p = ptr;
283114402Sru  int n = len;
284114402Sru  int nnuls = 0;
285114402Sru  int i;
286114402Sru  for (i = 0; i < n; i++)
287114402Sru    if (p[i] == '\0')
288114402Sru      nnuls++;
289114402Sru  char *q = new char[n + 1 - nnuls];
290114402Sru  char *r = q;
291114402Sru  for (i = 0; i < n; i++)
292114402Sru    if (p[i] != '\0')
293114402Sru      *r++ = p[i];
294114402Sru  *r = '\0';
295114402Sru  return q;
296114402Sru}
297114402Sru
298114402Sruvoid string::remove_spaces()
299114402Sru{
300114402Sru  int l = len - 1;
301114402Sru  while (l >= 0 && ptr[l] == ' ')
302114402Sru    l--;
303114402Sru  char *p = ptr;
304114402Sru  if (l > 0)
305114402Sru    while (*p == ' ') {
306114402Sru      p++;
307114402Sru      l--;
308114402Sru    }
309114402Sru  if (len - 1 != l) {
310114402Sru    if (l >= 0) {
311114402Sru      len = l + 1;
312114402Sru      char *tmp = new char[len];
313114402Sru      memcpy(tmp, p, len);
314114402Sru      a_delete ptr;
315114402Sru      ptr = tmp;
316114402Sru    }
317114402Sru    else {
318114402Sru      len = 0;
319114402Sru      if (ptr) {
320114402Sru	a_delete ptr;
321114402Sru	ptr = 0;
322114402Sru      }
323114402Sru    }
324114402Sru  }
325114402Sru}
326114402Sru
327114402Sruvoid put_string(const string &s, FILE *fp)
328114402Sru{
329114402Sru  int len = s.length();
330114402Sru  const char *ptr = s.contents();
331114402Sru  for (int i = 0; i < len; i++)
332114402Sru    putc(ptr[i], fp);
333114402Sru}
334114402Sru
335114402Srustring as_string(int i)
336114402Sru{
337114402Sru  static char buf[INT_DIGITS + 2];
338114402Sru  sprintf(buf, "%d", i);
339114402Sru  return string(buf);
340114402Sru}
341114402Sru
342