xref: /petsc/src/sys/utils/str.c (revision 7bdf51c94ab34bb5ee23d1e71be7a8794867c0b9)
1 
2 /*
3     We define the string operations here. The reason we just do not use
4   the standard string routines in the PETSc code is that on some machines
5   they are broken or have the wrong prototypes.
6 
7 */
8 #include <petscsys.h>                   /*I  "petscsys.h"   I*/
9 #if defined(PETSC_HAVE_STRING_H)
10 #include <string.h>             /* strstr */
11 #endif
12 #if defined(PETSC_HAVE_STRINGS_H)
13 #  include <strings.h>          /* strcasecmp */
14 #endif
15 
16 /*@C
17    PetscStrToArray - Separates a string by a charactor (for example ' ' or '\n') and creates an array of strings
18 
19    Not Collective
20 
21    Input Parameters:
22 +  s - pointer to string
23 -  sp - separator charactor
24 
25    Output Parameter:
26 +   argc - the number of entries in the array
27 -   args - an array of the entries with a null at the end
28 
29    Level: intermediate
30 
31    Notes: this may be called before PetscInitialize() or after PetscFinalize()
32 
33    Not for use in Fortran
34 
35    Developer Notes: Using raw malloc() and does not call error handlers since this may be used before PETSc is initialized. Used
36      to generate argc, args arguments passed to MPI_Init()
37 
38 .seealso: PetscStrToArrayDestroy(), PetscToken, PetscTokenCreate()
39 
40 @*/
41 PetscErrorCode  PetscStrToArray(const char s[],char sp,int *argc,char ***args)
42 {
43   int       i,j,n,*lens,cnt = 0;
44   PetscBool flg = PETSC_FALSE;
45 
46   if (!s) n = 0;
47   else    n = strlen(s);
48   *argc = 0;
49   *args = NULL;
50   for (; n>0; n--) {   /* remove separator chars at the end - and will empty the string if all chars are separator chars */
51     if (s[n-1] != sp) break;
52   }
53   if (!n) {
54     return(0);
55   }
56   for (i=0; i<n; i++) {
57     if (s[i] != sp) break;
58   }
59   for (;i<n+1; i++) {
60     if ((s[i] == sp || s[i] == 0) && !flg) {flg = PETSC_TRUE; (*argc)++;}
61     else if (s[i] != sp) {flg = PETSC_FALSE;}
62   }
63   (*args) = (char**) malloc(((*argc)+1)*sizeof(char*)); if (!*args) return PETSC_ERR_MEM;
64   lens    = (int*) malloc((*argc)*sizeof(int)); if (!lens) return PETSC_ERR_MEM;
65   for (i=0; i<*argc; i++) lens[i] = 0;
66 
67   *argc = 0;
68   for (i=0; i<n; i++) {
69     if (s[i] != sp) break;
70   }
71   for (;i<n+1; i++) {
72     if ((s[i] == sp || s[i] == 0) && !flg) {flg = PETSC_TRUE; (*argc)++;}
73     else if (s[i] != sp) {lens[*argc]++;flg = PETSC_FALSE;}
74   }
75 
76   for (i=0; i<*argc; i++) {
77     (*args)[i] = (char*) malloc((lens[i]+1)*sizeof(char));
78     if (!(*args)[i]) {
79       free(lens);
80       for (j=0; j<i; j++) free((*args)[j]);
81       free(*args);
82       return PETSC_ERR_MEM;
83     }
84   }
85   free(lens);
86   (*args)[*argc] = 0;
87 
88   *argc = 0;
89   for (i=0; i<n; i++) {
90     if (s[i] != sp) break;
91   }
92   for (;i<n+1; i++) {
93     if ((s[i] == sp || s[i] == 0) && !flg) {flg = PETSC_TRUE; (*args)[*argc][cnt++] = 0; (*argc)++; cnt = 0;}
94     else if (s[i] != sp && s[i] != 0) {(*args)[*argc][cnt++] = s[i]; flg = PETSC_FALSE;}
95   }
96   return 0;
97 }
98 
99 /*@C
100    PetscStrToArrayDestroy - Frees array created with PetscStrToArray().
101 
102    Not Collective
103 
104    Output Parameters:
105 +  argc - the number of arguments
106 -  args - the array of arguments
107 
108    Level: intermediate
109 
110    Concepts: command line arguments
111 
112    Notes: This may be called before PetscInitialize() or after PetscFinalize()
113 
114    Not for use in Fortran
115 
116 .seealso: PetscStrToArray()
117 
118 @*/
119 PetscErrorCode  PetscStrToArrayDestroy(int argc,char **args)
120 {
121   PetscInt i;
122 
123   for (i=0; i<argc; i++) free(args[i]);
124   if (args) free(args);
125   return 0;
126 }
127 
128 /*@C
129    PetscStrlen - Gets length of a string
130 
131    Not Collective
132 
133    Input Parameters:
134 .  s - pointer to string
135 
136    Output Parameter:
137 .  len - length in bytes
138 
139    Level: intermediate
140 
141    Note:
142    This routine is analogous to strlen().
143 
144    Null string returns a length of zero
145 
146    Not for use in Fortran
147 
148   Concepts: string length
149 
150 @*/
151 PetscErrorCode  PetscStrlen(const char s[],size_t *len)
152 {
153   PetscFunctionBegin;
154   if (!s) *len = 0;
155   else    *len = strlen(s);
156   PetscFunctionReturn(0);
157 }
158 
159 /*@C
160    PetscStrallocpy - Allocates space to hold a copy of a string then copies the string
161 
162    Not Collective
163 
164    Input Parameters:
165 .  s - pointer to string
166 
167    Output Parameter:
168 .  t - the copied string
169 
170    Level: intermediate
171 
172    Note:
173       Null string returns a new null string
174 
175       Not for use in Fortran
176 
177   Concepts: string copy
178 
179 @*/
180 PetscErrorCode  PetscStrallocpy(const char s[],char *t[])
181 {
182   PetscErrorCode ierr;
183   size_t         len;
184   char           *tmp = 0;
185 
186   PetscFunctionBegin;
187   if (s) {
188     ierr = PetscStrlen(s,&len);CHKERRQ(ierr);
189     ierr = PetscMalloc1(1+len,&tmp);CHKERRQ(ierr);
190     ierr = PetscStrcpy(tmp,s);CHKERRQ(ierr);
191   }
192   *t = tmp;
193   PetscFunctionReturn(0);
194 }
195 
196 /*@C
197    PetscStrArrayallocpy - Allocates space to hold a copy of an array of strings then copies the strings
198 
199    Not Collective
200 
201    Input Parameters:
202 .  s - pointer to array of strings (final string is a null)
203 
204    Output Parameter:
205 .  t - the copied array string
206 
207    Level: intermediate
208 
209    Note:
210       Not for use in Fortran
211 
212   Concepts: string copy
213 
214 .seealso: PetscStrallocpy() PetscStrArrayDestroy()
215 
216 @*/
217 PetscErrorCode  PetscStrArrayallocpy(const char *const *list,char ***t)
218 {
219   PetscErrorCode ierr;
220   PetscInt       i,n = 0;
221 
222   PetscFunctionBegin;
223   while (list[n++]) ;
224   ierr = PetscMalloc1(n+1,t);CHKERRQ(ierr);
225   for (i=0; i<n; i++) {
226     ierr = PetscStrallocpy(list[i],(*t)+i);CHKERRQ(ierr);
227   }
228   (*t)[n] = NULL;
229   PetscFunctionReturn(0);
230 }
231 
232 /*@C
233    PetscStrArrayDestroy - Frees array of strings created with PetscStrArrayallocpy().
234 
235    Not Collective
236 
237    Output Parameters:
238 .   list - array of strings
239 
240    Level: intermediate
241 
242    Concepts: command line arguments
243 
244    Notes: Not for use in Fortran
245 
246 .seealso: PetscStrArrayallocpy()
247 
248 @*/
249 PetscErrorCode PetscStrArrayDestroy(char ***list)
250 {
251   PetscInt       n = 0;
252   PetscErrorCode ierr;
253 
254   PetscFunctionBegin;
255   if (!*list) PetscFunctionReturn(0);
256   while ((*list)[n]) {
257     ierr = PetscFree((*list)[n]);CHKERRQ(ierr);
258     n++;
259   }
260   ierr = PetscFree(*list);CHKERRQ(ierr);
261   PetscFunctionReturn(0);
262 }
263 
264 /*@C
265    PetscStrNArrayallocpy - Allocates space to hold a copy of an array of strings then copies the strings
266 
267    Not Collective
268 
269    Input Parameters:
270 +  n - the number of string entries
271 -  s - pointer to array of strings
272 
273    Output Parameter:
274 .  t - the copied array string
275 
276    Level: intermediate
277 
278    Note:
279       Not for use in Fortran
280 
281   Concepts: string copy
282 
283 .seealso: PetscStrallocpy() PetscStrArrayDestroy()
284 
285 @*/
286 PetscErrorCode  PetscStrNArrayallocpy(PetscInt n,const char *const *list,char ***t)
287 {
288   PetscErrorCode ierr;
289   PetscInt       i;
290 
291   PetscFunctionBegin;
292   ierr = PetscMalloc1(n,t);CHKERRQ(ierr);
293   for (i=0; i<n; i++) {
294     ierr = PetscStrallocpy(list[i],(*t)+i);CHKERRQ(ierr);
295   }
296   PetscFunctionReturn(0);
297 }
298 
299 /*@C
300    PetscStrNArrayDestroy - Frees array of strings created with PetscStrArrayallocpy().
301 
302    Not Collective
303 
304    Output Parameters:
305 +   n - number of string entries
306 -   list - array of strings
307 
308    Level: intermediate
309 
310    Notes: Not for use in Fortran
311 
312 .seealso: PetscStrArrayallocpy()
313 
314 @*/
315 PetscErrorCode PetscStrNArrayDestroy(PetscInt n,char ***list)
316 {
317   PetscErrorCode ierr;
318   PetscInt       i;
319 
320   PetscFunctionBegin;
321   if (!*list) PetscFunctionReturn(0);
322   for (i=0; i<n; i++){
323     ierr = PetscFree((*list)[i]);CHKERRQ(ierr);
324   }
325   ierr = PetscFree(*list);CHKERRQ(ierr);
326   PetscFunctionReturn(0);
327 }
328 
329 /*@C
330    PetscStrcpy - Copies a string
331 
332    Not Collective
333 
334    Input Parameters:
335 .  t - pointer to string
336 
337    Output Parameter:
338 .  s - the copied string
339 
340    Level: intermediate
341 
342    Notes:
343      Null string returns a string starting with zero
344 
345      Not for use in Fortran
346 
347   Concepts: string copy
348 
349 .seealso: PetscStrncpy(), PetscStrcat(), PetscStrlcat()
350 
351 @*/
352 
353 PetscErrorCode  PetscStrcpy(char s[],const char t[])
354 {
355   PetscFunctionBegin;
356   if (t && !s) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Trying to copy string into null pointer");
357   if (t) strcpy(s,t);
358   else if (s) s[0] = 0;
359   PetscFunctionReturn(0);
360 }
361 
362 /*@C
363    PetscStrncpy - Copies a string up to a certain length
364 
365    Not Collective
366 
367    Input Parameters:
368 +  t - pointer to string
369 -  n - the length to copy
370 
371    Output Parameter:
372 .  s - the copied string
373 
374    Level: intermediate
375 
376    Note:
377      Null string returns a string starting with zero
378 
379      If the string that is being copied is of length n or larger then the entire string is not
380      copied and the file location of s is set to NULL. This is different then the behavior of
381      strncpy() which leaves s non-terminated.
382 
383   Concepts: string copy
384 
385 .seealso: PetscStrcpy(), PetscStrcat(), PetscStrlcat()
386 
387 @*/
388 PetscErrorCode  PetscStrncpy(char s[],const char t[],size_t n)
389 {
390   PetscFunctionBegin;
391   if (t && !s) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Trying to copy string into null pointer");
392   if (t) {
393     if (n > 1) {
394       strncpy(s,t,n-1);
395       s[n-1] = '\0';
396     } else {
397       s[0] = '\0';
398     }
399   } else if (s) s[0] = 0;
400   PetscFunctionReturn(0);
401 }
402 
403 /*@C
404    PetscStrcat - Concatenates a string onto a given string
405 
406    Not Collective
407 
408    Input Parameters:
409 +  s - string to be added to
410 -  t - pointer to string to be added to end
411 
412    Level: intermediate
413 
414    Notes: Not for use in Fortran
415 
416   Concepts: string copy
417 
418 .seealso: PetscStrcpy(), PetscStrncpy(), PetscStrlcat()
419 
420 @*/
421 PetscErrorCode  PetscStrcat(char s[],const char t[])
422 {
423   PetscFunctionBegin;
424   if (!t) PetscFunctionReturn(0);
425   strcat(s,t);
426   PetscFunctionReturn(0);
427 }
428 
429 /*@C
430    PetscStrlcat - Concatenates a string onto a given string, up to a given length
431 
432    Not Collective
433 
434    Input Parameters:
435 +  s - pointer to string to be added to end
436 .  t - string to be added to
437 -  n - length of the original allocated string
438 
439    Level: intermediate
440 
441   Notes:
442   Not for use in Fortran
443 
444   Unlike the system call strncat(), the length passed in is the length of the
445   original allocated space, not the length of the left-over space. This is
446   similar to the BSD system call strlcat().
447 
448   Concepts: string copy
449 
450 .seealso: PetscStrcpy(), PetscStrncpy(), PetscStrcat()
451 
452 @*/
453 PetscErrorCode  PetscStrlcat(char s[],const char t[],size_t n)
454 {
455   size_t         len;
456   PetscErrorCode ierr;
457 
458   PetscFunctionBegin;
459   ierr = PetscStrlen(t,&len);CHKERRQ(ierr);
460   strncat(s,t,n - len);
461   PetscFunctionReturn(0);
462 }
463 
464 /*
465    Only to be used with PetscCheck__FUNCT__()!
466 
467 */
468 void  PetscStrcmpNoError(const char a[],const char b[],PetscBool  *flg)
469 {
470   int c;
471 
472   if (!a && !b)      *flg = PETSC_TRUE;
473   else if (!a || !b) *flg = PETSC_FALSE;
474   else {
475     c = strcmp(a,b);
476     if (c) *flg = PETSC_FALSE;
477     else   *flg = PETSC_TRUE;
478   }
479 }
480 
481 /*@C
482    PetscStrcmp - Compares two strings,
483 
484    Not Collective
485 
486    Input Parameters:
487 +  a - pointer to string first string
488 -  b - pointer to second string
489 
490    Output Parameter:
491 .  flg - PETSC_TRUE if the two strings are equal
492 
493    Level: intermediate
494 
495    Notes:    Not for use in Fortran
496 
497 .seealso: PetscStrgrt(), PetscStrncmp(), PetscStrcasecmp()
498 
499 @*/
500 PetscErrorCode  PetscStrcmp(const char a[],const char b[],PetscBool  *flg)
501 {
502   int c;
503 
504   PetscFunctionBegin;
505   if (!a && !b)      *flg = PETSC_TRUE;
506   else if (!a || !b) *flg = PETSC_FALSE;
507   else {
508     c = strcmp(a,b);
509     if (c) *flg = PETSC_FALSE;
510     else   *flg = PETSC_TRUE;
511   }
512   PetscFunctionReturn(0);
513 }
514 
515 /*@C
516    PetscStrgrt - If first string is greater than the second
517 
518    Not Collective
519 
520    Input Parameters:
521 +  a - pointer to first string
522 -  b - pointer to second string
523 
524    Output Parameter:
525 .  flg - if the first string is greater
526 
527    Notes:
528     Null arguments are ok, a null string is considered smaller than
529     all others
530 
531    Not for use in Fortran
532 
533    Level: intermediate
534 
535 .seealso: PetscStrcmp(), PetscStrncmp(), PetscStrcasecmp()
536 
537 @*/
538 PetscErrorCode  PetscStrgrt(const char a[],const char b[],PetscBool  *t)
539 {
540   int c;
541 
542   PetscFunctionBegin;
543   if (!a && !b) *t = PETSC_FALSE;
544   else if (a && !b) *t = PETSC_TRUE;
545   else if (!a && b) *t = PETSC_FALSE;
546   else {
547     c = strcmp(a,b);
548     if (c > 0) *t = PETSC_TRUE;
549     else       *t = PETSC_FALSE;
550   }
551   PetscFunctionReturn(0);
552 }
553 
554 /*@C
555    PetscStrcasecmp - Returns true if the two strings are the same
556      except possibly for case.
557 
558    Not Collective
559 
560    Input Parameters:
561 +  a - pointer to first string
562 -  b - pointer to second string
563 
564    Output Parameter:
565 .  flg - if the two strings are the same
566 
567    Notes:
568     Null arguments are ok
569 
570    Not for use in Fortran
571 
572    Level: intermediate
573 
574 .seealso: PetscStrcmp(), PetscStrncmp(), PetscStrgrt()
575 
576 @*/
577 PetscErrorCode  PetscStrcasecmp(const char a[],const char b[],PetscBool  *t)
578 {
579   int c;
580 
581   PetscFunctionBegin;
582   if (!a && !b) c = 0;
583   else if (!a || !b) c = 1;
584 #if defined(PETSC_HAVE_STRCASECMP)
585   else c = strcasecmp(a,b);
586 #elif defined(PETSC_HAVE_STRICMP)
587   else c = stricmp(a,b);
588 #else
589   else {
590     char           *aa,*bb;
591     PetscErrorCode ierr;
592     ierr = PetscStrallocpy(a,&aa);CHKERRQ(ierr);
593     ierr = PetscStrallocpy(b,&bb);CHKERRQ(ierr);
594     ierr = PetscStrtolower(aa);CHKERRQ(ierr);
595     ierr = PetscStrtolower(bb);CHKERRQ(ierr);
596     ierr = PetscStrcmp(aa,bb,t);CHKERRQ(ierr);
597     ierr = PetscFree(aa);CHKERRQ(ierr);
598     ierr = PetscFree(bb);CHKERRQ(ierr);
599     PetscFunctionReturn(0);
600   }
601 #endif
602   if (!c) *t = PETSC_TRUE;
603   else    *t = PETSC_FALSE;
604   PetscFunctionReturn(0);
605 }
606 
607 
608 
609 /*@C
610    PetscStrncmp - Compares two strings, up to a certain length
611 
612    Not Collective
613 
614    Input Parameters:
615 +  a - pointer to first string
616 .  b - pointer to second string
617 -  n - length to compare up to
618 
619    Output Parameter:
620 .  t - if the two strings are equal
621 
622    Level: intermediate
623 
624    Notes:    Not for use in Fortran
625 
626 .seealso: PetscStrgrt(), PetscStrcmp(), PetscStrcasecmp()
627 
628 @*/
629 PetscErrorCode  PetscStrncmp(const char a[],const char b[],size_t n,PetscBool  *t)
630 {
631   int c;
632 
633   PetscFunctionBegin;
634   c = strncmp(a,b,n);
635   if (!c) *t = PETSC_TRUE;
636   else    *t = PETSC_FALSE;
637   PetscFunctionReturn(0);
638 }
639 
640 /*@C
641    PetscStrchr - Locates first occurance of a character in a string
642 
643    Not Collective
644 
645    Input Parameters:
646 +  a - pointer to string
647 -  b - character
648 
649    Output Parameter:
650 .  c - location of occurance, NULL if not found
651 
652    Level: intermediate
653 
654    Notes:    Not for use in Fortran
655 
656 @*/
657 PetscErrorCode  PetscStrchr(const char a[],char b,char *c[])
658 {
659   PetscFunctionBegin;
660   *c = (char*)strchr(a,b);
661   PetscFunctionReturn(0);
662 }
663 
664 /*@C
665    PetscStrrchr - Locates one location past the last occurance of a character in a string,
666       if the character is not found then returns entire string
667 
668    Not Collective
669 
670    Input Parameters:
671 +  a - pointer to string
672 -  b - character
673 
674    Output Parameter:
675 .  tmp - location of occurance, a if not found
676 
677    Level: intermediate
678 
679    Notes:    Not for use in Fortran
680 
681 @*/
682 PetscErrorCode  PetscStrrchr(const char a[],char b,char *tmp[])
683 {
684   PetscFunctionBegin;
685   *tmp = (char*)strrchr(a,b);
686   if (!*tmp) *tmp = (char*)a;
687   else *tmp = *tmp + 1;
688   PetscFunctionReturn(0);
689 }
690 
691 /*@C
692    PetscStrtolower - Converts string to lower case
693 
694    Not Collective
695 
696    Input Parameters:
697 .  a - pointer to string
698 
699    Level: intermediate
700 
701    Notes:    Not for use in Fortran
702 
703 @*/
704 PetscErrorCode  PetscStrtolower(char a[])
705 {
706   PetscFunctionBegin;
707   while (*a) {
708     if (*a >= 'A' && *a <= 'Z') *a += 'a' - 'A';
709     a++;
710   }
711   PetscFunctionReturn(0);
712 }
713 
714 /*@C
715    PetscStrtoupper - Converts string to upper case
716 
717    Not Collective
718 
719    Input Parameters:
720 .  a - pointer to string
721 
722    Level: intermediate
723 
724    Notes:    Not for use in Fortran
725 
726 @*/
727 PetscErrorCode  PetscStrtoupper(char a[])
728 {
729   PetscFunctionBegin;
730   while (*a) {
731     if (*a >= 'a' && *a <= 'z') *a += 'A' - 'a';
732     a++;
733   }
734   PetscFunctionReturn(0);
735 }
736 
737 /*@C
738    PetscStrendswith - Determines if a string ends with a certain string
739 
740    Not Collective
741 
742    Input Parameters:
743 +  a - pointer to string
744 -  b - string to endwith
745 
746    Output Parameter:
747 .  flg - PETSC_TRUE or PETSC_FALSE
748 
749    Notes:     Not for use in Fortran
750 
751    Level: intermediate
752 
753 @*/
754 PetscErrorCode  PetscStrendswith(const char a[],const char b[],PetscBool *flg)
755 {
756   char           *test;
757   PetscErrorCode ierr;
758   size_t         na,nb;
759 
760   PetscFunctionBegin;
761   *flg = PETSC_FALSE;
762   ierr = PetscStrrstr(a,b,&test);CHKERRQ(ierr);
763   if (test) {
764     ierr = PetscStrlen(a,&na);CHKERRQ(ierr);
765     ierr = PetscStrlen(b,&nb);CHKERRQ(ierr);
766     if (a+na-nb == test) *flg = PETSC_TRUE;
767   }
768   PetscFunctionReturn(0);
769 }
770 
771 /*@C
772    PetscStrbeginswith - Determines if a string begins with a certain string
773 
774    Not Collective
775 
776    Input Parameters:
777 +  a - pointer to string
778 -  b - string to begin with
779 
780    Output Parameter:
781 .  flg - PETSC_TRUE or PETSC_FALSE
782 
783    Notes:     Not for use in Fortran
784 
785    Level: intermediate
786 
787 .seealso: PetscStrendswithwhich(), PetscStrendswith(), PetscStrtoupper, PetscStrtolower(), PetscStrrchr(), PetscStrchr(),
788           PetscStrncmp(), PetscStrlen(), PetscStrncmp(), PetscStrcmp()
789 
790 @*/
791 PetscErrorCode  PetscStrbeginswith(const char a[],const char b[],PetscBool *flg)
792 {
793   char           *test;
794   PetscErrorCode ierr;
795 
796   PetscFunctionBegin;
797   *flg = PETSC_FALSE;
798   ierr = PetscStrrstr(a,b,&test);CHKERRQ(ierr);
799   if (test && (test == a)) *flg = PETSC_TRUE;
800   PetscFunctionReturn(0);
801 }
802 
803 
804 /*@C
805    PetscStrendswithwhich - Determines if a string ends with one of several possible strings
806 
807    Not Collective
808 
809    Input Parameters:
810 +  a - pointer to string
811 -  bs - strings to endwith (last entry must be null)
812 
813    Output Parameter:
814 .  cnt - the index of the string it ends with or 1+the last possible index
815 
816    Notes:     Not for use in Fortran
817 
818    Level: intermediate
819 
820 @*/
821 PetscErrorCode  PetscStrendswithwhich(const char a[],const char *const *bs,PetscInt *cnt)
822 {
823   PetscBool      flg;
824   PetscErrorCode ierr;
825 
826   PetscFunctionBegin;
827   *cnt = 0;
828   while (bs[*cnt]) {
829     ierr = PetscStrendswith(a,bs[*cnt],&flg);CHKERRQ(ierr);
830     if (flg) PetscFunctionReturn(0);
831     *cnt += 1;
832   }
833   PetscFunctionReturn(0);
834 }
835 
836 /*@C
837    PetscStrrstr - Locates last occurance of string in another string
838 
839    Not Collective
840 
841    Input Parameters:
842 +  a - pointer to string
843 -  b - string to find
844 
845    Output Parameter:
846 .  tmp - location of occurance
847 
848    Notes:     Not for use in Fortran
849 
850    Level: intermediate
851 
852 @*/
853 PetscErrorCode  PetscStrrstr(const char a[],const char b[],char *tmp[])
854 {
855   const char *stmp = a, *ltmp = 0;
856 
857   PetscFunctionBegin;
858   while (stmp) {
859     stmp = (char*)strstr(stmp,b);
860     if (stmp) {ltmp = stmp;stmp++;}
861   }
862   *tmp = (char*)ltmp;
863   PetscFunctionReturn(0);
864 }
865 
866 /*@C
867    PetscStrstr - Locates first occurance of string in another string
868 
869    Not Collective
870 
871    Input Parameters:
872 +  haystack - string to search
873 -  needle - string to find
874 
875    Output Parameter:
876 .  tmp - location of occurance, is a NULL if the string is not found
877 
878    Notes: Not for use in Fortran
879 
880    Level: intermediate
881 
882 @*/
883 PetscErrorCode  PetscStrstr(const char haystack[],const char needle[],char *tmp[])
884 {
885   PetscFunctionBegin;
886   *tmp = (char*)strstr(haystack,needle);
887   PetscFunctionReturn(0);
888 }
889 
890 struct _p_PetscToken {char token;char *array;char *current;};
891 
892 /*@C
893    PetscTokenFind - Locates next "token" in a string
894 
895    Not Collective
896 
897    Input Parameters:
898 .  a - pointer to token
899 
900    Output Parameter:
901 .  result - location of occurance, NULL if not found
902 
903    Notes:
904 
905      This version is different from the system version in that
906   it allows you to pass a read-only string into the function.
907 
908      This version also treats all characters etc. inside a double quote "
909    as a single token.
910 
911      For example if the separator character is + and the string is xxxx+y then the first fine will return a pointer to a null terminated xxxx and the
912    second will return a null terminated y
913 
914      If the separator character is + and the string is xxxx then the first and only token found will be a pointer to a null terminated xxxx
915 
916     Not for use in Fortran
917 
918    Level: intermediate
919 
920 
921 .seealso: PetscTokenCreate(), PetscTokenDestroy()
922 @*/
923 PetscErrorCode  PetscTokenFind(PetscToken a,char *result[])
924 {
925   char *ptr = a->current,token;
926 
927   PetscFunctionBegin;
928   *result = a->current;
929   if (ptr && !*ptr) {*result = 0;PetscFunctionReturn(0);}
930   token = a->token;
931   if (ptr && (*ptr == '"')) {token = '"';(*result)++;ptr++;}
932   while (ptr) {
933     if (*ptr == token) {
934       *ptr++ = 0;
935       while (*ptr == a->token) ptr++;
936       a->current = ptr;
937       break;
938     }
939     if (!*ptr) {
940       a->current = 0;
941       break;
942     }
943     ptr++;
944   }
945   PetscFunctionReturn(0);
946 }
947 
948 /*@C
949    PetscTokenCreate - Creates a PetscToken used to find tokens in a string
950 
951    Not Collective
952 
953    Input Parameters:
954 +  string - the string to look in
955 -  b - the separator character
956 
957    Output Parameter:
958 .  t- the token object
959 
960    Notes:
961 
962      This version is different from the system version in that
963   it allows you to pass a read-only string into the function.
964 
965     Not for use in Fortran
966 
967    Level: intermediate
968 
969 .seealso: PetscTokenFind(), PetscTokenDestroy()
970 @*/
971 PetscErrorCode  PetscTokenCreate(const char a[],const char b,PetscToken *t)
972 {
973   PetscErrorCode ierr;
974 
975   PetscFunctionBegin;
976   ierr = PetscNew(t);CHKERRQ(ierr);
977   ierr = PetscStrallocpy(a,&(*t)->array);CHKERRQ(ierr);
978 
979   (*t)->current = (*t)->array;
980   (*t)->token   = b;
981   PetscFunctionReturn(0);
982 }
983 
984 /*@C
985    PetscTokenDestroy - Destroys a PetscToken
986 
987    Not Collective
988 
989    Input Parameters:
990 .  a - pointer to token
991 
992    Level: intermediate
993 
994    Notes:     Not for use in Fortran
995 
996 .seealso: PetscTokenCreate(), PetscTokenFind()
997 @*/
998 PetscErrorCode  PetscTokenDestroy(PetscToken *a)
999 {
1000   PetscErrorCode ierr;
1001 
1002   PetscFunctionBegin;
1003   if (!*a) PetscFunctionReturn(0);
1004   ierr = PetscFree((*a)->array);CHKERRQ(ierr);
1005   ierr = PetscFree(*a);CHKERRQ(ierr);
1006   PetscFunctionReturn(0);
1007 }
1008 
1009 /*@C
1010    PetscStrInList - search string in character-delimited list
1011 
1012    Not Collective
1013 
1014    Input Parameters:
1015 +  str - the string to look for
1016 .  list - the list to search in
1017 -  sep - the separator character
1018 
1019    Output Parameter:
1020 .  found - whether str is in list
1021 
1022    Level: intermediate
1023 
1024    Notes: Not for use in Fortran
1025 
1026 .seealso: PetscTokenCreate(), PetscTokenFind(), PetscStrcmp()
1027 @*/
1028 PetscErrorCode PetscStrInList(const char str[],const char list[],char sep,PetscBool *found)
1029 {
1030   PetscToken     token;
1031   char           *item;
1032   PetscErrorCode ierr;
1033 
1034   PetscFunctionBegin;
1035   *found = PETSC_FALSE;
1036   ierr = PetscTokenCreate(list,sep,&token);CHKERRQ(ierr);
1037   ierr = PetscTokenFind(token,&item);CHKERRQ(ierr);
1038   while (item) {
1039     ierr = PetscStrcmp(str,item,found);CHKERRQ(ierr);
1040     if (*found) break;
1041     ierr = PetscTokenFind(token,&item);CHKERRQ(ierr);
1042   }
1043   ierr = PetscTokenDestroy(&token);CHKERRQ(ierr);
1044   PetscFunctionReturn(0);
1045 }
1046 
1047 /*@C
1048    PetscGetPetscDir - Gets the directory PETSc is installed in
1049 
1050    Not Collective
1051 
1052    Output Parameter:
1053 .  dir - the directory
1054 
1055    Level: developer
1056 
1057    Notes: Not for use in Fortran
1058 
1059 @*/
1060 PetscErrorCode  PetscGetPetscDir(const char *dir[])
1061 {
1062   PetscFunctionBegin;
1063   *dir = PETSC_DIR;
1064   PetscFunctionReturn(0);
1065 }
1066 
1067 /*@C
1068    PetscStrreplace - Replaces substrings in string with other substrings
1069 
1070    Not Collective
1071 
1072    Input Parameters:
1073 +   comm - MPI_Comm of processors that are processing the string
1074 .   aa - the string to look in
1075 .   b - the resulting copy of a with replaced strings (b can be the same as a)
1076 -   len - the length of b
1077 
1078    Notes:
1079       Replaces   ${PETSC_ARCH},${PETSC_DIR},${PETSC_LIB_DIR},${DISPLAY},
1080       ${HOMEDIRECTORY},${WORKINGDIRECTORY},${USERNAME}, ${HOSTNAME} with appropriate values
1081       as well as any environmental variables.
1082 
1083       PETSC_LIB_DIR uses the environmental variable if it exists. PETSC_ARCH and PETSC_DIR use what
1084       PETSc was built with and do not use environmental variables.
1085 
1086       Not for use in Fortran
1087 
1088    Level: intermediate
1089 
1090 @*/
1091 PetscErrorCode  PetscStrreplace(MPI_Comm comm,const char aa[],char b[],size_t len)
1092 {
1093   PetscErrorCode ierr;
1094   int            i = 0;
1095   size_t         l,l1,l2,l3;
1096   char           *work,*par,*epar,env[1024],*tfree,*a = (char*)aa;
1097   const char     *s[] = {"${PETSC_ARCH}","${PETSC_DIR}","${PETSC_LIB_DIR}","${DISPLAY}","${HOMEDIRECTORY}","${WORKINGDIRECTORY}","${USERNAME}","${HOSTNAME}",0};
1098   char           *r[] = {0,0,0,0,0,0,0,0,0};
1099   PetscBool      flag;
1100 
1101   PetscFunctionBegin;
1102   if (!a || !b) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"a and b strings must be nonnull");
1103   if (aa == b) {
1104     ierr = PetscStrallocpy(aa,(char**)&a);CHKERRQ(ierr);
1105   }
1106   ierr = PetscMalloc1(len,&work);CHKERRQ(ierr);
1107 
1108   /* get values for replaced variables */
1109   ierr = PetscStrallocpy(PETSC_ARCH,&r[0]);CHKERRQ(ierr);
1110   ierr = PetscStrallocpy(PETSC_DIR,&r[1]);CHKERRQ(ierr);
1111   ierr = PetscStrallocpy(PETSC_LIB_DIR,&r[2]);CHKERRQ(ierr);
1112   ierr = PetscMalloc1(256,&r[3]);CHKERRQ(ierr);
1113   ierr = PetscMalloc1(PETSC_MAX_PATH_LEN,&r[4]);CHKERRQ(ierr);
1114   ierr = PetscMalloc1(PETSC_MAX_PATH_LEN,&r[5]);CHKERRQ(ierr);
1115   ierr = PetscMalloc1(256,&r[6]);CHKERRQ(ierr);
1116   ierr = PetscMalloc1(256,&r[7]);CHKERRQ(ierr);
1117   ierr = PetscGetDisplay(r[3],256);CHKERRQ(ierr);
1118   ierr = PetscGetHomeDirectory(r[4],PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
1119   ierr = PetscGetWorkingDirectory(r[5],PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
1120   ierr = PetscGetUserName(r[6],256);CHKERRQ(ierr);
1121   ierr = PetscGetHostName(r[7],256);CHKERRQ(ierr);
1122 
1123   /* replace that are in environment */
1124   ierr = PetscOptionsGetenv(comm,"PETSC_LIB_DIR",env,1024,&flag);CHKERRQ(ierr);
1125   if (flag) {
1126     ierr = PetscFree(r[2]);CHKERRQ(ierr);
1127     ierr = PetscStrallocpy(env,&r[2]);CHKERRQ(ierr);
1128   }
1129 
1130   /* replace the requested strings */
1131   ierr = PetscStrncpy(b,a,len);CHKERRQ(ierr);
1132   while (s[i]) {
1133     ierr = PetscStrlen(s[i],&l);CHKERRQ(ierr);
1134     ierr = PetscStrstr(b,s[i],&par);CHKERRQ(ierr);
1135     while (par) {
1136       *par =  0;
1137       par += l;
1138 
1139       ierr = PetscStrlen(b,&l1);CHKERRQ(ierr);
1140       ierr = PetscStrlen(r[i],&l2);CHKERRQ(ierr);
1141       ierr = PetscStrlen(par,&l3);CHKERRQ(ierr);
1142       if (l1 + l2 + l3 >= len) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"b len is not long enough to hold new values");
1143       ierr = PetscStrcpy(work,b);CHKERRQ(ierr);
1144       ierr = PetscStrcat(work,r[i]);CHKERRQ(ierr);
1145       ierr = PetscStrcat(work,par);CHKERRQ(ierr);
1146       ierr = PetscStrncpy(b,work,len);CHKERRQ(ierr);
1147       ierr = PetscStrstr(b,s[i],&par);CHKERRQ(ierr);
1148     }
1149     i++;
1150   }
1151   i = 0;
1152   while (r[i]) {
1153     tfree = (char*)r[i];
1154     ierr  = PetscFree(tfree);CHKERRQ(ierr);
1155     i++;
1156   }
1157 
1158   /* look for any other ${xxx} strings to replace from environmental variables */
1159   ierr = PetscStrstr(b,"${",&par);CHKERRQ(ierr);
1160   while (par) {
1161     *par  = 0;
1162     par  += 2;
1163     ierr  = PetscStrcpy(work,b);CHKERRQ(ierr);
1164     ierr  = PetscStrstr(par,"}",&epar);CHKERRQ(ierr);
1165     *epar = 0;
1166     epar += 1;
1167     ierr  = PetscOptionsGetenv(comm,par,env,256,&flag);CHKERRQ(ierr);
1168     if (!flag) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Substitution string ${%s} not found as environmental variable",par);
1169     ierr = PetscStrcat(work,env);CHKERRQ(ierr);
1170     ierr = PetscStrcat(work,epar);CHKERRQ(ierr);
1171     ierr = PetscStrcpy(b,work);CHKERRQ(ierr);
1172     ierr = PetscStrstr(b,"${",&par);CHKERRQ(ierr);
1173   }
1174   ierr = PetscFree(work);CHKERRQ(ierr);
1175   if (aa == b) {
1176     ierr = PetscFree(a);CHKERRQ(ierr);
1177   }
1178   PetscFunctionReturn(0);
1179 }
1180 
1181 /*@C
1182    PetscEListFind - searches list of strings for given string, using case insensitive matching
1183 
1184    Not Collective
1185 
1186    Input Parameters:
1187 +  n - number of strings in
1188 .  list - list of strings to search
1189 -  str - string to look for, empty string "" accepts default (first entry in list)
1190 
1191    Output Parameters:
1192 +  value - index of matching string (if found)
1193 -  found - boolean indicating whether string was found (can be NULL)
1194 
1195    Notes:
1196    Not for use in Fortran
1197 
1198    Level: advanced
1199 @*/
1200 PetscErrorCode PetscEListFind(PetscInt n,const char *const *list,const char *str,PetscInt *value,PetscBool *found)
1201 {
1202   PetscErrorCode ierr;
1203   PetscBool matched;
1204   PetscInt i;
1205 
1206   PetscFunctionBegin;
1207   if (found) *found = PETSC_FALSE;
1208   for (i=0; i<n; i++) {
1209     ierr = PetscStrcasecmp(str,list[i],&matched);CHKERRQ(ierr);
1210     if (matched || !str[0]) {
1211       if (found) *found = PETSC_TRUE;
1212       *value = i;
1213       break;
1214     }
1215   }
1216   PetscFunctionReturn(0);
1217 }
1218 
1219 /*@C
1220    PetscEnumFind - searches enum list of strings for given string, using case insensitive matching
1221 
1222    Not Collective
1223 
1224    Input Parameters:
1225 +  enumlist - list of strings to search, followed by enum name, then enum prefix, then NUL
1226 -  str - string to look for
1227 
1228    Output Parameters:
1229 +  value - index of matching string (if found)
1230 -  found - boolean indicating whether string was found (can be NULL)
1231 
1232    Notes:
1233    Not for use in Fortran
1234 
1235    Level: advanced
1236 @*/
1237 PetscErrorCode PetscEnumFind(const char *const *enumlist,const char *str,PetscEnum *value,PetscBool *found)
1238 {
1239   PetscErrorCode ierr;
1240   PetscInt n = 0,evalue;
1241   PetscBool efound;
1242 
1243   PetscFunctionBegin;
1244   while (enumlist[n++]) if (n > 50) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"List argument appears to be wrong or have more than 50 entries");
1245   if (n < 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"List argument must have at least two entries: typename and type prefix");
1246   n -= 3; /* drop enum name, prefix, and null termination */
1247   ierr = PetscEListFind(n,enumlist,str,&evalue,&efound);CHKERRQ(ierr);
1248   if (efound) *value = (PetscEnum)evalue;
1249   if (found) *found = efound;
1250   PetscFunctionReturn(0);
1251 }
1252