Mercurial > ~dholland > hg > ag > index.cgi
comparison anagram/support/agstring.cpp @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children | 57b2cc9b87f7 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:13d2b8934445 |
---|---|
1 /********************************************************** | |
2 | |
3 The AnaGram Class Library | |
4 | |
5 The AgString Class | |
6 Copyright 1997-2002 Parsifal Software. All Rights Reserved. | |
7 See the file COPYING for license and usage terms. | |
8 | |
9 ***********************************************************/ | |
10 | |
11 #include <stdarg.h> | |
12 #include <stdio.h> | |
13 #include <stdlib.h> | |
14 #include "port.h" | |
15 | |
16 #include "agstring.h" | |
17 #include "assert.h" | |
18 #include "csexp.h" // sigh... XXX (for agToUpper) | |
19 | |
20 //#define INCLUDE_LOGGING | |
21 #include "log.h" | |
22 | |
23 | |
24 void AgString::allocate(unsigned n) { | |
25 // XXX shouldn't this be just n+sizeof(short)? There's no need to round | |
26 // up, and this isn't a correct roundup anyway... | |
27 // (and what if malloc returns NULL?) | |
28 store = (char *) malloc(((n+sizeof(short))/sizeof(short) + 1)*sizeof(short)) | |
29 + sizeof(short); | |
30 } | |
31 | |
32 void AgString::lock() { | |
33 if (store) { | |
34 (((short *) (void *)store)[-1])++; | |
35 } | |
36 } | |
37 | |
38 void AgString::unlock() { | |
39 if (store && --(((short *) (void *) store)[-1]) <= 0) { | |
40 //delete [] (store - sizeof(short)); | |
41 free(store - sizeof(short)); | |
42 } | |
43 store = 0; | |
44 } | |
45 | |
46 AgString::AgString(const char *s) | |
47 : AgIndexedContainer<char>() | |
48 { | |
49 LOGSECTION("AgString::AgString(const char *)"); | |
50 LOGV(s); | |
51 if (s) { | |
52 allocate(strlen(s)); | |
53 assert(store != 0); | |
54 ((short *) (void *)store)[-1] = 1; | |
55 strcpy(store, s); | |
56 LOGV(store); | |
57 } | |
58 else store = 0; | |
59 } | |
60 | |
61 AgString::AgString(const unsigned n) | |
62 { | |
63 if (n) { | |
64 allocate(n); | |
65 assert(store != 0); | |
66 ((short *) (void *)store)[-1] = 1; | |
67 memset(store, 0, n+1); | |
68 } | |
69 else { | |
70 store = 0; | |
71 } | |
72 } | |
73 | |
74 AgString::AgString(const char *s, const unsigned n) | |
75 { | |
76 if (n) { | |
77 allocate(n); | |
78 unsigned k = strlen(s); | |
79 if (n < k) { | |
80 k = n; | |
81 } | |
82 assert(store != 0); | |
83 ((short *)(void *) store)[-1] = 1; | |
84 if (s) { | |
85 strncpy(store, s, k); | |
86 } | |
87 store[k] = 0; | |
88 } | |
89 else { | |
90 store = 0; | |
91 } | |
92 } | |
93 | |
94 AgString::AgString(const AgString &s, const unsigned n) | |
95 { | |
96 if (n) { | |
97 allocate(n); | |
98 assert(store != 0); | |
99 ((short *)(void *) store)[-1] = 1; | |
100 if (s.store) { | |
101 strncpy(store, s.store, n); | |
102 } | |
103 store[n] = 0; | |
104 } | |
105 else { | |
106 store = 0; | |
107 } | |
108 } | |
109 | |
110 char &AgString::operator [] (const unsigned x) { | |
111 assert(x < size()); | |
112 return store[x]; | |
113 } | |
114 | |
115 const char &AgString::operator [] (const unsigned x) const { | |
116 assert(x < size()); | |
117 return store[x]; | |
118 } | |
119 | |
120 AgString &AgString::operator = (const AgString &s) { | |
121 unlock(); | |
122 store = s.store; | |
123 lock(); | |
124 return *this; | |
125 } | |
126 | |
127 AgString &AgString::toUpper() { | |
128 if (store) { | |
129 char *s = store; | |
130 while (*s) { | |
131 *s = (char) agToUpper(*s); | |
132 s++; | |
133 } | |
134 } | |
135 return *this; | |
136 } | |
137 | |
138 /* | |
139 AgString &AgString::toLower() { | |
140 if (store) { | |
141 char *s = store; | |
142 while (*s) { | |
143 *s = (char) tolower(*s); | |
144 s++; | |
145 } | |
146 } | |
147 return *this; | |
148 } | |
149 */ | |
150 | |
151 int AgString::operator < (const AgString &s) const { | |
152 //LOGSECTION("AgString::operator <"); | |
153 if (store == s.store) { | |
154 return 0; | |
155 } | |
156 else if (store && s.store) { | |
157 //LOGV(store) LCV(s.store); | |
158 return strcmp(store, s.store) < 0; | |
159 } | |
160 else { | |
161 return store == 0; | |
162 } | |
163 } | |
164 | |
165 int AgString::operator < (const char *s) const { | |
166 if (store == s) { | |
167 return 0; | |
168 } | |
169 else if (store && s) { | |
170 return strcmp(store, s) < 0; | |
171 } | |
172 else { | |
173 return store == 0; | |
174 } | |
175 } | |
176 | |
177 int AgString::operator <= (const AgString &s) const { | |
178 if (store == s.store) { | |
179 return 1; | |
180 } | |
181 else if (store && s.store) { | |
182 return strcmp(store, s.store) <= 0; | |
183 } | |
184 else { | |
185 return store == 0; | |
186 } | |
187 } | |
188 | |
189 int AgString::operator <= (const char *s) const { | |
190 if (store == s) { | |
191 return 1; | |
192 } | |
193 else if (store && s) { | |
194 return strcmp(store, s) <= 0; | |
195 } | |
196 else { | |
197 return store == 0; | |
198 } | |
199 } | |
200 | |
201 int AgString::operator > (const AgString &s) const { | |
202 if (store == s.store) { | |
203 return 0; | |
204 } | |
205 else if (store && s.store) { | |
206 return strcmp(store, s.store) > 0; | |
207 } | |
208 else { | |
209 return s.store == 0; | |
210 } | |
211 } | |
212 | |
213 int AgString::operator > (const char *s) const { | |
214 if (store == s) { | |
215 return 0; | |
216 } | |
217 else if (store && s) { | |
218 return strcmp(store, s) > 0; | |
219 } | |
220 else { | |
221 return s == 0; | |
222 } | |
223 } | |
224 | |
225 int AgString::operator >= (const AgString &s) const { | |
226 if (store == s.store) { | |
227 return 1; | |
228 } | |
229 else if (store && s.store) { | |
230 return strcmp(store, s.store) >= 0; | |
231 } | |
232 else { | |
233 return s.store == 0; | |
234 } | |
235 } | |
236 | |
237 int AgString::operator >= (const char *s) const { | |
238 if (store == s) { | |
239 return 1; | |
240 } | |
241 else if (store && s) { | |
242 return strcmp(store, s) >= 0; | |
243 } | |
244 else { | |
245 return s == 0; | |
246 } | |
247 } | |
248 | |
249 int AgString::iEq(const AgString &s) const { | |
250 if (store == s.store) { | |
251 return 1; | |
252 } | |
253 if (store && s.store) { | |
254 return stricmp(store, s.store) == 0; | |
255 } | |
256 else { | |
257 return 0; | |
258 } | |
259 } | |
260 | |
261 int AgString::iEq(const char *s) const { | |
262 if (store == s) { | |
263 return 1; | |
264 } | |
265 if (store && s) { | |
266 return stricmp(store, s) == 0; | |
267 } | |
268 else { | |
269 return 0; | |
270 } | |
271 } | |
272 | |
273 int AgString::operator == (const AgString &s) const { | |
274 if (store == s.store) { | |
275 return 1; | |
276 } | |
277 if (store && s.store) { | |
278 return strcmp(store, s.store) == 0; | |
279 } | |
280 else { | |
281 return 0; | |
282 } | |
283 } | |
284 | |
285 int AgString::operator == (const char *s) const { | |
286 if (store == s) { | |
287 return 1; | |
288 } | |
289 if (store && s) { | |
290 return strcmp(store, s) == 0; | |
291 } | |
292 else { | |
293 return 0; | |
294 } | |
295 } | |
296 | |
297 int AgString::operator != (const AgString &s) const { | |
298 if (store == s.store) { | |
299 return 0; | |
300 } | |
301 if (store && s.store) { | |
302 return strcmp(store, s.store) != 0; | |
303 } | |
304 else { | |
305 return 1; | |
306 } | |
307 } | |
308 | |
309 int AgString::operator != (const char *s) const { | |
310 if (store == s) { | |
311 return 0; | |
312 } | |
313 if (store && s) { | |
314 return strcmp(store, s) != 0; | |
315 } | |
316 else { | |
317 return 1; | |
318 } | |
319 } | |
320 | |
321 AgString AgString::format(const char *fs, ...) { | |
322 va_list ap; | |
323 int n; | |
324 | |
325 if (fs == NULL) { | |
326 return AgString(); | |
327 } | |
328 //int bufLength = 3*strlen(fs); | |
329 //if (bufLength < 2000) bufLength = 2000; | |
330 //char *buf = new char[bufLength]; | |
331 char buf[2000]; | |
332 | |
333 //assert(buf != NULL); | |
334 | |
335 va_start(ap, fs); | |
336 n = vsprintf(buf, fs, ap); | |
337 assert(n < 2000); | |
338 va_end(ap); | |
339 | |
340 AgString result(buf, n); | |
341 //delete [] buf; | |
342 return result; | |
343 } | |
344 | |
345 | |
346 // concatenation operators | |
347 | |
348 AgString AgString::concat(const char *s) const { | |
349 LOGSECTION("AgString::concat"); | |
350 LOGV(store) LCV(s); | |
351 if (s == NULL) { | |
352 return *this; | |
353 } | |
354 if (store == NULL) { | |
355 return AgString(s); | |
356 } | |
357 AgString result(store, size() + strlen(s)); | |
358 LOGV(result); | |
359 strcat(result.pointer(), s); | |
360 LOGV(result); | |
361 return result; | |
362 } | |
363 | |
364 AgString AgString::concat(const AgString s) const { | |
365 if (s.store == NULL) { | |
366 return *this; | |
367 } | |
368 if (store == NULL) { | |
369 return s; | |
370 } | |
371 AgString result(store, size() + s.size()); | |
372 strcat(result.pointer(), s.pointer()); | |
373 return result; | |
374 } | |
375 | |
376 AgString::Cut AgString::firstCut(const char c) const { | |
377 LOGSECTION("AgString::firstCut(char)"); | |
378 if (store) { | |
379 char *p = strchr(store, c); | |
380 LOGV(p) LCV(c); | |
381 /* | |
382 int n = p ? (int)( p - store) : -1; | |
383 return AgString::Cut(*this, n); | |
384 */ | |
385 if (p) { | |
386 return AgString::Cut(*this, p - store); | |
387 } | |
388 } | |
389 return AgString::Cut(); | |
390 } | |
391 | |
392 AgString::Cut AgString::lastCut(const char c) const { | |
393 //LOGSECTION("lastCut"); | |
394 if (store) { | |
395 char *p = strrchr(store, c); | |
396 //LOGV(store); | |
397 //LOGV(c); | |
398 //LOGV(p); | |
399 int n = p ? (int) (p - store) : strlen(store); | |
400 return AgString::Cut(*this, n); | |
401 } | |
402 return AgString::Cut(); | |
403 } | |
404 | |
405 AgString::Cut AgString::firstCut(const char *s) const { | |
406 LOGSECTION("firstCut(const char *)"); | |
407 if (store) { | |
408 unsigned k = strcspn(store, s); | |
409 LOGV(store); | |
410 LOGV(s); | |
411 LOGV(k); | |
412 if (k < size()) { | |
413 return AgString::Cut(*this, k); | |
414 } | |
415 } | |
416 return AgString::Cut(); | |
417 } | |
418 | |
419 AgString::Cut AgString::lastCut(const char *s) const { | |
420 //LOGSECTION("lastCut"); | |
421 if (store) { | |
422 int k = size(); | |
423 while (k--) { | |
424 if (strchr(s, store[k])) { | |
425 //LOGV(store); | |
426 //LOGV(&store[k]); | |
427 //LOGV(k); | |
428 return AgString::Cut(*this, k); | |
429 } | |
430 } | |
431 return AgString::Cut(*this, size()); | |
432 } | |
433 return AgString::Cut(); | |
434 } | |
435 | |
436 AgString::Cut::Cut(const AgString &s, const int x) | |
437 : store(s.pointer()) | |
438 , index(x) | |
439 { | |
440 if (store) { | |
441 assert((unsigned) x <= strlen(store)); | |
442 } | |
443 lock(); | |
444 } | |
445 | |
446 void AgString::Cut::lock() { | |
447 if (store) { | |
448 (((short *) (void *)store)[-1])++; | |
449 } | |
450 } | |
451 | |
452 void AgString::Cut::unlock() { | |
453 if (store && --(((short *) (void *) store)[-1]) <= 0) { | |
454 //delete [] (store - sizeof(short)); | |
455 free(store - sizeof(short)); | |
456 store = 0; | |
457 } | |
458 } | |
459 | |
460 char &AgString::Cut::character() const { | |
461 assert(store != 0); | |
462 return store[index]; | |
463 } | |
464 | |
465 AgString AgString::Cut::leftI() const { | |
466 //LOGSECTION("Cut::leftI"); | |
467 //LOGV(store); | |
468 //LOGV(index); | |
469 if (store == 0 || index < 0) { | |
470 return AgString(); | |
471 } | |
472 /* Include the separator... but not if it's the null terminator. */ | |
473 int pos = index; | |
474 if (store[pos]) { | |
475 pos++; | |
476 } | |
477 return AgString(store, pos); | |
478 } | |
479 | |
480 AgString AgString::Cut::leftX() const { | |
481 LOGSECTION("Cut::leftX"); | |
482 LOGV(store); | |
483 LOGV(index); | |
484 if (store == 0 || index <= 0) { | |
485 return AgString(); | |
486 } | |
487 /* Does this end up with the wrong length if store[index]==0? XXX */ | |
488 return AgString(store, index); | |
489 } | |
490 | |
491 AgString AgString::Cut::rightI() const { | |
492 //LOGSECTION("Cut::rightI"); | |
493 //LOGV(store); | |
494 //LOGV(index); | |
495 if (store == 0) { | |
496 return AgString(); | |
497 } | |
498 if (index < 0) { | |
499 return AgString(store); | |
500 } | |
501 return AgString(store + index); | |
502 } | |
503 | |
504 AgString AgString::Cut::rightX() const { | |
505 //LOGSECTION("Cut::rightX"); | |
506 //LOGV(store); | |
507 //LOGV(index); | |
508 if (store == 0) { | |
509 return AgString(); | |
510 } | |
511 /* Exclude the separator... but not if it's the null terminator. */ | |
512 int pos = index; | |
513 if (store[pos]) { | |
514 pos++; | |
515 } | |
516 return AgString(store + pos); | |
517 } | |
518 | |
519 /* | |
520 AgString AgString::Cut::insertLeft(const AgString &s) const { | |
521 AgString newString(store, strlen(store) + s.size()); | |
522 char *p = newString.pointer(); | |
523 p[index] = 0; | |
524 strcat(p, s.pointer()); | |
525 strcat(p, store+index); | |
526 return newString; | |
527 } | |
528 | |
529 AgString AgString::Cut::insertLeft(const char *s) const { | |
530 AgString newString(store, strlen(store) + strlen(s)); | |
531 char *p = newString.pointer(); | |
532 p[index] = 0; | |
533 strcat(p, s); | |
534 strcat(p, store+index); | |
535 return newString; | |
536 } | |
537 | |
538 AgString AgString::Cut::insertRight(const AgString &s) const { | |
539 AgString newString(store, strlen(store) + s.size()); | |
540 char *p = newString.pointer(); | |
541 p[index+1] = 0; | |
542 strcat(p, s.pointer()); | |
543 strcat(p, store+index+1); | |
544 return newString; | |
545 } | |
546 | |
547 AgString AgString::Cut::insertRight(const char *s) const { | |
548 AgString newString(store, strlen(store) + strlen(s)); | |
549 char *p = newString.pointer(); | |
550 p[index+1] = 0; | |
551 strcat(p, s); | |
552 strcat(p, store+index+1); | |
553 return newString; | |
554 } | |
555 | |
556 AgString AgString::Cut::replace(const AgString &s) const { | |
557 if (store == 0) return AgString(); | |
558 if (index < 0 || index > strlen(store)) return AgString(store); | |
559 AgString newString(store, strlen(store) + s.size() - 1); | |
560 char *p = newString.pointer(); | |
561 p[index] = 0; | |
562 if (s.size()) strcat(p, s.pointer()); | |
563 strcat(p, store+index+1); | |
564 return newString; | |
565 } | |
566 | |
567 AgString AgString::Cut::replace(const char *s) const { | |
568 if (store == 0) return AgString(); | |
569 if (index < 0 || index > strlen(store)) return AgString(store); | |
570 int n = s!= 0 ? strlen(s) : 0; | |
571 AgString newString(store, strlen(store) + n - 1); | |
572 char *p = newString.pointer(); | |
573 p[index] = 0; | |
574 if (n) strcat(p, s); | |
575 strcat(p, store+index+1); | |
576 return newString; | |
577 } | |
578 */ |