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