00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "Basics.H"
00024 #include "Text.H"
00025
00026
00027 static const char* const EmptyStr = "";
00028
00029 static const char *StrCopy(const char *str) throw ()
00030
00031 {
00032 int len = strlen(str) + 1;
00033 char *res = NEW_PTRFREE_ARRAY(char, len);
00034 memcpy(res, str, len);
00035 return res;
00036 }
00037
00038 static const char *StrCopy(const char *s, int len) throw ()
00039
00040
00041
00042 {
00043 char *res = NEW_PTRFREE_ARRAY(char, len+1);
00044 memcpy(res, s, len);
00045 res[len] = '\0';
00046 return res;
00047 }
00048
00049
00050 Text::Text() throw ()
00051 {
00052 this->s = EmptyStr;
00053 }
00054
00055 Text::Text(const char *str, void *copy) throw ()
00056 {
00057 this->s = (copy == (void *)NULL) ? StrCopy(str) : str;
00058 }
00059
00060 Text::Text(const char *bytes, int len) throw ()
00061 {
00062 this->s = StrCopy(bytes, len);
00063 }
00064
00065 Text Text::Sub(int start, int len) const throw ()
00066 {
00067 int tLen = Length();
00068 Text res;
00069 if (start >= tLen || len == 0) {
00070 res.s = EmptyStr;
00071 } else {
00072 if ((unsigned int)start + (unsigned int)len > tLen) {
00073
00074 len = tLen - start + 1;
00075 char *temp = NEW_PTRFREE_ARRAY(char, len);
00076 memcpy(temp, this->s + start, len);
00077 res.s = temp;
00078 } else {
00079
00080 char *temp = NEW_PTRFREE_ARRAY(char, len+1);
00081 memcpy(temp, this->s + start, len);
00082 temp[len] = '\0';
00083 res.s = temp;
00084 }
00085 }
00086 return res;
00087 }
00088
00089 int Text::FindChar(char c, int start) const throw ()
00090 {
00091 int tLen = Length();
00092 for (register int i = max(start, 0); i < tLen; i++) {
00093 if (this->s[i] == c) return i;
00094 }
00095 return -1;
00096 }
00097
00098 int Text::FindCharR(char c, int start) const throw ()
00099 {
00100 int tLen = Length();
00101 for (register int i = min(start, tLen - 1); i >= 0; i--) {
00102 if (this->s[i] == c) return i;
00103 }
00104 return -1;
00105 }
00106
00107 int Text::FindText(const Text &substr, int start) const throw ()
00108 {
00109 start = max(start, 0);
00110 if (start + substr.Length() > this->Length()) return -1;
00111 char *match = strstr(this->s + start, substr.s);
00112 if (match != (char *)NULL) return (match - this->s);
00113 return -1;
00114 }
00115
00116 const int
00117 N = sizeof(Word),
00118 ByteBits = 8,
00119 WordBits = N * 8;
00120
00121 Word RotateWord(Word w, int b) throw ()
00122
00123
00124 {
00125 b = (b % WordBits);
00126
00127
00128
00129
00130
00131 #if BYTE_ORDER == BIG_ENDIAN
00132 if (b < 0)
00133 {
00134 b = -b;
00135 Word hiMask = (((Word) -1) << b);
00136 Word loMask = (((Word) -1) ^ hiMask);
00137 w = ((w & loMask) << (WordBits - b)) | ((w & hiMask) >> b);
00138 }
00139 #else
00140
00141 if (b > 0)
00142 {
00143 Word hiMask = (((Word) -1) << (WordBits - b));
00144 Word loMask = (((Word) -1) ^ hiMask);
00145 w = ((w & loMask) << b) | ((w & hiMask) >> (WordBits - b));
00146 }
00147 #endif
00148
00149 return w;
00150 }
00151
00152 const int
00153 Up1 = ByteBits,
00154 LgUp1 = 3;
00155
00156 Word Text::Hash() const throw ()
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 {
00181 const PointerInt modNmask = (Word)N - 1UL;
00182 Word temp = 0UL;
00183 const char *p = this->s;
00184 Word m = (Word)strlen(p);
00185 const char *endp = p + m;
00186
00187 #if defined(VALGRIND_SUPPORT)
00188
00189
00190 char *temp_c = ((char *) &temp);
00191 for(unsigned int i = 0; i < m; i++)
00192 {
00193 temp_c[i % sizeof(temp)] ^= this->s[i];
00194 }
00195 return m + temp;
00196 #else
00197
00198 PointerInt jpre = (PointerInt)p & modNmask, jpost;
00199 if ((jpre != 0) && (p != endp))
00200 {
00201
00202
00203
00204 jpost = max(0, N - jpre - m);
00205
00206
00207
00208 temp = *((Word *)(p-jpre));
00209
00210
00211
00212
00213 #if BYTE_ORDER == BIG_ENDIAN
00214 temp <<= (jpre << LgUp1);
00215 temp >>= ((jpost + jpre) << LgUp1);
00216 #else
00217 temp >>= (jpre << LgUp1);
00218 temp <<= ((jpost + jpre) << LgUp1);
00219 #endif
00220
00221
00222
00223 p += (N - jpre - jpost);
00224 }
00225
00226
00227 while (p + N <= endp) {
00228 temp ^= *((Word *)p);
00229 p += N;
00230 }
00231
00232
00233 if (p != endp)
00234 {
00235
00236
00237 Word w = *((Word *)p);
00238
00239
00240
00241
00242 jpost = N - (endp - p);
00243 Word jpostUp1 = (jpost << LgUp1);
00244
00245
00246
00247
00248
00249 #if BYTE_ORDER == BIG_ENDIAN
00250 w >>= jpostUp1;
00251 temp = RotateWord(temp, -jpostUp1);
00252 #else
00253 w <<= jpostUp1;
00254 temp = RotateWord(temp, jpostUp1);
00255 #endif
00256
00257
00258
00259 temp ^= w;
00260 }
00261
00262
00263
00264
00265
00266
00267 #if BYTE_ORDER == BIG_ENDIAN
00268 return m + RotateWord(temp, -(m << LgUp1));
00269 #else
00270 return m + RotateWord(temp, (m << LgUp1));
00271 #endif
00272
00273 #endif // SAFE_HASH
00274 }
00275
00276 Text Text::WordWrap(const Text &prefix, unsigned int columns)
00277 const throw ()
00278 {
00279 Text result = prefix;
00280 unsigned int line_len = result.Length();
00281 const char *read_p = s;
00282
00283
00284 while(*read_p)
00285 {
00286
00287 const char *next_word_start = read_p, *next_word_end;
00288 while(*next_word_start && isspace(*next_word_start))
00289 next_word_start++;
00290 next_word_end = next_word_start;
00291 while(*next_word_end && !isspace(*next_word_end))
00292 next_word_end++;
00293
00294
00295
00296 if((line_len + (next_word_end - read_p)) > columns)
00297 {
00298
00299
00300 unsigned int next_word_len = (next_word_end - next_word_start);
00301 result += (Text("\n") + prefix +
00302 Text(next_word_start, next_word_len));
00303 line_len = prefix.Length() + next_word_len;
00304 }
00305
00306
00307 else
00308 {
00309 unsigned int added_len = (next_word_end - read_p);
00310 result += Text(read_p, added_len);
00311 line_len += added_len;
00312 }
00313
00314
00315 read_p = next_word_end;
00316 }
00317
00318
00319 return result;
00320 }
00321
00322
00323
00324
00325
00326 static void PaddingCopies(unsigned int baseLen,
00327 unsigned int finalLen,
00328 unsigned int padLen,
00329 unsigned int &copies,
00330 unsigned int &partial,
00331 char *&dest)
00332 {
00333 assert(padLen > 0);
00334 unsigned int needed = (finalLen > baseLen) ? (finalLen - baseLen) : 0;
00335 copies = needed/padLen;
00336 partial = needed - (copies*padLen);
00337 unsigned int totalLen = baseLen + (copies*padLen) + partial;
00338 assert(totalLen >= finalLen);
00339 dest = NEW_PTRFREE_ARRAY(char, totalLen+1);
00340 *dest = 0;
00341 }
00342
00343
00344
00345
00346 static void CopyPadding(unsigned int copies, unsigned int partial,
00347 char *dest, const Text &padding)
00348 {
00349 while(copies > 0)
00350 {
00351 strcat(dest, padding.cchars());
00352 copies--;
00353 }
00354 if(partial)
00355 {
00356 strncat(dest, padding.cchars(), partial);
00357 }
00358 }
00359
00360 Text Text::PadLeft(unsigned int toLen, const Text &padding)
00361 const throw()
00362 {
00363
00364 unsigned int copies, partial;
00365 char *dest;
00366 PaddingCopies(this->Length(), toLen, padding.Length(),
00367 copies, partial, dest);
00368
00369
00370 CopyPadding(copies, partial, dest, padding);
00371
00372 strcat(dest, this->s);
00373
00374 Text res;
00375 res.s = dest;
00376 return res;
00377 }
00378
00379 Text Text::PadRight(unsigned int toLen, const Text &padding)
00380 const throw()
00381 {
00382 unsigned int copies, partial;
00383 char *dest;
00384 PaddingCopies(this->Length(), toLen, padding.Length(),
00385 copies, partial, dest);
00386
00387
00388 strcat(dest, this->s);
00389
00390 CopyPadding(copies, partial, dest, padding);
00391
00392 Text res;
00393 res.s = dest;
00394 return res;
00395 }