LCOV - code coverage report
Current view: top level - frmts/grib/degrib/degrib - myutil.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 6 46 13.0 %
Date: 2024-04-27 17:22:41 Functions: 1 5 20.0 %

          Line data    Source code
       1             : /*****************************************************************************
       2             :  * myutil.c
       3             :  *
       4             :  * DESCRIPTION
       5             :  *    This file contains some simple utility functions.
       6             :  *
       7             :  * HISTORY
       8             :  * 12/2002 Arthur Taylor (MDL / RSIS): Created.
       9             :  *
      10             :  * NOTES
      11             :  *****************************************************************************
      12             :  */
      13             : 
      14             : /* For S_IFDIR */
      15             : #if defined(__sun__) && __STDC_VERSION__ >= 201112L
      16             : #if _XOPEN_SOURCE < 600
      17             : #ifdef _XOPEN_SOURCE
      18             : #undef _XOPEN_SOURCE
      19             : #endif
      20             : #define _XOPEN_SOURCE 600
      21             : #endif
      22             : #else
      23             : #ifdef _XOPEN_SOURCE
      24             : #undef _XOPEN_SOURCE
      25             : #endif
      26             : #define _XOPEN_SOURCE 500
      27             : #endif
      28             : 
      29             : #include <stdlib.h>
      30             : #include <stdio.h>
      31             : #include <ctype.h>
      32             : #include <string.h>
      33             : #include <math.h>
      34             : #include <sys/stat.h>
      35             : //#include <direct.h>
      36             : //#include <dirent.h>
      37             : #include "myutil.h"
      38             : #include "myassert.h"
      39             : 
      40             : #include "cpl_port.h"
      41             : 
      42             : /* Android compat */
      43             : #ifndef S_IREAD
      44             : #define S_IREAD S_IRUSR
      45             : #endif
      46             : 
      47             : #ifndef S_IWRITE
      48             : #define S_IWRITE S_IWUSR
      49             : #endif
      50             : 
      51             : #ifndef S_IEXEC
      52             : #define S_IEXEC S_IXUSR
      53             : #endif
      54             : /* End of Android compat */
      55             : 
      56             : #ifdef MEMWATCH
      57             : #include "memwatch.h"
      58             : #endif
      59             : 
      60             : /*****************************************************************************
      61             :  * reallocFGets() -- Arthur Taylor / MDL
      62             :  *
      63             :  * PURPOSE
      64             :  *   Read in data from file until a \n is read.  Reallocate memory as needed.
      65             :  * Similar to fgets, except we don't know ahead of time that the line is a
      66             :  * specific length.
      67             :  *   Assumes that Ptr is either NULL, or points to lenBuff memory.
      68             :  *   Responsibility of caller to free the memory.
      69             :  *
      70             :  * ARGUMENTS
      71             :  *     Ptr = An array of data that is of size LenBuff. (Input/Output)
      72             :  * LenBuff = The Allocated length of Ptr. (Input/Output)
      73             :  *      fp = Input file stream (Input)
      74             :  *
      75             :  * RETURNS: size_t
      76             :  *   strlen (buffer)
      77             :  *     0 = We read only EOF
      78             :  *     1 = We have "\nEOF" or "<char>EOF"
      79             :  *
      80             :  * 12/2002 Arthur Taylor (MDL/RSIS): Created.
      81             :  *
      82             :  * NOTES
      83             :  *  1) Based on getline (see K&R C book (2nd edition) p 29) and on the
      84             :  *     behavior of Tcl's gets routine.
      85             :  *  2) Chose MIN_STEPSIZE = 80 because pages are usually 80 columns.
      86             :  *  3) Could switch lenBuff = i + 1 / lenBuff = i to always true.
      87             :  *     Rather not... Less allocs... This way code behaves almost the
      88             :  *     same as fgets except it can expand as needed.
      89             :  *****************************************************************************
      90             :  */
      91             : #if 0  // Unused with GDAL.
      92             : #define MIN_STEPSIZE 80
      93             : size_t reallocFGets (char **Ptr, size_t *LenBuff, FILE *fp)
      94             : {
      95             :    char *buffer = *Ptr; /* Local copy of Ptr. */
      96             :    size_t lenBuff = *LenBuff; /* Local copy of LenBuff. */
      97             :    int c;               /* Current char read from stream. */
      98             :    size_t i;            /* Where to store c. */
      99             : 
     100             :    myAssert (sizeof (char) == 1);
     101             :    for (i = 0; ((c = getc (fp)) != EOF) && (c != '\n'); ++i) {
     102             :       if (i >= lenBuff) {
     103             :          lenBuff += MIN_STEPSIZE;
     104             :          buffer = (char *) realloc ((void *) buffer, lenBuff);
     105             :       }
     106             :       buffer[i] = (char) c;
     107             :    }
     108             :    if (c == '\n') {
     109             :       if (lenBuff <= i + 1) {
     110             :          lenBuff = i + 2; /* Make room for \n\0. */
     111             :          buffer = (char *) realloc ((void *) buffer, lenBuff);
     112             :       }
     113             :       buffer[i] = (char) c;
     114             :       ++i;
     115             :    } else {
     116             :       if (lenBuff <= i) {
     117             :          lenBuff = i + 1; /* Make room for \0. */
     118             :          buffer = (char *) realloc ((void *) buffer, lenBuff);
     119             :       }
     120             :    }
     121             :    buffer[i] = '\0';
     122             :    *Ptr = buffer;
     123             :    *LenBuff = lenBuff;
     124             :    return i;
     125             : }
     126             : 
     127             : #undef MIN_STEPSIZE
     128             : #endif
     129             : 
     130             : /*****************************************************************************
     131             :  * mySplit() --
     132             :  *
     133             :  * Arthur Taylor / MDL
     134             :  *
     135             :  * PURPOSE
     136             :  *   Split a character array according to a given symbol.
     137             :  *   Responsibility of caller to free the memory.
     138             :  *
     139             :  * ARGUMENTS
     140             :  *   data = character string to look through. (Input)
     141             :  * symbol = character to split based on. (Input)
     142             :  *   argc = number of groupings found. (Output)
     143             :  *   argv = characters in each grouping. (Output)
     144             :  * f_trim = True if we should white space trim each element in list. (Input)
     145             :  *
     146             :  * RETURNS: void
     147             :  *
     148             :  * HISTORY
     149             :  *  5/2004 Arthur Taylor (MDL/RSIS): Created.
     150             :  *
     151             :  * NOTES
     152             :  *****************************************************************************
     153             :  */
     154             : 
     155             : #if 0  // Unused with GDAL.
     156             : void mySplit (const char *data, char symbol, size_t *Argc, char ***Argv,
     157             :               char f_trim)
     158             : {
     159             :    const char *head;    /* The head of the current string */
     160             :    const char *ptr;     /* a pointer to walk over the data. */
     161             :    size_t argc = 0;     /* Local copy of Argc */
     162             :    char **argv = NULL;  /* Local copy of Argv */
     163             :    size_t len;          /* length of current string. */
     164             : 
     165             :    myAssert (*Argc == 0);
     166             :    myAssert (*Argv == NULL);
     167             :    myAssert (sizeof (char) == 1);
     168             : 
     169             :    head = data;
     170             :    while (head != NULL) {
     171             :       argv = (char **) realloc ((void *) argv, (argc + 1) * sizeof (char *));
     172             :       ptr = strchr (head, symbol);
     173             :       if (ptr != NULL) {
     174             :          len = ptr - head;
     175             :          argv[argc] = (char *) malloc (len + 1);
     176             :          strncpy (argv[argc], head, len);
     177             :          argv[argc][len] = '\0';
     178             :          if (f_trim) {
     179             :             strTrim (argv[argc]);
     180             :          }
     181             :          argc++;
     182             :          head = ptr + 1;
     183             :          /* The following head != NULL is in case data is not '\0' terminated
     184             :           */
     185             :          if ((head != NULL) && (*head == '\0')) {
     186             :             /* Handle a break character just before the \0 */
     187             :             /* This results in not adding a "" to end of list. */
     188             :             head = NULL;
     189             :          }
     190             :       } else {
     191             :          /* Handle from here to end of text. */
     192             :          len = strlen (head);
     193             :          argv[argc] = (char *) malloc (len + 1);
     194             :          strcpy (argv[argc], head);
     195             :          if (f_trim) {
     196             :             strTrim (argv[argc]);
     197             :          }
     198             :          argc++;
     199             :          head = NULL;
     200             :       }
     201             :    }
     202             :    *Argc = argc;
     203             :    *Argv = argv;
     204             : }
     205             : #endif
     206             : 
     207             : #if 0  // Unused with GDAL.
     208             : int myAtoI (const char *ptr, sInt4 *value)
     209             : {
     210             :    char *extra = NULL;         /* The data after the end of the double. */
     211             : 
     212             :    myAssert (ptr != NULL);
     213             :    *value = 0;
     214             :    while (*ptr != '\0') {
     215             :       if (isdigit ((unsigned char)*ptr) || (*ptr == '+') || (*ptr == '-')) {
     216             :          *value = (int)strtol (ptr, &extra, 10);
     217             :          myAssert (extra != NULL);
     218             :          if (*extra == '\0') {
     219             :             return 1;
     220             :          }
     221             :          break;
     222             :       } else if (!isspace ((unsigned char)*ptr)) {
     223             :          return 0;
     224             :       }
     225             :       ptr++;
     226             :    }
     227             :    /* Check if all white space. */
     228             :    if (*ptr == '\0') {
     229             :       return 0;
     230             :    }
     231             :    myAssert (extra != NULL);
     232             :    /* Allow first trailing char for ',' */
     233             :    if (!isspace ((unsigned char)*extra)) {
     234             :       if (*extra != ',') {
     235             :          *value = 0;
     236             :          return 0;
     237             :       }
     238             :    }
     239             :    extra++;
     240             :    /* Make sure the rest is all white space. */
     241             :    while (*extra != '\0') {
     242             :       if (!isspace ((unsigned char)*extra)) {
     243             :          *value = 0;
     244             :          return 0;
     245             :       }
     246             :       extra++;
     247             :    }
     248             :    return 1;
     249             : }
     250             : #endif
     251             : 
     252             : /*****************************************************************************
     253             :  * myAtoF() -- used to be myIsReal()
     254             :  *
     255             :  * Arthur Taylor / MDL
     256             :  *
     257             :  * PURPOSE
     258             :  *    Returns true if all char are digits except a leading + or -, or a
     259             :  * trailing ','.  Ignores leading or trailing white space.  Value is set to
     260             :  * atof (ptr).
     261             :  *
     262             :  * ARGUMENTS
     263             :  *   ptr = character string to look at. (Input)
     264             :  * value = the converted value of ptr, if ptr is a number. (Output)
     265             :  *
     266             :  * RETURNS: int
     267             :  *   0 = Not a real number,
     268             :  *   1 = Real number.
     269             :  *
     270             :  * HISTORY
     271             :  *  7/2004 Arthur Taylor (MDL): Updated
     272             :  *  4/2005 AAT (MDL): Did a code walk through.
     273             :  *
     274             :  * NOTES
     275             :  *****************************************************************************
     276             :  */
     277             : 
     278             : #if 0  // Unused with GDAL.
     279             : int myAtoF (const char *ptr, double *value)
     280             : {
     281             :    char *extra = NULL;         /* The data after the end of the double. */
     282             : 
     283             :    myAssert (ptr != NULL);
     284             :    *value = 0;
     285             :    while (*ptr != '\0') {
     286             :       if (isdigit ((unsigned char)*ptr) || (*ptr == '+') || (*ptr == '-') || (*ptr == '.')) {
     287             :          *value = strtod (ptr, &extra);
     288             :          myAssert (extra != NULL);
     289             :          if (*extra == '\0') {
     290             :             return 1;
     291             :          }
     292             :          break;
     293             :       } else if (!isspace ((unsigned char)*ptr)) {
     294             :          return 0;
     295             :       }
     296             :       ptr++;
     297             :    }
     298             :    /* Check if all white space. */
     299             :    if (*ptr == '\0') {
     300             :       return 0;
     301             :    }
     302             :    myAssert (extra != NULL);
     303             :    /* Allow first trailing char for ',' */
     304             :    if (!isspace ((unsigned char)*extra)) {
     305             :       if (*extra != ',') {
     306             :          *value = 0;
     307             :          return 0;
     308             :       }
     309             :    }
     310             :    extra++;
     311             :    /* Make sure the rest is all white space. */
     312             :    while (*extra != '\0') {
     313             :       if (!isspace ((unsigned char)*extra)) {
     314             :          *value = 0;
     315             :          return 0;
     316             :       }
     317             :       extra++;
     318             :    }
     319             :    return 1;
     320             : }
     321             : #endif
     322             : 
     323             : #if 0  // Unused with GDAL.
     324             : /* Change of name was to deprecate usage... Switch to myAtoF */
     325             : int myIsReal_old (const char *ptr, double *value)
     326             : {
     327             :    size_t len, i;
     328             : 
     329             :    *value = 0;
     330             :    if ((!isdigit ((unsigned char)*ptr)) && (*ptr != '.'))
     331             :       if (*ptr != '-')
     332             :          return 0;
     333             :    len = strlen (ptr);
     334             :    for (i = 1; i < len - 1; i++) {
     335             :       if ((!isdigit ((unsigned char)ptr[i])) && (ptr[i] != '.'))
     336             :          return 0;
     337             :    }
     338             :    if ((!isdigit ((unsigned char)ptr[len - 1])) && (ptr[len - 1] != '.')) {
     339             :       if (ptr[len - 1] != ',') {
     340             :          return 0;
     341             :       } else {
     342             : /*         ptr[len - 1] = '\0';*/
     343             :          *value = atof (ptr);
     344             : /*         ptr[len - 1] = ',';*/
     345             :          return 1;
     346             :       }
     347             :    }
     348             :    *value = atof (ptr);
     349             :    return 1;
     350             : }
     351             : #endif
     352             : 
     353             : /* Return:
     354             :  * 0 if 'can't stat the file' (most likely not a file)
     355             :  * 1 if it is a directory
     356             :  * 2 if it is a file
     357             :  * 3 if it doesn't understand the file
     358             :  */
     359             : /* mtime may behave oddly...
     360             :  * stat appeared correct if I was in EST and the file was in EST,
     361             :  * but was off by 1 hour if I was in EST and the file was in EDT.
     362             :  * rddirlst.c solved this through use of "clock".
     363             :  *
     364             :  * Could return mode: RDCF___rwxrwxrwx where R is 1/0 based on regular file
     365             :  * D is 1/0 based on directory, first rwx is user permissions...
     366             :  */
     367             : #if 0  // Unused with GDAL.
     368             : int myStat (char *filename, char *perm, sInt4 *size, double *mtime)
     369             : {
     370             :    struct stat stbuf;
     371             :    char f_cnt;
     372             :    char *ptr;
     373             :    int ans;
     374             : 
     375             :    myAssert (filename != NULL);
     376             : 
     377             :    /* Check for unmatched quotes (apparently stat on MS-Windows lets:
     378             :     * ./data/ndfd/geodata\" pass, which causes issues later. */
     379             :    f_cnt = 0;
     380             :    for (ptr = filename; *ptr != '\0'; ptr++) {
     381             :       if (*ptr == '"')
     382             :          f_cnt = !f_cnt;
     383             :    }
     384             :    if (f_cnt) {
     385             :       /* unmatched quotes. */
     386             :       if (size)
     387             :          *size = 0;
     388             :       if (mtime)
     389             :          *mtime = 0;
     390             :       if (perm)
     391             :          *perm = 0;
     392             :       return 0;
     393             :    }
     394             : 
     395             :    /* Try to stat file. */
     396             :    if ((ans = stat (filename, &stbuf)) == -1) {
     397             :       if ((filename[strlen (filename) - 1] == '/') ||
     398             :           (filename[strlen (filename) - 1] == '\\')) {
     399             :          filename[strlen (filename) - 1] = '\0';
     400             :          ans = stat (filename, &stbuf);
     401             :       }
     402             :    }
     403             :    /* Can't stat */
     404             :    if (ans == -1) {
     405             :       if (size)
     406             :          *size = 0;
     407             :       if (mtime)
     408             :          *mtime = 0;
     409             :       if (perm)
     410             :          *perm = 0;
     411             :       return 0;
     412             :    }
     413             : 
     414             :    if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
     415             :       /* Is a directory */
     416             :       if (size)
     417             :          *size = (sInt4)stbuf.st_size;
     418             :       if (mtime)
     419             :          *mtime = stbuf.st_mtime;
     420             :       if (perm) {
     421             :          *perm = (stbuf.st_mode & S_IREAD) ? 4 : 0;
     422             :          if (stbuf.st_mode & S_IWRITE)
     423             :             *perm += 2;
     424             :          if (stbuf.st_mode & S_IEXEC)
     425             :             *perm += 1;
     426             :       }
     427             :       return MYSTAT_ISDIR;
     428             :    } else if ((stbuf.st_mode & S_IFMT) == S_IFREG) {
     429             :       /* Is a file */
     430             :       if (size)
     431             :          *size = (sInt4)stbuf.st_size;
     432             :       if (mtime)
     433             :          *mtime = stbuf.st_mtime;
     434             :       if (perm) {
     435             :          *perm = (stbuf.st_mode & S_IREAD) ? 4 : 0;
     436             :          if (stbuf.st_mode & S_IWRITE)
     437             :             *perm += 2;
     438             :          if (stbuf.st_mode & S_IEXEC)
     439             :             *perm += 1;
     440             :       }
     441             :       return MYSTAT_ISFILE;
     442             :    } else {
     443             :       /* unrecognized file type */
     444             :       if (size)
     445             :          *size = 0;
     446             :       if (mtime)
     447             :          *mtime = 0;
     448             :       if (perm)
     449             :          *perm = 0;
     450             :       return 3;
     451             :    }
     452             : }
     453             : #endif
     454             : 
     455             : /**
     456             : static int FileMatch (const char *filename, const char *filter)
     457             : {
     458             :    const char *ptr1;
     459             :    const char *ptr2;
     460             : 
     461             :    ptr2 = filename;
     462             :    for (ptr1 = filter; *ptr1 != '\0'; ptr1++) {
     463             :       if (*ptr1 == '*') {
     464             :          if (ptr1[1] == '\0') {
     465             :             return 1;
     466             :          } else {
     467             :             ptr2 = strchr (ptr2, ptr1[1]);
     468             :             if (ptr2 == NULL) {
     469             :                return 0;
     470             :             }
     471             :          }
     472             :       } else if (*ptr2 == '\0') {
     473             :          return 0;
     474             :       } else if (*ptr1 == '?') {
     475             :          ptr2++;
     476             :       } else {
     477             :          if (*ptr1 == *ptr2) {
     478             :             ptr2++;
     479             :          } else {
     480             :             return 0;
     481             :          }
     482             :       }
     483             :    }
     484             :    return (*ptr2 == '\0');
     485             : }
     486             : **/
     487             : 
     488             : #if 0  // Unused with GDAL.
     489             : int myGlob (CPL_UNUSED const char *dirName,
     490             :             CPL_UNUSED const char *filter,
     491             :             CPL_UNUSED size_t *Argc,
     492             :             CPL_UNUSED char ***Argv)
     493             : {
     494             : return 0; // TODO: reimplement for Win32
     495             : #if 0
     496             :    size_t argc = 0;     // Local copy of Argc
     497             :    char **argv = NULL;  // Local copy of Argv
     498             :    struct dirent *dp;
     499             :    DIR *dir;
     500             : 
     501             :    myAssert (*Argc == 0);
     502             :    myAssert (*Argv == NULL);
     503             : 
     504             :    if ((dir = opendir (dirName)) == NULL)
     505             :       return -1;
     506             : 
     507             :    while ((dp = readdir (dir)) != NULL) {
     508             :       /* Skip self and parent. */
     509             :       if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
     510             :          continue;
     511             :       if (FileMatch (dp->d_name, filter)) {
     512             :          argv = (char **) realloc (argv, (argc + 1) * sizeof (char *));
     513             :          argv[argc] = (char *) malloc ((strlen (dirName) + 1 +
     514             :                                         strlen (dp->d_name) +
     515             :                                         1) * sizeof (char));
     516             :          sprintf (argv[argc], "%s/%s", dirName, dp->d_name);
     517             :          argc++;
     518             :       }
     519             :    }
     520             :    *Argc = argc;
     521             :    *Argv = argv;
     522             :    return 0;
     523             : #endif
     524             : }
     525             : #endif
     526             : 
     527             : /*****************************************************************************
     528             :  * FileCopy() --
     529             :  *
     530             :  * Arthur Taylor / MDL
     531             :  *
     532             :  * PURPOSE
     533             :  *   Copy a file from one location to another.
     534             :  *
     535             :  * ARGUMENTS
     536             :  *  fileIn = source file to read from. (Input)
     537             :  *  fileOut = destination file to write to. (Input)
     538             :  *
     539             :  * RETURNS: int
     540             :  *   0 = success.
     541             :  *   1 = problems opening fileIn
     542             :  *   2 = problems opening fileOut
     543             :  *
     544             :  * HISTORY
     545             :  *  5/2004 Arthur Taylor (MDL/RSIS): Created.
     546             :  *  4/2005 AAT (MDL): Did a code walk through.
     547             :  *
     548             :  * NOTES
     549             :  *****************************************************************************
     550             :  */
     551             : #if 0  // Unused with GDAL.
     552             : int FileCopy (const char *fileIn, const char *fileOut)
     553             : {
     554             :    FILE *ifp;           /* The file pointer to read from. */
     555             :    FILE *ofp;           /* The file pointer to write to. */
     556             :    int c;               /* temporary variable while reading / writing. */
     557             : 
     558             :    if ((ifp = fopen (fileIn, "rb")) == NULL) {
     559             : #ifdef DEBUG
     560             :       printf ("Couldn't open %s for read\n", fileIn);
     561             : #endif
     562             :       return 1;
     563             :    }
     564             :    if ((ofp = fopen (fileOut, "wb")) == NULL) {
     565             : #ifdef DEBUG
     566             :       printf ("Couldn't open %s for write\n", fileOut);
     567             : #endif
     568             :       fclose (ifp);
     569             :       return 2;
     570             :    }
     571             :    while ((c = getc (ifp)) != EOF) {
     572             :       putc (c, ofp);
     573             :    }
     574             :    fclose (ifp);
     575             :    fclose (ofp);
     576             :    return 0;
     577             : }
     578             : #endif
     579             : 
     580             : /*****************************************************************************
     581             :  * FileTail() --
     582             :  *
     583             :  * Arthur Taylor / MDL
     584             :  *
     585             :  * PURPOSE
     586             :  *   Returns the characters in a filename after the last directory separator.
     587             :  *   Responsibility of caller to free the memory.
     588             :  *
     589             :  * ARGUMENTS
     590             :  * fileName = fileName to look at. (Input)
     591             :  *     tail = Tail of the filename. (Output)
     592             :  *
     593             :  * RETURNS: void
     594             :  *
     595             :  * HISTORY
     596             :  *  5/2004 Arthur Taylor (MDL/RSIS): Created.
     597             :  *
     598             :  * NOTES
     599             :  *****************************************************************************
     600             :  */
     601             : 
     602             : #if 0  // Unused with GDAL.
     603             : void FileTail (const char *fileName, char **tail)
     604             : {
     605             :    const char *ptr;     /* A pointer to last \ or // in fileName. */
     606             : 
     607             :    myAssert (fileName != NULL);
     608             :    myAssert (sizeof (char) == 1);
     609             : 
     610             :    ptr = strrchr (fileName, '/');
     611             :    if (ptr == NULL) {
     612             :       ptr = strrchr (fileName, '\\');
     613             :       if (ptr == NULL) {
     614             :          ptr = fileName;
     615             :       } else {
     616             :          ptr++;
     617             :       }
     618             :    } else {
     619             :       ptr++;
     620             :    }
     621             :    *tail = (char *) malloc (strlen (ptr) + 1);
     622             :    strcpy (*tail, ptr);
     623             : }
     624             : #endif
     625             : 
     626             : /*****************************************************************************
     627             :  * myRound() --
     628             :  *
     629             :  * Arthur Taylor / MDL
     630             :  *
     631             :  * PURPOSE
     632             :  *   Round a number to a given number of decimal places.
     633             :  *
     634             :  * ARGUMENTS
     635             :  *  data = number to round (Input)
     636             :  * place = How many decimals to round to (Input)
     637             :  *
     638             :  * RETURNS: double (rounded value)
     639             :  *
     640             :  * HISTORY
     641             :  *  5/2003 Arthur Taylor (MDL/RSIS): Created.
     642             :  *  2/2006 AAT: Added the (double) (.5) cast, and the mult by POWERS_OVER_ONE
     643             :  *         instead of division.
     644             :  *
     645             :  * NOTES
     646             :  *  1) It is probably inadvisable to make a lot of calls to this routine,
     647             :  *     considering the fact that a context swap is made, so this is provided
     648             :  *     primarily as an example, but it can be used for some rounding.
     649             :  *****************************************************************************
     650             :  */
     651             : static const double POWERS_ONE[] = {
     652             :    1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
     653             :    1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17
     654             : };
     655             : 
     656           0 : double myRound (double data, uChar place)
     657             : {
     658           0 :    if (place > 17)
     659           0 :       place = 17;
     660             : 
     661           0 :    return (floor (data * POWERS_ONE[place] + 5e-1)) / POWERS_ONE[place];
     662             : 
     663             :    /* Tried some other options to see if I could fix test 40 on linux, but
     664             :     * changing it appears to make other tests fail on other OS's. */
     665             : /*
     666             :    return (((sInt4) (data * POWERS_ONE[place] + .5)) / POWERS_ONE[place]);
     667             : */
     668             : /*
     669             :    return (floor (data * POWERS_ONE[place] + .5)) / POWERS_ONE[place];
     670             : */
     671             : }
     672             : 
     673             : /*****************************************************************************
     674             :  * strTrim() --
     675             :  *
     676             :  * Arthur Taylor / MDL
     677             :  *
     678             :  * PURPOSE
     679             :  *   Trim the white space from both sides of a char string.
     680             :  *
     681             :  * ARGUMENTS
     682             :  * str = The string to trim (Input/Output)
     683             :  *
     684             :  * RETURNS: void
     685             :  *
     686             :  * HISTORY
     687             :  *  10/2003 Arthur Taylor (MDL/RSIS): Created.
     688             :  *
     689             :  * NOTES
     690             :  *   See K&R p106 for strcpy part.
     691             :  *****************************************************************************
     692             :  */
     693           0 : void strTrim (char *str)
     694             : {
     695             :    char *ptr;           /* Pointer to where first non-white space is. */
     696             :    char *ptr2;          /* Pointer to just past last non-white space. */
     697             : 
     698             :    /* str shouldn't be null, but if it is, we want to handle it. */
     699           0 :    myAssert (str != NULL);
     700           0 :    if (str == NULL) {
     701           0 :       return;
     702             :    }
     703             : 
     704             :    /* Trim the string to the left first. */
     705           0 :    for (ptr = str; isspace ((unsigned char)*ptr); ptr++) {
     706             :    }
     707             :    /* Did we hit the end of an all space string? */
     708           0 :    if (*ptr == '\0') {
     709           0 :       *str = '\0';
     710           0 :       return;
     711             :    }
     712             : 
     713             :    /* now work on the right side. */
     714           0 :    for (ptr2 = ptr + (strlen (ptr) - 1); isspace ((unsigned char)*ptr2); ptr2--) {
     715             :    }
     716             : 
     717             :    /* adjust the pointer to add the null byte. */
     718           0 :    ptr2++;
     719           0 :    *ptr2 = '\0';
     720             : 
     721           0 :    if (ptr != str) {
     722             :       /* Can't do a strcpy here since we don't know that they start at left
     723             :        * and go right. */
     724           0 :       while ((*str++ = *ptr++) != '\0') {
     725             :       }
     726           0 :       *str = '\0';
     727             :    }
     728             : }
     729             : 
     730             : /*****************************************************************************
     731             :  * strTrimRight() --
     732             :  *
     733             :  * Arthur Taylor / MDL
     734             :  *
     735             :  * PURPOSE
     736             :  *   Trim white space and a given char from the right.
     737             :  *
     738             :  * ARGUMENTS
     739             :  * str = The string to trim (Input/Output)
     740             :  *   c = The character to remove. (Input)
     741             :  *
     742             :  * RETURNS: void
     743             :  *
     744             :  * HISTORY
     745             :  *  7/2004 Arthur Taylor (MDL/RSIS): Created.
     746             :  *
     747             :  * NOTES
     748             :  *****************************************************************************
     749             :  */
     750         792 : void strTrimRight (char *str, char c)
     751             : {
     752             :    int i;               /* loop counter for traversing str. */
     753             : 
     754             :    /* str shouldn't be null, but if it is, we want to handle it. */
     755         792 :    myAssert (str != NULL);
     756         792 :    if (str == NULL) {
     757           0 :       return;
     758             :    }
     759             : 
     760        5544 :    for (i = (int)strlen (str) - 1;
     761        5544 :         ((i >= 0) && ((isspace ((unsigned char)str[i])) || (str[i] == c))); i--) {
     762             :    }
     763         792 :    str[i + 1] = '\0';
     764             : }
     765             : 
     766             : /*****************************************************************************
     767             :  * strCompact() --
     768             :  *
     769             :  * Arthur Taylor / MDL
     770             :  *
     771             :  * PURPOSE
     772             :  *   Replace any multiple instances of 'c' in the string with 1 instance.
     773             :  *
     774             :  * ARGUMENTS
     775             :  * str = The string to compact (Input/Output)
     776             :  *   c = The character to look for. (Input)
     777             :  *
     778             :  * RETURNS: void
     779             :  *
     780             :  * HISTORY
     781             :  * 10/2004 Arthur Taylor (MDL): Created.
     782             :  *
     783             :  * NOTES
     784             :  *****************************************************************************
     785             :  */
     786           0 : void strCompact (char *str, char c)
     787             : {
     788             :    char *ptr;           /* The next good value in str to keep. */
     789             : 
     790             :    /* str shouldn't be null, but if it is, we want to handle it. */
     791           0 :    myAssert (str != NULL);
     792           0 :    if (str == NULL) {
     793           0 :       return;
     794             :    }
     795             : 
     796           0 :    ptr = str;
     797           0 :    while ((*str = *(ptr++)) != '\0') {
     798           0 :       if (*(str++) == c) {
     799           0 :          while ((*ptr != '\0') && (*ptr == c)) {
     800           0 :             ptr++;
     801             :          }
     802             :       }
     803             :    }
     804             : }
     805             : 
     806             : /*****************************************************************************
     807             :  * strReplace() --
     808             :  *
     809             :  * Arthur Taylor / MDL
     810             :  *
     811             :  * PURPOSE
     812             :  *   Replace all instances of c1 in str with c2.
     813             :  *
     814             :  * ARGUMENTS
     815             :  * str = The string to trim (Input/Output)
     816             :  *  c1 = The character(s) in str to be replaced. (Input)
     817             :  *  c2 = The char to replace c1 with. (Input)
     818             :  *
     819             :  * RETURNS: void
     820             :  *
     821             :  * HISTORY
     822             :  *  7/2004 Arthur Taylor (MDL/RSIS): Created.
     823             :  *
     824             :  * NOTES
     825             :  *****************************************************************************
     826             :  */
     827             : #if 0  // Unused with GDAL.
     828             : void strReplace (char *str, char c1, char c2)
     829             : {
     830             :    char *ptr = str;
     831             : 
     832             :    /* str shouldn't be null, but if it is, we want to handle it. */
     833             :    myAssert (str != NULL);
     834             :    if (str == NULL) {
     835             :       return;
     836             :    }
     837             : 
     838             :    for (ptr = str; *ptr != '\0'; ptr++) {
     839             :       if (*ptr == c1) {
     840             :          *ptr = c2;
     841             :       }
     842             :    }
     843             : }
     844             : #endif
     845             : 
     846             : /*****************************************************************************
     847             :  * strToUpper() --
     848             :  *
     849             :  * Arthur Taylor / MDL
     850             :  *
     851             :  * PURPOSE
     852             :  *   Convert a string to all uppercase.
     853             :  *
     854             :  * ARGUMENTS
     855             :  * str = The string to adjust (Input/Output)
     856             :  *
     857             :  * RETURNS: void
     858             :  *
     859             :  * HISTORY
     860             :  *  10/2003 Arthur Taylor (MDL/RSIS): Created.
     861             :  *
     862             :  * NOTES
     863             :  *****************************************************************************
     864             :  */
     865             : #if 0  // Unused with GDAL.
     866             : void strToUpper (char *str)
     867             : {
     868             :    char *ptr = str;     /* Used to traverse str. */
     869             : 
     870             :    /* str shouldn't be null, but if it is, we want to handle it. */
     871             :    myAssert (str != NULL);
     872             :    if (str == NULL) {
     873             :       return;
     874             :    }
     875             : 
     876             :    while ((*ptr++ = toupper ((unsigned char)(*str++))) != '\0') {
     877             :    }
     878             : }
     879             : #endif
     880             : 
     881             : /*****************************************************************************
     882             :  * strToLower() --
     883             :  *
     884             :  * Arthur Taylor / MDL
     885             :  *
     886             :  * PURPOSE
     887             :  *   Convert a string to all lowercase.
     888             :  *
     889             :  * ARGUMENTS
     890             :  * str = The string to adjust (Input/Output)
     891             :  *
     892             :  * RETURNS: void
     893             :  *
     894             :  * HISTORY
     895             :  *  5/2004 Arthur Taylor (MDL/RSIS): Created.
     896             :  *
     897             :  * NOTES
     898             :  *****************************************************************************
     899             :  */
     900             : #if 0  // Unused with GDAL.
     901             : void strToLower (char *str)
     902             : {
     903             :    char *ptr = str;     /* Used to traverse str. */
     904             : 
     905             :    /* str shouldn't be null, but if it is, we want to handle it. */
     906             :    myAssert (str != NULL);
     907             :    if (str == NULL) {
     908             :       return;
     909             :    }
     910             : 
     911             :    while ((*ptr++ = tolower ((unsigned char)*str++)) != '\0') {
     912             :    }
     913             : }
     914             : #endif
     915             : 
     916             : /*
     917             :  * Returns: Length of the string.
     918             :  * History: 1/29/98 AAT Commented.
     919             :  *
     920             : int str2lw (char *s) {
     921             :   int i = 0, len = strlen (s);
     922             :   while (i < len) {
     923             :     s[i] = (char) tolower((unsigned char)s[i]);
     924             :     i++;
     925             :   }
     926             :   return len;
     927             : }
     928             : */
     929             : 
     930             : /*****************************************************************************
     931             :  * strcmpNoCase() --
     932             :  *
     933             :  * Arthur Taylor / MDL
     934             :  *
     935             :  * PURPOSE
     936             :  *   Compare two strings without concern for case.
     937             :  *
     938             :  * ARGUMENTS
     939             :  * str1 = String1 to compare (Input)
     940             :  * str2 = String2 to compare (Input)
     941             :  *
     942             :  * RETURNS: int
     943             :  *   -1 = (str1 < str2)
     944             :  *    0 = (str1 == str2)
     945             :  *    1 = (str1 > str2)
     946             :  *
     947             :  * HISTORY
     948             :  *  5/2004 Arthur Taylor (MDL/RSIS): Created.
     949             :  *
     950             :  * NOTES
     951             :  *   See K&R p 106
     952             :  *****************************************************************************
     953             :  */
     954             : #if 0  // Unused with GDAL.
     955             : int strcmpNoCase (const char *str1, const char *str2)
     956             : {
     957             :    /* str1, str2 shouldn't be null, but if it is, we want to handle it. */
     958             :    myAssert (str1 != NULL);
     959             :    myAssert (str2 != NULL);
     960             :    if (str1 == NULL) {
     961             :       if (str2 == NULL) {
     962             :          return 0;
     963             :       } else {
     964             :          return -1;
     965             :       }
     966             :    }
     967             :    if (str2 == NULL) {
     968             :       return 1;
     969             :    }
     970             : 
     971             :    for (; tolower ((unsigned char)*str1) == tolower ((unsigned char)*str2); str1++, str2++) {
     972             :       if (*str1 == '\0')
     973             :          return 0;
     974             :    }
     975             :    return (tolower ((unsigned char)*str1) - tolower ((unsigned char)*str2) < 0) ? -1 : 1;
     976             : /*
     977             :    strlen1 = strlen (str1);
     978             :    strlen2 = strlen (str2);
     979             :    min = (strlen1 < strlen2) ? strlen1 : strlen2;
     980             :    for (i = 0; i < min; i++) {
     981             :       c1 = tolower ((unsigned char)str1[i]);
     982             :       c2 = tolower ((unsigned char)str2[i]);
     983             :       if (c1 < c2)
     984             :          return -1;
     985             :       if (c1 > c2)
     986             :          return 1;
     987             :    }
     988             :    if (strlen1 < strlen2) {
     989             :       return -1;
     990             :    }
     991             :    if (strlen1 > strlen2) {
     992             :       return 1;
     993             :    }
     994             :    return 0;
     995             : */
     996             : }
     997             : #endif
     998             : 
     999             :  /*****************************************************************************
    1000             :  * GetIndexFromStr() -- Review 12/2002
    1001             :  *
    1002             :  * Arthur Taylor / MDL
    1003             :  *
    1004             :  * PURPOSE
    1005             :  *   Looks through a list of strings (with a NULL value at the end) for a
    1006             :  * given string.  Returns the index where it found it.
    1007             :  *
    1008             :  * ARGUMENTS
    1009             :  *   str = The string to look for. (Input)
    1010             :  *   Opt = The list to look for arg in. (Input)
    1011             :  * Index = The location of arg in Opt (or -1 if it couldn't find it) (Output)
    1012             :  *
    1013             :  * RETURNS: int
    1014             :  *  # = Where it found it.
    1015             :  * -1 = Couldn't find it.
    1016             :  *
    1017             :  * HISTORY
    1018             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    1019             :  *  12/2002 (TK,AC,TB,&MS): Code Review.
    1020             :  *
    1021             :  * NOTES
    1022             :  *   Why not const char **Opt?
    1023             :  *****************************************************************************
    1024             :  */
    1025           0 : int GetIndexFromStr (const char *str, const char * const *Opt, int *Index)
    1026             : {
    1027           0 :    int cnt = 0;         /* Current Count in Opt. */
    1028             : 
    1029           0 :    myAssert (str != NULL);
    1030           0 :    if (str == NULL) {
    1031           0 :       *Index = -1;
    1032           0 :       return -1;
    1033             :    }
    1034             : 
    1035           0 :    for (; *Opt != NULL; Opt++, cnt++) {
    1036           0 :       if (strcmp (str, *Opt) == 0) {
    1037           0 :          *Index = cnt;
    1038           0 :          return cnt;
    1039             :       }
    1040             :    }
    1041           0 :    *Index = -1;
    1042           0 :    return -1;
    1043             : }
    1044             : 
    1045             : /*****************************************************************************
    1046             :  * Clock_GetTimeZone() --
    1047             :  *
    1048             :  * Arthur Taylor / MDL
    1049             :  *
    1050             :  * PURPOSE
    1051             :  *   Returns the time zone offset in hours to add to local time to get UTC.
    1052             :  * So EST is +5 not -5.
    1053             :  *
    1054             :  * ARGUMENTS
    1055             :  *
    1056             :  * RETURNS: sInt2
    1057             :  *
    1058             :  * HISTORY
    1059             :  *   6/2004 Arthur Taylor (MDL): Created.
    1060             :  *   3/2005 AAT: Found bug... Used to use 1/1/1970 00Z and find the local
    1061             :  *        hour.  If CET, this means use 1969 date, which causes it to die.
    1062             :  *        Switched to 1/2/1970 00Z.
    1063             :  *   3/2005 AAT: timeZone (see CET) can be < 0. don't add 24 if timeZone < 0
    1064             :  *
    1065             :  * NOTES
    1066             :  *****************************************************************************
    1067             :  */
    1068             : #if 0  // Unused with GDAL.
    1069             : static sChar Clock_GetTimeZone ()
    1070             : {
    1071             :    struct tm l_time;
    1072             :    time_t ansTime;
    1073             :    struct tm *gmTime;
    1074             :    static sChar timeZone = 127;
    1075             : 
    1076             :    if (timeZone == 127) {
    1077             :       /* Cheap method of getting global time_zone variable. */
    1078             :       memset (&l_time, 0, sizeof (struct tm));
    1079             :       l_time.tm_year = 70;
    1080             :       l_time.tm_mday = 2;
    1081             :       ansTime = mktime (&l_time);
    1082             :       gmTime = gmtime (&ansTime);
    1083             :       timeZone = gmTime->tm_hour;
    1084             :       if (gmTime->tm_mday != 2) {
    1085             :          timeZone -= 24;
    1086             :       }
    1087             :    }
    1088             :    return timeZone;
    1089             : }
    1090             : #endif
    1091             : 
    1092             : /*****************************************************************************
    1093             :  * myParseTime() --
    1094             :  *
    1095             :  * Arthur Taylor / MDL
    1096             :  *
    1097             :  * PURPOSE
    1098             :  *   Parse a string such as "19730724000000" and return time since the
    1099             :  * beginning of the epoch.
    1100             :  *
    1101             :  * ARGUMENTS
    1102             :  *      is = String to read the date from (Input)
    1103             :  * AnsTime = Time to String2 to compare (Input)
    1104             :  *
    1105             :  * RETURNS: int
    1106             :  *    0 = success
    1107             :  *    1 = error
    1108             :  *
    1109             :  * HISTORY
    1110             :  *  4/2005 Arthur Taylor (MDL): Commented
    1111             :  *
    1112             :  * NOTES
    1113             :  *   Rename (myParseTime -> myParseTime2) because changed error return from
    1114             :  *      -1 to 1
    1115             :  *   Rename (myParseTime2 -> myParseTime3) because I'm trying to phase it out.
    1116             :  *   Use: int Clock_ScanDateNumber (double *clock, char *buffer) instead.
    1117             :  *****************************************************************************
    1118             :  */
    1119             : #if 0  // Unused with GDAL.
    1120             : int myParseTime3 (const char *is, time_t * AnsTime)
    1121             : {
    1122             :    char buffer[5];      /* A temporary variable for parsing "is". */
    1123             :    sShort2 year;        /* The year. */
    1124             :    uChar mon;           /* The month. */
    1125             :    uChar day;           /* The day. */
    1126             :    uChar hour;          /* The hour. */
    1127             :    uChar min;           /* The minute. */
    1128             :    uChar sec;           /* The second. */
    1129             :    struct tm l_time;      /* A temporary variable to put the time info into. */
    1130             : 
    1131             :    memset (&l_time, 0, sizeof (struct tm));
    1132             :    myAssert (strlen (is) == 14);
    1133             :    if (strlen (is) != 14) {
    1134             :       printf ("%s is not formatted correctly\n", is);
    1135             :       return 1;
    1136             :    }
    1137             :    strncpy (buffer, is, 4);
    1138             :    buffer[4] = '\0';
    1139             :    year = atoi (buffer);
    1140             :    strncpy (buffer, is + 4, 2);
    1141             :    buffer[2] = '\0';
    1142             :    mon = atoi (buffer);
    1143             :    strncpy (buffer, is + 6, 2);
    1144             :    day = atoi (buffer);
    1145             :    strncpy (buffer, is + 8, 2);
    1146             :    hour = atoi (buffer);
    1147             :    strncpy (buffer, is + 10, 2);
    1148             :    min = atoi (buffer);
    1149             :    strncpy (buffer, is + 12, 2);
    1150             :    sec = atoi (buffer);
    1151             :    if ((year > 2001) || (year < 1900) || (mon > 12) || (mon < 1) ||
    1152             :        (day > 31) || (day < 1) || (hour > 23) || (min > 59) || (sec > 60)) {
    1153             :       printf ("date %s is invalid\n", is);
    1154             :       printf ("%d %d %d %d %d %d\n", year, mon, day, hour, min, sec);
    1155             :       return 1;
    1156             :    }
    1157             :    l_time.tm_year = year - 1900;
    1158             :    l_time.tm_mon = mon - 1;
    1159             :    l_time.tm_mday = day;
    1160             :    l_time.tm_hour = hour;
    1161             :    l_time.tm_min = min;
    1162             :    l_time.tm_sec = sec;
    1163             :    *AnsTime = mktime (&l_time) - (Clock_GetTimeZone () * 3600);
    1164             :    return 0;
    1165             : }
    1166             : #endif
    1167             : 
    1168             : #ifdef MYUTIL_TEST
    1169             : int main (int argc, char **argv)
    1170             : {
    1171             :    char buffer[] = "Hello , World, This, is, a , test\n";
    1172             :    char buffer2[] = "";
    1173             :    size_t listLen = 0;
    1174             :    char **List = NULL;
    1175             :    size_t i;
    1176             :    size_t j;
    1177             :    char ans;
    1178             :    double value;
    1179             :    char *tail;
    1180             : 
    1181             : /*
    1182             :    printf ("1 :: %f\n", clock() / (double) (CLOCKS_PER_SEC));
    1183             :    for (j = 0; j < 25000; j++) {
    1184             :       mySplit (buffer, ',', &listLen, &List, 1);
    1185             :       for (i = 0; i < listLen; i++) {
    1186             :          free (List[i]);
    1187             :       }
    1188             :       free (List);
    1189             :       List = NULL;
    1190             :       listLen = 0;
    1191             :    }
    1192             :    printf ("1 :: %f\n", clock() / (double) (CLOCKS_PER_SEC));
    1193             : */
    1194             :    mySplit (buffer, ',', &listLen, &List, 1);
    1195             :    for (i = 0; i < listLen; i++) {
    1196             :       printf ("%d:'%s'\n", i, List[i]);
    1197             :       free (List[i]);
    1198             :    }
    1199             :    free (List);
    1200             :    List = NULL;
    1201             :    listLen = 0;
    1202             : 
    1203             :    mySplit (buffer2, ',', &listLen, &List, 1);
    1204             :    for (i = 0; i < listLen; i++) {
    1205             :       printf ("%d:'%s'\n", i, List[i]);
    1206             :       free (List[i]);
    1207             :    }
    1208             :    free (List);
    1209             :    List = NULL;
    1210             :    listLen = 0;
    1211             : 
    1212             :    strcpy (buffer, "  0.95");
    1213             :    ans = myAtoF (buffer, &value);
    1214             :    printf ("%d %f : ", ans, value);
    1215             :    ans = myIsReal_old (buffer, &value);
    1216             :    printf ("%d %f : '%s'\n", ans, value, buffer);
    1217             : 
    1218             :    strcpy (buffer, "0.95");
    1219             :    ans = myAtoF (buffer, &value);
    1220             :    printf ("%d %f : ", ans, value);
    1221             :    ans = myIsReal_old (buffer, &value);
    1222             :    printf ("%d %f : '%s'\n", ans, value, buffer);
    1223             : 
    1224             :    strcpy (buffer, "+0.95");
    1225             :    ans = myAtoF (buffer, &value);
    1226             :    printf ("%d %f : ", ans, value);
    1227             :    ans = myIsReal_old (buffer, &value);
    1228             :    printf ("%d %f : '%s'\n", ans, value, buffer);
    1229             : 
    1230             :    strcpy (buffer, "0.95,  ");
    1231             :    ans = myAtoF (buffer, &value);
    1232             :    printf ("%d %f : ", ans, value);
    1233             :    ans = myIsReal_old (buffer, &value);
    1234             :    printf ("%d %f : '%s'\n", ans, value, buffer);
    1235             : 
    1236             :    strcpy (buffer, "0.95,");
    1237             :    ans = myAtoF (buffer, &value);
    1238             :    printf ("%d %f : ", ans, value);
    1239             :    ans = myIsReal_old (buffer, &value);
    1240             :    printf ("%d %f : '%s'\n", ans, value, buffer);
    1241             : 
    1242             :    strcpy (buffer, "0.9.5");
    1243             :    ans = myAtoF (buffer, &value);
    1244             :    printf ("%d %f : ", ans, value);
    1245             :    ans = myIsReal_old (buffer, &value);
    1246             :    printf ("%d %f : '%s'\n", ans, value, buffer);
    1247             : 
    1248             :    strcpy (buffer, "  alph 0.9.5");
    1249             :    ans = myAtoF (buffer, &value);
    1250             :    printf ("%d %f : ", ans, value);
    1251             :    ans = myIsReal_old (buffer, &value);
    1252             :    printf ("%d %f : '%s'\n", ans, value, buffer);
    1253             : 
    1254             :    strcpy (buffer, "  ");
    1255             :    ans = myAtoF (buffer, &value);
    1256             :    printf ("%d %f : ", ans, value);
    1257             :    ans = myIsReal_old (buffer, &value);
    1258             :    printf ("%d %f : '%s'\n", ans, value, buffer);
    1259             : 
    1260             :    strcpy (buffer, "");
    1261             :    ans = myAtoF (buffer, &value);
    1262             :    printf ("%d %f : ", ans, value);
    1263             :    ans = myIsReal_old (buffer, &value);
    1264             :    printf ("%d %f : '%s'\n", ans, value, buffer);
    1265             : 
    1266             :    tail = NULL;
    1267             :    FileTail ("test\\me/now", &tail);
    1268             :    printf ("%s \n", tail);
    1269             :    free (tail);
    1270             :    tail = NULL;
    1271             :    FileTail ("test/me\\now", &tail);
    1272             :    printf ("%s \n", tail);
    1273             :    free (tail);
    1274             : 
    1275             :    strcpy (buffer, "  here  ");
    1276             :    strTrim (buffer);
    1277             :    printf ("%s\n", buffer);
    1278             : 
    1279             :    strcpy (buffer, "  here  ");
    1280             :    strCompact (buffer, ' ');
    1281             :    printf ("'%s'\n", buffer);
    1282             :    return 0;
    1283             : }
    1284             : #endif

Generated by: LCOV version 1.14