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