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