LCOV - code coverage report
Current view: top level - src - misc.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info Lines: 45 312 14.4 %
Date: 2017-06-21 14:32:49 Functions: 6 35 17.1 %

          Line data    Source code
       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             : {
      27           1 :     sqDir_Init() {
      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,
      32           1 :                                   DOWN_LEFT, DOWN_RIGHT, NULL_DIR };
      33             :         // First, set everything to NULL_DIR:
      34          67 :         for (i=A1; i <= NS; i++) {
      35        8778 :             for (j=A1; j <= NS; j++) {
      36        4356 :                 sqDir[i][j] = NULL_DIR;
      37             :             }
      38             :         }
      39             :         // Now fill in the valid directions:
      40         129 :         for (i=A1; i <= H8; i++) {
      41             :             directionT * dirptr = dirArray;
      42        1088 :             while (*dirptr != NULL_DIR) {
      43        1024 :                 j = square_Move (i, *dirptr);
      44        3424 :                 while (j != NS) {
      45        1456 :                     sqDir[i][j] = *dirptr;
      46        1456 :                     j = square_Move (j, *dirptr);
      47             :                 }
      48         512 :                 dirptr++;
      49             :             }
      50             :         }
      51           1 :     }
      52           1 : } sqDir_Init_singleton;
      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           0 : eco_FromString (const char * ecoStr)
      70             : {
      71           0 :     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           0 :     if (*ecoStr >= 'A'  &&  *ecoStr <= 'E') {
      77           0 :         eco = (*ecoStr - 'A') * 13100;
      78           0 :     } else if (*ecoStr >= 'a'  &&  *ecoStr <= 'e') {
      79           0 :         eco = (*ecoStr - 'a') * 13100;
      80             :     } else {
      81             :         return 0;
      82             :     }
      83           0 :     ecoStr++;
      84           0 :     if (! *ecoStr) { return eco + 1; }
      85             : 
      86           0 :     if (*ecoStr < '0'  ||  *ecoStr > '9') { return 0; }
      87           0 :     eco += (*ecoStr - '0') * 1310;
      88           0 :     ecoStr++;
      89           0 :     if (! *ecoStr) { return eco + 1; }
      90             : 
      91           0 :     if (*ecoStr < '0'  ||  *ecoStr > '9') { return 0; }
      92           0 :     eco += (*ecoStr - '0') * 131;
      93           0 :     ecoStr++;
      94             : 
      95             :     // Now check for the optional extended code: a, a1, ... z2, z3, z4.
      96           0 :     if (*ecoStr >= 'a'  &&  *ecoStr <= 'z') {
      97           0 :         eco++;
      98           0 :         eco += (*ecoStr - 'a') * 5;
      99           0 :         ecoStr++;
     100           0 :         if (*ecoStr >= '1'  &&  *ecoStr <= '4') {
     101           0 :             eco += *ecoStr - '0';
     102             :         }
     103             :     }
     104           0 :     return eco + 1;
     105             : }
     106             : 
     107             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     108             : // eco_ToString():
     109             : //      Convert an ECO code to its string representation.
     110             : void
     111           0 : eco_ToString (ecoT ecoCode, char * ecoStr, bool extensions)
     112             : {
     113           0 :     char * s = ecoStr;
     114           0 :     if (ecoCode == ECO_None) { *s = 0; return; }
     115           0 :     ecoCode--;
     116             :     
     117             :     // First the base code value:
     118             :     
     119           0 :     ecoT basicCode = ecoCode / 131;    // 131 = 26 * 5 + 1 subcodes.
     120           0 :     *s++ = basicCode / 100 + 'A';
     121           0 :     *s++ = (basicCode % 100) / 10 + '0';
     122           0 :     *s++ = (basicCode % 10) + '0';
     123             :     
     124             :     // Now the optional extensions:
     125           0 :     if (extensions) {
     126           0 :         ecoCode = ecoCode % 131;
     127           0 :         if (ecoCode > 0) {
     128           0 :             ecoCode--;
     129           0 :             *s++ = (ecoCode / 5) + 'a';
     130           0 :             ecoCode = ecoCode % 5;
     131           0 :             if (ecoCode > 0) { *s++ = (ecoCode + '0'); }
     132             :         }
     133           0 :         *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
     143           0 : eco_BasicCode (ecoT eco)
     144             : {
     145           0 :     if (eco == ECO_None) { return ECO_None; }
     146             : 
     147           0 :     eco--;
     148           0 :     eco /= 131;
     149           0 :     eco *= 131;
     150           0 :     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             :  */
     163           0 : ecoT eco_Reduce(ecoT eco) {
     164           0 :         ASSERT(eco != 0);
     165             : 
     166           0 :         eco--;
     167           0 :         ecoT res = (eco / 131) * 27;
     168           0 :         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
     176           0 : eco_LastSubCode (ecoT eco)
     177             : {
     178           0 :     if (eco == ECO_None) { return ECO_None; }
     179             : 
     180             :     // if just a basic ECO code (1 letter, 2 digits), add the "z":
     181           0 :     eco--;
     182           0 :     if ((eco % 131) == 0) { eco += 126; }  // 126 = 5 * 25 + 1.
     183             : 
     184             :     // Now if no final digit, add the "4":
     185           0 :     if (((eco % 131) % 5) == 1) { eco += 4; }
     186           0 :     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           0 : strCopyExclude (char * target, const char * original,
     197             :                 const char * excludeChars)
     198             : {
     199           0 :     while (*original != 0) {
     200             :         int exclude = 0;
     201           0 :         for (char * s = (char *) excludeChars; *s; s++) {
     202           0 :             if (*original == *s) {
     203             :                 exclude = 1;
     204             :                 break;
     205             :             }
     206             :         }
     207           0 :         if (!exclude) {
     208           0 :             *target = *original;
     209           0 :             target++;
     210             :         }
     211           0 :         original++;
     212             :     }
     213           0 :     *target = 0;
     214           0 : }
     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           6 : strAppend (char * target, const char * extra)
     223             : {
     224           6 :     ASSERT (target != NULL  &&  extra != NULL);
     225          60 :     while (*target != 0)  { target++; }  // get to end of target string
     226           6 :     while (*extra != 0) {
     227           0 :         *target = *extra;
     228           0 :         target++;
     229           0 :         extra++;
     230             :     }
     231           6 :     *target = 0;
     232           6 :     return target;
     233             : }
     234             : 
     235             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     236             : // strDuplicate(): Duplicates a string using new[] operator.
     237             : //
     238             : char *
     239          11 : strDuplicate (const char * original)
     240             : {
     241          11 :     ASSERT (original != NULL);
     242          11 :     char * newStr = new char [strLength(original) + 1];
     243          11 :     if (newStr == NULL)  return NULL;
     244             :     char *s = newStr;
     245         231 :     while (*original != 0) {
     246         110 :         *s = *original;
     247         110 :         s++; original++;
     248             :     }
     249          11 :     *s = 0;   // Add trailing '\0'.
     250             :     //printf ("Dup: %p: %s\n", newStr, newStr);
     251          11 :     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           0 : strPad (char * target, const char * original, int width, char padding)
     269             : {
     270           0 :     ASSERT (target != NULL  &&  original != NULL);
     271           0 :     if (width < 0) {
     272           0 :         strCopy (target, original);
     273           0 :         return strLength (original);
     274             :     }
     275             :     int len = width;
     276           0 :     while (len > 0) {
     277           0 :         if (*original == 0) {
     278             :             break;
     279             :         }
     280           0 :         *target = *original;
     281           0 :         target++;
     282           0 :         original++;
     283           0 :         len--;
     284             :     }
     285           0 :     while (len--) { *target++ = padding; }
     286           0 :     *target = 0;
     287           0 :     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           0 : strFirstChar (const char * target, char matchChar)
     298             : {
     299           0 :     const char * s = target;
     300           0 :     while (*s != 0) {
     301           0 :         if (*s == matchChar) { return s; }
     302           0 :         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           6 : strLastChar (const char * target, char matchChar)
     315             : {
     316          12 :     const char * s = target;
     317          12 :     const char * last = NULL;
     318         174 :     while (*s != 0) {
     319         108 :         if (*s == matchChar) { last = s; }
     320         108 :         s++;
     321             :     }
     322           6 :     return last;
     323             : }
     324             : 
     325             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     326             : // strStrip():
     327             : //      Removes all occurrences of the specified char from the string.
     328             : void
     329           0 : strStrip (char * str, char ch)
     330             : {
     331           0 :     char * s = str;
     332           0 :     while (*str != 0) {
     333           0 :         if (*str != ch) {
     334           0 :             if (s != str) { *s = *str; }
     335           0 :             s++;
     336             :         }
     337           0 :         str++;
     338             :     }
     339           0 :     *s = 0;
     340           0 : }
     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           0 : strTrimLeft (const char * target, const char * trimChars)
     348             : {
     349           0 :     const char * s = target;
     350           0 :     while (*s != 0) {
     351           0 :         if (! strContainsChar (trimChars, *s)) { break; }
     352           0 :         s++;
     353             :     }
     354           0 :     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           0 : strTrimSuffix (char * target, char suffixChar)
     366             : {
     367           0 :     uint trimCount = 0;
     368           0 :     char * lastSuffixPtr = NULL;
     369           0 :     char * s = target;
     370           0 :     while (*s) {
     371           0 :         if (*s == suffixChar) {
     372           0 :             lastSuffixPtr = s;
     373           0 :             trimCount = 0;
     374             :         }
     375           0 :         trimCount++;
     376           0 :         s++;
     377             :     }
     378           0 :     if (lastSuffixPtr == NULL) { return 0; }
     379           0 :     *lastSuffixPtr = 0;
     380           0 :     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           0 : strTrimDate (char * str)
     390             : {
     391           0 :     if (str[7] == '.'  &&  str[8] == '?'  &&  str[9] == '?') {
     392           0 :         str[7] = 0;
     393           0 :         if (str[4] == '.'  &&  str[5] == '?'  &&  str[6] == '?') {
     394           0 :             str[4] = 0;
     395             :         }
     396             :     }
     397           0 : }
     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           0 : strTrimMarkCodes (char * str)
     405             : {
     406           0 :     char * in = str;
     407           0 :     char * out = str;
     408           0 :     bool inCode = false;
     409           0 :     char * startLocation = NULL;
     410             : 
     411             :     while (1) {
     412           0 :         char ch = *in;
     413           0 :         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           0 :             if (ch == 0  ||  ch == '[') {
     418           0 :                 *out++ = *startLocation;
     419           0 :                 inCode = false;
     420           0 :                 in = startLocation;
     421           0 :             } else if (ch == ']') {
     422             :                 // See a code-ending ']', so end the code.
     423           0 :                 inCode = false;
     424             :             }
     425             :             // For all other characters in a code, just ignore it.
     426             :         } else {
     427             :             // Stop at end-of-string:
     428           0 :             if (ch == 0) { break; }
     429             :             // Look for the start of a code that is to be stripped:
     430           0 :             if (ch == '['  &&  in[1] == '%') {
     431             :                 inCode = true;
     432             :                 startLocation = in;
     433             :             } else {
     434           0 :                 *out++ = ch;
     435             :             }
     436             :         }
     437           0 :         in++;
     438           0 :     }
     439             :     // Terminate the modified string:
     440           0 :     *out = 0;
     441           0 : }
     442             : 
     443             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     444             : // strTrimMarkup():
     445             : //    Trims in-place all HTML-like markup codes (<b>, </i>, etc)
     446             : //    from the provided string.
     447             : void
     448           0 : strTrimMarkup (char * str)
     449             : {
     450           0 :     char * in = str;
     451           0 :     char * out = str;
     452           0 :     bool inTag = false;
     453             : 
     454           0 :     while (*in != 0) {
     455           0 :         char ch = *in;
     456           0 :         if (inTag) {
     457           0 :             if (ch == '>') { inTag = false; }
     458             :         } else {
     459           0 :             if (ch == '<') { inTag = true; } else { *out++ = ch; }
     460             :         }
     461           0 :         in++;
     462             :     }
     463           0 :     *out = 0;
     464           0 : }
     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           0 : strTrimSurname (char * str, uint initials)
     473             : {
     474           0 :     char * in = str;
     475           0 :     char * out = str;
     476           0 :     bool seenComma = false;
     477             : 
     478           0 :     while (*in != 0) {
     479           0 :         char ch = *in;
     480           0 :         if (seenComma) {
     481           0 :             if (isupper(ch)) {
     482           0 :                 *out++ = ch;
     483           0 :                 initials--;
     484           0 :                 if (initials == 0) { break; }
     485             :             }
     486             :         } else {
     487           0 :             if (ch == ',') {
     488           0 :                 seenComma = true;
     489           0 :                 if (initials == 0) { break; }
     490             :             }
     491           0 :             *out++ = ch;
     492             :         }
     493           0 :         in++;
     494             :     }
     495           0 :     *out = 0;
     496           0 : }
     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           0 : strFirstWord (const char * str)
     504             : {
     505           0 :     ASSERT (str != NULL);
     506           0 :     while (*str != 0  &&  isspace(*str)) { str++; }
     507           0 :     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           0 : strNextWord (const char * str)
     517             : {
     518           0 :     ASSERT (str != NULL);
     519           0 :     while (*str != 0  &&  !isspace(*str)) { str++; }
     520           0 :     while (*str != 0  &&  isspace(*str)) { str++; }
     521           0 :     return str;
     522             : }
     523             : 
     524             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     525             : // strIsAllWhitespace():
     526             : //    Returns true if the string contains only whitespace characters.
     527             : bool
     528           0 : strIsAllWhitespace (const char * str)
     529             : {
     530           0 :     while (*str != 0) {
     531           0 :         if (! isspace(*str)) { return false; }
     532           0 :         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           0 : strIsUnknownName (const char * str)
     545             : {
     546           0 :     if (str[0] == 0) { return true; }
     547           0 :     if (str[0] == '-'  &&  str[1] == 0) { return true; }
     548           0 :     if (str[0] == '?'  &&  str[1] == 0) { return true; }
     549           0 :     return false;
     550             : }
     551             : 
     552             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     553             : // strIsSurnameOnly():
     554             : //    Returns true if the name appears to be a surname only.
     555             : bool
     556           0 : strIsSurnameOnly (const char * name)
     557             : {
     558           0 :     uint capcount = 0;
     559           0 :     const char * s = name;
     560           0 :     while (*s != 0) {
     561           0 :         unsigned char c = *s;
     562           0 :         if (! isalpha(c)) { return false; }
     563           0 :         if (isupper(c)) {
     564           0 :             capcount++;
     565           0 :             if (capcount > 1) { return false; }
     566             :         }
     567           0 :         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           0 : 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           0 :     if (str[0] == 0) { return false; }
     588             : 
     589             :     bool matchedTrue = false;
     590             :     bool matchedFalse = false;
     591             : 
     592             :     const char ** next = sTrue;
     593           0 :     while (*next != NULL) {
     594           0 :         if (strIsCasePrefix (str, *next)  ||  strIsCasePrefix (*next, str)) {
     595           0 :            matchedTrue = true;
     596             :         }
     597           0 :         next++;
     598             :     }
     599             :     next = sFalse;
     600           0 :     while (*next != NULL) {
     601           0 :         if (strIsCasePrefix (str, *next)  ||  strIsCasePrefix (*next, str)) {
     602           0 :            matchedFalse = true;
     603             :         }
     604           0 :         next++;
     605             :     }
     606           0 :     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           0 : strGetIntegers (const char * str, int * results, uint nResults)
     619             : {
     620           0 :     for (uint i=0; i < nResults; i++) {
     621           0 :         while (*str != 0  &&  isspace(*str)) { str++; }
     622           0 :         results[i] = strGetInteger (str);
     623           0 :         while (*str != 0  &&  !isspace(*str)) { str++; }
     624             :     }
     625           0 : }
     626             : 
     627             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     628             : // strGetUnsigneds:
     629             : //    Extracts the specified number of unsigned integers in a
     630             : //    whitespace-separated string to an array.
     631             : void
     632           0 : strGetUnsigneds (const char * str, uint * results, uint nResults)
     633             : {
     634           0 :     for (uint i=0; i < nResults; i++) {
     635           0 :         while (*str != 0  &&  isspace(*str)) { str++; }
     636           0 :         results[i] = strGetUnsigned (str);
     637           0 :         while (*str != 0  &&  !isspace(*str)) { str++; }
     638             :     }
     639           0 : }
     640             : 
     641             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     642             : // strGetResult:
     643             : //    Extracts a game result value from a string.
     644             : resultT
     645           0 : strGetResult (const char * str)
     646             : {
     647           0 :     switch (*str) {
     648             :     case '1':
     649             :         // Check for "1/2"-style draw result:
     650           0 :         if (str[1] == '/'  &&  str[2] == '2') {
     651             :             return RESULT_Draw;
     652             :         }
     653           0 :         return RESULT_White;
     654             :     case '=': return RESULT_Draw;
     655           0 :     case '0': return RESULT_Black;
     656           0 :     case '*': return RESULT_None;
     657             :     }
     658           0 :     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           0 : strGetFlag (const char * str)
     667             : {
     668           0 :     char c = *str;
     669           0 :     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           0 : strGetSquare (const char * str)
     694             : {
     695           0 :     char chFyle = str[0];
     696           0 :     if (chFyle < 'a'  ||  chFyle > 'h') { return NULL_SQUARE; }
     697           0 :     char chRank = str[1];
     698           0 :     if (chRank < '1'  ||  chRank > '8') { return NULL_SQUARE; }
     699           0 :     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           0 : strUniqueExactMatch (const char * keyStr, const char ** strTable, bool exact)
     719             : {
     720           0 :     int index = -1;
     721           0 :     int abbrevMatches = 0;
     722             :     const char * s1;
     723             :     const char * s2;
     724           0 :     const char ** entryPtr = strTable;
     725             :     
     726             :     // If keyStr or strTable are null, return no match:
     727           0 :     if (keyStr == NULL  ||  strTable == NULL) { return -1; }
     728             :     
     729             :     // Check each entry in turn:
     730           0 :     for (int i=0;  *entryPtr != NULL;  entryPtr++, i++) {
     731             :         // Check the key against this entry, character by character:
     732           0 :         for (s1 = keyStr, s2 = *entryPtr;  *s1 == *s2;  s1++, s2++) {
     733             :             // If *s1 is 0, we found an EXACT match, so return it now:
     734           0 :             if (*s1 == 0) {
     735             :                 return i;
     736             :             }
     737             :         }
     738             :         // If *s1 == 0 now, key is an abbreviation of this entry:
     739           0 :         if (*s1 == 0) {
     740           0 :             index = i;
     741           0 :             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           0 :     if (exact  ||  abbrevMatches != 1) {
     748             :         return -1;
     749             :     }
     750             :     // Otherwise, return the match found:
     751           0 :     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           6 : fileSize (const char * name, const char * suffix)
     765             : {
     766             :     fileNameT fname;
     767           6 :     strCopy (fname, name);
     768           6 :     strAppend (fname, suffix);
     769           6 :     const char * lastSuffix = strFileSuffix (fname);
     770           6 :     if (lastSuffix != NULL  &&  strEqual (lastSuffix, GZIP_SUFFIX)) {
     771           0 :         return gzipFileSize (fname);
     772             :     }
     773           6 :     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           0 : rawFileSize (const char * name)
     782             : {
     783             :     struct stat statBuf;    // Defined in <sys/stat.h>
     784           6 :     if (stat (name, &statBuf) != 0) {
     785             :         return 0;
     786             :     }
     787           6 :     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           0 : gzipFileSize (const char * name)
     797             : {
     798             :     FILE * fp;
     799           0 :     fp = fopen (name, "rb");
     800           0 :     if (fp == NULL) { return 0; }
     801             :     // Seek to 4 bytes from the end:
     802           0 :     if (fseek (fp, -4L, SEEK_END) != 0) {
     803           0 :         fclose (fp);
     804           0 :         return 0;
     805             :     }
     806             :     // Read the 4-byte number in little-endian format:
     807           0 :     uint size = 0;
     808           0 :     uint b0 = (uint) getc(fp);
     809           0 :     uint b1 = (uint) getc(fp);
     810           0 :     uint b2 = (uint) getc(fp);
     811           0 :     uint b3 = (uint) getc(fp);
     812           0 :     size = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
     813           0 :     fclose (fp);
     814           0 :     return size;
     815           2 : }
     816             : 
     817             : //////////////////////////////////////////////////////////////////////
     818             : //  EOF: misc.cpp
     819             : //////////////////////////////////////////////////////////////////////
     820             : 

Generated by: LCOV version 1.12