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