1131087Smarcel/*	$NetBSD: string.cpp,v 1.1.1.1 2016/01/13 18:41:48 christos Exp $	*/
2131087Smarcel
3131087Smarcel// -*- C++ -*-
4138215Smarcel/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
5138215Smarcel   Free Software Foundation, Inc.
6138215Smarcel     Written by James Clark (jjc@jclark.com)
7138215Smarcel
8241193SfjoeThis file is part of groff.
9138215Smarcel
10183957Sobriengroff is free software; you can redistribute it and/or modify it under
11131087Smarcelthe terms of the GNU General Public License as published by the Free
12131087SmarcelSoftware Foundation; either version 2, or (at your option) any later
13131087Smarcelversion.
14131087Smarcel
15131087Smarcelgroff is distributed in the hope that it will be useful, but WITHOUT ANY
16131087SmarcelWARRANTY; without even the implied warranty of MERCHANTABILITY or
17131087SmarcelFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18131087Smarcelfor more details.
19131087Smarcel
20169713SkanYou should have received a copy of the GNU General Public License along
21183957Sobrienwith groff; see the file COPYING.  If not, write to the Free Software
22183957SobrienFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
23169713Skan
24169713Skan#include "lib.h"
25
26#include "stringclass.h"
27
28static char *salloc(int len, int *sizep);
29static void sfree(char *ptr, int size);
30static char *sfree_alloc(char *ptr, int size, int len, int *sizep);
31static char *srealloc(char *ptr, int size, int oldlen, int newlen, int *sizep);
32
33static char *salloc(int len, int *sizep)
34{
35  if (len == 0) {
36    *sizep = 0;
37    return 0;
38  }
39  else
40    return new char[*sizep = len*2];
41}
42
43static void sfree(char *ptr, int)
44{
45  a_delete ptr;
46}
47
48static char *sfree_alloc(char *ptr, int oldsz, int len, int *sizep)
49{
50  if (oldsz >= len) {
51    *sizep = oldsz;
52    return ptr;
53  }
54  a_delete ptr;
55  if (len == 0) {
56    *sizep = 0;
57    return 0;
58  }
59  else
60    return new char[*sizep = len*2];
61}
62
63static char *srealloc(char *ptr, int oldsz, int oldlen, int newlen, int *sizep)
64{
65  if (oldsz >= newlen) {
66    *sizep = oldsz;
67    return ptr;
68  }
69  if (newlen == 0) {
70    a_delete ptr;
71    *sizep = 0;
72    return 0;
73  }
74  else {
75    char *p = new char[*sizep = newlen*2];
76    if (oldlen < newlen && oldlen != 0)
77      memcpy(p, ptr, oldlen);
78    a_delete ptr;
79    return p;
80  }
81}
82
83string::string() : ptr(0), len(0), sz(0)
84{
85}
86
87string::string(const char *p, int n) : len(n)
88{
89  assert(n >= 0);
90  ptr = salloc(n, &sz);
91  if (n != 0)
92    memcpy(ptr, p, n);
93}
94
95string::string(const char *p)
96{
97  if (p == 0) {
98    len = 0;
99    ptr = 0;
100    sz = 0;
101  }
102  else {
103    len = strlen(p);
104    ptr = salloc(len, &sz);
105    memcpy(ptr, p, len);
106  }
107}
108
109string::string(char c) : len(1)
110{
111  ptr = salloc(1, &sz);
112  *ptr = c;
113}
114
115string::string(const string &s) : len(s.len)
116{
117  ptr = salloc(len, &sz);
118  if (len != 0)
119    memcpy(ptr, s.ptr, len);
120}
121
122string::~string()
123{
124  sfree(ptr, sz);
125}
126
127string &string::operator=(const string &s)
128{
129  ptr = sfree_alloc(ptr, sz, s.len, &sz);
130  len = s.len;
131  if (len != 0)
132    memcpy(ptr, s.ptr, len);
133  return *this;
134}
135
136string &string::operator=(const char *p)
137{
138  if (p == 0) {
139    sfree(ptr, len);
140    len = 0;
141    ptr = 0;
142    sz = 0;
143  }
144  else {
145    int slen = strlen(p);
146    ptr = sfree_alloc(ptr, sz, slen, &sz);
147    len = slen;
148    memcpy(ptr, p, len);
149  }
150  return *this;
151}
152
153string &string::operator=(char c)
154{
155  ptr = sfree_alloc(ptr, sz, 1, &sz);
156  len = 1;
157  *ptr = c;
158  return *this;
159}
160
161void 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
172void string::grow1()
173{
174  ptr = srealloc(ptr, sz, len, len + 1, &sz);
175}
176
177string &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
190string &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
202void 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
213string::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
233int 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
240int 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
247int 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
254int 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
261void 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
269void string::clear()
270{
271  len = 0;
272}
273
274int 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
282char *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 = new char[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
300void 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[len];
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      }
325    }
326  }
327}
328
329void put_string(const string &s, FILE *fp)
330{
331  int len = s.length();
332  const char *ptr = s.contents();
333  for (int i = 0; i < len; i++)
334    putc(ptr[i], fp);
335}
336
337string as_string(int i)
338{
339  static char buf[INT_DIGITS + 2];
340  sprintf(buf, "%d", i);
341  return string(buf);
342}
343
344