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
|