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