xref: /petsc/src/sys/utils/str.c (revision 7a46b59513fac54acb317385fa9864cc0988b1fb)
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 / or \ 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     Works for both Unix and Windows path separators
471 
472 .seealso: `PetscStrgrt()`, `PetscStrncmp()`, `PetscStrcasecmp()`, `PetscStrrchr()`,`PetscStrcmp()`,`PetscStrstr()`,
473           `PetscTokenCreate()`, `PetscStrToArray()`, `PetscStrInList()`
474 @*/
475 const char *PetscBasename(const char a[])
476 {
477   const char *ptr;
478 
479   if (PetscStrrchr(a,'/',(char **)&ptr)) ptr = NULL;
480   if (ptr == a) {
481     if (PetscStrrchr(a,'\\',(char **)&ptr)) ptr = NULL;
482   }
483   return ptr;
484 }
485 
486 /*@C
487    PetscStrcmp - Compares two strings,
488 
489    Not Collective
490 
491    Input Parameters:
492 +  a - pointer to string first string
493 -  b - pointer to second string
494 
495    Output Parameter:
496 .  flg - PETSC_TRUE if the two strings are equal
497 
498    Level: intermediate
499 
500    Notes:
501     Not for use in Fortran
502 
503 .seealso: `PetscStrgrt()`, `PetscStrncmp()`, `PetscStrcasecmp()`
504 @*/
505 PetscErrorCode  PetscStrcmp(const char a[],const char b[],PetscBool *flg)
506 {
507   PetscFunctionBegin;
508   PetscValidBoolPointer(flg,3);
509   if (!a && !b)      *flg = PETSC_TRUE;
510   else if (!a || !b) *flg = PETSC_FALSE;
511   else               *flg = (PetscBool)!strcmp(a,b);
512   PetscFunctionReturn(0);
513 }
514 
515 /*@C
516    PetscStrgrt - If first string is greater than the second
517 
518    Not Collective
519 
520    Input Parameters:
521 +  a - pointer to first string
522 -  b - pointer to second string
523 
524    Output Parameter:
525 .  flg - if the first string is greater
526 
527    Notes:
528     Null arguments are ok, a null string is considered smaller than
529     all others
530 
531    Not for use in Fortran
532 
533    Level: intermediate
534 
535 .seealso: `PetscStrcmp()`, `PetscStrncmp()`, `PetscStrcasecmp()`
536 
537 @*/
538 PetscErrorCode PetscStrgrt(const char a[], const char b[], PetscBool *t)
539 {
540   PetscFunctionBegin;
541   PetscValidBoolPointer(t,3);
542   if (!a && !b)     *t = PETSC_FALSE;
543   else if (a && !b) *t = PETSC_TRUE;
544   else if (!a && b) *t = PETSC_FALSE;
545   else {
546     PetscValidCharPointer(a,1);
547     PetscValidCharPointer(b,2);
548     *t = strcmp(a,b) > 0 ? PETSC_TRUE : PETSC_FALSE;
549   }
550   PetscFunctionReturn(0);
551 }
552 
553 /*@C
554    PetscStrcasecmp - Returns true if the two strings are the same
555      except possibly for case.
556 
557    Not Collective
558 
559    Input Parameters:
560 +  a - pointer to first string
561 -  b - pointer to second string
562 
563    Output Parameter:
564 .  flg - if the two strings are the same
565 
566    Notes:
567     Null arguments are ok
568 
569    Not for use in Fortran
570 
571    Level: intermediate
572 
573 .seealso: `PetscStrcmp()`, `PetscStrncmp()`, `PetscStrgrt()`
574 
575 @*/
576 PetscErrorCode PetscStrcasecmp(const char a[], const char b[], PetscBool *t)
577 {
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    Notes:
621     Not for use in Fortran
622 
623 .seealso: `PetscStrgrt()`, `PetscStrcmp()`, `PetscStrcasecmp()`
624 
625 @*/
626 PetscErrorCode PetscStrncmp(const char a[], const char b[], size_t n, PetscBool *t)
627 {
628   PetscFunctionBegin;
629   if (n) {
630     PetscValidCharPointer(a,1);
631     PetscValidCharPointer(b,2);
632   }
633   PetscValidBoolPointer(t,4);
634   *t = strncmp(a,b,n) ? PETSC_FALSE : PETSC_TRUE;
635   PetscFunctionReturn(0);
636 }
637 
638 /*@C
639    PetscStrchr - Locates first occurrence of a character in a string
640 
641    Not Collective
642 
643    Input Parameters:
644 +  a - pointer to string
645 -  b - character
646 
647    Output Parameter:
648 .  c - location of occurrence, NULL if not found
649 
650    Level: intermediate
651 
652    Notes:
653     Not for use in Fortran
654 
655 @*/
656 PetscErrorCode PetscStrchr(const char a[], char b, char *c[])
657 {
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 {
686   PetscFunctionBegin;
687   PetscValidCharPointer(a,1);
688   PetscValidPointer(tmp,3);
689   *tmp = (char*)strrchr(a,b);
690   if (!*tmp) *tmp = (char*)a;
691   else *tmp = *tmp + 1;
692   PetscFunctionReturn(0);
693 }
694 
695 /*@C
696    PetscStrtolower - Converts string to lower case
697 
698    Not Collective
699 
700    Input Parameters:
701 .  a - pointer to string
702 
703    Level: intermediate
704 
705    Notes:
706     Not for use in Fortran
707 
708 @*/
709 PetscErrorCode PetscStrtolower(char a[])
710 {
711   PetscFunctionBegin;
712   PetscValidCharPointer(a,1);
713   while (*a) {
714     if (*a >= 'A' && *a <= 'Z') *a += 'a' - 'A';
715     a++;
716   }
717   PetscFunctionReturn(0);
718 }
719 
720 /*@C
721    PetscStrtoupper - Converts string to upper case
722 
723    Not Collective
724 
725    Input Parameters:
726 .  a - pointer to string
727 
728    Level: intermediate
729 
730    Notes:
731     Not for use in Fortran
732 
733 @*/
734 PetscErrorCode PetscStrtoupper(char a[])
735 {
736   PetscFunctionBegin;
737   PetscValidCharPointer(a,1);
738   while (*a) {
739     if (*a >= 'a' && *a <= 'z') *a += 'A' - 'a';
740     a++;
741   }
742   PetscFunctionReturn(0);
743 }
744 
745 /*@C
746    PetscStrendswith - Determines if a string ends with a certain string
747 
748    Not Collective
749 
750    Input Parameters:
751 +  a - pointer to string
752 -  b - string to endwith
753 
754    Output Parameter:
755 .  flg - PETSC_TRUE or PETSC_FALSE
756 
757    Notes:
758     Not for use in Fortran
759 
760    Level: intermediate
761 
762 @*/
763 PetscErrorCode PetscStrendswith(const char a[], const char b[], PetscBool *flg)
764 {
765   char *test;
766 
767   PetscFunctionBegin;
768   PetscValidBoolPointer(flg,3);
769   *flg = PETSC_FALSE;
770   PetscCall(PetscStrrstr(a,b,&test));
771   if (test) {
772     size_t na,nb;
773 
774     PetscCall(PetscStrlen(a,&na));
775     PetscCall(PetscStrlen(b,&nb));
776     if (a+na-nb == test) *flg = PETSC_TRUE;
777   }
778   PetscFunctionReturn(0);
779 }
780 
781 /*@C
782    PetscStrbeginswith - Determines if a string begins with a certain string
783 
784    Not Collective
785 
786    Input Parameters:
787 +  a - pointer to string
788 -  b - string to begin with
789 
790    Output Parameter:
791 .  flg - PETSC_TRUE or PETSC_FALSE
792 
793    Notes:
794     Not for use in Fortran
795 
796    Level: intermediate
797 
798 .seealso: `PetscStrendswithwhich()`, `PetscStrendswith()`, `PetscStrtoupper`, `PetscStrtolower()`, `PetscStrrchr()`, `PetscStrchr()`,
799           `PetscStrncmp()`, `PetscStrlen()`, `PetscStrncmp()`, `PetscStrcmp()`
800 
801 @*/
802 PetscErrorCode PetscStrbeginswith(const char a[], const char b[], PetscBool *flg)
803 {
804   char *test;
805 
806   PetscFunctionBegin;
807   PetscValidCharPointer(a,1);
808   PetscValidCharPointer(b,2);
809   PetscValidBoolPointer(flg,3);
810   *flg = PETSC_FALSE;
811   PetscCall(PetscStrrstr(a,b,&test));
812   if (test && (test == a)) *flg = PETSC_TRUE;
813   PetscFunctionReturn(0);
814 }
815 
816 /*@C
817    PetscStrendswithwhich - Determines if a string ends with one of several possible strings
818 
819    Not Collective
820 
821    Input Parameters:
822 +  a - pointer to string
823 -  bs - strings to end with (last entry must be NULL)
824 
825    Output Parameter:
826 .  cnt - the index of the string it ends with or the index of NULL
827 
828    Notes:
829     Not for use in Fortran
830 
831    Level: intermediate
832 
833 @*/
834 PetscErrorCode PetscStrendswithwhich(const char a[], const char *const *bs, PetscInt *cnt)
835 {
836   PetscFunctionBegin;
837   PetscValidPointer(bs,2);
838   PetscValidIntPointer(cnt,3);
839   *cnt = 0;
840   while (bs[*cnt]) {
841     PetscBool flg;
842 
843     PetscCall(PetscStrendswith(a,bs[*cnt],&flg));
844     if (flg) PetscFunctionReturn(0);
845     ++(*cnt);
846   }
847   PetscFunctionReturn(0);
848 }
849 
850 /*@C
851    PetscStrrstr - Locates last occurrence of string in another string
852 
853    Not Collective
854 
855    Input Parameters:
856 +  a - pointer to string
857 -  b - string to find
858 
859    Output Parameter:
860 .  tmp - location of occurrence
861 
862    Notes:
863     Not for use in Fortran
864 
865    Level: intermediate
866 
867 @*/
868 PetscErrorCode PetscStrrstr(const char a[], const char b[], char *tmp[])
869 {
870   const char *ltmp = NULL;
871 
872   PetscFunctionBegin;
873   PetscValidCharPointer(a,1);
874   PetscValidCharPointer(b,2);
875   PetscValidPointer(tmp,3);
876   while (a) {
877     a = (char*)strstr(a,b);
878     if (a) ltmp = a++;
879   }
880   *tmp = (char*)ltmp;
881   PetscFunctionReturn(0);
882 }
883 
884 /*@C
885    PetscStrstr - Locates first occurrence of string in another string
886 
887    Not Collective
888 
889    Input Parameters:
890 +  haystack - string to search
891 -  needle - string to find
892 
893    Output Parameter:
894 .  tmp - location of occurrence, is a NULL if the string is not found
895 
896    Notes:
897     Not for use in Fortran
898 
899    Level: intermediate
900 
901 @*/
902 PetscErrorCode PetscStrstr(const char haystack[],const char needle[],char *tmp[])
903 {
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 {char token;char *array;char *current;};
913 
914 /*@C
915    PetscTokenFind - Locates next "token" in a string
916 
917    Not Collective
918 
919    Input Parameters:
920 .  a - pointer to token
921 
922    Output Parameter:
923 .  result - location of occurrence, NULL if not found
924 
925    Notes:
926 
927      This version is different from the system version in that
928   it allows you to pass a read-only string into the function.
929 
930      This version also treats all characters etc. inside a double quote "
931    as a single token.
932 
933      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
934    second will return a null terminated y
935 
936      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
937 
938     Not for use in Fortran
939 
940    Level: intermediate
941 
942 .seealso: `PetscTokenCreate()`, `PetscTokenDestroy()`
943 @*/
944 PetscErrorCode PetscTokenFind(PetscToken a, char *result[])
945 {
946   char *ptr,token;
947 
948   PetscFunctionBegin;
949   PetscValidPointer(a,1);
950   PetscValidPointer(result,2);
951   *result = ptr = a->current;
952   if (ptr && !*ptr) {*result = NULL; PetscFunctionReturn(0);}
953   token = a->token;
954   if (ptr && (*ptr == '"')) {token = '"';(*result)++;ptr++;}
955   while (ptr) {
956     if (*ptr == token) {
957       *ptr++ = 0;
958       while (*ptr == a->token) ptr++;
959       a->current = ptr;
960       break;
961     }
962     if (!*ptr) {
963       a->current = NULL;
964       break;
965     }
966     ptr++;
967   }
968   PetscFunctionReturn(0);
969 }
970 
971 /*@C
972    PetscTokenCreate - Creates a PetscToken used to find tokens in a string
973 
974    Not Collective
975 
976    Input Parameters:
977 +  string - the string to look in
978 -  b - the separator character
979 
980    Output Parameter:
981 .  t- the token object
982 
983    Notes:
984 
985      This version is different from the system version in that
986   it allows you to pass a read-only string into the function.
987 
988     Not for use in Fortran
989 
990    Level: intermediate
991 
992 .seealso: `PetscTokenFind()`, `PetscTokenDestroy()`
993 @*/
994 PetscErrorCode PetscTokenCreate(const char a[], const char b, PetscToken *t)
995 {
996   PetscFunctionBegin;
997   PetscValidCharPointer(a,1);
998   PetscValidPointer(t,3);
999   PetscCall(PetscNew(t));
1000   PetscCall(PetscStrallocpy(a,&(*t)->array));
1001 
1002   (*t)->current = (*t)->array;
1003   (*t)->token   = b;
1004   PetscFunctionReturn(0);
1005 }
1006 
1007 /*@C
1008    PetscTokenDestroy - Destroys a PetscToken
1009 
1010    Not Collective
1011 
1012    Input Parameters:
1013 .  a - pointer to token
1014 
1015    Level: intermediate
1016 
1017    Notes:
1018     Not for use in Fortran
1019 
1020 .seealso: `PetscTokenCreate()`, `PetscTokenFind()`
1021 @*/
1022 PetscErrorCode PetscTokenDestroy(PetscToken *a)
1023 {
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 {
1053   PetscToken  token;
1054   char       *item;
1055 
1056   PetscFunctionBegin;
1057   PetscValidBoolPointer(found,4);
1058   *found = PETSC_FALSE;
1059   PetscCall(PetscTokenCreate(list,sep,&token));
1060   PetscCall(PetscTokenFind(token,&item));
1061   while (item) {
1062     PetscCall(PetscStrcmp(str,item,found));
1063     if (*found) break;
1064     PetscCall(PetscTokenFind(token,&item));
1065   }
1066   PetscCall(PetscTokenDestroy(&token));
1067   PetscFunctionReturn(0);
1068 }
1069 
1070 /*@C
1071    PetscGetPetscDir - Gets the directory PETSc is installed in
1072 
1073    Not Collective
1074 
1075    Output Parameter:
1076 .  dir - the directory
1077 
1078    Level: developer
1079 
1080    Notes:
1081     Not for use in Fortran
1082 
1083 @*/
1084 PetscErrorCode PetscGetPetscDir(const char *dir[])
1085 {
1086   PetscFunctionBegin;
1087   PetscValidPointer(dir,1);
1088   *dir = PETSC_DIR;
1089   PetscFunctionReturn(0);
1090 }
1091 
1092 /*@C
1093    PetscStrreplace - Replaces substrings in string with other substrings
1094 
1095    Not Collective
1096 
1097    Input Parameters:
1098 +   comm - MPI_Comm of processors that are processing the string
1099 .   aa - the string to look in
1100 .   b - the resulting copy of a with replaced strings (b can be the same as a)
1101 -   len - the length of b
1102 
1103    Notes:
1104       Replaces   ${PETSC_ARCH},${PETSC_DIR},${PETSC_LIB_DIR},${DISPLAY},
1105       ${HOMEDIRECTORY},${WORKINGDIRECTORY},${USERNAME}, ${HOSTNAME} with appropriate values
1106       as well as any environmental variables.
1107 
1108       PETSC_LIB_DIR uses the environmental variable if it exists. PETSC_ARCH and PETSC_DIR use what
1109       PETSc was built with and do not use environmental variables.
1110 
1111       Not for use in Fortran
1112 
1113    Level: intermediate
1114 
1115 @*/
1116 PetscErrorCode PetscStrreplace(MPI_Comm comm, const char aa[], char b[], size_t len)
1117 {
1118   int            i = 0;
1119   size_t         l,l1,l2,l3;
1120   char           *work,*par,*epar,env[1024],*tfree,*a = (char*)aa;
1121   const char     *s[] = {"${PETSC_ARCH}","${PETSC_DIR}","${PETSC_LIB_DIR}","${DISPLAY}","${HOMEDIRECTORY}","${WORKINGDIRECTORY}","${USERNAME}","${HOSTNAME}",NULL};
1122   char           *r[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
1123   PetscBool      flag;
1124   static size_t  DISPLAY_LENGTH = 265,USER_LENGTH = 256, HOST_LENGTH = 256;
1125 
1126   PetscFunctionBegin;
1127   PetscValidCharPointer(aa,2);
1128   PetscValidCharPointer(b,3);
1129   if (aa == b) PetscCall(PetscStrallocpy(aa,(char**)&a));
1130   PetscCall(PetscMalloc1(len,&work));
1131 
1132   /* get values for replaced variables */
1133   PetscCall(PetscStrallocpy(PETSC_ARCH,&r[0]));
1134   PetscCall(PetscStrallocpy(PETSC_DIR,&r[1]));
1135   PetscCall(PetscStrallocpy(PETSC_LIB_DIR,&r[2]));
1136   PetscCall(PetscMalloc1(DISPLAY_LENGTH,&r[3]));
1137   PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN,&r[4]));
1138   PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN,&r[5]));
1139   PetscCall(PetscMalloc1(USER_LENGTH,&r[6]));
1140   PetscCall(PetscMalloc1(HOST_LENGTH,&r[7]));
1141   PetscCall(PetscGetDisplay(r[3],DISPLAY_LENGTH));
1142   PetscCall(PetscGetHomeDirectory(r[4],PETSC_MAX_PATH_LEN));
1143   PetscCall(PetscGetWorkingDirectory(r[5],PETSC_MAX_PATH_LEN));
1144   PetscCall(PetscGetUserName(r[6],USER_LENGTH));
1145   PetscCall(PetscGetHostName(r[7],HOST_LENGTH));
1146 
1147   /* replace that are in environment */
1148   PetscCall(PetscOptionsGetenv(comm,"PETSC_LIB_DIR",env,sizeof(env),&flag));
1149   if (flag) {
1150     PetscCall(PetscFree(r[2]));
1151     PetscCall(PetscStrallocpy(env,&r[2]));
1152   }
1153 
1154   /* replace the requested strings */
1155   PetscCall(PetscStrncpy(b,a,len));
1156   while (s[i]) {
1157     PetscCall(PetscStrlen(s[i],&l));
1158     PetscCall(PetscStrstr(b,s[i],&par));
1159     while (par) {
1160       *par = 0;
1161       par += l;
1162 
1163       PetscCall(PetscStrlen(b,&l1));
1164       PetscCall(PetscStrlen(r[i],&l2));
1165       PetscCall(PetscStrlen(par,&l3));
1166       PetscCheck(l1 + l2 + l3 < len,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"b len is not long enough to hold new values");
1167       PetscCall(PetscStrncpy(work,b,len));
1168       PetscCall(PetscStrlcat(work,r[i],len));
1169       PetscCall(PetscStrlcat(work,par,len));
1170       PetscCall(PetscStrncpy(b,work,len));
1171       PetscCall(PetscStrstr(b,s[i],&par));
1172     }
1173     i++;
1174   }
1175   i = 0;
1176   while (r[i]) {
1177     tfree = (char*)r[i];
1178     PetscCall(PetscFree(tfree));
1179     i++;
1180   }
1181 
1182   /* look for any other ${xxx} strings to replace from environmental variables */
1183   PetscCall(PetscStrstr(b,"${",&par));
1184   while (par) {
1185     *par  = 0;
1186     par  += 2;
1187     PetscCall(PetscStrncpy(work,b,len));
1188     PetscCall(PetscStrstr(par,"}",&epar));
1189     *epar = 0;
1190     epar += 1;
1191     PetscCall(PetscOptionsGetenv(comm,par,env,sizeof(env),&flag));
1192     PetscCheck(flag,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Substitution string ${%s} not found as environmental variable",par);
1193     PetscCall(PetscStrlcat(work,env,len));
1194     PetscCall(PetscStrlcat(work,epar,len));
1195     PetscCall(PetscStrncpy(b,work,len));
1196     PetscCall(PetscStrstr(b,"${",&par));
1197   }
1198   PetscCall(PetscFree(work));
1199   if (aa == b) PetscCall(PetscFree(a));
1200   PetscFunctionReturn(0);
1201 }
1202 
1203 /*@C
1204    PetscEListFind - searches list of strings for given string, using case insensitive matching
1205 
1206    Not Collective
1207 
1208    Input Parameters:
1209 +  n - number of strings in
1210 .  list - list of strings to search
1211 -  str - string to look for, empty string "" accepts default (first entry in list)
1212 
1213    Output Parameters:
1214 +  value - index of matching string (if found)
1215 -  found - boolean indicating whether string was found (can be NULL)
1216 
1217    Notes:
1218    Not for use in Fortran
1219 
1220    Level: advanced
1221 @*/
1222 PetscErrorCode PetscEListFind(PetscInt n, const char *const *list, const char *str, PetscInt *value, PetscBool *found)
1223 {
1224   PetscFunctionBegin;
1225   if (found) {
1226     PetscValidBoolPointer(found,5);
1227     *found = PETSC_FALSE;
1228   }
1229   for (PetscInt i = 0; i < n; ++i) {
1230     PetscBool matched;
1231 
1232     PetscCall(PetscStrcasecmp(str,list[i],&matched));
1233     if (matched || !str[0]) {
1234       if (found) *found = PETSC_TRUE;
1235       *value = i;
1236       break;
1237     }
1238   }
1239   PetscFunctionReturn(0);
1240 }
1241 
1242 /*@C
1243    PetscEnumFind - searches enum list of strings for given string, using case insensitive matching
1244 
1245    Not Collective
1246 
1247    Input Parameters:
1248 +  enumlist - list of strings to search, followed by enum name, then enum prefix, then NUL
1249 -  str - string to look for
1250 
1251    Output Parameters:
1252 +  value - index of matching string (if found)
1253 -  found - boolean indicating whether string was found (can be NULL)
1254 
1255    Notes:
1256    Not for use in Fortran
1257 
1258    Level: advanced
1259 @*/
1260 PetscErrorCode PetscEnumFind(const char *const *enumlist, const char *str, PetscEnum *value, PetscBool *found)
1261 {
1262   PetscInt  n = 0,evalue;
1263   PetscBool efound;
1264 
1265   PetscFunctionBegin;
1266   PetscValidPointer(enumlist,1);
1267   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");
1268   PetscCheck(n >= 3,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"List argument must have at least two entries: typename and type prefix");
1269   n -= 3; /* drop enum name, prefix, and null termination */
1270   PetscCall(PetscEListFind(n,enumlist,str,&evalue,&efound));
1271   if (efound) {
1272     PetscValidPointer(value,3);
1273     *value = (PetscEnum)evalue;
1274   }
1275   if (found) {
1276     PetscValidBoolPointer(found,4);
1277     *found = efound;
1278   }
1279   PetscFunctionReturn(0);
1280 }
1281 
1282 /*@C
1283   PetscCIFilename - returns the basename of a file name when the PETSc CI portable error output mode is enabled.
1284 
1285   Not collective
1286 
1287   Input Parameter:
1288 . file - the file name
1289 
1290   Note:
1291   PETSc CI mode is a mode of running PETSc where output (both error and non-error) is made portable across all systems
1292   so that comparisons of output between runs are easy to make.
1293 
1294   This mode is used for all tests in the test harness, it applies to both debug and optimized builds.
1295 
1296   Use the option -petsc_ci to turn on PETSc CI mode. It changes certain output in non-error situations to be portable for
1297   all systems, mainly the output of options. It is passed to all PETSc programs automatically by the test harness.
1298 
1299   Always uses the Unix / as the file separate even on Microsoft Windows systems
1300 
1301   The option -petsc_ci_portable_error_output attempts to output the same error messages on all systems for the test harness.
1302   In particular the output of filenames and line numbers in PETSc stacks. This is to allow (limited) checking of PETSc
1303   error handling by the test harness. This options also causes PETSc to attempt to return an error code of 0 so that the test
1304   harness can process the output for differences in the usual manner as for successful runs. It should be provided to the test
1305   harness in the args: argument for specific examples. It will not neccessarily produce portable output if different errors
1306   (or no errors) occur on a subset of the MPI ranks.
1307 
1308   Level: developer
1309 
1310 .seealso: `PetscCILinenumber()`
1311 
1312 @*/
1313 const char *PetscCIFilename(const char *file)
1314 {
1315   if (!PetscCIEnabledPortableErrorOutput) return file;
1316   return PetscBasename(file);
1317 }
1318 
1319 /*@C
1320   PetscCILinenumber - returns a line number except if PetscCIEnablePortableErrorOutput) is set when it returns 0
1321 
1322   Not collective
1323 
1324   Input Parameter:
1325 . linenumber - the initial line number
1326 
1327   Note:
1328   See `PetscCIFilename()` for details on usage
1329 
1330   Level: developer
1331 
1332 .seealso: `PetscCIFilename()`
1333 
1334 @*/
1335 int PetscCILinenumber(int linenumber)
1336 {
1337   if (!PetscCIEnabledPortableErrorOutput) return linenumber;
1338   return 0;
1339 }
1340