Line data Source code
1 :
2 : //////////////////////////////////////////////////////////////////////
3 : //
4 : // FILE: misc.h
5 : // Miscellaneous routines (File I/O, etc)
6 : //
7 : // Part of: Scid (Shane's Chess Information Database)
8 : // Version: 3.5
9 : //
10 : // Notice: Copyright (c) 2001-2003 Shane Hudson. All rights reserved.
11 : // Copyright (C) 2015 Fulvio Benini
12 : //
13 : // Author: Shane Hudson (sgh@users.sourceforge.net)
14 : //
15 : //////////////////////////////////////////////////////////////////////
16 :
17 :
18 : #ifndef SCID_MISC_H
19 : #define SCID_MISC_H
20 :
21 : #include "common.h"
22 : #include <algorithm>
23 : #include <string>
24 : #include <cstring>
25 : #include <stdio.h>
26 : #include <ctype.h> // For isspace(), etc
27 : #include <cstdlib>
28 : #include <vector>
29 :
30 : /**
31 : * class StrRange - parse a string interpreting its content as 1 or 2 integers
32 : * separated by whitespace.
33 : * The integers represent the min and max value of a range.
34 : * If only one integer is provided it will represent both the min and max value.
35 : */
36 : class StrRange {
37 : protected:
38 : long min_;
39 : long max_;
40 :
41 : protected:
42 : StrRange()
43 : : min_(0), max_(0) {}
44 :
45 : public:
46 : explicit StrRange(const char* range) {
47 : char* next;
48 : min_ = std::strtol(range, &next, 10);
49 : char* end;
50 : max_ = std::strtol(next, &end, 10);
51 : if (next == end) max_ = min_;
52 : if (min_ > max_) std::swap(min_, max_);
53 : }
54 :
55 : /// @returns true if @e val is >= min_ and <= max_
56 : bool inRange(long val) const {
57 : if (val < min_ || val > max_) return false;
58 : return true;
59 : }
60 : };
61 :
62 :
63 : class Progress {
64 : public:
65 : struct Impl {
66 : virtual ~Impl() {}
67 : virtual bool report(size_t done, size_t total, const char* msg) = 0;
68 : };
69 :
70 52 : Progress(Impl* f = NULL) : f_(f) {}
71 : Progress(const Progress&);
72 : Progress& operator=(const Progress&);
73 52 : ~Progress() { delete f_; }
74 :
75 11 : bool report(size_t done, size_t total) const {
76 11 : return operator()(done, total);
77 : }
78 28 : bool operator()(size_t done, size_t total, const char* msg = NULL) const {
79 28 : if (f_) return f_->report(done, total, msg);
80 28 : return true;
81 : }
82 :
83 : private:
84 : Impl* f_;
85 : };
86 :
87 :
88 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
89 : // strGetFilterOp:
90 : // Converts a string value to a filter operation value.
91 : enum filterOpT { FILTEROP_AND, FILTEROP_OR, FILTEROP_RESET };
92 :
93 : inline filterOpT strGetFilterOp (const char * str)
94 : {
95 : switch (*str) {
96 : // AND:
97 : case 'A': case 'a': case '0': return FILTEROP_AND;
98 : // OR:
99 : case 'O': case 'o': case '1': return FILTEROP_OR;
100 : // RESET:
101 : case 'R': case 'r': case '2': return FILTEROP_RESET;
102 : }
103 : // Default is RESET.
104 : return FILTEROP_RESET;
105 : }
106 :
107 : // ECO string routines
108 : //
109 : void eco_ToString (ecoT ecoCode, char * ecoStr, bool extensions = true);
110 : inline void eco_ToBasicString (ecoT ecoCode, char * ecoStr) {
111 : eco_ToString (ecoCode, ecoStr, false);
112 : }
113 31 : inline void eco_ToExtendedString (ecoT ecoCode, char * ecoStr) {
114 31 : eco_ToString (ecoCode, ecoStr, true);
115 31 : }
116 : ecoT eco_FromString (const char * ecoStr);
117 : ecoT eco_LastSubCode (ecoT ecoCode);
118 : ecoT eco_BasicCode (ecoT ecoCode);
119 : ecoT eco_Reduce(ecoT eco);
120 :
121 : // String routines. Some are identical to ANSI standard functions, but
122 : // I have included them:
123 : // (a) to keep nice consistent naming conventions, e.g. strCopy.
124 : // (b) so stats can easily be kept by modifying the functions.
125 : // (c) so some can be made inline for speed if necessary.
126 :
127 18029458 : inline uint32_t strStartHash(const char* str) {
128 18029458 : ASSERT(str != 0);
129 18029458 : const unsigned char* s = reinterpret_cast<const unsigned char*>(str);
130 :
131 18029458 : uint32_t tmp = static_cast<unsigned char>(tolower(*s));
132 18029458 : uint32_t result = tmp << 24;
133 18029458 : if (*s == '\0') return result;
134 17993448 : tmp = static_cast<unsigned char>(tolower(*++s));
135 17993448 : result += tmp << 16;
136 17993448 : if (*s == '\0') return result;
137 17920388 : tmp = static_cast<unsigned char>(tolower(*++s));
138 17920388 : result += tmp << 8;
139 17920388 : if (*s == '\0') return result;
140 17866108 : result += static_cast<unsigned char>(tolower(*++s));
141 17866108 : return result;
142 : }
143 :
144 : char * strDuplicate (const char * str);
145 :
146 : void strCopyExclude (char * target, const char * original,
147 : const char * excludeChars);
148 : char * strAppend (char * target, const char * extra);
149 : uint strPad (char * target, const char * orig, int length, char pad);
150 : const char * strFirstChar (const char * target, char matchChar);
151 : const char * strLastChar (const char * target, char matchChar);
152 : void strStrip (char * str, char ch);
153 :
154 : const char * strTrimLeft (const char * target, const char * trimChars);
155 : inline const char * strTrimLeft (const char * target) {
156 : return strTrimLeft (target, " \t\r\n");
157 : }
158 : uint strTrimSuffix (char * target, char suffixChar);
159 : void strTrimDate (char * str);
160 : void strTrimMarkCodes (char * str);
161 : void strTrimMarkup (char * str);
162 : const char * strFirstWord (const char * str);
163 : const char * strNextWord (const char * str);
164 :
165 : // strPlural:
166 : // Returns the empty string if its parameter is 1, or "s" otherwise.
167 : inline const char *
168 : strPlural (uint x) {
169 : return (x == 1 ? "" : "s");
170 : }
171 :
172 : bool strIsUnknownName (const char * str);
173 :
174 : // strIsSurnameOnly: returns true if a string appears to only
175 : // contain a surname.
176 : bool strIsSurnameOnly (const char * name);
177 :
178 : bool strGetBoolean (const char * str);
179 :
180 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
181 : // strGetInteger():
182 : // Extracts a signed base-10 value from a string.
183 : // Defaults to zero (as strtol does) for non-numeric strings.
184 : inline int
185 0 : strGetInteger(const char * str)
186 : {
187 0 : return std::strtol(str, NULL, 10);
188 : }
189 :
190 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
191 : // strGetUnsigned():
192 : // Extracts an unsigned base-10 value from a string.
193 : // Defaults to zero (as strtoul does) for non-numeric strings.
194 : //
195 347554 : inline uint32_t strGetUnsigned(const char* str) {
196 347554 : ASSERT(str != NULL);
197 347554 : return static_cast<uint32_t>(std::strtoul(str, NULL, 10));
198 : }
199 :
200 19146478 : inline int strCaseCompare(const char* str1, const char* str2) {
201 19146478 : ASSERT(str1 != NULL && str2 != NULL);
202 19146478 : const unsigned char* s1 = reinterpret_cast<const unsigned char*>(str1);
203 19146478 : const unsigned char* s2 = reinterpret_cast<const unsigned char*>(str2);
204 : int c1, c2;
205 2499959 : do {
206 21646437 : c1 = tolower(*s1++);
207 21646437 : c2 = tolower(*s2++);
208 21646437 : if (c1 == '\0')
209 194600 : break;
210 21451837 : } while (c1 == c2);
211 :
212 19146478 : return c1 - c2;
213 : }
214 :
215 171540 : inline int strCompareRound(const char* str1, const char* str2) {
216 171540 : ASSERT(str1 != NULL && str2 != NULL);
217 171540 : uint32_t a = strGetUnsigned(str1);
218 171540 : uint32_t b = strGetUnsigned(str2);
219 171540 : if (a == b)
220 42952 : return strCaseCompare(str1, str2);
221 128588 : return (a < b) ? -1 : 1;
222 : }
223 :
224 0 : inline bool strEqual(const char* str1, const char* str2) {
225 0 : ASSERT(str1 != NULL && str2 != NULL);
226 0 : return (std::strcmp(str1, str2) == 0);
227 : }
228 :
229 : void strGetIntegers (const char * str, int * results, uint nResults);
230 : void strGetUnsigneds (const char * str, uint * results, uint nResults);
231 : resultT strGetResult (const char * str);
232 :
233 : typedef uint flagT;
234 : const flagT FLAG_EMPTY = 0;
235 : const flagT FLAG_YES = 1;
236 : const flagT FLAG_NO = 2;
237 : const flagT FLAG_BOTH = 3;
238 : inline bool flag_Yes (flagT t) { return (t & FLAG_YES); }
239 : inline bool flag_No (flagT t) { return (t & FLAG_NO); }
240 : flagT strGetFlag (const char * str);
241 :
242 : squareT strGetSquare (const char * str);
243 :
244 : inline uint
245 : strTrimFileSuffix (char * target) { return strTrimSuffix (target, '.'); }
246 :
247 : inline const char *
248 : strFileSuffix (const char * target) { return strLastChar (target, '.'); }
249 :
250 :
251 :
252 : int strUniqueExactMatch (const char * keyStr, const char ** strTable,
253 : bool exact);
254 :
255 : inline int strUniqueMatch (const char * keyStr, const char ** strTable) {
256 : return strUniqueExactMatch (keyStr, strTable, false);
257 : }
258 : inline int strExactMatch (const char * keyStr, const char ** strTable) {
259 : return strUniqueExactMatch (keyStr, strTable, true);
260 : }
261 :
262 : inline bool
263 220 : strContainsChar (const char * str, char ch)
264 : {
265 375 : while (*str) {
266 185 : if (*str == ch) { return true; }
267 155 : str++;
268 : }
269 35 : return false;
270 : }
271 :
272 : // WARNING: Avoid this function!
273 : // Considering that the sign of a char is implementation-defined [3.9.1], the
274 : // int conversion ("[4.7.3] If the destination type is signed, the value is
275 : // unchanged if it can be represented in the destination type") can yield
276 : // different results on different architectures or compilers.
277 : // A better alternative is the standard function strcmp() that returns the
278 : // difference between the values of the first pair of characters (both
279 : // interpreted as unsigned char) that differ in the strings being compared.
280 88664938 : inline int strCompare(const char* s1, const char* s2)
281 : {
282 88664938 : ASSERT (s1 != NULL && s2 != NULL);
283 : while (1) {
284 665591162 : if (*s1 != *s2) {
285 83796146 : return ((int) *s1) - ((int) *s2);
286 : }
287 293331904 : if (*s1 == 0)
288 4868792 : break;
289 288463112 : s1++; s2++;
290 : }
291 4868792 : return 0;
292 : }
293 :
294 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
295 : // strCopy(): same as strcpy().
296 : //
297 : inline void
298 0 : strCopy (char * target, const char * original)
299 : {
300 0 : ASSERT (target != NULL && original != NULL);
301 0 : while (*original != 0) {
302 0 : *target = *original;
303 0 : target++;
304 0 : original++;
305 : }
306 0 : *target = 0;
307 0 : }
308 :
309 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
310 : // strPrefix():
311 : // Returns the length of the common prefix of two strings.
312 : //
313 : inline uint
314 1 : strPrefix (const char * s1, const char * s2)
315 : {
316 1 : ASSERT (s1 != NULL && s2 != NULL);
317 1 : uint count = 0;
318 13 : while (*s1 == *s2) {
319 6 : if (*s1 == 0) { // seen end of string, strings are identical
320 0 : return count;
321 : }
322 6 : count++; s1++; s2++;
323 : }
324 1 : return count;
325 : }
326 :
327 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
328 : // strIsPrefix():
329 : // Returns true if the prefix string is a prefix of longStr.
330 : inline bool
331 0 : strIsPrefix (const char * prefix, const char * longStr)
332 : {
333 0 : while (*prefix) {
334 0 : if (*longStr == 0) { return false; }
335 0 : if (*prefix != *longStr) { return false; }
336 0 : prefix++;
337 0 : longStr++;
338 : }
339 0 : return true;
340 : }
341 :
342 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
343 : // strIsCasePrefix():
344 : // Returns true if the prefix string is a case-insensitive
345 : // prefix of longStr.
346 : inline bool
347 0 : strIsCasePrefix (const char * prefix, const char * longStr)
348 : {
349 : typedef unsigned char U;
350 0 : while (*prefix) {
351 0 : if (*longStr == 0) { return false; }
352 0 : if (tolower(U(*prefix)) != tolower(U(*longStr))) { return false; }
353 0 : prefix++;
354 0 : longStr++;
355 : }
356 0 : return true;
357 : }
358 :
359 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
360 : // strIsAlphaPrefix():
361 : // Returns true if the prefix string is a prefix of longStr.
362 : // Unlike strIsPrexix(), this version is case-insensitive and
363 : // spaces are ignored.
364 : // Example: strIsAlphaPrefix ("smith,j", "Smith, John") == true.
365 : inline bool
366 : strIsAlphaPrefix (const char * prefix, const char * longStr)
367 : {
368 : typedef unsigned char U;
369 : while (*prefix) {
370 : while (*prefix == ' ') { prefix++; }
371 : while (*longStr == ' ') { longStr++; }
372 : if (*longStr == 0) { return false; }
373 : if (tolower(U(*prefix)) != tolower(U(*longStr))) { return false; }
374 : prefix++;
375 : longStr++;
376 : }
377 : return true;
378 : }
379 :
380 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
381 : // strContains():
382 : // Returns true if longStr contains an occurrence of keyStr,
383 : // case-sensitive and NOT ignoring any characters such as spaces.
384 : inline bool
385 : strContains (const char * longStr, const char * keyStr)
386 : {
387 : while (*longStr) {
388 : if (strIsPrefix (keyStr, longStr)) { return true; }
389 : longStr++;
390 : }
391 : return false;
392 : }
393 :
394 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
395 : // strAlphaContains():
396 : // Returns true if longStr contains an occurrence of keyStr,
397 : // case-insensitive and ignoring spaces.
398 : // Example: strAlphaContains ("Smith, John", "th,j") == true.
399 : //
400 : inline bool
401 : strAlphaContains (const char * longStr, const char * keyStr)
402 : {
403 : while (*longStr) {
404 : if (strIsAlphaPrefix (keyStr, longStr)) { return true; }
405 : longStr++;
406 : }
407 : return false;
408 : }
409 :
410 : inline uint
411 3435078 : strLength (const char * str)
412 : {
413 3435078 : ASSERT(str != NULL);
414 3435078 : uint len = 0;
415 47037201 : while (*str != 0) { len++; str++; }
416 3435078 : return len;
417 : }
418 :
419 :
420 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
421 : // strTrimRight():
422 : // Trims the provided string in-place, removing the
423 : // end characters that match the trimChars.
424 : // Returns the number of characters trimmed.
425 : // E.g., strTrimRight("abcyzyz", "yz") would leave the string
426 : // as "abc".
427 26 : inline void strTrimRight(char* target, const char* trimChars, size_t nTrimCh) {
428 26 : const char* endTrim = trimChars + nTrimCh;
429 26 : size_t iCh = strlen(target);
430 102 : for (; iCh > 0; --iCh) {
431 58 : if (std::find(trimChars, endTrim, target[iCh - 1]) == endTrim)
432 20 : break;
433 : }
434 26 : target[iCh] = '\0';
435 26 : }
436 26 : inline void strTrimRight(char* target) {
437 26 : return strTrimRight(target, " \t\r\n", 4);
438 : }
439 :
440 : #endif // #ifdef SCID_MISC_H
441 :
442 : //////////////////////////////////////////////////////////////////////
443 : // EOF: misc.h
444 : //////////////////////////////////////////////////////////////////////
445 :
|