00001
00002
00003
00004
00005
00006
00007
00008 #include "strutils.h"
00009 #include "wvbuf.h"
00010 #include <ctype.h>
00011 #include <stdio.h>
00012 #include <string.h>
00013 #include <time.h>
00014 #include <errno.h>
00015
00016 #ifndef _WIN32
00017
00018 #include <errno.h>
00019 #include <netdb.h>
00020 #include <unistd.h>
00021 #else
00022 #undef errno
00023 #define errno GetLastError()
00024 #define strcasecmp _stricmp
00025 #include <winsock2.h>
00026 #include <direct.h>
00027 #ifndef EACCES
00028 #define EACCES 0xfff
00029 #endif
00030 #endif
00031
00032 char *terminate_string(char *string, char c)
00033
00034
00035
00036
00037 {
00038 char *p;
00039
00040 if (string == NULL)
00041 return NULL;
00042
00043 p = string + strlen(string) - 1;
00044 while (p >= string)
00045 {
00046 if (*p == '\r' || *p == '\n')
00047 --p;
00048 else
00049 break;
00050 }
00051
00052 *(++p) = c;
00053 *(++p) = 0;
00054
00055 return string;
00056 }
00057
00058
00059 char *trim_string(char *string)
00060
00061
00062
00063 {
00064 char *p;
00065 char *q;
00066
00067 if (string == NULL)
00068 return NULL;
00069
00070 p = string;
00071 q = string + strlen(string) - 1;
00072
00073 while (q >= p && isspace(*q))
00074 *(q--) = 0;
00075 while (isspace(*p))
00076 p++;
00077
00078 return p;
00079 }
00080
00081
00082 char *trim_string(char *string, char c)
00083
00084
00085 {
00086 char *p;
00087
00088 if (string == NULL)
00089 return NULL;
00090
00091 p = string;
00092
00093 while (*p != 0 && *p != c)
00094 p++;
00095
00096 while (*p)
00097 *(p++) = 0;
00098
00099 return string;
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 WvString spacecat(WvStringParm a, WvStringParm b, char sep, bool onesep)
00115 {
00116 size_t alen = strlen(a);
00117 size_t blen = strlen(b);
00118
00119
00120 if (onesep && alen)
00121 {
00122 while (a[alen-1] == sep)
00123 --alen;
00124 }
00125
00126
00127
00128 WvString s;
00129 s.setsize(alen + blen + 2);
00130 char *cptr = s.edit();
00131
00132 memcpy(cptr, a, alen);
00133
00134
00135 cptr[alen] = sep;
00136
00137
00138 size_t boffset = 0;
00139 if (onesep)
00140 {
00141 while (b[boffset] == sep)
00142 ++boffset;
00143 }
00144
00145
00146 memcpy(cptr+alen+1, b.cstr()+boffset, blen-boffset);
00147 cptr[alen+1+blen-boffset] = 0;
00148
00149 return s;
00150 }
00151
00152
00153
00154 char *non_breaking(const char * string)
00155 {
00156 if (string == NULL)
00157 return (NULL);
00158
00159 WvDynBuf buf;
00160
00161 while (*string)
00162 {
00163 if (isspace(*string))
00164 buf.putstr(" ");
00165 else
00166 buf.putch(*string);
00167 string++;
00168 }
00169
00170 WvString s(buf.getstr());
00171 char *nbstr = new char[s.len() + 1];
00172 return strcpy(nbstr, s.edit());
00173 }
00174
00175
00176
00177
00178 void replace_char(void *_string, char c1, char c2, int length)
00179 {
00180 char *string = (char *)_string;
00181 for (int i=0; i < length; i++)
00182 if (*(string+i) == c1)
00183 *(string+i) = c2;
00184 }
00185
00186
00187 char *snip_string(char *haystack, char *needle)
00188 {
00189 if(!haystack)
00190 return NULL;
00191 if(!needle)
00192 return haystack;
00193 char *p = strstr(haystack, needle);
00194 if(!p || p != haystack)
00195 return haystack;
00196 else
00197 return haystack + strlen(needle);
00198 }
00199
00200
00201 char *strlwr(char *string)
00202 {
00203 char *p = string;
00204 while (p && *p)
00205 {
00206 *p = tolower(*p);
00207 p++;
00208 }
00209
00210 return string;
00211 }
00212
00213
00214 char *strupr(char *string)
00215 {
00216 char *p = string;
00217 while (p && *p)
00218 {
00219 *p = toupper(*p);
00220 p++;
00221 }
00222
00223 return string;
00224 }
00225
00226
00227
00228 bool is_word(const char *p)
00229 {
00230 assert(p);
00231
00232 while (*p)
00233 {
00234 if(!isalnum(*p++))
00235 return false;
00236 }
00237
00238 return true;
00239 }
00240
00241
00242
00243
00244
00245 WvString hexdump_buffer(const void *_buf, size_t len, bool charRep)
00246 {
00247 const unsigned char *buf = (const unsigned char *)_buf;
00248 size_t count, count2, top;
00249 WvString out;
00250
00251 out.setsize(len / 16 * 80 + 80);
00252 char *cptr = out.edit();
00253
00254 for (count = 0; count < len; count+=16)
00255 {
00256 top = len-count < 16 ? len-count : 16;
00257 cptr += sprintf(cptr, "[%03X] ", (unsigned int)count);
00258
00259
00260 for (count2 = 0; count2 < top; count2++)
00261 {
00262 if (count2 && !(count2 % 4))
00263 *cptr++ = ' ';
00264 cptr += sprintf(cptr, "%02X", buf[count+count2]);
00265 }
00266
00267
00268 for (count2 = top; count2 < 16; count2++)
00269 {
00270 if (count2 && !(count2 % 4))
00271 {
00272 strcat(cptr, " ");
00273 cptr += 3;
00274 }
00275 else
00276 {
00277 strcat(cptr, " ");
00278 cptr += 2;
00279 }
00280 }
00281
00282 *cptr++ = ' ';
00283
00284
00285 if (charRep)
00286 {
00287 for (count2 = 0; count2 < top; count2++)
00288 {
00289 if (!(count2 % 4))
00290 *cptr++ = ' ';
00291 *cptr++ = (isprint(buf[count+count2])
00292 ? buf[count+count2] : '.');
00293 }
00294 }
00295
00296 *cptr++ = '\n';
00297 }
00298 *cptr = 0;
00299 return out;
00300 }
00301
00302
00303
00304 bool isnewline(char c)
00305 {
00306 return c=='\n' || c=='\r';
00307 }
00308
00309
00310
00311 WvString url_decode(WvStringParm str, bool no_space)
00312 {
00313 if (!str)
00314 return str;
00315
00316 const char *iptr;
00317 char *optr;
00318 const char *idx1, *idx2;
00319 static const char hex[] = "0123456789ABCDEF";
00320 WvString in, intmp(str), out;
00321
00322 in = trim_string(intmp.edit());
00323 out.setsize(strlen(in) + 1);
00324
00325 optr = out.edit();
00326 for (iptr = in, optr = out.edit(); *iptr; iptr++)
00327 {
00328 if (*iptr == '+' && !no_space)
00329 *optr++ = ' ';
00330 else if (*iptr == '%' && iptr[1] && iptr[2])
00331 {
00332 idx1 = strchr(hex, toupper((unsigned char) iptr[1]));
00333 idx2 = strchr(hex, toupper((unsigned char) iptr[2]));
00334
00335 if (idx1 && idx2)
00336 *optr++ = ((idx1 - hex) << 4) | (idx2 - hex);
00337
00338 iptr += 2;
00339 }
00340 else
00341 *optr++ = *iptr;
00342 }
00343
00344 *optr = 0;
00345
00346 return out;
00347 }
00348
00349
00350
00351 WvString url_encode(WvStringParm str, WvStringParm unsafe)
00352 {
00353 unsigned int i;
00354 WvDynBuf retval;
00355
00356 for (i=0; i < str.len(); i++)
00357 {
00358 if (((!!unsafe && !strchr(unsafe, str[i])) ||
00359 (!unsafe && (isalnum(str[i]) || strchr("_.!~*'()-", str[i])))) &&
00360 str[i] != '%')
00361 {
00362 retval.put(&str[i], 1);
00363 }
00364 else
00365 {
00366 char buf[4];
00367 sprintf(buf, "%%%02X", str[i] & 0xff);
00368 retval.put(&buf, 3);
00369 }
00370 }
00371
00372 return retval.getstr();
00373 }
00374
00375
00376 WvString diff_dates(time_t t1, time_t t2)
00377 {
00378 char out[25];
00379 double diff = difftime(t1, t2);
00380 if(diff < 0)
00381 diff = -diff;
00382 if(diff > (60 * 60 * 24))
00383
00384 sprintf(out, "%.1f day(s)", diff / (60 * 60 * 24));
00385 else if(diff > (60 * 60))
00386 sprintf(out, "%.0f hour(s)", diff / (60 * 60));
00387 else if(diff > 60)
00388 sprintf(out, "%.0f minute(s)", diff / 60);
00389 else
00390 sprintf(out, "%.0f second(s)", diff);
00391 return out;
00392 }
00393
00394
00395 WvString rfc822_date(time_t when)
00396 {
00397 WvString out;
00398 out.setsize(80);
00399
00400 if (when < 0)
00401 when = time(NULL);
00402
00403 struct tm *tmwhen = localtime(&when);
00404 strftime(out.edit(), 80, "%a, %d %b %Y %H:%M:%S %z", tmwhen);
00405
00406 return out;
00407 }
00408
00409
00410 WvString backslash_escape(WvStringParm s1)
00411 {
00412
00413 if (!s1)
00414 return "";
00415
00416 WvString s2;
00417 s2.setsize(s1.len() * 2 + 1);
00418
00419 const char *p1 = s1;
00420 char *p2 = s2.edit();
00421 while (*p1)
00422 {
00423 if (!isalnum(*p1))
00424 *p2++ = '\\';
00425 *p2++ = *p1++;
00426 }
00427 *p2 = 0;
00428
00429 return s2;
00430 }
00431
00432
00433 int strcount(WvStringParm s, const char c)
00434 {
00435 int n=0;
00436 const char *p = s;
00437 while ((p=strchr(p, c)) != NULL && p++)
00438 n++;
00439
00440 return n;
00441 }
00442
00443
00444 WvString encode_hostname_as_DN(WvStringParm hostname)
00445 {
00446 WvString dn("");
00447
00448 WvStringList fqdnlist;
00449 WvStringList::Iter i(fqdnlist);
00450
00451 fqdnlist.split(hostname, ".");
00452 for (i.rewind(); i.next(); )
00453 dn.append("dc=%s,", *i);
00454 dn.append("cn=%s", hostname);
00455
00456 return dn;
00457 }
00458
00459
00460 WvString nice_hostname(WvStringParm name)
00461 {
00462 WvString nice;
00463 char *optr, *optr_start;
00464 const char *iptr;
00465 bool last_was_dash;
00466
00467 nice.setsize(name.len() + 2);
00468
00469 iptr = name;
00470 optr = optr_start = nice.edit();
00471 if (!isascii(*iptr) || !isalnum(*(const unsigned char *)iptr))
00472 *optr++ = 'x';
00473
00474 last_was_dash = false;
00475 for (; *iptr; iptr++)
00476 {
00477 if (!isascii(*iptr))
00478 continue;
00479
00480 if (*iptr == '-' || *iptr == '_')
00481 {
00482 if (last_was_dash)
00483 continue;
00484 last_was_dash = true;
00485 *optr++ = '-';
00486 }
00487 else if (isalnum(*(const unsigned char *)iptr) || *iptr == '.')
00488 {
00489 *optr++ = *iptr;
00490 last_was_dash = false;
00491 }
00492 }
00493
00494 if (optr > optr_start && !isalnum(*(const unsigned char *)(optr-1)))
00495 *optr++ = 'x';
00496
00497 *optr++ = 0;
00498
00499 if (!nice.len())
00500 return "UNKNOWN";
00501
00502 return nice;
00503 }
00504
00505
00506 WvString getfilename(WvStringParm fullname)
00507 {
00508 WvString tmp(fullname);
00509 char *cptr = strrchr(tmp.edit(), '/');
00510
00511 if (!cptr)
00512 return fullname;
00513 else if (!cptr[1])
00514 {
00515 *cptr = 0;
00516 return getfilename(tmp);
00517 }
00518 else
00519 return cptr+1;
00520 }
00521
00522
00523 WvString getdirname(WvStringParm fullname)
00524 {
00525 WvString tmp(fullname);
00526 char *cptr = strrchr(tmp.edit(), '/');
00527
00528 if (!cptr)
00529 return ".";
00530 else if (!cptr[1])
00531 {
00532 *cptr = 0;
00533 return getdirname(tmp);
00534 }
00535 else
00536 {
00537 *cptr = 0;
00538 return !tmp ? WvString("/") : tmp;
00539 }
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549 struct prefix_t
00550 {
00551 const char *name;
00552 unsigned long long base;
00553 };
00554
00555
00556
00557 static const prefix_t si[] =
00558 {
00559 { "k", 1000ull },
00560 { "M", 1000ull * 1000ull },
00561 { "G", 1000ull * 1000ull * 1000ull },
00562 { "T", 1000ull * 1000ull * 1000ull * 1000ull },
00563 { "P", 1000ull * 1000ull * 1000ull * 1000ull * 1000ull},
00564 { "E", 1000ull * 1000ull * 1000ull * 1000ull * 1000ull * 1000ull},
00565 { "Z", 0 },
00566 { "Y", 0 },
00567 { NULL, 0 }
00568 };
00569
00570
00571
00572 static const prefix_t iec[] =
00573 {
00574 { "Ki", 1024ull },
00575 { "Mi", 1024ull * 1024ull},
00576 { "Gi", 1024ull * 1024ull * 1024ull },
00577 { "Ti", 1024ull * 1024ull * 1024ull * 1024ull },
00578 { "Pi", 1024ull * 1024ull * 1024ull * 1024ull * 1024ull},
00579 { "Ei", 1024ull * 1024ull * 1024ull * 1024ull * 1024ull * 1024ull},
00580 { "Zi", 0 },
00581 { "Yi", 0 },
00582 { NULL, 0 }
00583 };
00584
00585
00586
00587 static inline unsigned long long _sizetoa_rounder(RoundingMethod method,
00588 unsigned long long size,
00589 unsigned long long remainder,
00590 unsigned long long base)
00591 {
00592 unsigned long long half = base / 2;
00593 unsigned long long significant_digits = size / base;
00594 switch (method)
00595 {
00596 case ROUND_DOWN:
00597 break;
00598
00599 case ROUND_UP:
00600 if (remainder || (size % base))
00601 ++significant_digits;
00602 break;
00603
00604 case ROUND_UP_AT_POINT_FIVE:
00605 if ((size % base) >= half)
00606 ++significant_digits;
00607 break;
00608
00609 case ROUND_DOWN_AT_POINT_FIVE:
00610 unsigned long long r = size % base;
00611 if ((r > half) || (remainder && (r == half)))
00612 ++significant_digits;
00613 break;
00614 }
00615 return significant_digits;
00616 }
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627 static WvString _sizetoa(unsigned long long size, unsigned long blocksize,
00628 RoundingMethod rounding_method,
00629 const prefix_t *prefixes, WvStringParm unit)
00630 {
00631 assert(blocksize);
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645 const unsigned long long group_base = prefixes[0].base;
00646 int shift = 0;
00647 unsigned long prev_blocksize = 0;
00648 while (blocksize >= group_base)
00649 {
00650 prev_blocksize = blocksize;
00651 blocksize /= group_base;
00652 ++shift;
00653 }
00654
00655
00656
00657 if (prev_blocksize && prev_blocksize != group_base)
00658 {
00659 blocksize = prev_blocksize;
00660 --shift;
00661 }
00662
00663 int p = -1;
00664 unsigned long long significant_digits = size * 10;
00665 unsigned int remainder = 0;
00666 if (significant_digits < size)
00667 {
00668
00669 remainder = size % group_base;
00670 size /= group_base;
00671 ++shift;
00672 }
00673 while (size >= group_base)
00674 {
00675 ++p;
00676 significant_digits = _sizetoa_rounder(rounding_method,
00677 size * 10,
00678 remainder,
00679 prefixes[p].base);
00680 if (significant_digits < (group_base * 10)
00681 || !prefixes[p + shift + 1].name)
00682 break;
00683 }
00684
00685
00686 if (blocksize > 1)
00687 {
00688 significant_digits *= blocksize;
00689 while (significant_digits >= (group_base * 10)
00690 && prefixes[p + shift + 1].name)
00691 {
00692 significant_digits = _sizetoa_rounder(rounding_method,
00693 significant_digits,
00694 0,
00695 group_base);
00696 ++p;
00697 }
00698 }
00699
00700
00701 return WvString("%s.%s %s%s",
00702 significant_digits / 10,
00703 significant_digits % 10,
00704 prefixes[p + shift].name,
00705 unit);
00706 }
00707
00708 WvString sizetoa(unsigned long long blocks, unsigned long blocksize,
00709 RoundingMethod rounding_method)
00710 {
00711 unsigned long long bytes = blocks * blocksize;
00712
00713
00714 if (bytes < 1000 && bytes >= blocks)
00715 return WvString("%s bytes", bytes);
00716
00717 return _sizetoa(blocks, blocksize, rounding_method, si, "B");
00718 }
00719
00720
00721 WvString sizektoa(unsigned long long kbytes, RoundingMethod rounding_method)
00722 {
00723 if (kbytes < 1000)
00724 return WvString("%s kB", kbytes);
00725
00726 return sizetoa(kbytes, 1000, rounding_method);
00727 }
00728
00729 WvString sizeitoa(unsigned long long blocks, unsigned long blocksize,
00730 RoundingMethod rounding_method)
00731 {
00732 unsigned long long bytes = blocks * blocksize;
00733
00734
00735 if (bytes < 1024 && bytes >= blocks)
00736 return WvString("%s bytes", bytes);
00737
00738 return _sizetoa(blocks, blocksize, rounding_method, iec, "B");
00739 }
00740
00741
00742 WvString sizekitoa(unsigned long long kbytes, RoundingMethod rounding_method)
00743 {
00744 if (kbytes < 1024)
00745 return WvString("%s KiB", kbytes);
00746
00747 return sizeitoa(kbytes, 1024, rounding_method);
00748 }
00749
00750 WvString secondstoa(unsigned int total_seconds)
00751 {
00752 WvString result("");
00753
00754 unsigned int days = total_seconds / (3600*24);
00755 total_seconds %= (3600*24);
00756 unsigned int hours = total_seconds / 3600;
00757 total_seconds %= 3600;
00758 unsigned int mins = total_seconds / 60;
00759 unsigned int secs = total_seconds % 60;
00760
00761 int num_elements = (days > 0) + (hours > 0) + (mins > 0);
00762
00763 if (days > 0)
00764 {
00765 result.append(days);
00766 result.append(days > 1 ? " days" : " day");
00767 num_elements--;
00768 if (num_elements > 1)
00769 result.append(", ");
00770 else if (num_elements == 1)
00771 result.append(" and ");
00772 }
00773 if (hours > 0)
00774 {
00775 result.append(hours);
00776 result.append(hours > 1 ? " hours" : " hour");
00777 num_elements--;
00778 if (num_elements > 1)
00779 result.append(", ");
00780 else if (num_elements == 1)
00781 result.append(" and ");
00782 }
00783 if (mins > 0)
00784 {
00785 result.append(mins);
00786 result.append(mins > 1 ? " minutes" : " minute");
00787 }
00788 if (days == 0 && hours == 0 && mins == 0)
00789 {
00790 result.append(secs);
00791 result.append(secs != 1 ? " seconds" : " second");
00792 }
00793
00794 return result;
00795 }
00796
00797 WvString strreplace(WvStringParm s, WvStringParm a, WvStringParm b)
00798 {
00799 WvDynBuf buf;
00800 const char *sptr = s, *eptr;
00801
00802 while ((eptr = strstr(sptr, a)) != NULL)
00803 {
00804 buf.put(sptr, eptr-sptr);
00805 buf.putstr(b);
00806 sptr = eptr + strlen(a);
00807 }
00808
00809 buf.put(sptr, strlen(sptr));
00810
00811 return buf.getstr();
00812 }
00813
00814 WvString undupe(WvStringParm s, char c)
00815 {
00816 WvDynBuf out;
00817
00818 bool last = false;
00819
00820 for (int i = 0; s[i] != '\0'; i++)
00821 {
00822 if (s[i] != c)
00823 {
00824 out.putch(s[i]);
00825 last = false;
00826 }
00827 else if (!last)
00828 {
00829 out.putch(c);
00830 last = true;
00831 }
00832 }
00833
00834 return out.getstr();
00835 }
00836
00837
00838 WvString rfc1123_date(time_t t)
00839 {
00840 struct tm *tm = gmtime(&t);
00841 WvString s;
00842
00843 s.setsize(128);
00844 strftime(s.edit(), 128, "%a, %d %b %Y %H:%M:%S GMT", tm);
00845
00846 return s;
00847 }
00848
00849
00850 int lookup(const char *str, const char * const *table, bool case_sensitive)
00851 {
00852 for (int i = 0; table[i]; ++i)
00853 {
00854 if (case_sensitive)
00855 {
00856 if (strcmp(str, table[i]) != 0)
00857 continue;
00858 }
00859 else
00860 {
00861 if (strcasecmp(str, table[i]) != 0)
00862 continue;
00863 }
00864 return i;
00865 }
00866 return -1;
00867 }
00868
00869
00870 WvString hostname()
00871 {
00872 int maxlen = 0;
00873 for (;;)
00874 {
00875 maxlen += 80;
00876 char *name = new char[maxlen];
00877 int result = gethostname(name, maxlen);
00878 if (result == 0)
00879 {
00880 WvString hostname(name);
00881 deletev name;
00882 return hostname;
00883 }
00884 #ifdef _WIN32
00885 assert(errno == WSAEFAULT);
00886 #else
00887 assert(errno == EINVAL);
00888 #endif
00889 }
00890 }
00891
00892
00893 WvString fqdomainname()
00894 {
00895 struct hostent *myhost;
00896
00897 myhost = gethostbyname(hostname());
00898 if (myhost)
00899 return myhost->h_name;
00900 else
00901 return WvString::null;
00902 }
00903
00904
00905 WvString wvgetcwd()
00906 {
00907 int maxlen = 0;
00908 for (;;)
00909 {
00910 maxlen += 80;
00911 char *name = new char[maxlen];
00912 char *res = getcwd(name, maxlen);
00913 if (res)
00914 {
00915 WvString s(name);
00916 deletev name;
00917 return s;
00918 }
00919 if (errno == EACCES || errno == ENOENT)
00920 return ".";
00921 assert(errno == ERANGE);
00922 }
00923 }
00924
00925
00926 WvString metriculate(const off_t i)
00927 {
00928 WvString res;
00929 int digits=0;
00930 int digit=0;
00931 long long int j=i;
00932 char *p;
00933
00934 while (j)
00935 {
00936 digits++;
00937 j/=10;
00938 }
00939
00940 j=i;
00941
00942 res.setsize(digits + ((digits - 1) / 3) + ((j < 0) ? 1 : 0));
00943 p = res.edit();
00944 if (j < 0)
00945 {
00946 *p++ = '-';
00947 j = -j;
00948 }
00949
00950 p += digits + ((digits - 1) / 3);
00951 *p-- = '\0';
00952
00953 for (digit=0; digit<digits; digit++)
00954 {
00955 *p-- = '0' + ( j%10 );
00956 if (((digit+1) % 3) == 0 && digit < digits - 1)
00957 *p-- = ' ';
00958 j /= 10;
00959 }
00960
00961 return res;
00962 }
00963
00964
00965 WvString afterstr(WvStringParm line, WvStringParm a)
00966 {
00967 if (!line || !a)
00968 return WvString::null;
00969
00970 const char *loc = strstr(line, a);
00971 if (loc == 0)
00972 return "";
00973
00974 loc += a.len();
00975 WvString ret = loc;
00976 ret.unique();
00977 return ret;
00978 }
00979
00980
00981 WvString beforestr(WvStringParm line, WvStringParm a)
00982 {
00983 if (!line || !a)
00984 return WvString::null;
00985
00986 WvString ret = line;
00987 ret.unique();
00988 char *loc = strstr(ret.edit(), a);
00989
00990 if (loc == 0)
00991 return line;
00992
00993 loc[0] = '\0';
00994 return ret;
00995 }
00996
00997
00998 WvString substr(WvString line, unsigned int pos, unsigned int len)
00999 {
01000 const char *tmp = line.cstr();
01001 if (pos > line.len()-1)
01002 return "";
01003 tmp += pos;
01004
01005 WvString ret = tmp;
01006 char *tmp2 = ret.edit();
01007 if (pos + len < line.len())
01008 tmp2[len] = '\0';
01009
01010 return ret;
01011 }
01012
01013 const CStrExtraEscape CSTR_TCLSTR_ESCAPES[3] =
01014 {
01015 { '{', "\\<" },
01016 { '}', "\\>" },
01017 { 0, NULL }
01018 };
01019
01020 static inline const char *cstr_escape_char(char ch)
01021 {
01022 static const char *xlat[256] =
01023 {
01024 "\\0", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\a",
01025 "\\b", "\\t", "\\n", "\\v", "\\x0C", "\\r", "\\x0E", "\\x0F",
01026 "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17",
01027 "\\x18", "\\x19", "\\x1A", "\\x1B", "\\x1C", "\\x1D", "\\x1E", "\\x1F",
01028 " ", "!", "\\\"", "#", "$", "%", "&", "'",
01029 "(", ")", "*", "+", ",", "-", ".", "/",
01030 "0", "1", "2", "3", "4", "5", "6", "7",
01031 "8", "9", ":", ";", "<", "=", ">", "?",
01032 "@", "A", "B", "C", "D", "E", "F", "G",
01033 "H", "I", "J", "K", "L", "M", "N", "O",
01034 "P", "Q", "R", "S", "T", "U", "V", "W",
01035 "X", "Y", "Z", "[", "\\\\", "]", "^", "_",
01036 "`", "a", "b", "c", "d", "e", "f", "g",
01037 "h", "i", "j", "k", "l", "m", "n", "o",
01038 "p", "q", "r", "s", "t", "u", "v", "w",
01039 "x", "y", "z", "{", "|", "}", "~", "\\x7F",
01040 "\\x80", "\\x81", "\\x82", "\\x83", "\\x84", "\\x85", "\\x86", "\\x87",
01041 "\\x88", "\\x89", "\\x8A", "\\x8B", "\\x8C", "\\x8D", "\\x8E", "\\x8F",
01042 "\\x90", "\\x91", "\\x92", "\\x93", "\\x94", "\\x95", "\\x96", "\\x97",
01043 "\\x98", "\\x99", "\\x9A", "\\x9B", "\\x9C", "\\x9D", "\\x9E", "\\x9F",
01044 "\\xA0", "\\xA1", "\\xA2", "\\xA3", "\\xA4", "\\xA5", "\\xA6", "\\xA7",
01045 "\\xA8", "\\xA9", "\\xAA", "\\xAB", "\\xAC", "\\xAD", "\\xAE", "\\xAF",
01046 "\\xB0", "\\xB1", "\\xB2", "\\xB3", "\\xB4", "\\xB5", "\\xB6", "\\xB7",
01047 "\\xB8", "\\xB9", "\\xBA", "\\xBB", "\\xBC", "\\xBD", "\\xBE", "\\xBF",
01048 "\\xC0", "\\xC1", "\\xC2", "\\xC3", "\\xC4", "\\xC5", "\\xC6", "\\xC7",
01049 "\\xC8", "\\xC9", "\\xCA", "\\xCB", "\\xCC", "\\xCD", "\\xCE", "\\xCF",
01050 "\\xD0", "\\xD1", "\\xD2", "\\xD3", "\\xD4", "\\xD5", "\\xD6", "\\xD7",
01051 "\\xD8", "\\xD9", "\\xDA", "\\xDB", "\\xDC", "\\xDD", "\\xDE", "\\xDF",
01052 "\\xE0", "\\xE1", "\\xE2", "\\xE3", "\\xE4", "\\xE5", "\\xE6", "\\xE7",
01053 "\\xE8", "\\xE9", "\\xEA", "\\xEB", "\\xEC", "\\xED", "\\xEE", "\\xEF",
01054 "\\xF0", "\\xF1", "\\xF2", "\\xF3", "\\xF4", "\\xF5", "\\xF6", "\\xF7",
01055 "\\xF8", "\\xF9", "\\xFA", "\\xFB", "\\xFC", "\\xFD", "\\xFE", "\\xFF"
01056 };
01057 return xlat[(unsigned char)ch];
01058 }
01059
01060 static inline int hex_digit_val(char ch)
01061 {
01062 static int val[256] =
01063 {
01064 -1, -1, -1, -1, -1, -1, -1, -1,
01065 -1, -1, -1, -1, -1, -1, -1, -1,
01066 -1, -1, -1, -1, -1, -1, -1, -1,
01067 -1, -1, -1, -1, -1, -1, -1, -1,
01068 -1, -1, -1, -1, -1, -1, -1, -1,
01069 -1, -1, -1, -1, -1, -1, -1, -1,
01070 0, 1, 2, 3, 4, 5, 6, 7,
01071 8, 9, -1, -1, -1, -1, -1, -1,
01072 -1, 10, 11, 12, 13, 14, 15, -1,
01073 -1, -1, -1, -1, -1, -1, -1, -1,
01074 -1, -1, -1, -1, -1, -1, -1, -1,
01075 -1, -1, -1, -1, -1, -1, -1, -1,
01076 -1, 10, 11, 12, 13, 14, 15, -1,
01077 -1, -1, -1, -1, -1, -1, -1, -1,
01078 -1, -1, -1, -1, -1, -1, -1, -1,
01079 -1, -1, -1, -1, -1, -1, -1, -1,
01080 -1, -1, -1, -1, -1, -1, -1, -1,
01081 -1, -1, -1, -1, -1, -1, -1, -1,
01082 -1, -1, -1, -1, -1, -1, -1, -1,
01083 -1, -1, -1, -1, -1, -1, -1, -1,
01084 -1, -1, -1, -1, -1, -1, -1, -1,
01085 -1, -1, -1, -1, -1, -1, -1, -1,
01086 -1, -1, -1, -1, -1, -1, -1, -1,
01087 -1, -1, -1, -1, -1, -1, -1, -1,
01088 -1, -1, -1, -1, -1, -1, -1, -1,
01089 -1, -1, -1, -1, -1, -1, -1, -1,
01090 -1, -1, -1, -1, -1, -1, -1, -1,
01091 -1, -1, -1, -1, -1, -1, -1, -1,
01092 -1, -1, -1, -1, -1, -1, -1, -1,
01093 -1, -1, -1, -1, -1, -1, -1, -1,
01094 -1, -1, -1, -1, -1, -1, -1, -1,
01095 -1, -1, -1, -1, -1, -1, -1, -1
01096 };
01097 return val[(unsigned char)ch];
01098 }
01099
01100 static inline bool cstr_unescape_char(const char *&cstr, char &ch)
01101 {
01102 if (*cstr == '\\')
01103 {
01104 ++cstr;
01105
01106 switch (*cstr)
01107 {
01108 case '"': ch = '"'; break;
01109 case 't': ch = '\t'; break;
01110 case 'n': ch = '\n'; break;
01111 case '\\': ch = '\\'; break;
01112 case 'r': ch = '\r'; break;
01113 case 'a': ch = '\a'; break;
01114 case 'v': ch = '\v'; break;
01115 case 'b': ch = '\b'; break;
01116 case '0': ch = '\0'; break;
01117 case 'x':
01118 {
01119 int vals[2];
01120 int i;
01121 for (i=0; i<2; ++i)
01122 {
01123 if ((vals[i] = hex_digit_val(*++cstr)) == -1)
01124 return false;
01125 }
01126 ch = (vals[0] << 4) | vals[1];
01127 }
01128 break;
01129 default: return false;
01130 }
01131
01132 ++cstr;
01133
01134 return true;
01135 }
01136 else
01137 {
01138 ch = *cstr++;
01139 return true;
01140 }
01141 }
01142
01143 WvString cstr_escape(const void *data, size_t size,
01144 const CStrExtraEscape extra_escapes[])
01145 {
01146 if (!data) return WvString::null;
01147
01148 const char *cdata = (const char *)data;
01149
01150 WvString result;
01151 result.setsize(4*size + 3);
01152 char *cstr = result.edit();
01153
01154 *cstr++ = '\"';
01155 while (size-- > 0)
01156 {
01157 const char *esc = NULL;
01158 if (extra_escapes)
01159 {
01160 const CStrExtraEscape *extra = &extra_escapes[0];
01161 while (extra->ch && extra->esc)
01162 {
01163 if (*cdata == extra->ch)
01164 {
01165 esc = extra->esc;
01166 break;
01167 }
01168
01169 ++extra;
01170 }
01171 }
01172 if (!esc) esc = cstr_escape_char(*cdata);
01173 ++cdata;
01174 while (*esc) *cstr++ = *esc++;
01175 }
01176 *cstr++ = '\"';
01177 *cstr = '\0';
01178
01179 return result;
01180 }
01181
01182 bool cstr_unescape(WvStringParm cstr, void *data, size_t max_size, size_t &size,
01183 const CStrExtraEscape extra_escapes[])
01184 {
01185 const char *q = cstr;
01186 char *cdata = (char *)data;
01187
01188 if (!q) goto misformatted;
01189 size = 0;
01190
01191 for (;;)
01192 {
01193 while (isspace(*q)) q++;
01194 if (*q == '\0') break;
01195
01196 if (*q++ != '\"') goto misformatted;
01197 while (*q && *q != '\"')
01198 {
01199 bool found = false;
01200 char unesc;
01201 if (extra_escapes)
01202 {
01203 const CStrExtraEscape *extra = &extra_escapes[0];
01204 while (extra->ch && extra->esc)
01205 {
01206 size_t len = strlen(extra->esc);
01207 if (strncmp(extra->esc, q, len) == 0)
01208 {
01209 unesc = extra->ch;
01210 q += len;
01211 found = true;
01212 break;
01213 }
01214
01215 ++extra;
01216 }
01217 }
01218 if (!found && !cstr_unescape_char(q, unesc)) goto misformatted;
01219 if (size++ < max_size && cdata) *cdata++ = unesc;
01220 }
01221 if (*q++ != '\"') goto misformatted;
01222 }
01223
01224 return size <= max_size;
01225
01226 misformatted:
01227
01228 size = 0;
01229 return false;
01230 }
01231
01232 WvString local_date(time_t when)
01233 {
01234 WvString out;
01235 out.setsize(80);
01236
01237 if (when < 0)
01238 when = time(NULL);
01239
01240 struct tm *tmwhen = localtime(&when);
01241 strftime(out.edit(), 80, "%b %d %I:%M:%S %p", tmwhen);
01242
01243 return out;
01244 }
01245
01246 WvString intl_time(time_t when)
01247 {
01248 WvString out;
01249 out.setsize(12);
01250
01251 if (when < 0)
01252 when = time(NULL);
01253
01254 struct tm *tmwhen = localtime(&when);
01255 strftime(out.edit(), 12, "%H:%M:%S", tmwhen);
01256
01257 return out;
01258 }
01259
01260 WvString intl_date(time_t when)
01261 {
01262 WvString out;
01263 out.setsize(16);
01264
01265 if (when < 0)
01266 when = time(NULL);
01267
01268 struct tm *tmwhen = localtime(&when);
01269 strftime(out.edit(), 16, "%Y-%m-%d", tmwhen);
01270
01271 return out;
01272 }
01273
01274 WvString intl_datetime(time_t when)
01275 {
01276 WvString out;
01277 out.setsize(24);
01278
01279 if (when < 0)
01280 when = time(NULL);
01281
01282 struct tm *tmwhen = localtime(&when);
01283 strftime(out.edit(), 24, "%Y-%m-%d %H:%M:%S", tmwhen);
01284
01285 return out;
01286 }
01287
01288
01294 time_t intl_gmtoff(time_t t)
01295 {
01296 struct tm *l = localtime(&t);
01297 l->tm_isdst = 0;
01298 time_t local = mktime(l);
01299 time_t gmt = mktime(gmtime(&t));
01300
01301 return local-gmt;
01302 }
01303
01304
01305
01306 WvString depunctuate(WvStringParm line)
01307 {
01308 WvString ret = line;
01309 char * edit = ret.edit();
01310 int last = ret.len() - 1;
01311 if (edit[last] == '.' || edit[last] == '?' || edit[last] == '!')
01312 edit[last] = '\0';
01313
01314 return ret;
01315 }
01316
01317
01318 WvString ptr2str(void* ptr)
01319 {
01320 char buf[(sizeof(ptr) * 2) + 3];
01321 int rv;
01322
01323 rv = snprintf(buf, sizeof(buf), "%p", ptr);
01324
01325 assert(rv != -1);
01326
01327 return buf;
01328 }