Actual source code: str.c
petsc-3.3-p7 2013-05-11
2: /*
3: We define the string operations here. The reason we just do not use
4: the standard string routines in the PETSc code is that on some machines
5: they are broken or have the wrong prototypes.
7: */
8: #include <petscsys.h> /*I "petscsys.h" I*/
9: #if defined(PETSC_HAVE_STRING_H)
10: #include <string.h>
11: #endif
12: #if defined(PETSC_HAVE_STRINGS_H)
13: #include <strings.h>
14: #endif
18: /*@C
19: PetscStrToArray - Seperates a string by its spaces and creates an array of strings
21: Not Collective
23: Input Parameters:
24: . s - pointer to string
26: Output Parameter:
27: + argc - the number of entries in the array
28: - args - an array of the entries with a null at the end
30: Level: intermediate
32: Notes: this may be called before PetscInitialize() or after PetscFinalize()
34: Not for use in Fortran
36: Developer Notes: Using raw malloc() and does not call error handlers since this may be used before PETSc is initialized. Used
37: to generate argc, args arguments passed to MPI_Init()
39: .seealso: PetscStrToArrayDestroy(), PetscToken, PetscTokenCreate()
41: @*/
42: PetscErrorCode PetscStrToArray(const char s[],int *argc,char ***args)
43: {
44: int i,n,*lens,cnt = 0;
45: PetscBool flg = PETSC_FALSE;
47: n = strlen(s);
48: *argc = 0;
49: for (i=0; i<n; i++) {
50: if (s[i] != ' ') break;
51: }
52: for (;i<n+1; i++) {
53: if ((s[i] == ' ' || s[i] == 0) && !flg) {flg = PETSC_TRUE; (*argc)++;}
54: else if (s[i] != ' ') {flg = PETSC_FALSE;}
55: }
56: (*args) = (char **) malloc(((*argc)+1)*sizeof(char**)); if (!*args) return PETSC_ERR_MEM;
57: lens = (int*) malloc((*argc)*sizeof(int)); if (!lens) return PETSC_ERR_MEM;
58: for (i=0; i<*argc; i++) lens[i] = 0;
60: *argc = 0;
61: for (i=0; i<n; i++) {
62: if (s[i] != ' ') break;
63: }
64: for (;i<n+1; i++) {
65: if ((s[i] == ' ' || s[i] == 0) && !flg) {flg = PETSC_TRUE; (*argc)++;}
66: else if (s[i] != ' ') {lens[*argc]++;flg = PETSC_FALSE;}
67: }
69: for (i=0; i<*argc; i++) {
70: (*args)[i] = (char*) malloc((lens[i]+1)*sizeof(char)); if (!(*args)[i]) return PETSC_ERR_MEM;
71: }
72: (*args)[*argc] = 0;
74: *argc = 0;
75: for (i=0; i<n; i++) {
76: if (s[i] != ' ') break;
77: }
78: for (;i<n+1; i++) {
79: if ((s[i] == ' ' || s[i] == 0) && !flg) {flg = PETSC_TRUE; (*args)[*argc][cnt++] = 0; (*argc)++; cnt = 0;}
80: else if (s[i] != ' ' && s[i] != 0) {(*args)[*argc][cnt++] = s[i]; flg = PETSC_FALSE;}
81: }
82: return 0;
83: }
87: /*@C
88: PetscStrToArrayDestroy - Frees array created with PetscStrToArray().
90: Not Collective
92: Output Parameters:
93: + argc - the number of arguments
94: - args - the array of arguments
96: Level: intermediate
98: Concepts: command line arguments
99:
100: Notes: This may be called before PetscInitialize() or after PetscFinalize()
102: Not for use in Fortran
104: .seealso: PetscStrToArray()
106: @*/
107: PetscErrorCode PetscStrToArrayDestroy(int argc,char **args)
108: {
109: PetscInt i;
111: for (i=0; i<argc; i++) {
112: free(args[i]);
113: }
114: free(args);
115: return 0;
116: }
120: /*@C
121: PetscStrlen - Gets length of a string
123: Not Collective
125: Input Parameters:
126: . s - pointer to string
128: Output Parameter:
129: . len - length in bytes
131: Level: intermediate
133: Note:
134: This routine is analogous to strlen().
136: Null string returns a length of zero
138: Not for use in Fortran
140: Concepts: string length
141:
142: @*/
143: PetscErrorCode PetscStrlen(const char s[],size_t *len)
144: {
146: if (!s) {
147: *len = 0;
148: } else {
149: *len = strlen(s);
150: }
151: return(0);
152: }
156: /*@C
157: PetscStrallocpy - Allocates space to hold a copy of a string then copies the string
159: Not Collective
161: Input Parameters:
162: . s - pointer to string
164: Output Parameter:
165: . t - the copied string
167: Level: intermediate
169: Note:
170: Null string returns a new null string
172: Not for use in Fortran
174: Concepts: string copy
175:
176: @*/
177: PetscErrorCode PetscStrallocpy(const char s[],char *t[])
178: {
180: size_t len;
181: char *tmp = 0;
184: if (s) {
185: PetscStrlen(s,&len);
186: PetscMalloc((1+len)*sizeof(char),&tmp);
187: PetscStrcpy(tmp,s);
188: }
189: *t = tmp;
190: return(0);
191: }
195: /*@C
196: PetscStrArrayallocpy - Allocates space to hold a copy of an array of strings then copies the strings
198: Not Collective
200: Input Parameters:
201: . s - pointer to array of strings (final string is a null)
203: Output Parameter:
204: . t - the copied array string
206: Level: intermediate
208: Note:
209: Not for use in Fortran
211: Concepts: string copy
213: .seealso: PetscStrallocpy() PetscStrArrayDestroy()
214:
215: @*/
216: PetscErrorCode PetscStrArrayallocpy(const char *const*list,char ***t)
217: {
219: PetscInt i,n = 0;
222: while (list[n++]) ;
223: PetscMalloc((n+1)*sizeof(char**),t);
224: for (i=0; i<n; i++) {
225: PetscStrallocpy(list[i],(*t)+i);
226: }
227: (*t)[n] = PETSC_NULL;
228: return(0);
229: }
233: /*@C
234: PetscStrArrayDestroy - Frees array of strings created with PetscStrArrayallocpy().
236: Not Collective
238: Output Parameters:
239: . list - array of strings
241: Level: intermediate
243: Concepts: command line arguments
244:
245: Notes: Not for use in Fortran
247: .seealso: PetscStrArrayallocpy()
249: @*/
250: PetscErrorCode PetscStrArrayDestroy(char ***list)
251: {
252: PetscInt n = 0;
256: if (!*list) return(0);
257: while ((*list)[n]) {
258: PetscFree((*list)[n]);
259: n++;
260: }
261: PetscFree(*list);
262: return(0);
263: }
267: /*@C
268: PetscStrcpy - Copies a string
270: Not Collective
272: Input Parameters:
273: . t - pointer to string
275: Output Parameter:
276: . s - the copied string
278: Level: intermediate
280: Notes:
281: Null string returns a string starting with zero
283: Not for use in Fortran
285: Concepts: string copy
286:
287: .seealso: PetscStrncpy(), PetscStrcat(), PetscStrncat()
289: @*/
291: PetscErrorCode PetscStrcpy(char s[],const char t[])
292: {
294: if (t && !s) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Trying to copy string into null pointer");
295: if (t) {strcpy(s,t);}
296: else if (s) {s[0] = 0;}
297: return(0);
298: }
302: /*@C
303: PetscStrncpy - Copies a string up to a certain length
305: Not Collective
307: Input Parameters:
308: + t - pointer to string
309: - n - the length to copy
311: Output Parameter:
312: . s - the copied string
314: Level: intermediate
316: Note:
317: Null string returns a string starting with zero
319: Concepts: string copy
321: .seealso: PetscStrcpy(), PetscStrcat(), PetscStrncat()
322:
323: @*/
324: PetscErrorCode PetscStrncpy(char s[],const char t[],size_t n)
325: {
327: if (t && !s) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Trying to copy string into null pointer");
328: if (t) {strncpy(s,t,n);}
329: else if (s) {s[0] = 0;}
330: return(0);
331: }
335: /*@C
336: PetscStrcat - Concatenates a string onto a given string
338: Not Collective
340: Input Parameters:
341: + s - string to be added to
342: - t - pointer to string to be added to end
344: Level: intermediate
346: Notes: Not for use in Fortran
348: Concepts: string copy
350: .seealso: PetscStrcpy(), PetscStrncpy(), PetscStrncat()
351:
352: @*/
353: PetscErrorCode PetscStrcat(char s[],const char t[])
354: {
356: if (!t) return(0);
357: strcat(s,t);
358: return(0);
359: }
363: /*@C
364: PetscStrncat - Concatenates a string onto a given string, up to a given length
366: Not Collective
368: Input Parameters:
369: + s - pointer to string to be added to end
370: . t - string to be added to
371: . n - maximum length to copy
373: Level: intermediate
375: Notes: Not for use in Fortran
377: Concepts: string copy
379: .seealso: PetscStrcpy(), PetscStrncpy(), PetscStrcat()
380:
381: @*/
382: PetscErrorCode PetscStrncat(char s[],const char t[],size_t n)
383: {
385: strncat(s,t,n);
386: return(0);
387: }
391: /*@C
392: PetscStrcmp - Compares two strings,
394: Not Collective
396: Input Parameters:
397: + a - pointer to string first string
398: - b - pointer to second string
400: Output Parameter:
401: . flg - PETSC_TRUE if the two strings are equal
403: Level: intermediate
405: Notes: Not for use in Fortran
407: .seealso: PetscStrgrt(), PetscStrncmp(), PetscStrcasecmp()
409: @*/
410: PetscErrorCode PetscStrcmp(const char a[],const char b[],PetscBool *flg)
411: {
412: int c;
415: if (!a && !b) {
416: *flg = PETSC_TRUE;
417: } else if (!a || !b) {
418: *flg = PETSC_FALSE;
419: } else {
420: c = strcmp(a,b);
421: if (c) *flg = PETSC_FALSE;
422: else *flg = PETSC_TRUE;
423: }
424: return(0);
425: }
429: /*@C
430: PetscStrgrt - If first string is greater than the second
432: Not Collective
434: Input Parameters:
435: + a - pointer to first string
436: - b - pointer to second string
438: Output Parameter:
439: . flg - if the first string is greater
441: Notes:
442: Null arguments are ok, a null string is considered smaller than
443: all others
445: Not for use in Fortran
447: Level: intermediate
449: .seealso: PetscStrcmp(), PetscStrncmp(), PetscStrcasecmp()
451: @*/
452: PetscErrorCode PetscStrgrt(const char a[],const char b[],PetscBool *t)
453: {
454: int c;
457: if (!a && !b) {
458: *t = PETSC_FALSE;
459: } else if (a && !b) {
460: *t = PETSC_TRUE;
461: } else if (!a && b) {
462: *t = PETSC_FALSE;
463: } else {
464: c = strcmp(a,b);
465: if (c > 0) *t = PETSC_TRUE;
466: else *t = PETSC_FALSE;
467: }
468: return(0);
469: }
473: /*@C
474: PetscStrcasecmp - Returns true if the two strings are the same
475: except possibly for case.
477: Not Collective
479: Input Parameters:
480: + a - pointer to first string
481: - b - pointer to second string
483: Output Parameter:
484: . flg - if the two strings are the same
486: Notes:
487: Null arguments are ok
489: Not for use in Fortran
491: Level: intermediate
493: .seealso: PetscStrcmp(), PetscStrncmp(), PetscStrgrt()
495: @*/
496: PetscErrorCode PetscStrcasecmp(const char a[],const char b[],PetscBool *t)
497: {
498: int c;
501: if (!a && !b) c = 0;
502: else if (!a || !b) c = 1;
503: #if defined(PETSC_HAVE_STRCASECMP)
504: else c = strcasecmp(a,b);
505: #elif defined(PETSC_HAVE_STRICMP)
506: else c = stricmp(a,b);
507: #else
508: else {
509: char *aa,*bb;
511: PetscStrallocpy(a,&aa);
512: PetscStrallocpy(b,&bb);
513: PetscStrtolower(aa);
514: PetscStrtolower(bb);
515: PetscStrcmp(aa,bb,t);
516: PetscFree(aa);
517: PetscFree(bb);
518: return(0);
519: }
520: #endif
521: if (!c) *t = PETSC_TRUE;
522: else *t = PETSC_FALSE;
523: return(0);
524: }
530: /*@C
531: PetscStrncmp - Compares two strings, up to a certain length
533: Not Collective
535: Input Parameters:
536: + a - pointer to first string
537: . b - pointer to second string
538: - n - length to compare up to
540: Output Parameter:
541: . t - if the two strings are equal
543: Level: intermediate
545: Notes: Not for use in Fortran
547: .seealso: PetscStrgrt(), PetscStrcmp(), PetscStrcasecmp()
549: @*/
550: PetscErrorCode PetscStrncmp(const char a[],const char b[],size_t n,PetscBool *t)
551: {
552: int c;
555: c = strncmp(a,b,n);
556: if (!c) *t = PETSC_TRUE;
557: else *t = PETSC_FALSE;
558: return(0);
559: }
563: /*@C
564: PetscStrchr - Locates first occurance of a character in a string
566: Not Collective
568: Input Parameters:
569: + a - pointer to string
570: - b - character
572: Output Parameter:
573: . c - location of occurance, PETSC_NULL if not found
575: Level: intermediate
577: Notes: Not for use in Fortran
579: @*/
580: PetscErrorCode PetscStrchr(const char a[],char b,char *c[])
581: {
583: *c = (char *)strchr(a,b);
584: return(0);
585: }
589: /*@C
590: PetscStrrchr - Locates one location past the last occurance of a character in a string,
591: if the character is not found then returns entire string
593: Not Collective
595: Input Parameters:
596: + a - pointer to string
597: - b - character
599: Output Parameter:
600: . tmp - location of occurance, a if not found
602: Level: intermediate
604: Notes: Not for use in Fortran
606: @*/
607: PetscErrorCode PetscStrrchr(const char a[],char b,char *tmp[])
608: {
610: *tmp = (char *)strrchr(a,b);
611: if (!*tmp) *tmp = (char*)a; else *tmp = *tmp + 1;
612: return(0);
613: }
617: /*@C
618: PetscStrtolower - Converts string to lower case
620: Not Collective
622: Input Parameters:
623: . a - pointer to string
625: Level: intermediate
627: Notes: Not for use in Fortran
629: @*/
630: PetscErrorCode PetscStrtolower(char a[])
631: {
633: while (*a) {
634: if (*a >= 'A' && *a <= 'Z') *a += 'a' - 'A';
635: a++;
636: }
637: return(0);
638: }
642: /*@C
643: PetscStrendswith - Determines if a string ends with a certain string
645: Not Collective
647: Input Parameters:
648: + a - pointer to string
649: - b - string to endwith
651: Output Parameter:
652: . flg - PETSC_TRUE or PETSC_FALSE
654: Notes: Not for use in Fortran
656: Level: intermediate
658: @*/
659: PetscErrorCode PetscStrendswith(const char a[],const char b[],PetscBool *flg)
660: {
661: char *test;
663: size_t na,nb;
666: *flg = PETSC_FALSE;
667: PetscStrrstr(a,b,&test);
668: if (test) {
669: PetscStrlen(a,&na);
670: PetscStrlen(b,&nb);
671: if (a+na-nb == test) *flg = PETSC_TRUE;
672: }
673: return(0);
674: }
678: /*@C
679: PetscStrendswithwhich - Determines if a string ends with one of several possible strings
681: Not Collective
683: Input Parameters:
684: + a - pointer to string
685: - bs - strings to endwith (last entry must be null)
687: Output Parameter:
688: . cnt - the index of the string it ends with or 1+the last possible index
690: Notes: Not for use in Fortran
692: Level: intermediate
694: @*/
695: PetscErrorCode PetscStrendswithwhich(const char a[],const char *const *bs,PetscInt *cnt)
696: {
697: PetscBool flg;
701: *cnt = 0;
702: while (bs[*cnt]) {
703: PetscStrendswith(a,bs[*cnt],&flg);
704: if (flg) return(0);
705: *cnt += 1;
706: }
707: return(0);
708: }
712: /*@C
713: PetscStrrstr - Locates last occurance of string in another string
715: Not Collective
717: Input Parameters:
718: + a - pointer to string
719: - b - string to find
721: Output Parameter:
722: . tmp - location of occurance
724: Notes: Not for use in Fortran
726: Level: intermediate
728: @*/
729: PetscErrorCode PetscStrrstr(const char a[],const char b[],char *tmp[])
730: {
731: const char *stmp = a, *ltmp = 0;
734: while (stmp) {
735: stmp = (char *)strstr(stmp,b);
736: if (stmp) {ltmp = stmp;stmp++;}
737: }
738: *tmp = (char *)ltmp;
739: return(0);
740: }
744: /*@C
745: PetscStrstr - Locates first occurance of string in another string
747: Not Collective
749: Input Parameters:
750: + haystack - string to search
751: - needle - string to find
753: Output Parameter:
754: . tmp - location of occurance, is a PETSC_NULL if the string is not found
756: Notes: Not for use in Fortran
758: Level: intermediate
760: @*/
761: PetscErrorCode PetscStrstr(const char haystack[],const char needle[],char *tmp[])
762: {
764: *tmp = (char *)strstr(haystack,needle);
765: return(0);
766: }
768: struct _p_PetscToken {char token;char *array;char *current;};
772: /*@C
773: PetscTokenFind - Locates next "token" in a string
775: Not Collective
777: Input Parameters:
778: . a - pointer to token
780: Output Parameter:
781: . result - location of occurance, PETSC_NULL if not found
783: Notes:
785: This version is different from the system version in that
786: it allows you to pass a read-only string into the function.
788: This version also treats all characters etc. inside a double quote "
789: as a single token.
791: Not for use in Fortran
793: Level: intermediate
796: .seealso: PetscTokenCreate(), PetscTokenDestroy()
797: @*/
798: PetscErrorCode PetscTokenFind(PetscToken a,char *result[])
799: {
800: char *ptr = a->current,token;
803: *result = a->current;
804: if (ptr && !*ptr) {*result = 0;return(0);}
805: token = a->token;
806: if (ptr && (*ptr == '"')) {token = '"';(*result)++;ptr++;}
807: while (ptr) {
808: if (*ptr == token) {
809: *ptr++ = 0;
810: while (*ptr == a->token) ptr++;
811: a->current = ptr;
812: break;
813: }
814: if (!*ptr) {
815: a->current = 0;
816: break;
817: }
818: ptr++;
819: }
820: return(0);
821: }
825: /*@C
826: PetscTokenCreate - Creates a PetscToken used to find tokens in a string
828: Not Collective
830: Input Parameters:
831: + string - the string to look in
832: - token - the character to look for
834: Output Parameter:
835: . a - pointer to token
837: Notes:
839: This version is different from the system version in that
840: it allows you to pass a read-only string into the function.
842: Not for use in Fortran
844: Level: intermediate
846: .seealso: PetscTokenFind(), PetscTokenDestroy()
847: @*/
848: PetscErrorCode PetscTokenCreate(const char a[],const char b,PetscToken *t)
849: {
853: PetscNew(struct _p_PetscToken,t);
854: PetscStrallocpy(a,&(*t)->array);
855: (*t)->current = (*t)->array;
856: (*t)->token = b;
857: return(0);
858: }
862: /*@C
863: PetscTokenDestroy - Destroys a PetscToken
865: Not Collective
867: Input Parameters:
868: . a - pointer to token
870: Level: intermediate
872: Notes: Not for use in Fortran
874: .seealso: PetscTokenCreate(), PetscTokenFind()
875: @*/
876: PetscErrorCode PetscTokenDestroy(PetscToken *a)
877: {
881: if (!*a) return(0);
882: PetscFree((*a)->array);
883: PetscFree(*a);
884: return(0);
885: }
890: /*@C
891: PetscGetPetscDir - Gets the directory PETSc is installed in
893: Not Collective
895: Output Parameter:
896: . dir - the directory
898: Level: developer
900: Notes: Not for use in Fortran
902: @*/
903: PetscErrorCode PetscGetPetscDir(const char *dir[])
904: {
906: *dir = PETSC_DIR;
907: return(0);
908: }
912: /*@C
913: PetscStrreplace - Replaces substrings in string with other substrings
915: Not Collective
917: Input Parameters:
918: + comm - MPI_Comm of processors that are processing the string
919: . aa - the string to look in
920: . b - the resulting copy of a with replaced strings (b can be the same as a)
921: - len - the length of b
923: Notes:
924: Replaces ${PETSC_ARCH},${PETSC_DIR},${PETSC_LIB_DIR},${DISPLAY},
925: ${HOMEDIRECTORY},${WORKINGDIRECTORY},${USERNAME}, ${HOSTNAME} with appropriate values
926: as well as any environmental variables.
928: PETSC_LIB_DIR uses the environmental variable if it exists. PETSC_ARCH and PETSC_DIR use what
929: PETSc was built with and do not use environmental variables.
930:
931: Not for use in Fortran
932:
933: Level: intermediate
935: @*/
936: PetscErrorCode PetscStrreplace(MPI_Comm comm,const char aa[],char b[],size_t len)
937: {
939: int i = 0;
940: size_t l,l1,l2,l3;
941: char *work,*par,*epar,env[1024],*tfree,*a = (char*)aa;
942: const char *s[] = {"${PETSC_ARCH}","${PETSC_DIR}","${PETSC_LIB_DIR}","${DISPLAY}","${HOMEDIRECTORY}","${WORKINGDIRECTORY}","${USERNAME}","${HOSTNAME}",0};
943: const char *r[] = {0,0,0,0,0,0,0,0,0};
944: PetscBool flag;
947: if (!a || !b) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"a and b strings must be nonnull");
948: if (aa == b) {
949: PetscStrallocpy(aa,(char **)&a);
950: }
951: PetscMalloc(len*sizeof(char*),&work);
953: /* get values for replaced variables */
954: PetscStrallocpy(PETSC_ARCH,(char**)&r[0]);
955: PetscStrallocpy(PETSC_DIR,(char**)&r[1]);
956: PetscStrallocpy(PETSC_LIB_DIR,(char**)&r[2]);
957: PetscMalloc(256*sizeof(char),&r[3]);
958: PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&r[4]);
959: PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&r[5]);
960: PetscMalloc(256*sizeof(char),&r[6]);
961: PetscMalloc(256*sizeof(char),&r[7]);
962: PetscGetDisplay((char*)r[3],256);
963: PetscGetHomeDirectory((char*)r[4],PETSC_MAX_PATH_LEN);
964: PetscGetWorkingDirectory((char*)r[5],PETSC_MAX_PATH_LEN);
965: PetscGetUserName((char*)r[6],256);
966: PetscGetHostName((char*)r[7],256);
968: /* replace that are in environment */
969: PetscOptionsGetenv(comm,"PETSC_LIB_DIR",env,1024,&flag);
970: if (flag) {
971: PetscStrallocpy(env,(char**)&r[2]);
972: }
974: /* replace the requested strings */
975: PetscStrncpy(b,a,len);
976: while (s[i]) {
977: PetscStrlen(s[i],&l);
978: PetscStrstr(b,s[i],&par);
979: while (par) {
980: *par = 0;
981: par += l;
983: PetscStrlen(b,&l1);
984: PetscStrlen(r[i],&l2);
985: PetscStrlen(par,&l3);
986: if (l1 + l2 + l3 >= len) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"b len is not long enough to hold new values");
987: PetscStrcpy(work,b);
988: PetscStrcat(work,r[i]);
989: PetscStrcat(work,par);
990: PetscStrncpy(b,work,len);
991: PetscStrstr(b,s[i],&par);
992: }
993: i++;
994: }
995: i = 0;
996: while (r[i]) {
997: tfree = (char*)r[i];
998: PetscFree(tfree);
999: i++;
1000: }
1002: /* look for any other ${xxx} strings to replace from environmental variables */
1003: PetscStrstr(b,"${",&par);
1004: while (par) {
1005: *par = 0;
1006: par += 2;
1007: PetscStrcpy(work,b);
1008: PetscStrstr(par,"}",&epar);
1009: *epar = 0;
1010: epar += 1;
1011: PetscOptionsGetenv(comm,par,env,256,&flag);
1012: if (!flag) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Substitution string ${%s} not found as environmental variable",par);
1013: PetscStrcat(work,env);
1014: PetscStrcat(work,epar);
1015: PetscStrcpy(b,work);
1016: PetscStrstr(b,"${",&par);
1017: }
1018: PetscFree(work);
1019: if (aa == b) {
1020: PetscFree(a);
1021: }
1022: return(0);
1023: }