source: cpp/frams/util/sstring.cpp @ 128

Last change on this file since 128 was 128, checked in by sz, 7 years ago

warning: deprecated conversion from string constant to char*

  • Property svn:eol-style set to native
File size: 7.5 KB
Line 
1// This file is a part of the Framsticks GDK.
2// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
3// Refer to http://www.framsticks.com/ for further information.
4
5#include "sstring.h"
6
7#ifdef SSTRING_SIMPLE
8
9// simple sstring implementation using direct character arrays
10// - duplicate = copy all characters
11// - no mutex needed
12
13#include "sstring-simple.cpp"
14
15#else
16///////////////////////////////////////////////////////////////////////////
17// old sstring implementation using SBuf references
18// - duplicate = copy buffer pointer
19// - mutex required to be thread safe
20
21#include <common/nonstd_stl.h>
22#include "extvalue.h"
23#include <assert.h>
24
25#ifdef MULTITHREADED
26#include <pthread.h>
27static pthread_mutex_t sstring_ref_lock=PTHREAD_MUTEX_INITIALIZER;
28#define REF_LOCK pthread_mutex_lock(&sstring_ref_lock);
29#define REF_UNLOCK pthread_mutex_unlock(&sstring_ref_lock)
30#else
31#define REF_LOCK
32#define REF_UNLOCK
33#endif
34
35static int guessMemSize(int request)
36{
37return request+min(request/2,10000)+8;
38}
39
40SBuf::SBuf()
41{
42txt=(char*)"";
43size=used=0;
44refcount=1;
45}
46
47SBuf::SBuf(int initsize)
48{
49size=guessMemSize(initsize);
50if (size>0)     { txt=(char*)malloc(size+1); txt[0]=0; }
51        else    txt=(char*)"";
52used=0;
53refcount=1;
54}
55
56SBuf::~SBuf()
57{
58freeBuf();
59}
60
61void SBuf::initEmpty()
62{
63txt=(char*)"";
64used=size=0;
65refcount=1;
66}
67
68void SBuf::freeBuf()
69{
70if (!size) return;
71free(txt); used=0;
72}
73
74void SBuf::copyFrom(const char *ch,int chlen)
75{
76if (chlen==-1) chlen=strlen(ch);
77if (chlen>0)
78{
79if (chlen<size)
80        {
81        memcpy(txt,ch,chlen);
82        }
83else
84        {
85        size=guessMemSize(chlen);
86        char *newtxt=(char*)malloc(size+1);
87        memcpy(newtxt,ch,chlen);
88        free(txt);
89        txt=newtxt;
90        }
91}
92txt[chlen]=0;
93used=chlen;
94}
95
96void SBuf::append(const char *ch,int chlen)
97{ // doesn't check anything!
98memcpy(txt+used,ch,chlen);
99used+=chlen;
100txt[used]=0;
101}
102
103void SBuf::ensureSize(int needed)
104{
105if (size>=needed) return;
106needed=guessMemSize(needed);
107txt=(char*)realloc(txt,needed+1);
108size=needed;
109}
110
111/////////////////////////////////////////////
112
113SString::SString()
114{
115initEmpty();
116}
117
118SString::~SString()
119{
120REF_LOCK;
121detach();
122REF_UNLOCK;
123}
124
125SString::SString(int x)
126{
127buf=new SBuf(x);
128}
129
130SString::SString(const char *t,int t_len)
131{
132initEmpty();
133if (!t) return;
134copyFrom(t,t_len);
135}
136
137SString::SString(const SString &from)
138{
139if (from.buf==&SBuf::empty())
140        buf=&SBuf::empty();
141else
142        {
143        REF_LOCK;
144        buf=from.buf;
145        if (buf->size)
146                buf->refcount++;
147        REF_UNLOCK;
148        }
149}
150
151void SString::initEmpty()
152{
153buf=&SBuf::empty();
154}
155
156void SString::memoryHint(int howbig)
157{
158detachCopy(howbig);
159}
160       
161void SString::detachEmpty(int ensuresize)
162{
163if (buf==&SBuf::empty()) { buf=new SBuf(ensuresize); return; }
164if (buf->refcount<2) buf->ensureSize(ensuresize);
165else
166        {
167        buf->refcount--;
168        buf=new SBuf(ensuresize);
169        }
170}
171
172void SString::detach()
173{
174if (buf==&SBuf::empty()) return;
175if (!--buf->refcount) delete buf;
176}
177
178void SString::detachCopy(int ensuresize)
179{
180if (buf==&SBuf::empty()) { buf=new SBuf(ensuresize); return; }
181if (buf->refcount<2)
182        {
183        buf->ensureSize(ensuresize);
184        return;
185        }
186buf->refcount--;
187SBuf *newbuf=new SBuf(ensuresize);
188newbuf->copyFrom(buf->txt,min(ensuresize,buf->used));
189buf=newbuf;
190}
191
192char *SString::directWrite(int ensuresize)
193{
194if (ensuresize<0) ensuresize=len();
195REF_LOCK;
196detachCopy(ensuresize);
197REF_UNLOCK;
198appending=buf->used;
199return buf->txt;
200}
201
202/*
203char *SString::directWrite()
204{
205return directWrite(buf->used);
206}
207*/
208char *SString::directAppend(int maxappend)
209{
210REF_LOCK;
211detachCopy(buf->used+maxappend);
212REF_UNLOCK;
213appending=buf->used;
214return buf->txt+appending;
215}
216
217void SString::endWrite(int newlength)
218{
219if (newlength<0) newlength=strlen(buf->txt);
220else buf->txt[newlength]=0;
221buf->used=newlength;
222}
223
224void SString::endAppend(int newappend)
225{
226if (newappend<0) newappend=strlen(buf->txt+appending);
227else buf->txt[appending+newappend]=0;
228buf->used=appending+newappend;
229}
230
231////////////// append /////////////////
232
233void SString::operator+=(const char *s)
234{
235if (!s) return;
236int x=strlen(s);
237if (!x) return;
238append(s,x);
239}
240
241void SString::append(const char *txt,int count)
242{
243if (!count) return;
244REF_LOCK;
245detachCopy(buf->used+count);
246REF_UNLOCK;
247buf->append(txt,count);
248}
249
250void SString::operator+=(const SString&s)
251{
252append((const char*)s,s.len());
253}
254
255SString SString::operator+(const SString& s) const
256{
257SString ret(*this);
258ret+=s;
259return ret;
260}
261
262/////////////////////////////
263
264void SString::copyFrom(const char *ch,int chlen)
265{
266if (!ch) chlen=0;
267else if (chlen<0) chlen=strlen(ch);
268REF_LOCK;
269detachEmpty(chlen);
270REF_UNLOCK;
271memcpy(buf->txt,ch,chlen);
272buf->txt[chlen]=0; buf->used=chlen;
273}
274
275void SString::operator=(const char *ch)
276{
277copyFrom(ch);
278}
279
280void SString::operator=(const SString&s)
281{
282if (s.buf==buf) return;
283REF_LOCK;
284detach();
285buf=s.buf;
286if (buf->size) buf->refcount++;
287REF_UNLOCK;
288}
289///////////////////////////////////////
290
291SString SString::substr(int begin, int length) const
292{
293if (begin<0) { length+=begin; begin=0; }
294if (length>=(len()-begin)) length=len()-begin;
295if (length<=0) return SString();
296if (length==len()) return *this;
297return SString((*this)(begin),length);
298}
299
300///////////////////////////////////////
301
302int SString::equals(const SString& s) const
303{
304if (s.buf==buf) return 1;
305return !strcmp(buf->txt,s.buf->txt);
306}
307
308///////////////////////////////////////
309
310int SString::indexOf(int character,int start) const
311{
312const char *found=strchr(buf->txt+start,character);
313return found?found-buf->txt:-1;
314}
315
316int SString::indexOf(const char *substring,int start) const
317{
318char *found=strstr(buf->txt+start,substring);
319return found?found-buf->txt:-1;
320}
321
322int SString::indexOf(const SString & substring,int start) const
323{
324char *found=strstr(buf->txt+start,((const char*)substring));
325return found?found-buf->txt:-1;
326}
327
328int SString::getNextToken (int& pos,SString &token,char separator) const
329{
330if (pos>=len()) {token=0;return 0;}
331int p1=pos,p2;
332const char *t1=buf->txt+pos;
333const char *t2=strchr(t1,separator);
334if (t2) pos=(p2=(t2-buf->txt))+1; else p2=pos=len();
335strncpy(token.directWrite(p2-p1),t1,p2-p1);
336token.endWrite(p2-p1);
337return 1;
338}
339
340int SString::startsWith(const char *pattern) const
341{
342const char *t=(const char*)(*this);
343for (;*pattern;pattern++,t++)
344        if (*t != *pattern) return 0;
345return 1;
346}
347
348SString SString::valueOf(int i)
349{
350return SString::sprintf("%d",i);
351}
352SString SString::valueOf(long i)
353{
354return SString::sprintf("%d",i);
355}
356SString SString::valueOf(double d)
357{
358SString tmp=SString::sprintf("%.15g",d);
359if ((!strchr(tmp,'.'))&&(!strchr(tmp,'e'))) tmp+=".0";
360return tmp;
361}
362SString SString::valueOf(const SString& s)
363{
364return s;
365}
366
367#ifdef LINUX
368#define VSNPRINTF_RETURNS_REQUIRED_SIZE
369#endif
370#if defined _WIN32 && !defined __BORLANDC__
371#define USE_VSCPRINTF
372#endif
373
374
375#if 0 //testing _vscprintf
376#define USE_VSCPRINTF
377int _vscprintf(const char *format,va_list argptr)
378{
379return vsnprintf("",0,format,argptr);
380}
381#endif
382
383SString SString::sprintf(const char* format, ...)
384{
385int n, size = 30;
386va_list ap;
387
388SString ret;
389
390#ifdef USE_VSCPRINTF
391va_start(ap, format);
392size=_vscprintf(format, ap);
393va_end(ap);
394#endif
395
396while (1)
397        {
398        char* p=ret.directWrite(size);
399        assert(p!=NULL);
400        size=ret.directMaxLen()+1;
401        /* Try to print in the allocated space. */
402        va_start(ap, format);
403        n = vsnprintf(p, size, format, ap);
404        va_end(ap);
405        /* If that worked, return the string. */
406        if (n > -1 && n < size)
407                {
408                ret.endWrite(n);
409                return ret;
410                }
411        /* Else try again with more space. */
412#ifdef VSNPRINTF_RETURNS_REQUIRED_SIZE
413        if (n > -1)    /* glibc 2.1 */
414                size = n; /* precisely what is needed */
415        else           /* glibc 2.0 */
416#endif
417                size *= 2;  /* twice the old size */
418        }
419}
420
421SString &SString::empty()
422{
423static SString empty;
424return empty;
425}
426
427SBuf &SBuf::empty()
428{
429static SBuf empty;
430return empty;
431}
432
433#endif //#ifdef SSTRING_SIMPLE
Note: See TracBrowser for help on using the repository browser.