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 */