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