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 (*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 (*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 (*ptr)) && (*ptr != '.'))
331       if (*ptr != '-')
332          return 0;
333    len = strlen (ptr);
334    for (i = 1; i < len - 1; i++) {
335       if ((!isdigit (ptr[i])) && (ptr[i] != '.'))
336          return 0;
337    }
338    if ((!isdigit (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 
myRound(double data,uChar place)656 double myRound (double data, uChar place)
657 {
658    if (place > 17)
659       place = 17;
660 
661    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  */
strTrim(char * str)693 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    myAssert (str != NULL);
700    if (str == NULL) {
701       return;
702    }
703 
704    /* Trim the string to the left first. */
705    for (ptr = str; isspace (*ptr); ptr++) {
706    }
707    /* Did we hit the end of an all space string? */
708    if (*ptr == '\0') {
709       *str = '\0';
710       return;
711    }
712 
713    /* now work on the right side. */
714    for (ptr2 = ptr + (strlen (ptr) - 1); isspace (*ptr2); ptr2--) {
715    }
716 
717    /* adjust the pointer to add the null byte. */
718    ptr2++;
719    *ptr2 = '\0';
720 
721    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       while ((*str++ = *ptr++) != '\0') {
725       }
726       *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  */
strTrimRight(char * str,char c)750 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    myAssert (str != NULL);
756    if (str == NULL) {
757       return;
758    }
759 
760    for (i = (int)strlen (str) - 1;
761         ((i >= 0) && ((isspace ((unsigned char)str[i])) || (str[i] == c))); i--) {
762    }
763    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  */
strCompact(char * str,char c)786 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    myAssert (str != NULL);
792    if (str == NULL) {
793       return;
794    }
795 
796    ptr = str;
797    while ((*str = *(ptr++)) != '\0') {
798       if (*(str++) == c) {
799          while ((*ptr != '\0') && (*ptr == c)) {
800             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 (*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 (*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(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 (*str1) == tolower (*str2); str1++, str2++) {
972       if (*str1 == '\0')
973          return 0;
974    }
975    return (tolower (*str1) - tolower (*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 (str1[i]);
982       c2 = tolower (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  */
GetIndexFromStr(const char * str,const char * const * Opt,int * Index)1025 int GetIndexFromStr (const char *str, const char * const *Opt, int *Index)
1026 {
1027    int cnt = 0;         /* Current Count in Opt. */
1028 
1029    myAssert (str != NULL);
1030    if (str == NULL) {
1031       *Index = -1;
1032       return -1;
1033    }
1034 
1035    for (; *Opt != NULL; Opt++, cnt++) {
1036       if (strcmp (str, *Opt) == 0) {
1037          *Index = cnt;
1038          return cnt;
1039       }
1040    }
1041    *Index = -1;
1042    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
main(int argc,char ** argv)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
1285