1251881Speter// -*- C++ -*- 2251881Speter/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002 3251881Speter Free Software Foundation, Inc. 4251881Speter Written by James Clark (jjc@jclark.com) 5251881Speter 6251881SpeterThis file is part of groff. 7251881Speter 8251881Spetergroff is free software; you can redistribute it and/or modify it under 9251881Speterthe terms of the GNU General Public License as published by the Free 10251881SpeterSoftware Foundation; either version 2, or (at your option) any later 11251881Speterversion. 12251881Speter 13251881Spetergroff is distributed in the hope that it will be useful, but WITHOUT ANY 14251881SpeterWARRANTY; without even the implied warranty of MERCHANTABILITY or 15251881SpeterFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16251881Speterfor more details. 17251881Speter 18251881SpeterYou should have received a copy of the GNU General Public License along 19251881Speterwith groff; see the file COPYING. If not, write to the Free Software 20251881SpeterFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 21251881Speter 22251881Speter#include "lib.h" 23251881Speter 24251881Speter#include "stringclass.h" 25251881Speter 26251881Speterstatic char *salloc(int len, int *sizep); 27251881Speterstatic void sfree(char *ptr, int size); 28251881Speterstatic char *sfree_alloc(char *ptr, int size, int len, int *sizep); 29251881Speterstatic char *srealloc(char *ptr, int size, int oldlen, int newlen, int *sizep); 30251881Speter 31251881Speterstatic char *salloc(int len, int *sizep) 32251881Speter{ 33251881Speter if (len == 0) { 34251881Speter *sizep = 0; 35251881Speter return 0; 36251881Speter } 37251881Speter else 38251881Speter return new char[*sizep = len*2]; 39251881Speter} 40251881Speter 41251881Speterstatic void sfree(char *ptr, int) 42251881Speter{ 43251881Speter a_delete ptr; 44251881Speter} 45251881Speter 46251881Speterstatic char *sfree_alloc(char *ptr, int oldsz, int len, int *sizep) 47251881Speter{ 48251881Speter if (oldsz >= len) { 49251881Speter *sizep = oldsz; 50251881Speter return ptr; 51251881Speter } 52251881Speter a_delete ptr; 53251881Speter if (len == 0) { 54251881Speter *sizep = 0; 55251881Speter return 0; 56251881Speter } 57251881Speter else 58251881Speter return new char[*sizep = len*2]; 59251881Speter} 60251881Speter 61251881Speterstatic char *srealloc(char *ptr, int oldsz, int oldlen, int newlen, int *sizep) 62251881Speter{ 63251881Speter if (oldsz >= newlen) { 64251881Speter *sizep = oldsz; 65251881Speter return ptr; 66251881Speter } 67251881Speter if (newlen == 0) { 68251881Speter a_delete ptr; 69251881Speter *sizep = 0; 70251881Speter return 0; 71251881Speter } 72251881Speter else { 73251881Speter char *p = new char[*sizep = newlen*2]; 74251881Speter if (oldlen < newlen && oldlen != 0) 75251881Speter memcpy(p, ptr, oldlen); 76251881Speter a_delete ptr; 77251881Speter return p; 78251881Speter } 79251881Speter} 80251881Speter 81251881Speterstring::string() : ptr(0), len(0), sz(0) 82251881Speter{ 83251881Speter} 84251881Speter 85251881Speterstring::string(const char *p, int n) : len(n) 86251881Speter{ 87251881Speter assert(n >= 0); 88251881Speter ptr = salloc(n, &sz); 89251881Speter if (n != 0) 90251881Speter memcpy(ptr, p, n); 91251881Speter} 92251881Speter 93251881Speterstring::string(const char *p) 94251881Speter{ 95251881Speter if (p == 0) { 96251881Speter len = 0; 97251881Speter ptr = 0; 98251881Speter sz = 0; 99251881Speter } 100251881Speter 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