1 /*
2  *
3  *  C++ Portable Types Library (PTypes)
4  *  Version 2.1.1  Released 27-Jun-2007
5  *
6  *  Copyright (C) 2001-2007 Hovik Melikyan
7  *
8  *  http://www.melikyan.com/ptypes/
9  *
10  */
11 
12 #include <stdlib.h>
13 #include <string.h>
14 #include <time.h>
15 
16 #include "ptypes.h"
17 #include "ptime.h"      // nowstring() is defined in this module
18 
19 
20 PTYPES_BEGIN
21 
22 
23 const int strrecsize = sizeof(_strrec);
24 
25 
stringoverflow()26 static void stringoverflow()
27 {
28     fatal(CRIT_FIRST + 21, "String overflow");
29 }
30 
31 
idxerror()32 void string::idxerror()
33 {
34     fatal(CRIT_FIRST + 20, "String index overflow");
35 }
36 
37 
38 int stralloc;
39 
40 char   emptystrbuf[strrecsize + 4];
41 char*  emptystr = emptystrbuf + strrecsize;
42 
43 
44 string nullstring;
45 
46 
quantize(int numchars)47 inline int quantize(int numchars)
48 {
49 	return memquantize(numchars + 1 + strrecsize);
50 }
51 
52 
_alloc(int numchars)53 void string::_alloc(int numchars)
54 {
55     if (numchars <= 0)
56         stringoverflow();
57     size_t a = quantize(numchars);
58 #ifdef DEBUG
59     stralloc += a;
60 #endif
61     data = (char*)(memalloc(a)) + strrecsize;
62     STR_LENGTH(data) = numchars;
63     STR_REFCOUNT(data) = 1;
64     data[numchars] = 0;
65 }
66 
67 
_realloc(int numchars)68 void string::_realloc(int numchars)
69 {
70     if (numchars <= 0 || STR_LENGTH(data) <= 0)
71         stringoverflow();
72     int a = quantize(numchars);
73     int b = quantize(STR_LENGTH(data));
74     if (a != b)
75     {
76 #ifdef DEBUG
77         stralloc += a - b;
78 #endif
79         data = (char*)(memrealloc(data - strrecsize, a)) + strrecsize;
80     }
81     STR_LENGTH(data) = numchars;
82     data[numchars] = 0;
83 }
84 
85 
_freestrbuf(char * data)86 inline void _freestrbuf(char* data)
87 {
88 #ifdef DEBUG
89     stralloc -= quantize(STR_LENGTH(data));
90 #endif
91     memfree((char*)(STR_BASE(data)));
92 }
93 
94 
_free()95 void string::_free()
96 {
97     _freestrbuf(data);
98     data = emptystr;
99 }
100 
101 
initialize(const char * sc,int initlen)102 void string::initialize(const char* sc, int initlen)
103 {
104     if (initlen <= 0 || sc == nil)
105         data = emptystr;
106     else
107     {
108         _alloc(initlen);
109         memmove(data, sc, initlen);
110     }
111 }
112 
113 
initialize(const char * sc)114 void string::initialize(const char* sc)
115 {
116     initialize(sc, hstrlen(sc));
117 }
118 
119 
initialize(char c)120 void string::initialize(char c)
121 {
122     _alloc(1);
123     data[0] = c;
124 }
125 
126 
initialize(const string & s)127 void string::initialize(const string& s)
128 {
129     data = s.data;
130 #ifdef PTYPES_ST
131     STR_REFCOUNT(data)++;
132 #else
133     pincrement(&STR_REFCOUNT(data));
134 #endif
135 }
136 
137 
finalize()138 void string::finalize()
139 {
140     if (STR_LENGTH(data) != 0)
141     {
142 
143 #ifdef PTYPES_ST
144         if (--STR_REFCOUNT(data) == 0)
145 #else
146         if (pdecrement(&STR_REFCOUNT(data)) == 0)
147 #endif
148             _freestrbuf(data);
149 
150         data = emptystr;
151     }
152 }
153 
154 
unique(string & s)155 char* ptdecl unique(string& s)
156 {
157     if (STR_LENGTH(s.data) > 0 && STR_REFCOUNT(s.data) > 1)
158     {
159         char* odata = s.data;
160         s._alloc(STR_LENGTH(s.data));
161         memcpy(s.data, odata, STR_LENGTH(s.data));
162 #ifdef PTYPES_ST
163         STR_REFCOUNT(odata)--;
164 #else
165         if (pdecrement(&STR_REFCOUNT(odata)) == 0)
166             _freestrbuf(odata);
167 #endif
168     }
169     return s.data;
170 }
171 
172 
setlength(string & s,int newlen)173 char* ptdecl setlength(string& s, int newlen)
174 {
175     if (newlen < 0)
176         return nil;
177 
178     int curlen = STR_LENGTH(s.data);
179 
180     // if becoming empty
181     if (newlen == 0)
182         s.finalize();
183 
184     // if otherwise s was empty before
185     else if (curlen == 0)
186         s._alloc(newlen);
187 
188     // if length is not changing, return a unique string
189     else if (newlen == curlen)
190         unique(s);
191 
192     // non-unique reallocation
193     else if (STR_REFCOUNT(s.data) > 1)
194     {
195         char* odata = s.data;
196         s._alloc(newlen);
197         memcpy(s.data, odata, imin(curlen, newlen));
198 #ifdef PTYPES_ST
199         STR_REFCOUNT(odata)--;
200 #else
201         if (pdecrement(&STR_REFCOUNT(odata)) == 0)
202             _freestrbuf(odata);
203 #endif
204     }
205 
206     // unique reallocation
207     else
208         s._realloc(newlen);
209 
210     return s.data;
211 }
212 
213 
assign(const char * sc,int initlen)214 void string::assign(const char* sc, int initlen)
215 {
216     if (STR_LENGTH(data) > 0 && initlen > 0 && STR_REFCOUNT(data) == 1)
217     {
218         // reuse data buffer if unique
219         _realloc(initlen);
220         memmove(data, sc, initlen);
221     }
222     else
223     {
224         finalize();
225         if (initlen == 1)
226             initialize(sc[0]);
227         else if (initlen > 1)
228             initialize(sc, initlen);
229     }
230 }
231 
232 
assign(const char * sc)233 void string::assign(const char* sc)
234 {
235     assign(sc, hstrlen(sc));
236 }
237 
238 
assign(char c)239 void string::assign(char c)
240 {
241     assign(&c, 1);
242 }
243 
244 
assign(const string & s)245 void string::assign(const string& s)
246 {
247     if (data != s.data)
248     {
249         finalize();
250         initialize(s);
251     }
252 }
253 
254 
dup(const string & s)255 string ptdecl dup(const string& s)
256 {
257     // dup() only reads the data pointer so it is thread-safe
258     return string(s.data);
259 }
260 
261 
nowstring(const char * fmt,bool utc)262 string ptdecl nowstring(const char* fmt, bool utc)
263 {
264     char buf[128];
265     time_t longtime;
266     time(&longtime);
267 
268 #if defined(PTYPES_ST) || defined(WIN32)
269     tm* t;
270     if (utc)
271         t = gmtime(&longtime);
272     else
273         t = localtime(&longtime);
274     int r = strftime(buf, sizeof(buf), fmt, t);
275 #else
276     tm t;
277     if (utc)
278         gmtime_r(&longtime, &t);
279     else
280         localtime_r(&longtime, &t);
281     int r = strftime(buf, sizeof(buf), fmt, &t);
282 #endif
283 
284     buf[r] = 0;
285     return string(buf);
286 }
287 
288 
289 PTYPES_END
290