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