xref: /petsc/src/sys/utils/str.c (revision c3e4dd79e17d3f0a51a524340fae4661630fd09e)
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    PetscStrcmp - Compares two strings,
459 
460    Not Collective
461 
462    Input Parameters:
463 +  a - pointer to string first string
464 -  b - pointer to second string
465 
466    Output Parameter:
467 .  flg - PETSC_TRUE if the two strings are equal
468 
469    Level: intermediate
470 
471    Notes:
472     Not for use in Fortran
473 
474 .seealso: `PetscStrgrt()`, `PetscStrncmp()`, `PetscStrcasecmp()`
475 @*/
476 PetscErrorCode  PetscStrcmp(const char a[],const char b[],PetscBool *flg)
477 {
478   PetscFunctionBegin;
479   PetscValidBoolPointer(flg,3);
480   if (!a && !b)      *flg = PETSC_TRUE;
481   else if (!a || !b) *flg = PETSC_FALSE;
482   else               *flg = (PetscBool)!strcmp(a,b);
483   PetscFunctionReturn(0);
484 }
485 
486 /*@C
487    PetscStrgrt - If first string is greater than the second
488 
489    Not Collective
490 
491    Input Parameters:
492 +  a - pointer to first string
493 -  b - pointer to second string
494 
495    Output Parameter:
496 .  flg - if the first string is greater
497 
498    Notes:
499     Null arguments are ok, a null string is considered smaller than
500     all others
501 
502    Not for use in Fortran
503 
504    Level: intermediate
505 
506 .seealso: `PetscStrcmp()`, `PetscStrncmp()`, `PetscStrcasecmp()`
507 
508 @*/
509 PetscErrorCode PetscStrgrt(const char a[], const char b[], PetscBool *t)
510 {
511   PetscFunctionBegin;
512   PetscValidBoolPointer(t,3);
513   if (!a && !b)     *t = PETSC_FALSE;
514   else if (a && !b) *t = PETSC_TRUE;
515   else if (!a && b) *t = PETSC_FALSE;
516   else {
517     PetscValidCharPointer(a,1);
518     PetscValidCharPointer(b,2);
519     *t = strcmp(a,b) > 0 ? PETSC_TRUE : PETSC_FALSE;
520   }
521   PetscFunctionReturn(0);
522 }
523 
524 /*@C
525    PetscStrcasecmp - Returns true if the two strings are the same
526      except possibly for case.
527 
528    Not Collective
529 
530    Input Parameters:
531 +  a - pointer to first string
532 -  b - pointer to second string
533 
534    Output Parameter:
535 .  flg - if the two strings are the same
536 
537    Notes:
538     Null arguments are ok
539 
540    Not for use in Fortran
541 
542    Level: intermediate
543 
544 .seealso: `PetscStrcmp()`, `PetscStrncmp()`, `PetscStrgrt()`
545 
546 @*/
547 PetscErrorCode PetscStrcasecmp(const char a[], const char b[], PetscBool *t)
548 {
549   int c;
550 
551   PetscFunctionBegin;
552   PetscValidBoolPointer(t,3);
553   if (!a && !b)      c = 0;
554   else if (!a || !b) c = 1;
555 #if defined(PETSC_HAVE_STRCASECMP)
556   else c = strcasecmp(a,b);
557 #elif defined(PETSC_HAVE_STRICMP)
558   else c = stricmp(a,b);
559 #else
560   else {
561     char           *aa,*bb;
562     PetscCall(PetscStrallocpy(a,&aa));
563     PetscCall(PetscStrallocpy(b,&bb));
564     PetscCall(PetscStrtolower(aa));
565     PetscCall(PetscStrtolower(bb));
566     PetscCall(PetscStrcmp(aa,bb,t));
567     PetscCall(PetscFree(aa));
568     PetscCall(PetscFree(bb));
569     PetscFunctionReturn(0);
570   }
571 #endif
572   *t = c ? PETSC_FALSE : PETSC_TRUE;
573   PetscFunctionReturn(0);
574 }
575 
576 /*@C
577    PetscStrncmp - Compares two strings, up to a certain length
578 
579    Not Collective
580 
581    Input Parameters:
582 +  a - pointer to first string
583 .  b - pointer to second string
584 -  n - length to compare up to
585 
586    Output Parameter:
587 .  t - if the two strings are equal
588 
589    Level: intermediate
590 
591    Notes:
592     Not for use in Fortran
593 
594 .seealso: `PetscStrgrt()`, `PetscStrcmp()`, `PetscStrcasecmp()`
595 
596 @*/
597 PetscErrorCode PetscStrncmp(const char a[], const char b[], size_t n, PetscBool *t)
598 {
599   PetscFunctionBegin;
600   if (n) {
601     PetscValidCharPointer(a,1);
602     PetscValidCharPointer(b,2);
603   }
604   PetscValidBoolPointer(t,4);
605   *t = strncmp(a,b,n) ? PETSC_FALSE : PETSC_TRUE;
606   PetscFunctionReturn(0);
607 }
608 
609 /*@C
610    PetscStrchr - Locates first occurrence of a character in a string
611 
612    Not Collective
613 
614    Input Parameters:
615 +  a - pointer to string
616 -  b - character
617 
618    Output Parameter:
619 .  c - location of occurrence, NULL if not found
620 
621    Level: intermediate
622 
623    Notes:
624     Not for use in Fortran
625 
626 @*/
627 PetscErrorCode PetscStrchr(const char a[], char b, char *c[])
628 {
629   PetscFunctionBegin;
630   PetscValidCharPointer(a,1);
631   PetscValidPointer(c,3);
632   *c = (char*)strchr(a,b);
633   PetscFunctionReturn(0);
634 }
635 
636 /*@C
637    PetscStrrchr - Locates one location past the last occurrence of a character in a string,
638       if the character is not found then returns entire string
639 
640    Not Collective
641 
642    Input Parameters:
643 +  a - pointer to string
644 -  b - character
645 
646    Output Parameter:
647 .  tmp - location of occurrence, a if not found
648 
649    Level: intermediate
650 
651    Notes:
652     Not for use in Fortran
653 
654 @*/
655 PetscErrorCode PetscStrrchr(const char a[], char b, char *tmp[])
656 {
657   PetscFunctionBegin;
658   PetscValidCharPointer(a,1);
659   PetscValidPointer(tmp,3);
660   *tmp = (char*)strrchr(a,b);
661   if (!*tmp) *tmp = (char*)a;
662   else *tmp = *tmp + 1;
663   PetscFunctionReturn(0);
664 }
665 
666 /*@C
667    PetscStrtolower - Converts string to lower case
668 
669    Not Collective
670 
671    Input Parameters:
672 .  a - pointer to string
673 
674    Level: intermediate
675 
676    Notes:
677     Not for use in Fortran
678 
679 @*/
680 PetscErrorCode PetscStrtolower(char a[])
681 {
682   PetscFunctionBegin;
683   PetscValidCharPointer(a,1);
684   while (*a) {
685     if (*a >= 'A' && *a <= 'Z') *a += 'a' - 'A';
686     a++;
687   }
688   PetscFunctionReturn(0);
689 }
690 
691 /*@C
692    PetscStrtoupper - Converts string to upper case
693 
694    Not Collective
695 
696    Input Parameters:
697 .  a - pointer to string
698 
699    Level: intermediate
700 
701    Notes:
702     Not for use in Fortran
703 
704 @*/
705 PetscErrorCode PetscStrtoupper(char a[])
706 {
707   PetscFunctionBegin;
708   PetscValidCharPointer(a,1);
709   while (*a) {
710     if (*a >= 'a' && *a <= 'z') *a += 'A' - 'a';
711     a++;
712   }
713   PetscFunctionReturn(0);
714 }
715 
716 /*@C
717    PetscStrendswith - Determines if a string ends with a certain string
718 
719    Not Collective
720 
721    Input Parameters:
722 +  a - pointer to string
723 -  b - string to endwith
724 
725    Output Parameter:
726 .  flg - PETSC_TRUE or PETSC_FALSE
727 
728    Notes:
729     Not for use in Fortran
730 
731    Level: intermediate
732 
733 @*/
734 PetscErrorCode PetscStrendswith(const char a[], const char b[], PetscBool *flg)
735 {
736   char *test;
737 
738   PetscFunctionBegin;
739   PetscValidBoolPointer(flg,3);
740   *flg = PETSC_FALSE;
741   PetscCall(PetscStrrstr(a,b,&test));
742   if (test) {
743     size_t na,nb;
744 
745     PetscCall(PetscStrlen(a,&na));
746     PetscCall(PetscStrlen(b,&nb));
747     if (a+na-nb == test) *flg = PETSC_TRUE;
748   }
749   PetscFunctionReturn(0);
750 }
751 
752 /*@C
753    PetscStrbeginswith - Determines if a string begins with a certain string
754 
755    Not Collective
756 
757    Input Parameters:
758 +  a - pointer to string
759 -  b - string to begin with
760 
761    Output Parameter:
762 .  flg - PETSC_TRUE or PETSC_FALSE
763 
764    Notes:
765     Not for use in Fortran
766 
767    Level: intermediate
768 
769 .seealso: `PetscStrendswithwhich()`, `PetscStrendswith()`, `PetscStrtoupper`, `PetscStrtolower()`, `PetscStrrchr()`, `PetscStrchr()`,
770           `PetscStrncmp()`, `PetscStrlen()`, `PetscStrncmp()`, `PetscStrcmp()`
771 
772 @*/
773 PetscErrorCode PetscStrbeginswith(const char a[], const char b[], PetscBool *flg)
774 {
775   char *test;
776 
777   PetscFunctionBegin;
778   PetscValidCharPointer(a,1);
779   PetscValidCharPointer(b,2);
780   PetscValidBoolPointer(flg,3);
781   *flg = PETSC_FALSE;
782   PetscCall(PetscStrrstr(a,b,&test));
783   if (test && (test == a)) *flg = PETSC_TRUE;
784   PetscFunctionReturn(0);
785 }
786 
787 /*@C
788    PetscStrendswithwhich - Determines if a string ends with one of several possible strings
789 
790    Not Collective
791 
792    Input Parameters:
793 +  a - pointer to string
794 -  bs - strings to end with (last entry must be NULL)
795 
796    Output Parameter:
797 .  cnt - the index of the string it ends with or the index of NULL
798 
799    Notes:
800     Not for use in Fortran
801 
802    Level: intermediate
803 
804 @*/
805 PetscErrorCode PetscStrendswithwhich(const char a[], const char *const *bs, PetscInt *cnt)
806 {
807   PetscFunctionBegin;
808   PetscValidPointer(bs,2);
809   PetscValidIntPointer(cnt,3);
810   *cnt = 0;
811   while (bs[*cnt]) {
812     PetscBool flg;
813 
814     PetscCall(PetscStrendswith(a,bs[*cnt],&flg));
815     if (flg) PetscFunctionReturn(0);
816     ++(*cnt);
817   }
818   PetscFunctionReturn(0);
819 }
820 
821 /*@C
822    PetscStrrstr - Locates last occurrence of string in another string
823 
824    Not Collective
825 
826    Input Parameters:
827 +  a - pointer to string
828 -  b - string to find
829 
830    Output Parameter:
831 .  tmp - location of occurrence
832 
833    Notes:
834     Not for use in Fortran
835 
836    Level: intermediate
837 
838 @*/
839 PetscErrorCode PetscStrrstr(const char a[], const char b[], char *tmp[])
840 {
841   const char *ltmp = NULL;
842 
843   PetscFunctionBegin;
844   PetscValidCharPointer(a,1);
845   PetscValidCharPointer(b,2);
846   PetscValidPointer(tmp,3);
847   while (a) {
848     a = (char*)strstr(a,b);
849     if (a) ltmp = a++;
850   }
851   *tmp = (char*)ltmp;
852   PetscFunctionReturn(0);
853 }
854 
855 /*@C
856    PetscStrstr - Locates first occurrence of string in another string
857 
858    Not Collective
859 
860    Input Parameters:
861 +  haystack - string to search
862 -  needle - string to find
863 
864    Output Parameter:
865 .  tmp - location of occurrence, is a NULL if the string is not found
866 
867    Notes:
868     Not for use in Fortran
869 
870    Level: intermediate
871 
872 @*/
873 PetscErrorCode PetscStrstr(const char haystack[],const char needle[],char *tmp[])
874 {
875   PetscFunctionBegin;
876   PetscValidCharPointer(haystack,1);
877   PetscValidCharPointer(needle,2);
878   PetscValidPointer(tmp,3);
879   *tmp = (char*)strstr(haystack,needle);
880   PetscFunctionReturn(0);
881 }
882 
883 struct _p_PetscToken {char token;char *array;char *current;};
884 
885 /*@C
886    PetscTokenFind - Locates next "token" in a string
887 
888    Not Collective
889 
890    Input Parameters:
891 .  a - pointer to token
892 
893    Output Parameter:
894 .  result - location of occurrence, NULL if not found
895 
896    Notes:
897 
898      This version is different from the system version in that
899   it allows you to pass a read-only string into the function.
900 
901      This version also treats all characters etc. inside a double quote "
902    as a single token.
903 
904      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
905    second will return a null terminated y
906 
907      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
908 
909     Not for use in Fortran
910 
911    Level: intermediate
912 
913 .seealso: `PetscTokenCreate()`, `PetscTokenDestroy()`
914 @*/
915 PetscErrorCode PetscTokenFind(PetscToken a, char *result[])
916 {
917   char *ptr,token;
918 
919   PetscFunctionBegin;
920   PetscValidPointer(a,1);
921   PetscValidPointer(result,2);
922   *result = ptr = a->current;
923   if (ptr && !*ptr) {*result = NULL; PetscFunctionReturn(0);}
924   token = a->token;
925   if (ptr && (*ptr == '"')) {token = '"';(*result)++;ptr++;}
926   while (ptr) {
927     if (*ptr == token) {
928       *ptr++ = 0;
929       while (*ptr == a->token) ptr++;
930       a->current = ptr;
931       break;
932     }
933     if (!*ptr) {
934       a->current = NULL;
935       break;
936     }
937     ptr++;
938   }
939   PetscFunctionReturn(0);
940 }
941 
942 /*@C
943    PetscTokenCreate - Creates a PetscToken used to find tokens in a string
944 
945    Not Collective
946 
947    Input Parameters:
948 +  string - the string to look in
949 -  b - the separator character
950 
951    Output Parameter:
952 .  t- the token object
953 
954    Notes:
955 
956      This version is different from the system version in that
957   it allows you to pass a read-only string into the function.
958 
959     Not for use in Fortran
960 
961    Level: intermediate
962 
963 .seealso: `PetscTokenFind()`, `PetscTokenDestroy()`
964 @*/
965 PetscErrorCode PetscTokenCreate(const char a[], const char b, PetscToken *t)
966 {
967   PetscFunctionBegin;
968   PetscValidCharPointer(a,1);
969   PetscValidPointer(t,3);
970   PetscCall(PetscNew(t));
971   PetscCall(PetscStrallocpy(a,&(*t)->array));
972 
973   (*t)->current = (*t)->array;
974   (*t)->token   = b;
975   PetscFunctionReturn(0);
976 }
977 
978 /*@C
979    PetscTokenDestroy - Destroys a PetscToken
980 
981    Not Collective
982 
983    Input Parameters:
984 .  a - pointer to token
985 
986    Level: intermediate
987 
988    Notes:
989     Not for use in Fortran
990 
991 .seealso: `PetscTokenCreate()`, `PetscTokenFind()`
992 @*/
993 PetscErrorCode PetscTokenDestroy(PetscToken *a)
994 {
995   PetscFunctionBegin;
996   if (!*a) PetscFunctionReturn(0);
997   PetscCall(PetscFree((*a)->array));
998   PetscCall(PetscFree(*a));
999   PetscFunctionReturn(0);
1000 }
1001 
1002 /*@C
1003    PetscStrInList - search string in character-delimited list
1004 
1005    Not Collective
1006 
1007    Input Parameters:
1008 +  str - the string to look for
1009 .  list - the list to search in
1010 -  sep - the separator character
1011 
1012    Output Parameter:
1013 .  found - whether str is in list
1014 
1015    Level: intermediate
1016 
1017    Notes:
1018     Not for use in Fortran
1019 
1020 .seealso: `PetscTokenCreate()`, `PetscTokenFind()`, `PetscStrcmp()`
1021 @*/
1022 PetscErrorCode PetscStrInList(const char str[], const char list[], char sep, PetscBool *found)
1023 {
1024   PetscToken  token;
1025   char       *item;
1026 
1027   PetscFunctionBegin;
1028   PetscValidBoolPointer(found,4);
1029   *found = PETSC_FALSE;
1030   PetscCall(PetscTokenCreate(list,sep,&token));
1031   PetscCall(PetscTokenFind(token,&item));
1032   while (item) {
1033     PetscCall(PetscStrcmp(str,item,found));
1034     if (*found) break;
1035     PetscCall(PetscTokenFind(token,&item));
1036   }
1037   PetscCall(PetscTokenDestroy(&token));
1038   PetscFunctionReturn(0);
1039 }
1040 
1041 /*@C
1042    PetscGetPetscDir - Gets the directory PETSc is installed in
1043 
1044    Not Collective
1045 
1046    Output Parameter:
1047 .  dir - the directory
1048 
1049    Level: developer
1050 
1051    Notes:
1052     Not for use in Fortran
1053 
1054 @*/
1055 PetscErrorCode PetscGetPetscDir(const char *dir[])
1056 {
1057   PetscFunctionBegin;
1058   PetscValidPointer(dir,1);
1059   *dir = PETSC_DIR;
1060   PetscFunctionReturn(0);
1061 }
1062 
1063 /*@C
1064    PetscStrreplace - Replaces substrings in string with other substrings
1065 
1066    Not Collective
1067 
1068    Input Parameters:
1069 +   comm - MPI_Comm of processors that are processing the string
1070 .   aa - the string to look in
1071 .   b - the resulting copy of a with replaced strings (b can be the same as a)
1072 -   len - the length of b
1073 
1074    Notes:
1075       Replaces   ${PETSC_ARCH},${PETSC_DIR},${PETSC_LIB_DIR},${DISPLAY},
1076       ${HOMEDIRECTORY},${WORKINGDIRECTORY},${USERNAME}, ${HOSTNAME} with appropriate values
1077       as well as any environmental variables.
1078 
1079       PETSC_LIB_DIR uses the environmental variable if it exists. PETSC_ARCH and PETSC_DIR use what
1080       PETSc was built with and do not use environmental variables.
1081 
1082       Not for use in Fortran
1083 
1084    Level: intermediate
1085 
1086 @*/
1087 PetscErrorCode PetscStrreplace(MPI_Comm comm, const char aa[], char b[], size_t len)
1088 {
1089   int            i = 0;
1090   size_t         l,l1,l2,l3;
1091   char           *work,*par,*epar,env[1024],*tfree,*a = (char*)aa;
1092   const char     *s[] = {"${PETSC_ARCH}","${PETSC_DIR}","${PETSC_LIB_DIR}","${DISPLAY}","${HOMEDIRECTORY}","${WORKINGDIRECTORY}","${USERNAME}","${HOSTNAME}",NULL};
1093   char           *r[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
1094   PetscBool      flag;
1095   static size_t  DISPLAY_LENGTH = 265,USER_LENGTH = 256, HOST_LENGTH = 256;
1096 
1097   PetscFunctionBegin;
1098   PetscValidCharPointer(aa,2);
1099   PetscValidCharPointer(b,3);
1100   if (aa == b) PetscCall(PetscStrallocpy(aa,(char**)&a));
1101   PetscCall(PetscMalloc1(len,&work));
1102 
1103   /* get values for replaced variables */
1104   PetscCall(PetscStrallocpy(PETSC_ARCH,&r[0]));
1105   PetscCall(PetscStrallocpy(PETSC_DIR,&r[1]));
1106   PetscCall(PetscStrallocpy(PETSC_LIB_DIR,&r[2]));
1107   PetscCall(PetscMalloc1(DISPLAY_LENGTH,&r[3]));
1108   PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN,&r[4]));
1109   PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN,&r[5]));
1110   PetscCall(PetscMalloc1(USER_LENGTH,&r[6]));
1111   PetscCall(PetscMalloc1(HOST_LENGTH,&r[7]));
1112   PetscCall(PetscGetDisplay(r[3],DISPLAY_LENGTH));
1113   PetscCall(PetscGetHomeDirectory(r[4],PETSC_MAX_PATH_LEN));
1114   PetscCall(PetscGetWorkingDirectory(r[5],PETSC_MAX_PATH_LEN));
1115   PetscCall(PetscGetUserName(r[6],USER_LENGTH));
1116   PetscCall(PetscGetHostName(r[7],HOST_LENGTH));
1117 
1118   /* replace that are in environment */
1119   PetscCall(PetscOptionsGetenv(comm,"PETSC_LIB_DIR",env,sizeof(env),&flag));
1120   if (flag) {
1121     PetscCall(PetscFree(r[2]));
1122     PetscCall(PetscStrallocpy(env,&r[2]));
1123   }
1124 
1125   /* replace the requested strings */
1126   PetscCall(PetscStrncpy(b,a,len));
1127   while (s[i]) {
1128     PetscCall(PetscStrlen(s[i],&l));
1129     PetscCall(PetscStrstr(b,s[i],&par));
1130     while (par) {
1131       *par = 0;
1132       par += l;
1133 
1134       PetscCall(PetscStrlen(b,&l1));
1135       PetscCall(PetscStrlen(r[i],&l2));
1136       PetscCall(PetscStrlen(par,&l3));
1137       PetscCheck(l1 + l2 + l3 < len,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"b len is not long enough to hold new values");
1138       PetscCall(PetscStrncpy(work,b,len));
1139       PetscCall(PetscStrlcat(work,r[i],len));
1140       PetscCall(PetscStrlcat(work,par,len));
1141       PetscCall(PetscStrncpy(b,work,len));
1142       PetscCall(PetscStrstr(b,s[i],&par));
1143     }
1144     i++;
1145   }
1146   i = 0;
1147   while (r[i]) {
1148     tfree = (char*)r[i];
1149     PetscCall(PetscFree(tfree));
1150     i++;
1151   }
1152 
1153   /* look for any other ${xxx} strings to replace from environmental variables */
1154   PetscCall(PetscStrstr(b,"${",&par));
1155   while (par) {
1156     *par  = 0;
1157     par  += 2;
1158     PetscCall(PetscStrncpy(work,b,len));
1159     PetscCall(PetscStrstr(par,"}",&epar));
1160     *epar = 0;
1161     epar += 1;
1162     PetscCall(PetscOptionsGetenv(comm,par,env,sizeof(env),&flag));
1163     PetscCheck(flag,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Substitution string ${%s} not found as environmental variable",par);
1164     PetscCall(PetscStrlcat(work,env,len));
1165     PetscCall(PetscStrlcat(work,epar,len));
1166     PetscCall(PetscStrncpy(b,work,len));
1167     PetscCall(PetscStrstr(b,"${",&par));
1168   }
1169   PetscCall(PetscFree(work));
1170   if (aa == b) PetscCall(PetscFree(a));
1171   PetscFunctionReturn(0);
1172 }
1173 
1174 /*@C
1175    PetscEListFind - searches list of strings for given string, using case insensitive matching
1176 
1177    Not Collective
1178 
1179    Input Parameters:
1180 +  n - number of strings in
1181 .  list - list of strings to search
1182 -  str - string to look for, empty string "" accepts default (first entry in list)
1183 
1184    Output Parameters:
1185 +  value - index of matching string (if found)
1186 -  found - boolean indicating whether string was found (can be NULL)
1187 
1188    Notes:
1189    Not for use in Fortran
1190 
1191    Level: advanced
1192 @*/
1193 PetscErrorCode PetscEListFind(PetscInt n, const char *const *list, const char *str, PetscInt *value, PetscBool *found)
1194 {
1195   PetscFunctionBegin;
1196   if (found) {
1197     PetscValidBoolPointer(found,5);
1198     *found = PETSC_FALSE;
1199   }
1200   for (PetscInt i = 0; i < n; ++i) {
1201     PetscBool matched;
1202 
1203     PetscCall(PetscStrcasecmp(str,list[i],&matched));
1204     if (matched || !str[0]) {
1205       if (found) *found = PETSC_TRUE;
1206       *value = i;
1207       break;
1208     }
1209   }
1210   PetscFunctionReturn(0);
1211 }
1212 
1213 /*@C
1214    PetscEnumFind - searches enum list of strings for given string, using case insensitive matching
1215 
1216    Not Collective
1217 
1218    Input Parameters:
1219 +  enumlist - list of strings to search, followed by enum name, then enum prefix, then NUL
1220 -  str - string to look for
1221 
1222    Output Parameters:
1223 +  value - index of matching string (if found)
1224 -  found - boolean indicating whether string was found (can be NULL)
1225 
1226    Notes:
1227    Not for use in Fortran
1228 
1229    Level: advanced
1230 @*/
1231 PetscErrorCode PetscEnumFind(const char *const *enumlist, const char *str, PetscEnum *value, PetscBool *found)
1232 {
1233   PetscInt  n = 0,evalue;
1234   PetscBool efound;
1235 
1236   PetscFunctionBegin;
1237   PetscValidPointer(enumlist,1);
1238   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");
1239   PetscCheck(n >= 3,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"List argument must have at least two entries: typename and type prefix");
1240   n -= 3; /* drop enum name, prefix, and null termination */
1241   PetscCall(PetscEListFind(n,enumlist,str,&evalue,&efound));
1242   if (efound) {
1243     PetscValidPointer(value,3);
1244     *value = (PetscEnum)evalue;
1245   }
1246   if (found) {
1247     PetscValidBoolPointer(found,4);
1248     *found = efound;
1249   }
1250   PetscFunctionReturn(0);
1251 }
1252