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