00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "astring.h"
00014 #include "definitions.h"
00015 #include "functions.h"
00016 #include "guards.h"
00017
00018 #include <stdio.h>
00019 #include <stdlib.h>
00020 #include <string.h>
00021
00022 #ifdef __WIN32__
00023 #undef strcasecmp
00024 #undef strncasecmp
00025 #define strcasecmp strcmpi
00026 #define strncasecmp strnicmp
00027 #endif
00028
00029
00030
00031
00032 #define no_increment
00033
00034
00035 namespace basis {
00036
00037 const int LONGEST_SPRINTF = 600;
00038
00039 const char CASE_DIFFERENCE = char('A' - 'a');
00040
00041
00042
00043
00044 const int MAX_FIELD_FUDGE_FACTOR = 64;
00045
00046 const abyte empty_char_star[] = { 0 };
00047
00048
00050
00051 bool astring_comparator(const astring &a, const astring &b) { return a.equal_to(b); }
00052
00053 int calculate_proper_length(int repeat) { return negative(repeat)? 1 : repeat + 1; }
00054
00056
00057 astring::astring()
00058 : c_character_manager(1, empty_char_star),
00059 c_held_string((char * const *)c_character_manager.internal_offset_mem())
00060 {}
00061
00062 astring::astring(const base_string &initial)
00063 : c_character_manager(strlen(initial.observe()) + 1, (abyte *)initial.observe()),
00064 c_held_string((char * const *)c_character_manager.internal_offset_mem())
00065 {}
00066
00067 astring::astring(char initial, int repeat)
00068 : c_character_manager(calculate_proper_length(repeat))
00069 {
00070 if (!initial) initial = ' ';
00071 int new_size = c_character_manager.length() - 1;
00072 memset(c_character_manager.access(), initial, new_size);
00073 c_character_manager.put(new_size, '\0');
00074 c_held_string = (char * const *)c_character_manager.internal_offset_mem();
00075 }
00076
00077 astring::astring(const astring &s1)
00078 : base_string(),
00079 c_character_manager(s1.c_character_manager),
00080 c_held_string((char * const *)c_character_manager.internal_offset_mem())
00081 {
00082 }
00083
00084 astring::astring(const char *initial)
00085 : c_character_manager(calculate_proper_length(initial? int(strlen(initial)) : 0))
00086 {
00087 c_character_manager.put(0, '\0');
00088 if (!initial) return;
00089 strcpy(access(), initial);
00090 c_held_string = (char * const *)c_character_manager.internal_offset_mem();
00091 }
00092
00093 astring::astring(special_flag flag, const char *initial, ...)
00094 : c_character_manager(1, empty_char_star),
00095 c_held_string((char * const *)c_character_manager.internal_offset_mem())
00096 {
00097 if (!initial) return;
00098 if ( (flag != UNTERMINATED) && (flag != SPRINTF) ) {
00099 operator = (astring(astring::SPRINTF, "unknown flag %d", flag));
00100 return;
00101 }
00102
00103 va_list args;
00104 va_start(args, initial);
00105
00106 if (flag == UNTERMINATED) {
00107
00108 int length = va_arg(args, int);
00109 c_character_manager.reset(length, (abyte *)initial);
00110 c_character_manager += abyte(0);
00111 va_end(args);
00112 return;
00113 }
00114
00115
00116 base_sprintf(initial, args);
00117 va_end(args);
00118 }
00119
00120 astring::~astring() { c_held_string = NIL; }
00121
00122 const astring &astring::empty_string() { return bogonic<astring>(); }
00123
00124 void astring::text_form(base_string &state_fill) const { state_fill.assign(*this); }
00125
00126 int astring::length() const { return c_character_manager.length() - 1; }
00127
00128 byte_array &astring::get_implementation() { return c_character_manager; }
00129
00130 char *astring::access() { return (char *)c_character_manager.access(); }
00131
00132 char astring::get(int index) const { return (char)c_character_manager.get(index); }
00133
00134 const char *astring::observe() const
00135 { return (const char *)c_character_manager.observe(); }
00136
00137 bool astring::equal_to(const equalizable &s2) const
00138 {
00139 const astring *s2_cast = cast_or_throw(s2, *this);
00140 return comparator(*s2_cast) == 0;
00141 }
00142
00143 bool astring::less_than(const orderable &s2) const
00144 {
00145 const astring *s2_cast = dynamic_cast<const astring *>(&s2);
00146 if (!s2_cast) throw "error: astring::<: unknown type";
00147 return comparator(*s2_cast) < 0;
00148 }
00149
00150 int astring::comparator(const astring &s2) const
00151 { return strcmp(observe(), s2.observe()); }
00152
00153 bool astring::equal_to(const char *that) const
00154 { return strcmp(observe(), that) == 0; }
00155
00156 bool astring::contains(const astring &to_find) const
00157 { return (find(to_find, 0) < 0) ? false : true; }
00158
00159 astring &astring::operator += (const astring &s1)
00160 { insert(length(), s1); return *this; }
00161
00162 void astring::shrink()
00163 {
00164 astring copy_of_this(observe());
00165 c_character_manager.swap_contents(copy_of_this.c_character_manager);
00166 }
00167
00168 astring &astring::sprintf(const char *initial, ...)
00169 {
00170 va_list args;
00171 va_start(args, initial);
00172 astring &to_return = base_sprintf(initial, args);
00173 va_end(args);
00174 return to_return;
00175 }
00176
00177 astring &astring::base_sprintf(const char *initial, va_list &args)
00178 {
00179 reset();
00180 if (!initial) return *this;
00181 if (!initial[0]) return *this;
00182
00183
00184 char flag_chars[23], width_chars[23], precision_chars[23], modifier_chars[23];
00185
00186
00187 for (const char *traverser = initial; *traverser; traverser++) {
00188 #ifdef DEBUG_STRING
00189 printf("index=%d, char=%c\n", traverser - initial, *traverser);
00190 #endif
00191
00192 if (*traverser != '%') {
00193
00194 *this += *traverser;
00195 continue;
00196 }
00197 traverser++;
00198 #ifdef DEBUG_STRING
00199 printf("index=%d, char=%c\n", traverser - initial, *traverser);
00200 #endif
00201 if (*traverser == '%') {
00202
00203 *this += *traverser;
00204 continue;
00205 }
00206 bool failure = false;
00207
00208
00209 seek_flag(traverser, flag_chars, failure);
00210 if (failure) {
00211 *this += '%';
00212 *this += flag_chars;
00213 continue;
00214 }
00215 seek_width(traverser, width_chars);
00216 seek_precision(traverser, precision_chars);
00217 seek_modifier(traverser, modifier_chars);
00218 get_type_character(traverser, args, *this, flag_chars,
00219 width_chars, precision_chars, modifier_chars);
00220 }
00221 return *this;
00222 }
00223
00224 void astring::seek_flag(const char *&traverser, char *flag_chars, bool &failure)
00225 {
00226 flag_chars[0] = '\0';
00227 failure = false;
00228 bool keep_going = true;
00229 while (!failure && keep_going) {
00230 switch (*traverser) {
00231 case '-': case '+': case ' ': case '\011': case '#':
00232 flag_chars[strlen(flag_chars) + 1] = '\0';
00233 flag_chars[strlen(flag_chars)] = *traverser++;
00234 break;
00235 default:
00236
00237 keep_going = false;
00238 break;
00239 }
00240 }
00241 #ifdef DEBUG_STRING
00242 if (strlen(flag_chars)) printf("[flag=%s]\n", flag_chars);
00243 else printf("no flags\n");
00244 #endif
00245 }
00246
00247 void astring::seek_width(const char *&traverser, char *width_chars)
00248 {
00249 width_chars[0] = '\0';
00250 bool no_more_nums = false;
00251 bool first_num = true;
00252 while (!no_more_nums) {
00253 char wideness[2] = { *traverser, '\0' };
00254 if (first_num && (wideness[0] == '0')) {
00255 strcpy(width_chars, wideness);
00256 traverser++;
00257 } else if (first_num && (wideness[0] == '*') ) {
00258 strcpy(width_chars, wideness);
00259 traverser++;
00260 no_more_nums = true;
00261 } else if ( (wideness[0] <= '9') && (wideness[0] >= '0') ) {
00262
00263 strcat(width_chars, wideness);
00264 traverser++;
00265 } else no_more_nums = true;
00266 first_num = false;
00267 }
00268 #ifdef DEBUG_STRING
00269 if (strlen(width_chars)) printf("[width=%s]\n", width_chars);
00270 else printf("no widths\n");
00271 #endif
00272 }
00273
00274 void astring::seek_precision(const char *&traverser, char *precision_chars)
00275 {
00276 precision_chars[0] = '\0';
00277 if (*traverser != '.') return;
00278 strcpy(precision_chars, ".");
00279 traverser++;
00280 bool no_more_nums = false;
00281 bool first_num = true;
00282 while (!no_more_nums) {
00283 char preciseness[2] = { *traverser, '\0' };
00284 if (first_num && (preciseness[0] == '0')) {
00285 strcat(precision_chars, preciseness);
00286 traverser++;
00287 no_more_nums = true;
00288 } else if (first_num && (preciseness[0] == '*') ) {
00289 strcat(precision_chars, preciseness);
00290 traverser++;
00291 no_more_nums = true;
00292 } else if ( (preciseness[0] <= '9') && (preciseness[0] >= '0') ) {
00293 strcat(precision_chars, preciseness);
00294 traverser++;
00295 } else no_more_nums = true;
00296 first_num = false;
00297 }
00298 #ifdef DEBUG_STRING
00299 if (strlen(precision_chars)) printf("[precis=%s]\n", precision_chars);
00300 else printf("no precision\n");
00301 #endif
00302 }
00303
00304 void astring::seek_modifier(const char *&traverser, char *modifier_chars)
00305 {
00306 modifier_chars[0] = '\0';
00307 switch (*traverser) {
00308 case 'F': case 'N': case 'h': case 'l': case 'L': {
00309 modifier_chars[strlen(modifier_chars) + 1] = '\0';
00310 modifier_chars[strlen(modifier_chars)] = *traverser++;
00311 break;
00312 }
00313 }
00314 #ifdef DEBUG_STRING
00315 if (strlen(modifier_chars)) printf("[mod=%s]\n", modifier_chars);
00316 else printf("no modifiers\n");
00317 #endif
00318 }
00319
00320 void astring::get_type_character(const char * &traverser, va_list &args,
00321 astring &output_string, const char *flag_chars, const char *width_chars,
00322 const char *precision_chars, const char *modifier_chars)
00323 {
00324 char formatting[120];
00325 strcpy(formatting, "%");
00326 strcat(formatting, flag_chars);
00327 strcat(formatting, width_chars);
00328 strcat(formatting, precision_chars);
00329 strcat(formatting, modifier_chars);
00330 char tmposh[2] = { *traverser, '\0' };
00331 strcat(formatting, tmposh);
00332 #ifdef DEBUG_STRING
00333 printf("format: %s\n", formatting);
00334 #endif
00335
00336 enum argument_size { bits_8, bits_16, bits_32, bits_64, bits_80 };
00337 bool ints_are_32_bits;
00338 #ifdef __WIN32__
00339 ints_are_32_bits = true;
00340 #elif defined(__OS2__)
00341 ints_are_32_bits = true;
00342 #elif defined(__MSDOS__)
00343 ints_are_32_bits = false;
00344 #elif defined(__WIN32__)
00345 ints_are_32_bits = false;
00346 #else
00347 ints_are_32_bits = true;
00348 #endif
00349 argument_size next_argument;
00350 bool use_dynamic_sprintf = false;
00351
00352 switch (*traverser) {
00353 case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
00354 next_argument = bits_16;
00355 if (ints_are_32_bits) next_argument = bits_32;
00356 break;
00357 case 'f': case 'e': case 'g': case 'E': case 'G':
00358 next_argument = bits_64;
00359 break;
00360 case 'c':
00361 next_argument = bits_8;
00362 break;
00363 case 's':
00364 next_argument = bits_32;
00365 use_dynamic_sprintf = true;
00366 break;
00367 case 'n':
00368 next_argument = bits_32;
00369 break;
00370 case 'p':
00371 next_argument = bits_32;
00372 break;
00373 default:
00374
00375
00376 #ifdef DEBUG_STRING
00377 printf("failure in type char: %c\n", *traverser);
00378 #endif
00379 output_string += formatting;
00380 return;
00381 }
00382
00383
00384
00385
00386
00387
00388 if (strlen(modifier_chars)) {
00389 switch (modifier_chars[0]) {
00390 case 'N':
00391 next_argument = bits_16;
00392 if (ints_are_32_bits) next_argument = bits_32;
00393 break;
00394 case 'F':
00395 next_argument = bits_32;
00396 break;
00397 case 'h':
00398 next_argument = bits_16;
00399 break;
00400 case 'l':
00401 next_argument = bits_32;
00402 break;
00403 case 'L':
00404 next_argument = bits_80;
00405 break;
00406 default:
00407
00408
00409 #ifdef DEBUG_STRING
00410 printf("failure in modifier: %s\n", modifier_chars);
00411 #endif
00412 output_string += formatting;
00413 return;
00414 }
00415 }
00416
00417 char temp[LONGEST_SPRINTF];
00418 char *temp2 = NIL;
00419 switch (next_argument) {
00420
00421
00422 case bits_8: case bits_16:
00423 if (ints_are_32_bits) ::sprintf(temp, formatting, va_arg(args, long));
00424 else ::sprintf(temp, formatting, va_arg(args, int));
00425 break;
00426 case bits_32:
00427 if (use_dynamic_sprintf) {
00428
00429 char *to_print = va_arg(args, char *);
00430
00431 if (!to_print) {
00432
00433 use_dynamic_sprintf = false;
00434 ::sprintf(temp, "{error:parm=NIL}");
00435 } else if (strlen(to_print) < LONGEST_SPRINTF - 2) {
00436
00437
00438 use_dynamic_sprintf = false;
00439 ::sprintf(temp, formatting, to_print);
00440 } else {
00441
00442 temp2 = new char[strlen(to_print) + MAX_FIELD_FUDGE_FACTOR];
00443 ::sprintf(temp2, formatting, to_print);
00444 }
00445 } else ::sprintf(temp, formatting, va_arg(args, void *));
00446 break;
00447 case bits_64:
00448 ::sprintf(temp, formatting, va_arg(args, double));
00449 break;
00450 case bits_80:
00451 ::sprintf(temp, formatting, va_arg(args, long double));
00452 break;
00453 }
00454 if (use_dynamic_sprintf) {
00455 output_string += temp2;
00456 delete [] temp2;
00457 } else output_string += temp;
00458 }
00459
00460
00461 void astring::reset(special_flag flag, const char *initial, ...)
00462 {
00463 reset();
00464 if (!initial) return;
00465 if ( (flag != UNTERMINATED) && (flag != SPRINTF) ) {
00466 operator = (astring(astring::SPRINTF, "unknown flag %d", flag));
00467 return;
00468 }
00469
00470 va_list args;
00471 va_start(args, initial);
00472
00473 if (flag == UNTERMINATED) {
00474
00475 int length = va_arg(args, int);
00476 c_character_manager.reset(length, (abyte *)initial);
00477 c_character_manager += abyte(0);
00478 va_end(args);
00479 return;
00480 }
00481
00482
00483 base_sprintf(initial, args);
00484 va_end(args);
00485 }
00486
00487 void astring::pad(int len, char padding)
00488 {
00489 if (length() >= len) return;
00490 byte_array pad(len - length());
00491 memset(pad.access(), padding, pad.length());
00492 operator += (astring(UNTERMINATED, (char *)pad.observe(), pad.length()));
00493 }
00494
00495 void astring::trim(int len)
00496 {
00497 if (length() <= len) return;
00498 zap(len, end());
00499 }
00500
00501 astring &astring::operator = (const astring &s1)
00502 {
00503 if (this != &s1)
00504 c_character_manager = s1.c_character_manager;
00505 return *this;
00506 }
00507
00508 astring &astring::operator = (const char *s1)
00509 {
00510 reset();
00511 *this += s1;
00512 return *this;
00513 }
00514
00515 void astring::zap(int position1, int position2)
00516 {
00517 bounds_return(position1, 0, end(), );
00518 bounds_return(position2, 0, end(), );
00519 c_character_manager.zap(position1, position2);
00520 }
00521
00522 void astring::to_lower()
00523 {
00524 for (int i = 0; i < length(); i++)
00525 if ( (get(i) >= 'A') && (get(i) <= 'Z') )
00526 c_character_manager.put(i, char(get(i) - CASE_DIFFERENCE));
00527 }
00528
00529 void astring::to_upper()
00530 {
00531 for (int i = 0; i < length(); i++)
00532 if ( (get(i) >= 'a') && (get(i) <= 'z') )
00533 c_character_manager.put(i, char(get(i) + CASE_DIFFERENCE));
00534 }
00535
00536 astring astring::lower() const
00537 {
00538 astring to_return(*this);
00539 to_return.to_lower();
00540 return to_return;
00541 }
00542
00543 astring astring::upper() const
00544 {
00545 astring to_return(*this);
00546 to_return.to_upper();
00547 return to_return;
00548 }
00549
00550 void astring::copy(char *array_to_stuff, int how_many) const
00551 {
00552 if (!array_to_stuff) return;
00553 array_to_stuff[0] = '\0';
00554 if ( (how_many <= 0) || (length() <= 0) ) return;
00555 strncpy(array_to_stuff, observe(), minimum(how_many, int(length())));
00556 array_to_stuff[minimum(how_many, int(length()))] = '\0';
00557 }
00558
00559 bool astring::iequals(const astring &that) const
00560 { return strcasecmp(observe(), that.observe()) == 0; }
00561
00562 bool astring::iequals(const char *that) const
00563 { return strcasecmp(observe(), that) == 0; }
00564
00565 int astring::ifind(char to_find, int position, bool reverse) const
00566 { return char_find(to_find, position, reverse, false); }
00567
00568 int astring::find(char to_find, int position, bool reverse) const
00569 { return char_find(to_find, position, reverse, true); }
00570
00571 int astring::find_any(const char *to_find, int position, bool reverse) const
00572 { return char_find_any(to_find, position, reverse, true); }
00573
00574 int astring::ifind_any(const char *to_find, int position, bool reverse) const
00575 { return char_find_any(to_find, position, reverse, false); }
00576
00577 int astring::find_non_match(const char *to_find, int position,
00578 bool reverse) const
00579 { return char_find_any(to_find, position, reverse, false, true); }
00580
00581 char simple_lower(char input)
00582 {
00583 if ( (input <= 'Z') && (input >= 'A') ) return input - CASE_DIFFERENCE;
00584 return input;
00585 }
00586
00587 int astring::char_find(char to_find, int position, bool reverse,
00588 bool case_sense) const
00589 {
00590 if (position < 0) return common::OUT_OF_RANGE;
00591 if (position > end()) return common::OUT_OF_RANGE;
00592 if (reverse) {
00593 for (int i = position; i >= 0; i--) {
00594 if (case_sense && (get(i) == to_find)) return i;
00595 else if (simple_lower(get(i)) == simple_lower(to_find)) return i;
00596 }
00597 } else {
00598 if (case_sense) {
00599 const char *const pos = strchr(observe() + position, to_find);
00600 if (pos) return int(pos - observe());
00601 } else {
00602 for (int i = position; i < length(); i++)
00603 if (simple_lower(get(i)) == simple_lower(to_find)) return i;
00604 }
00605 }
00606 return common::NOT_FOUND;
00607 }
00608
00609 bool imatches_any(char to_check, const astring &list)
00610 {
00611 for (int i = 0; i < list.length(); i++)
00612 if (simple_lower(to_check) == simple_lower(list[i])) return true;
00613 return false;
00614 }
00615
00616 bool matches_any(char to_check, const astring &list)
00617 {
00618 for (int i = 0; i < list.length(); i++)
00619 if (to_check == list[i]) return true;
00620 return false;
00621 }
00622
00623 bool matches_none(char to_check, const astring &list)
00624 {
00625 bool saw_match = false;
00626 for (int i = 0; i < list.length(); i++)
00627 if (to_check == list[i]) {
00628 saw_match = true;
00629 break;
00630 }
00631 return !saw_match;
00632 }
00633
00634 int astring::char_find_any(const astring &to_find, int position, bool reverse,
00635 bool case_sense, bool invert_find) const
00636 {
00637 if (position < 0) return common::OUT_OF_RANGE;
00638 if (position > end()) return common::OUT_OF_RANGE;
00639 if (reverse) {
00640 for (int i = position; i >= 0; i--) {
00641 if (!invert_find) {
00642 if (case_sense && matches_any(get(i), to_find)) return i;
00643 else if (imatches_any(get(i), to_find)) return i;
00644 } else {
00645
00646
00647 if (matches_none(get(i), to_find)) return i;
00648 }
00649 }
00650 } else {
00651 for (int i = position; i < length(); i++) {
00652 if (!invert_find) {
00653 if (case_sense && matches_any(get(i), to_find)) return i;
00654 else if (imatches_any(get(i), to_find)) return i;
00655 } else {
00656
00657
00658 if (matches_none(get(i), to_find)) return i;
00659 }
00660 }
00661 }
00662 return common::NOT_FOUND;
00663 }
00664
00665 int astring::find(const astring &to_find, int posn, bool reverse) const
00666 { return str_find(to_find, posn, reverse, true); }
00667
00668 int astring::ifind(const astring &to_find, int posn, bool reverse) const
00669 { return str_find(to_find, posn, reverse, false); }
00670
00671 int astring::str_find(const astring &to_find, int posn, bool reverse,
00672 bool case_sense) const
00673 {
00674 bounds_return(posn, 0, end(), common::OUT_OF_RANGE);
00675 if (!to_find.length()) return common::BAD_INPUT;
00676
00677
00678
00679 if (case_sense)
00680 posn = find(to_find[0], posn, reverse);
00681 else posn = ifind(to_find[0], posn, reverse);
00682 if (posn < 0) return common::NOT_FOUND;
00683
00684
00685
00686 if (case_sense) {
00687
00688 if (reverse) {
00689 if (posn > length() - to_find.length())
00690 posn = length() - to_find.length();
00691 for (int i = posn; i >= 0; i--)
00692 if (!memcmp((void *)&observe()[i], (void *)to_find.observe(),
00693 to_find.length()))
00694 return i;
00695 } else {
00696 const int find_len = to_find.length();
00697 const int str_len = length();
00698 const char first_char = to_find[0];
00699 bounds_return(posn, 0, str_len - find_len, common::OUT_OF_RANGE);
00700 for (int i = posn - 1;
00701 ( ( (i = find(first_char, i + 1)) >= 0)
00702 && (str_len - i >= find_len) ); no_increment) {
00703 if (!memcmp((void *)&observe()[i], (void *)to_find.observe(),
00704 to_find.length()))
00705 return i;
00706 }
00707 }
00708 } else {
00709
00710 if (reverse) {
00711 if (posn > length() - to_find.length())
00712 posn = length() - to_find.length();
00713 for (int i = posn; i >= 0; i--)
00714 if (!strncasecmp(&observe()[i], to_find.observe(), to_find.length()))
00715 return i;
00716 } else {
00717 bounds_return(posn, 0, length() - to_find.length(), common::OUT_OF_RANGE);
00718 for (int i = posn; i < length() - to_find.length() + 1; i++)
00719 if (!strncasecmp(&observe()[i], to_find.observe(), to_find.length()))
00720 return i;
00721 }
00722 }
00723 return common::NOT_FOUND;
00724 }
00725
00726 astring astring::operator + (const astring &s1) const
00727 {
00728 astring to_return(*this);
00729 to_return += s1;
00730 return to_return;
00731 }
00732
00733 char &astring::operator [] (int position)
00734 {
00735 if (position < 0) position = 0;
00736 if (position > end()) position = 0;
00737 abyte &found = c_character_manager.use(position);
00738 char &to_return = *((char *)(&found));
00739 return to_return;
00740 }
00741
00742 const char &astring::operator [] (int position) const
00743 {
00744 if (position < 0) position = 0;
00745 if (position > end()) position = 0;
00746 const abyte &found = c_character_manager.get(position);
00747 const char &to_return = *((const char *)(&found));
00748 return to_return;
00749 }
00750
00751 int astring::convert(int default_value) const
00752 {
00753 if (!length()) return default_value;
00754 int to_return;
00755 int fields = sscanf(observe(), "%d", &to_return);
00756 if (fields < 1) return default_value;
00757 return to_return;
00758 }
00759
00760 long astring::convert(long default_value) const
00761 {
00762 if (!length()) return default_value;
00763 long to_return;
00764 int fields = sscanf(observe(), "%ld", &to_return);
00765 if (fields < 1) return default_value;
00766 return to_return;
00767 }
00768
00769 float astring::convert(float default_value) const
00770 {
00771 if (!length()) return default_value;
00772 float to_return;
00773 int fields = sscanf(observe(), "%f", &to_return);
00774 if (fields < 1) return default_value;
00775 return to_return;
00776 }
00777
00778 double astring::convert(double default_value) const
00779 {
00780 if (!length()) return default_value;
00781 double to_return;
00782 int fields = sscanf(observe(), "%lf", &to_return);
00783 if (fields < 1) return default_value;
00784 return to_return;
00785 }
00786
00787 astring &astring::operator += (const char *s1)
00788 {
00789 if (!s1) return *this;
00790 int len = length();
00791 c_character_manager.insert(len, int(strlen(s1)));
00792 memmove((char *)&c_character_manager[len], s1, int(strlen(s1)));
00793 return *this;
00794 }
00795
00796 astring &astring::operator += (char s1)
00797 {
00798 int len = length();
00799 c_character_manager.insert(len, 1);
00800 c_character_manager.put(len, s1);
00801 return *this;
00802 }
00803
00804 bool astring::compare(const astring &to_compare, int start_first,
00805 int start_second, int count, bool case_sensitive) const
00806 {
00807 bounds_return(start_first, 0, end(), false);
00808 bounds_return(start_second, 0, to_compare.end(), false);
00809 bounds_return(start_first + count, start_first, length(), false);
00810 bounds_return(start_second + count, start_second, to_compare.length(), false);
00811
00812 if (!case_sensitive) {
00813 return !strncasecmp(&observe()[start_first],
00814 &to_compare.observe()[start_second], count);
00815 } else {
00816 return !memcmp((void *)&observe()[start_first],
00817 (void *)&to_compare.observe()[start_second], count);
00818 }
00819 }
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859 bool astring::substring(astring &target, int start, int bender) const
00860 {
00861 target.reset();
00862 if (bender < start) return false;
00863 const int last = end();
00864 bounds_return(start, 0, last, false);
00865 bounds_return(bender, 0, last, false);
00866 target.reset(UNTERMINATED, observe() + start, bender - start + 1);
00867 return true;
00868 }
00869
00870 astring astring::substring(int start, int end) const
00871 {
00872 astring to_return;
00873 substring(to_return, start, end);
00874 return to_return;
00875 }
00876
00877 astring astring::middle(int start, int count)
00878 { return substring(start, start + count - 1); }
00879
00880 astring astring::left(int count)
00881 { return substring(0, count - 1); }
00882
00883 astring astring::right(int count)
00884 { return substring(end() - count + 1, end()); }
00885
00886 void astring::insert(int position, const astring &to_insert)
00887 {
00888 bounds_return(position, 0, length(), );
00889 if (this == &to_insert) {
00890 astring copy_of_me(to_insert);
00891 insert(position, copy_of_me);
00892 } else {
00893 c_character_manager.insert(position, to_insert.length());
00894 c_character_manager.overwrite(position, to_insert.c_character_manager,
00895 to_insert.length());
00896 }
00897 }
00898
00899 bool astring::replace(const astring &tag, const astring &replacement)
00900 {
00901 int where = find(tag);
00902 if (negative(where)) return false;
00903 zap(where, where + tag.end());
00904 insert(where, replacement);
00905 return true;
00906 }
00907
00908 bool astring::replace_all(const astring &to_replace, const astring &new_string)
00909 {
00910 bool did_any = false;
00911 for (int i = 0; i < length(); i++) {
00912 int indy = find(to_replace, i);
00913 if (negative(indy)) break;
00914 i = indy;
00915 zap(i, i + to_replace.length() - 1);
00916 insert(i, new_string);
00917 i += new_string.length() - 1;
00918 did_any = true;
00919 }
00920 return did_any;
00921 }
00922
00923 bool astring::replace_all(char to_replace, char new_char)
00924 {
00925 bool did_any = false;
00926 for (int i = 0; i < length(); i++) {
00927 if (get(i) == to_replace) {
00928 put(i, new_char);
00929 did_any = true;
00930 }
00931 }
00932 return did_any;
00933 }
00934
00935 bool astring::matches(const astring &match_list, char to_match)
00936 {
00937 for (int i = 0; i < match_list.length(); i++)
00938 if (to_match == match_list.get(i)) return true;
00939 return false;
00940 }
00941
00942 void astring::strip(const astring &strip_list, how_to_strip way)
00943 {
00944 if (way & FROM_FRONT)
00945 while (length() && matches(strip_list, get(0)))
00946 zap(0, 0);
00947
00948 if (way & FROM_END)
00949 while (length() && matches(strip_list, get(end())))
00950 zap(end(), end());
00951 }
00952
00953 int astring::packed_size() const { return length() + 1; }
00954
00955 void astring::pack(byte_array &target) const
00956 { attach(target, (char *)c_character_manager.observe()); }
00957
00958 bool astring::unpack(byte_array &source)
00959 { return detach(source, *this); }
00960
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00992
00993 a_sprintf::a_sprintf() : astring() {}
00994
00995 a_sprintf::a_sprintf(const astring &s) : astring(s) {}
00996
00997 a_sprintf::a_sprintf(const char *initial, ...)
00998 : astring()
00999 {
01000 if (!initial) return;
01001 va_list args;
01002 va_start(args, initial);
01003 base_sprintf(initial, args);
01004 va_end(args);
01005 }
01006
01008
01009 void attach(byte_array &packed_form, const char *to_attach)
01010 {
01011 const int len = int(strlen(to_attach));
01012 const int old_pos = packed_form.last();
01013 packed_form.insert(old_pos + 1, len + 1);
01014 memmove((char *)packed_form.observe() + old_pos + 1, to_attach, len + 1);
01015 }
01016
01017 bool detach(byte_array &packed_form, astring &to_detach)
01018 {
01019 if (!packed_form.length()) return false;
01020
01021 const void *zero_posn = memchr(packed_form.observe(), '\0',
01022 packed_form.length());
01023
01024 if (!zero_posn) {
01025
01026 to_detach.reset();
01027 return false;
01028 }
01029
01030
01031 to_detach = (char *)packed_form.observe();
01032
01033
01034 int find_len = int((abyte *)zero_posn - packed_form.observe());
01035
01036 packed_form.zap(0, find_len);
01037 return true;
01038 }
01039
01041
01042
01043
01044 base_string &astring::concatenate_string(const base_string &s)
01045 {
01046 const astring *cast = dynamic_cast<const astring *>(&s);
01047 if (cast) *this += *cast;
01048 else *this += astring(s.observe());
01049 return *this;
01050 }
01051
01052 base_string &astring::concatenate_char(char c)
01053 {
01054 *this += c;
01055 return *this;
01056 }
01057
01058 base_string &astring::assign(const base_string &s)
01059 {
01060 const astring *cast = dynamic_cast<const astring *>(&s);
01061 if (cast) *this = *cast;
01062 else *this = astring(s.observe());
01063 return *this;
01064 }
01065
01066 base_string &astring::upgrade(const char *s)
01067 {
01068 *this = s;
01069 return *this;
01070 }
01071
01072 bool astring::sub_string(base_string &target, int start, int end) const
01073 {
01074 astring *cast = dynamic_cast<astring *>(&target);
01075 if (!cast) throw "error: astring::sub_string: unknown type";
01076 return substring(*cast, start, end);
01077 }
01078
01079 bool astring::sub_compare(const base_string &to_compare, int start_first,
01080 int start_second, int count, bool case_sensitive) const
01081 {
01082 const astring *cast = dynamic_cast<const astring *>(&to_compare);
01083 if (cast) return compare(*cast, start_first, start_second, count, case_sensitive);
01084 else return compare(astring(to_compare.observe()), start_first, start_second,
01085 count, case_sensitive);
01086 }
01087
01088 void astring::insert(int position, const base_string &to_insert)
01089 {
01090 const astring *cast = dynamic_cast<const astring *>(&to_insert);
01091 if (cast) this->insert(position, *cast);
01092 else this->insert(position, astring(to_insert.observe()));
01093 }
01094
01095 }
01096