Scid  4.6.5
misc.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////
2 //
3 // FILE: misc.cpp
4 // Miscellaneous routines (File I/O, etc)
5 //
6 // Part of: Scid (Shane's Chess Information Database)
7 // Version: 3.5
8 //
9 // Notice: Copyright (c) 2001-2003 Shane Hudson. All rights reserved.
10 //
11 // Author: Shane Hudson (sgh@users.sourceforge.net)
12 //
13 //////////////////////////////////////////////////////////////////////
14 
15 #include "common.h"
16 #include "misc.h"
17 #include "sqmove.h"
18 #include <stdio.h>
19 #include <ctype.h> // For isspace() function.
20 #include <sys/stat.h> // Needed for fileSize() function.
21 #include <cmath>
22 
23 // Table of direction between any two chessboard squares
24 directionT sqDir[66][66];
25 struct sqDir_Init
26 {
28  // Initialise the sqDir[][] array of directions between every pair
29  // of squares.
30  squareT i, j;
31  directionT dirArray[] = { UP, DOWN, LEFT, RIGHT, UP_LEFT, UP_RIGHT,
33  // First, set everything to NULL_DIR:
34  for (i=A1; i <= NS; i++) {
35  for (j=A1; j <= NS; j++) {
36  sqDir[i][j] = NULL_DIR;
37  }
38  }
39  // Now fill in the valid directions:
40  for (i=A1; i <= H8; i++) {
41  directionT * dirptr = dirArray;
42  while (*dirptr != NULL_DIR) {
43  j = square_Move (i, *dirptr);
44  while (j != NS) {
45  sqDir[i][j] = *dirptr;
46  j = square_Move (j, *dirptr);
47  }
48  dirptr++;
49  }
50  }
51  }
53 
54 //////////////////////////////////////////////////////////////////////
55 // ECO Code Routines
56 
57 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
58 // eco_FromString():
59 // Extract an ECO code from a string.
60 //
61 // Eco code numbering: no eco = 0, A00 = 1, A01 = 132, etc.
62 // That is, each basic ECO code = previous + 131.
63 // The extra 130 subcodes are the extended code:
64 // a, a1, a2, a3, a4, b, b1, .... z, z1, z2, z3, z4. (130 in total).
65 //
66 // Improvement, March 2000: now case-insensitive for first letter,
67 // for example, a41 == A41.
68 ecoT
69 eco_FromString (const char * ecoStr)
70 {
71  ecoT eco = ECO_None;
72  // Get the basic Eco code from the first 3 characters: they MUST be in
73  // the range "A00" to "E99" or the eco code will be considered empty.
74  // Changed, June 1999: now accepts partial ECO codes, e.g. "C1" -> C10
75 
76  if (*ecoStr >= 'A' && *ecoStr <= 'E') {
77  eco = (*ecoStr - 'A') * 13100;
78  } else if (*ecoStr >= 'a' && *ecoStr <= 'e') {
79  eco = (*ecoStr - 'a') * 13100;
80  } else {
81  return 0;
82  }
83  ecoStr++;
84  if (! *ecoStr) { return eco + 1; }
85 
86  if (*ecoStr < '0' || *ecoStr > '9') { return 0; }
87  eco += (*ecoStr - '0') * 1310;
88  ecoStr++;
89  if (! *ecoStr) { return eco + 1; }
90 
91  if (*ecoStr < '0' || *ecoStr > '9') { return 0; }
92  eco += (*ecoStr - '0') * 131;
93  ecoStr++;
94 
95  // Now check for the optional extended code: a, a1, ... z2, z3, z4.
96  if (*ecoStr >= 'a' && *ecoStr <= 'z') {
97  eco++;
98  eco += (*ecoStr - 'a') * 5;
99  ecoStr++;
100  if (*ecoStr >= '1' && *ecoStr <= '4') {
101  eco += *ecoStr - '0';
102  }
103  }
104  return eco + 1;
105 }
106 
107 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108 // eco_ToString():
109 // Convert an ECO code to its string representation.
110 void
111 eco_ToString (ecoT ecoCode, char * ecoStr, bool extensions)
112 {
113  char * s = ecoStr;
114  if (ecoCode == ECO_None) { *s = 0; return; }
115  ecoCode--;
116 
117  // First the base code value:
118 
119  ecoT basicCode = ecoCode / 131; // 131 = 26 * 5 + 1 subcodes.
120  *s++ = basicCode / 100 + 'A';
121  *s++ = (basicCode % 100) / 10 + '0';
122  *s++ = (basicCode % 10) + '0';
123 
124  // Now the optional extensions:
125  if (extensions) {
126  ecoCode = ecoCode % 131;
127  if (ecoCode > 0) {
128  ecoCode--;
129  *s++ = (ecoCode / 5) + 'a';
130  ecoCode = ecoCode % 5;
131  if (ecoCode > 0) { *s++ = (ecoCode + '0'); }
132  }
133  *s = 0;
134  }
135  return;
136 }
137 
138 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
139 // eco_BasicCode():
140 // Converts an ECO code to its basic form, without any
141 // Scid-specific extensions.
142 ecoT
144 {
145  if (eco == ECO_None) { return ECO_None; }
146 
147  eco--;
148  eco /= 131;
149  eco *= 131;
150  return eco + 1;
151 }
152 
153 /**
154  * ecoReduce() - maps eco to a smaller set
155  * @eco: the eco value to convert (must be != 0)
156  *
157  * Scid ECO subcodes use 131 values for each canonical ECO.
158  * For example A00 is divided in A00,A00a,A00a1,A00a2,A00a3,A00a4,A00b...A00z4
159  * corresponding to eco values 1,2,3,4,5,6,7...131 (value 0 means no ECO).
160  * This functions will map subECOs like A00a1...A00a4 into A00a, reducing
161  * the 131 values to 27. The previous sequence will became 0,1,1,1,1,1,2...26
162  */
164  ASSERT(eco != 0);
165 
166  eco--;
167  ecoT res = (eco / 131) * 27;
168  return res + static_cast<ecoT>(std::ceil((eco % 131) / 5.0));
169 }
170 
171 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
172 // eco_LastSubCode():
173 // Converts an ECO code to the deepest subcode it could contain.
174 // Examples: B91a -> B91a4 and B91 -> B91z4.
175 ecoT
177 {
178  if (eco == ECO_None) { return ECO_None; }
179 
180  // if just a basic ECO code (1 letter, 2 digits), add the "z":
181  eco--;
182  if ((eco % 131) == 0) { eco += 126; } // 126 = 5 * 25 + 1.
183 
184  // Now if no final digit, add the "4":
185  if (((eco % 131) % 5) == 1) { eco += 4; }
186  return eco + 1;
187 }
188 
189 //////////////////////////////////////////////////////////////////////
190 // String Routines
191 
192 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
193 // strCopyExclude(): copies original to target, filtering out any
194 // characters in excludeChars.
195 void
196 strCopyExclude (char * target, const char * original,
197  const char * excludeChars)
198 {
199  while (*original != 0) {
200  int exclude = 0;
201  for (char * s = (char *) excludeChars; *s; s++) {
202  if (*original == *s) {
203  exclude = 1;
204  break;
205  }
206  }
207  if (!exclude) {
208  *target = *original;
209  target++;
210  }
211  original++;
212  }
213  *target = 0;
214 }
215 
216 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
217 // strAppend():
218 // Appends extra to the end of target, and returns a pointer
219 // to the new END of the string target.
220 //
221 char *
222 strAppend (char * target, const char * extra)
223 {
224  ASSERT (target != NULL && extra != NULL);
225  while (*target != 0) { target++; } // get to end of target string
226  while (*extra != 0) {
227  *target = *extra;
228  target++;
229  extra++;
230  }
231  *target = 0;
232  return target;
233 }
234 
235 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
236 // strDuplicate(): Duplicates a string using new[] operator.
237 //
238 char *
239 strDuplicate (const char * original)
240 {
241  ASSERT (original != NULL);
242  char * newStr = new char [strLength(original) + 1];
243  if (newStr == NULL) return NULL;
244  char *s = newStr;
245  while (*original != 0) {
246  *s = *original;
247  s++; original++;
248  }
249  *s = 0; // Add trailing '\0'.
250  //printf ("Dup: %p: %s\n", newStr, newStr);
251  return newStr;
252 }
253 
254 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
255 // strPad():
256 // Copies original string to target, but copies *exactly* 'width'
257 // bytes. If the original is longer than specified width, not all of
258 // original will be copied to target. If original is shorter, then
259 // target will be padded out to 'width' bytes with the padding char.
260 //
261 // If the width is negative, no trimming or padding is done and
262 // the result is just a regular string copy.
263 //
264 // The return value is the length copied: always 'width' if
265 // width is >= 0, or the length of original if 'width' is negative.
266 //
267 uint
268 strPad (char * target, const char * original, int width, char padding)
269 {
270  ASSERT (target != NULL && original != NULL);
271  if (width < 0) {
272  strCopy (target, original);
273  return strLength (original);
274  }
275  int len = width;
276  while (len > 0) {
277  if (*original == 0) {
278  break;
279  }
280  *target = *original;
281  target++;
282  original++;
283  len--;
284  }
285  while (len--) { *target++ = padding; }
286  *target = 0;
287  return width;
288 }
289 
290 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
291 // strFirstChar():
292 // Returns the pointer into the provided string where the
293 // FIRST occurrence of matchChar is, or NULL if the string
294 // does not contain matchChar at all.
295 // Equivalent to strchr().
296 const char *
297 strFirstChar (const char * target, char matchChar)
298 {
299  const char * s = target;
300  while (*s != 0) {
301  if (*s == matchChar) { return s; }
302  s++;
303  }
304  return NULL;
305 }
306 
307 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
308 // strLastChar():
309 // Returns the pointer into the provided string where the
310 // LAST occurrence of matchChar is, or NULL if the string
311 // does not contain matchChar at all.
312 // Equivalent to strrchr().
313 const char *
314 strLastChar (const char * target, char matchChar)
315 {
316  const char * s = target;
317  const char * last = NULL;
318  while (*s != 0) {
319  if (*s == matchChar) { last = s; }
320  s++;
321  }
322  return last;
323 }
324 
325 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
326 // strStrip():
327 // Removes all occurrences of the specified char from the string.
328 void
329 strStrip (char * str, char ch)
330 {
331  char * s = str;
332  while (*str != 0) {
333  if (*str != ch) {
334  if (s != str) { *s = *str; }
335  s++;
336  }
337  str++;
338  }
339  *s = 0;
340 }
341 
342 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
343 // strTrimLeft():
344 // Returns the pointer into the provided string where the first
345 // character that does NOT equal a trimChar occurs.
346 const char *
347 strTrimLeft (const char * target, const char * trimChars)
348 {
349  const char * s = target;
350  while (*s != 0) {
351  if (! strContainsChar (trimChars, *s)) { break; }
352  s++;
353  }
354  return s;
355 }
356 
357 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
358 // strTrimSuffix():
359 // Trims the provided string in-place, at the last
360 // occurrence of the provided suffix character.
361 // Returns the number of characters trimmed.
362 // E.g., strTrimSuffix ("file.txt", '.') would leave the
363 // string as "file" and return 4.
364 uint
365 strTrimSuffix (char * target, char suffixChar)
366 {
367  uint trimCount = 0;
368  char * lastSuffixPtr = NULL;
369  char * s = target;
370  while (*s) {
371  if (*s == suffixChar) {
372  lastSuffixPtr = s;
373  trimCount = 0;
374  }
375  trimCount++;
376  s++;
377  }
378  if (lastSuffixPtr == NULL) { return 0; }
379  *lastSuffixPtr = 0;
380  return trimCount;
381 }
382 
383 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
384 // strTrimDate():
385 // Takes a date string ("xxxx.xx.xx" format) and trims
386 // the day part if it is ".??", and also the month part
387 // if it too is ".??".
388 void
389 strTrimDate (char * str)
390 {
391  if (str[7] == '.' && str[8] == '?' && str[9] == '?') {
392  str[7] = 0;
393  if (str[4] == '.' && str[5] == '?' && str[6] == '?') {
394  str[4] = 0;
395  }
396  }
397 }
398 
399 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
400 // strTrimMarkCodes():
401 // Trims in-place all Scid-recognised board mark codes
402 // in a comment string, such as "[%mark ...]" and "[%arrow ...]"
403 void
404 strTrimMarkCodes (char * str)
405 {
406  char * in = str;
407  char * out = str;
408  bool inCode = false;
409  char * startLocation = NULL;
410 
411  while (1) {
412  char ch = *in;
413  if (inCode) {
414  // If we see end-of-string or code-starting '[', there is some
415  // error so go back to the start of this code and treat it
416  // normally.
417  if (ch == 0 || ch == '[') {
418  *out++ = *startLocation;
419  inCode = false;
420  in = startLocation;
421  } else if (ch == ']') {
422  // See a code-ending ']', so end the code.
423  inCode = false;
424  }
425  // For all other characters in a code, just ignore it.
426  } else {
427  // Stop at end-of-string:
428  if (ch == 0) { break; }
429  // Look for the start of a code that is to be stripped:
430  if (ch == '[' && in[1] == '%') {
431  inCode = true;
432  startLocation = in;
433  } else {
434  *out++ = ch;
435  }
436  }
437  in++;
438  }
439  // Terminate the modified string:
440  *out = 0;
441 }
442 
443 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
444 // strTrimMarkup():
445 // Trims in-place all HTML-like markup codes (<b>, </i>, etc)
446 // from the provided string.
447 void
448 strTrimMarkup (char * str)
449 {
450  char * in = str;
451  char * out = str;
452  bool inTag = false;
453 
454  while (*in != 0) {
455  char ch = *in;
456  if (inTag) {
457  if (ch == '>') { inTag = false; }
458  } else {
459  if (ch == '<') { inTag = true; } else { *out++ = ch; }
460  }
461  in++;
462  }
463  *out = 0;
464 }
465 
466 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
467 // strTrimSurname():
468 // Trims a person name string to contain only the
469 // surname, or only the surname and a maximum number
470 // of initials.
471 void
472 strTrimSurname (char * str, uint initials)
473 {
474  char * in = str;
475  char * out = str;
476  bool seenComma = false;
477 
478  while (*in != 0) {
479  char ch = *in;
480  if (seenComma) {
481  if (isupper(ch)) {
482  *out++ = ch;
483  initials--;
484  if (initials == 0) { break; }
485  }
486  } else {
487  if (ch == ',') {
488  seenComma = true;
489  if (initials == 0) { break; }
490  }
491  *out++ = ch;
492  }
493  in++;
494  }
495  *out = 0;
496 }
497 
498 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
499 // strFirstWord:
500 // Skips over all whitespace at the start of the
501 // string to reach the first word.
502 const char *
503 strFirstWord (const char * str)
504 {
505  ASSERT (str != NULL);
506  while (*str != 0 && isspace(*str)) { str++; }
507  return str;
508 }
509 
510 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
511 // strNextWord:
512 // Skips over all successive non-whitespace characters
513 // in the string, then all successive whitespace chars,
514 // to reach the next word in the string.
515 const char *
516 strNextWord (const char * str)
517 {
518  ASSERT (str != NULL);
519  while (*str != 0 && !isspace(*str)) { str++; }
520  while (*str != 0 && isspace(*str)) { str++; }
521  return str;
522 }
523 
524 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
525 // strIsAllWhitespace():
526 // Returns true if the string contains only whitespace characters.
527 bool
528 strIsAllWhitespace (const char * str)
529 {
530  while (*str != 0) {
531  if (! isspace(*str)) { return false; }
532  str++;
533  }
534  return true;
535 }
536 
537 
538 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
539 // strIsUnknownName():
540 // Returns true if the string is an "unknown" name: the empty
541 // string, "?" or "-". Used primarily to test if an event, site
542 // or round name string contains information worth printing.
543 bool
544 strIsUnknownName (const char * str)
545 {
546  if (str[0] == 0) { return true; }
547  if (str[0] == '-' && str[1] == 0) { return true; }
548  if (str[0] == '?' && str[1] == 0) { return true; }
549  return false;
550 }
551 
552 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
553 // strIsSurnameOnly():
554 // Returns true if the name appears to be a surname only.
555 bool
556 strIsSurnameOnly (const char * name)
557 {
558  uint capcount = 0;
559  const char * s = name;
560  while (*s != 0) {
561  unsigned char c = *s;
562  if (! isalpha(c)) { return false; }
563  if (isupper(c)) {
564  capcount++;
565  if (capcount > 1) { return false; }
566  }
567  s++;
568  }
569  return true;
570 }
571 
572 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
573 // strGetBoolean():
574 // Extracts a boolean value from a string.
575 // True strings start with one of "TtYy1", false strings with
576 // one of "FfNn0".
577 // Returns false if the string does not contain a boolean value.
578 bool
579 strGetBoolean (const char * str)
580 {
581  static const char * sTrue[] = {
582  "true", "yes", "on", "1", "ja", "si", "oui", NULL
583  };
584  static const char * sFalse[] = {
585  "false", "no", "off", "0", NULL
586  };
587  if (str[0] == 0) { return false; }
588 
589  bool matchedTrue = false;
590  bool matchedFalse = false;
591 
592  const char ** next = sTrue;
593  while (*next != NULL) {
594  if (strIsCasePrefix (str, *next) || strIsCasePrefix (*next, str)) {
595  matchedTrue = true;
596  }
597  next++;
598  }
599  next = sFalse;
600  while (*next != NULL) {
601  if (strIsCasePrefix (str, *next) || strIsCasePrefix (*next, str)) {
602  matchedFalse = true;
603  }
604  next++;
605  }
606  if (matchedTrue && !matchedFalse) { return true; }
607  if (matchedFalse && !matchedTrue) { return false; }
608 
609  // default: return false.
610  return false;
611 }
612 
613 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
614 // strGetIntegers:
615 // Extracts the specified number of signed integers in a
616 // whitespace-separated string to an array.
617 void
618 strGetIntegers (const char * str, int * results, uint nResults)
619 {
620  for (uint i=0; i < nResults; i++) {
621  while (*str != 0 && isspace(*str)) { str++; }
622  results[i] = strGetInteger (str);
623  while (*str != 0 && !isspace(*str)) { str++; }
624  }
625 }
626 
627 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
628 // strGetUnsigneds:
629 // Extracts the specified number of unsigned integers in a
630 // whitespace-separated string to an array.
631 void
632 strGetUnsigneds (const char * str, uint * results, uint nResults)
633 {
634  for (uint i=0; i < nResults; i++) {
635  while (*str != 0 && isspace(*str)) { str++; }
636  results[i] = strGetUnsigned (str);
637  while (*str != 0 && !isspace(*str)) { str++; }
638  }
639 }
640 
641 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
642 // strGetResult:
643 // Extracts a game result value from a string.
644 resultT
645 strGetResult (const char * str)
646 {
647  switch (*str) {
648  case '1':
649  // Check for "1/2"-style draw result:
650  if (str[1] == '/' && str[2] == '2') {
651  return RESULT_Draw;
652  }
653  return RESULT_White;
654  case '=': return RESULT_Draw;
655  case '0': return RESULT_Black;
656  case '*': return RESULT_None;
657  }
658  return RESULT_None;
659 }
660 
661 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
662 // strGetFlag():
663 // Extracts a flag (FLAG_YES, FLAG_NO or FLAG_BOTH) value from
664 // a string. Defaults to FLAG_EMPTY.
665 flagT
666 strGetFlag (const char * str)
667 {
668  char c = *str;
669  switch (c) {
670  case 'T': case 't':
671  case 'Y': case 'y':
672  case 'J': case 'j':
673  case 'O': case 'o':
674  case 'S': case 's':
675  case '1':
676  return FLAG_YES;
677  case 'F': case 'f':
678  case 'N': case 'n':
679  case '0':
680  return FLAG_NO;
681  case 'B': case 'b':
682  case '2':
683  return FLAG_BOTH;
684  }
685  // default: return empty.
686  return FLAG_EMPTY;
687 }
688 
689 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
690 // strGetSquare():
691 // Extracts a square value from a string, such as "a2".
692 squareT
693 strGetSquare (const char * str)
694 {
695  char chFyle = str[0];
696  if (chFyle < 'a' || chFyle > 'h') { return NULL_SQUARE; }
697  char chRank = str[1];
698  if (chRank < '1' || chRank > '8') { return NULL_SQUARE; }
699  return square_Make (fyle_FromChar(chFyle), rank_FromChar(chRank));
700 }
701 
702 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
703 // strUniqueExactMatch():
704 // Given a string <keyStr> and a null-terminated array of strings
705 // <strTable>, returns the index of the unique match of the key
706 // string in the string table. If no match was found, or there was
707 // more than one match, -1 is returned.
708 //
709 // If the flag <exact> is true, only complete matches are considered.
710 // Otherwise, unique abbreviations are accepted.
711 // Example: looking up "repl" in {"repeat", "replace", NULL} would
712 // return 1 (matching "replace") but looking up "rep" would
713 // return -1 because its match is ambiguous.
714 //
715 // The array "strTable" does NOT need to be in any order, but the last
716 // entry must be NULL.
717 int
718 strUniqueExactMatch (const char * keyStr, const char ** strTable, bool exact)
719 {
720  int index = -1;
721  int abbrevMatches = 0;
722  const char * s1;
723  const char * s2;
724  const char ** entryPtr = strTable;
725 
726  // If keyStr or strTable are null, return no match:
727  if (keyStr == NULL || strTable == NULL) { return -1; }
728 
729  // Check each entry in turn:
730  for (int i=0; *entryPtr != NULL; entryPtr++, i++) {
731  // Check the key against this entry, character by character:
732  for (s1 = keyStr, s2 = *entryPtr; *s1 == *s2; s1++, s2++) {
733  // If *s1 is 0, we found an EXACT match, so return it now:
734  if (*s1 == 0) {
735  return i;
736  }
737  }
738  // If *s1 == 0 now, key is an abbreviation of this entry:
739  if (*s1 == 0) {
740  index = i;
741  abbrevMatches++;
742  }
743  }
744 
745  // If we reach here, there is no exact match. If an exact match was
746  // required, or there is not exactly one abbreviation, return no match:
747  if (exact || abbrevMatches != 1) {
748  return -1;
749  }
750  // Otherwise, return the match found:
751  return index;
752 }
753 
754 
755 //////////////////////////////////////////////////////////////////////
756 // FILE I/O Routines
757 
758 
759 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
760 // fileSize():
761 // Computes the plain (uncompressed) size of the named file,
762 // using one of the other FileSize functions here.
763 uint
764 fileSize (const char * name, const char * suffix)
765 {
766  fileNameT fname;
767  strCopy (fname, name);
768  strAppend (fname, suffix);
769  const char * lastSuffix = strFileSuffix (fname);
770  if (lastSuffix != NULL && strEqual (lastSuffix, GZIP_SUFFIX)) {
771  return gzipFileSize (fname);
772  }
773  return rawFileSize (fname);
774 }
775 
776 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
777 // rawFileSize():
778 // Uses the stat() system call to get the size of the file.
779 // Returns 0 if any error occurs.
780 uint
781 rawFileSize (const char * name)
782 {
783  struct stat statBuf; // Defined in <sys/stat.h>
784  if (stat (name, &statBuf) != 0) {
785  return 0;
786  }
787  return (uint) statBuf.st_size;
788 }
789 
790 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
791 // gzipFileSize():
792 // Returns the UNCOMPRESSED size of a .gz file.
793 // This is stored the final 4 bytes, in little endian format.
794 // Returns 0 if any error occurs.
795 uint
796 gzipFileSize (const char * name)
797 {
798  FILE * fp;
799  fp = fopen (name, "rb");
800  if (fp == NULL) { return 0; }
801  // Seek to 4 bytes from the end:
802  if (fseek (fp, -4L, SEEK_END) != 0) {
803  fclose (fp);
804  return 0;
805  }
806  // Read the 4-byte number in little-endian format:
807  uint size = 0;
808  uint b0 = (uint) getc(fp);
809  uint b1 = (uint) getc(fp);
810  uint b2 = (uint) getc(fp);
811  uint b3 = (uint) getc(fp);
812  size = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
813  fclose (fp);
814  return size;
815 }
816 
817 //////////////////////////////////////////////////////////////////////
818 // EOF: misc.cpp
819 //////////////////////////////////////////////////////////////////////
820 
bool strIsAllWhitespace(const char *str)
Definition: misc.cpp:528
fyleT fyle_FromChar(char c)
Definition: common.h:368
void eco_ToString(ecoT ecoCode, char *ecoStr, bool extensions)
Definition: misc.cpp:111
byte resultT
Definition: common.h:183
uint strLength(const char *str)
Definition: misc.h:492
const char * strTrimLeft(const char *target, const char *trimChars)
Definition: misc.cpp:347
const directionT UP
Definition: common.h:547
struct sqDir_Init sqDir_Init_singleton
squareT square_Move(squareT sq, directionT dir)
Definition: sqmove.h:173
bool strEqual(const char *str1, const char *str2)
Definition: misc.h:305
const char * strFirstChar(const char *target, char matchChar)
Definition: misc.cpp:297
int strUniqueExactMatch(const char *keyStr, const char **strTable, bool exact)
Definition: misc.cpp:718
void strTrimSurname(char *str, uint initials)
Definition: misc.cpp:472
const squareT NULL_SQUARE
Definition: common.h:352
const ecoT ECO_None
Definition: common.h:164
char * strDuplicate(const char *original)
Definition: misc.cpp:239
const directionT LEFT
Definition: common.h:549
ecoT eco_LastSubCode(ecoT eco)
Definition: misc.cpp:176
#define ASSERT(f)
Definition: common.h:67
const directionT UP_LEFT
Definition: common.h:551
const resultT RESULT_Black
Definition: common.h:187
names
Definition: tablebase.tcl:260
squareT strGetSquare(const char *str)
Definition: misc.cpp:693
void strTrimMarkCodes(char *str)
Definition: misc.cpp:404
uint fileSize(const char *name, const char *suffix)
Definition: misc.cpp:764
const char * strFileSuffix(const char *target)
Definition: misc.h:329
const flagT FLAG_BOTH
Definition: misc.h:318
uint strTrimSuffix(char *target, char suffixChar)
Definition: misc.cpp:365
const resultT RESULT_Draw
Definition: common.h:188
const directionT RIGHT
Definition: common.h:550
uint flagT
Definition: misc.h:314
const char GZIP_SUFFIX[]
Definition: common.h:55
const squareT A1
Definition: common.h:343
squareT square_Make(fyleT f, rankT r)
Definition: common.h:372
const flagT FLAG_NO
Definition: misc.h:317
ecoT eco_Reduce(ecoT eco)
ecoReduce() - maps eco to a smaller set : the eco value to convert (must be != 0) ...
Definition: misc.cpp:163
const directionT UP_RIGHT
Definition: common.h:552
uint strPad(char *target, const char *original, int width, char padding)
Definition: misc.cpp:268
sizew
Definition: board.tcl:619
bool strIsCasePrefix(const char *prefix, const char *longStr)
Definition: misc.h:428
const resultT RESULT_White
Definition: common.h:186
uint32_t uint
Definition: common.h:99
bool strIsSurnameOnly(const char *name)
Definition: misc.cpp:556
bool strIsUnknownName(const char *str)
Definition: misc.cpp:544
void strGetIntegers(const char *str, int *results, uint nResults)
Definition: misc.cpp:618
rankT rank_FromChar(char c)
Definition: common.h:364
const squareT H8
Definition: common.h:350
int strGetInteger(const char *str)
Definition: misc.h:266
bool strContainsChar(const char *str, char ch)
Definition: misc.h:344
ushort ecoT
Definition: common.h:161
uint32_t strGetUnsigned(const char *str)
Definition: misc.h:276
const directionT NULL_DIR
Definition: common.h:546
const char * strNextWord(const char *str)
Definition: misc.cpp:516
char * strAppend(char *target, const char *extra)
Definition: misc.cpp:222
void strTrimMarkup(char *str)
Definition: misc.cpp:448
const char * strFirstWord(const char *str)
Definition: misc.cpp:503
void strCopyExclude(char *target, const char *original, const char *excludeChars)
Definition: misc.cpp:196
const directionT DOWN
Definition: common.h:548
flagT strGetFlag(const char *str)
Definition: misc.cpp:666
void strCopy(char *target, const char *original)
Definition: misc.h:379
const flagT FLAG_EMPTY
Definition: misc.h:315
ecoT eco_FromString(const char *ecoStr)
Definition: misc.cpp:69
const flagT FLAG_YES
Definition: misc.h:316
char fileNameT[512]
Definition: common.h:141
resultsreportType fmt
Definition: optable.tcl:642
byte directionT
Definition: common.h:114
resultT strGetResult(const char *str)
Definition: misc.cpp:645
ecoT eco_BasicCode(ecoT eco)
Definition: misc.cpp:143
bool strGetBoolean(const char *str)
Definition: misc.cpp:579
void strGetUnsigneds(const char *str, uint *results, uint nResults)
Definition: misc.cpp:632
const directionT DOWN_RIGHT
Definition: common.h:554
const resultT RESULT_None
Definition: common.h:185
directionT sqDir[66][66]
Definition: misc.cpp:24
const squareT NS
Definition: common.h:352
uint rawFileSize(const char *name)
Definition: misc.cpp:781
void strStrip(char *str, char ch)
Definition: misc.cpp:329
sqDir_Init()
Definition: misc.cpp:27
const directionT DOWN_LEFT
Definition: common.h:553
void strTrimDate(char *str)
Definition: misc.cpp:389
uint gzipFileSize(const char *name)
Definition: misc.cpp:796
byte squareT
Definition: common.h:113
const char * strLastChar(const char *target, char matchChar)
Definition: misc.cpp:314