xref: /petsc/src/sys/utils/str.c (revision 3f2090d5b101f83ad3b99db560935e7511b462d0)
1 #define PETSC_DLL
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.
6 
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
15 
16 #undef __FUNCT__
17 #define __FUNCT__ "PetscStrlen"
18 /*@C
19    PetscStrlen - Gets length of a string
20 
21    Not Collective
22 
23    Input Parameters:
24 .  s - pointer to string
25 
26    Output Parameter:
27 .  len - length in bytes
28 
29    Level: intermediate
30 
31    Note:
32    This routine is analogous to strlen().
33 
34    Null string returns a length of zero
35 
36   Concepts: string length
37 
38 @*/
39 PetscErrorCode PETSC_DLLEXPORT PetscStrlen(const char s[],size_t *len)
40 {
41   PetscFunctionBegin;
42   if (!s) {
43     *len = 0;
44   } else {
45     *len = strlen(s);
46   }
47   PetscFunctionReturn(0);
48 }
49 
50 #undef __FUNCT__
51 #define __FUNCT__ "PetscStrallocpy"
52 /*@C
53    PetscStrallocpy - Allocates space to hold a copy of a string then copies the string
54 
55    Not Collective
56 
57    Input Parameters:
58 .  s - pointer to string
59 
60    Output Parameter:
61 .  t - the copied string
62 
63    Level: intermediate
64 
65    Note:
66       Null string returns a new null string
67 
68   Concepts: string copy
69 
70 @*/
71 PetscErrorCode PETSC_DLLEXPORT PetscStrallocpy(const char s[],char *t[])
72 {
73   PetscErrorCode ierr;
74   size_t         len;
75   char           *tmp = 0;
76 
77   PetscFunctionBegin;
78   if (s) {
79     ierr = PetscStrlen(s,&len);CHKERRQ(ierr);
80     ierr = PetscMalloc((1+len)*sizeof(char),&tmp);CHKERRQ(ierr);
81     ierr = PetscStrcpy(tmp,s);CHKERRQ(ierr);
82   }
83   *t = tmp;
84   PetscFunctionReturn(0);
85 }
86 
87 #undef __FUNCT__
88 #define __FUNCT__ "PetscStrcpy"
89 /*@C
90    PetscStrcpy - Copies a string
91 
92    Not Collective
93 
94    Input Parameters:
95 .  t - pointer to string
96 
97    Output Parameter:
98 .  s - the copied string
99 
100    Level: intermediate
101 
102    Note:
103      Null string returns a string starting with zero
104 
105   Concepts: string copy
106 
107 .seealso: PetscStrncpy(), PetscStrcat(), PetscStrncat()
108 
109 @*/
110 
111 PetscErrorCode PETSC_DLLEXPORT PetscStrcpy(char s[],const char t[])
112 {
113   PetscFunctionBegin;
114   if (t && !s) {
115     SETERRQ(PETSC_ERR_ARG_NULL,"Trying to copy string into null pointer");
116   }
117   if (t) {strcpy(s,t);}
118   else if (s) {s[0] = 0;}
119   PetscFunctionReturn(0);
120 }
121 
122 #undef __FUNCT__
123 #define __FUNCT__ "PetscStrncpy"
124 /*@C
125    PetscStrncpy - Copies a string up to a certain length
126 
127    Not Collective
128 
129    Input Parameters:
130 +  t - pointer to string
131 -  n - the length to copy
132 
133    Output Parameter:
134 .  s - the copied string
135 
136    Level: intermediate
137 
138    Note:
139      Null string returns a string starting with zero
140 
141   Concepts: string copy
142 
143 .seealso: PetscStrcpy(), PetscStrcat(), PetscStrncat()
144 
145 @*/
146 PetscErrorCode PETSC_DLLEXPORT PetscStrncpy(char s[],const char t[],size_t n)
147 {
148   PetscFunctionBegin;
149   if (t && !s) {
150     SETERRQ(PETSC_ERR_ARG_NULL,"Trying to copy string into null pointer");
151   }
152   if (t) {strncpy(s,t,n);}
153   else if (s) {s[0] = 0;}
154   PetscFunctionReturn(0);
155 }
156 
157 #undef __FUNCT__
158 #define __FUNCT__ "PetscStrcat"
159 /*@C
160    PetscStrcat - Concatenates a string onto a given string
161 
162    Not Collective
163 
164    Input Parameters:
165 +  s - string to be added to
166 -  t - pointer to string to be added to end
167 
168    Level: intermediate
169 
170   Concepts: string copy
171 
172 .seealso: PetscStrcpy(), PetscStrncpy(), PetscStrncat()
173 
174 @*/
175 PetscErrorCode PETSC_DLLEXPORT PetscStrcat(char s[],const char t[])
176 {
177   PetscFunctionBegin;
178   if (!t) PetscFunctionReturn(0);
179   strcat(s,t);
180   PetscFunctionReturn(0);
181 }
182 
183 #undef __FUNCT__
184 #define __FUNCT__ "PetscStrncat"
185 /*@C
186    PetscStrncat - Concatenates a string onto a given string, up to a given length
187 
188    Not Collective
189 
190    Input Parameters:
191 +  s - pointer to string to be added to end
192 .  t - string to be added to
193 .  n - maximum length to copy
194 
195    Level: intermediate
196 
197   Concepts: string copy
198 
199 .seealso: PetscStrcpy(), PetscStrncpy(), PetscStrcat()
200 
201 @*/
202 PetscErrorCode PETSC_DLLEXPORT PetscStrncat(char s[],const char t[],size_t n)
203 {
204   PetscFunctionBegin;
205   strncat(s,t,n);
206   PetscFunctionReturn(0);
207 }
208 
209 #undef __FUNCT__
210 #define __FUNCT__ "PetscStrcmp"
211 /*@C
212    PetscStrcmp - Compares two strings,
213 
214    Not Collective
215 
216    Input Parameters:
217 +  a - pointer to string first string
218 -  b - pointer to second string
219 
220    Output Parameter:
221 .  flg - if the two strings are equal
222 
223    Level: intermediate
224 
225 .seealso: PetscStrgrt(), PetscStrncmp(), PetscStrcasecmp()
226 
227 @*/
228 PetscErrorCode PETSC_DLLEXPORT PetscStrcmp(const char a[],const char b[],PetscTruth *flg)
229 {
230   int c;
231 
232   PetscFunctionBegin;
233   if (!a && !b) {
234     *flg = PETSC_TRUE;
235   } else if (!a || !b) {
236     *flg = PETSC_FALSE;
237   } else {
238     c = strcmp(a,b);
239     if (c) *flg = PETSC_FALSE;
240     else   *flg = PETSC_TRUE;
241   }
242   PetscFunctionReturn(0);
243 }
244 
245 #undef __FUNCT__
246 #define __FUNCT__ "PetscStrgrt"
247 /*@C
248    PetscStrgrt - If first string is greater than the second
249 
250    Not Collective
251 
252    Input Parameters:
253 +  a - pointer to first string
254 -  b - pointer to second string
255 
256    Output Parameter:
257 .  flg - if the first string is greater
258 
259    Notes:
260     Null arguments are ok, a null string is considered smaller than
261     all others
262 
263    Level: intermediate
264 
265 .seealso: PetscStrcmp(), PetscStrncmp(), PetscStrcasecmp()
266 
267 @*/
268 PetscErrorCode PETSC_DLLEXPORT PetscStrgrt(const char a[],const char b[],PetscTruth *t)
269 {
270   int c;
271 
272   PetscFunctionBegin;
273   if (!a && !b) {
274     *t = PETSC_FALSE;
275   } else if (a && !b) {
276     *t = PETSC_TRUE;
277   } else if (!a && b) {
278     *t = PETSC_FALSE;
279   } else {
280     c = strcmp(a,b);
281     if (c > 0) *t = PETSC_TRUE;
282     else       *t = PETSC_FALSE;
283   }
284   PetscFunctionReturn(0);
285 }
286 
287 #undef __FUNCT__
288 #define __FUNCT__ "PetscStrcasecmp"
289 /*@C
290    PetscStrcasecmp - Returns true if the two strings are the same
291      except possibly for case.
292 
293    Not Collective
294 
295    Input Parameters:
296 +  a - pointer to first string
297 -  b - pointer to second string
298 
299    Output Parameter:
300 .  flg - if the two strings are the same
301 
302    Notes:
303     Null arguments are ok
304 
305    Level: intermediate
306 
307 .seealso: PetscStrcmp(), PetscStrncmp(), PetscStrgrt()
308 
309 @*/
310 PetscErrorCode PETSC_DLLEXPORT PetscStrcasecmp(const char a[],const char b[],PetscTruth *t)
311 {
312   int c;
313 
314   PetscFunctionBegin;
315   if (!a && !b) c = 0;
316   else if (!a || !b) c = 1;
317 #if defined(PETSC_HAVE_STRCASECMP)
318   else c = strcasecmp(a,b);
319 #elif defined(PETSC_HAVE_STRICMP)
320   else c = stricmp(a,b);
321 #else
322   else {
323     char *aa,*bb;
324     PetscErrorCode ierr;
325     ierr = PetscStrallocpy(a,&aa);CHKERRQ(ierr);
326     ierr = PetscStrallocpy(b,&bb);CHKERRQ(ierr);
327     ierr = PetscStrtolower(aa);CHKERRQ(ierr);
328     ierr = PetscStrtolower(bb);CHKERRQ(ierr);
329     ierr = PetscStrcmp(aa,bb,t);CHKERRQ(ierr);
330     ierr = PetscStrfree(aa);CHKERRQ(ierr);
331     ierr = PetscStrfree(bb);CHKERRQ(ierr);
332     PetscFunctionReturn(0);
333   }
334 #endif
335   if (!c) *t = PETSC_TRUE;
336   else    *t = PETSC_FALSE;
337   PetscFunctionReturn(0);
338 }
339 
340 
341 
342 #undef __FUNCT__
343 #define __FUNCT__ "PetscStrncmp"
344 /*@C
345    PetscStrncmp - Compares two strings, up to a certain length
346 
347    Not Collective
348 
349    Input Parameters:
350 +  a - pointer to first string
351 .  b - pointer to second string
352 -  n - length to compare up to
353 
354    Output Parameter:
355 .  t - if the two strings are equal
356 
357    Level: intermediate
358 
359 .seealso: PetscStrgrt(), PetscStrcmp(), PetscStrcasecmp()
360 
361 @*/
362 PetscErrorCode PETSC_DLLEXPORT PetscStrncmp(const char a[],const char b[],size_t n,PetscTruth *t)
363 {
364   int c;
365 
366   PetscFunctionBegin;
367   c = strncmp(a,b,n);
368   if (!c) *t = PETSC_TRUE;
369   else    *t = PETSC_FALSE;
370   PetscFunctionReturn(0);
371 }
372 
373 #undef __FUNCT__
374 #define __FUNCT__ "PetscStrchr"
375 /*@C
376    PetscStrchr - Locates first occurance of a character in a string
377 
378    Not Collective
379 
380    Input Parameters:
381 +  a - pointer to string
382 -  b - character
383 
384    Output Parameter:
385 .  c - location of occurance, PETSC_NULL if not found
386 
387    Level: intermediate
388 
389 @*/
390 PetscErrorCode PETSC_DLLEXPORT PetscStrchr(const char a[],char b,char *c[])
391 {
392   PetscFunctionBegin;
393   *c = (char *)strchr(a,b);
394   PetscFunctionReturn(0);
395 }
396 
397 #undef __FUNCT__
398 #define __FUNCT__ "PetscStrrchr"
399 /*@C
400    PetscStrrchr - Locates one location past the last occurance of a character in a string,
401       if the character is not found then returns entire string
402 
403    Not Collective
404 
405    Input Parameters:
406 +  a - pointer to string
407 -  b - character
408 
409    Output Parameter:
410 .  tmp - location of occurance, a if not found
411 
412    Level: intermediate
413 
414 @*/
415 PetscErrorCode PETSC_DLLEXPORT PetscStrrchr(const char a[],char b,char *tmp[])
416 {
417   PetscFunctionBegin;
418   *tmp = (char *)strrchr(a,b);
419   if (!*tmp) *tmp = (char*)a; else *tmp = *tmp + 1;
420   PetscFunctionReturn(0);
421 }
422 
423 #undef __FUNCT__
424 #define __FUNCT__ "PetscStrtolower"
425 /*@C
426    PetscStrtolower - Converts string to lower case
427 
428    Not Collective
429 
430    Input Parameters:
431 .  a - pointer to string
432 
433    Level: intermediate
434 
435 @*/
436 PetscErrorCode PETSC_DLLEXPORT PetscStrtolower(char a[])
437 {
438   PetscFunctionBegin;
439   while (*a) {
440     if (*a >= 'A' && *a <= 'Z') *a += 'a' - 'A';
441     a++;
442   }
443   PetscFunctionReturn(0);
444 }
445 
446 struct _p_PetscToken {char token;char *array;char *current;};
447 
448 
449 #undef __FUNCT__
450 #define __FUNCT__ "PetscTokenFind"
451 /*@C
452    PetscTokenFind - Locates next "token" in a string
453 
454    Not Collective
455 
456    Input Parameters:
457 .  a - pointer to token
458 
459    Output Parameter:
460 .  result - location of occurance, PETSC_NULL if not found
461 
462    Notes:
463 
464      This version is different from the system version in that
465   it allows you to pass a read-only string into the function.
466 
467      This version also treats all characters etc. inside a double quote "
468    as a single token.
469 
470    Level: intermediate
471 
472 .seealso: PetscTokenCreate(), PetscTokenDestroy()
473 @*/
474 PetscErrorCode PETSC_DLLEXPORT PetscTokenFind(PetscToken a,char *result[])
475 {
476   char *ptr = a->current,token;
477 
478   PetscFunctionBegin;
479   *result = a->current;
480   if (ptr && !*ptr) {*result = 0;PetscFunctionReturn(0);}
481   token = a->token;
482   if (ptr && (*ptr == '"')) {token = '"';(*result)++;ptr++;}
483   while (ptr) {
484     if (*ptr == token) {
485       *ptr++ = 0;
486       while (*ptr == a->token) ptr++;
487       a->current = ptr;
488       break;
489     }
490     if (!*ptr) {
491       a->current = 0;
492       break;
493     }
494     ptr++;
495   }
496   PetscFunctionReturn(0);
497 }
498 
499 #undef __FUNCT__
500 #define __FUNCT__ "PetscTokenCreate"
501 /*@C
502    PetscTokenCreate - Creates a PetscToken used to find tokens in a string
503 
504    Not Collective
505 
506    Input Parameters:
507 +  string - the string to look in
508 -  token - the character to look for
509 
510    Output Parameter:
511 .  a - pointer to token
512 
513    Notes:
514 
515      This version is different from the system version in that
516   it allows you to pass a read-only string into the function.
517 
518    Level: intermediate
519 
520 .seealso: PetscTokenFind(), PetscTokenDestroy()
521 @*/
522 PetscErrorCode PETSC_DLLEXPORT PetscTokenCreate(const char a[],const char b,PetscToken *t)
523 {
524   PetscErrorCode ierr;
525 
526   PetscFunctionBegin;
527   ierr = PetscNew(struct _p_PetscToken,t);CHKERRQ(ierr);
528   ierr = PetscStrallocpy(a,&(*t)->array);CHKERRQ(ierr);
529   (*t)->current = (*t)->array;
530   (*t)->token   = b;
531   PetscFunctionReturn(0);
532 }
533 
534 #undef __FUNCT__
535 #define __FUNCT__ "PetscTokenDestroy"
536 /*@C
537    PetscTokenDestroy - Destroys a PetscToken
538 
539    Not Collective
540 
541    Input Parameters:
542 .  a - pointer to token
543 
544    Level: intermediate
545 
546 .seealso: PetscTokenCreate(), PetscTokenFind()
547 @*/
548 PetscErrorCode PETSC_DLLEXPORT PetscTokenDestroy(PetscToken a)
549 {
550   PetscErrorCode ierr;
551 
552   PetscFunctionBegin;
553   ierr = PetscFree(a->array);CHKERRQ(ierr);
554   ierr = PetscFree(a);CHKERRQ(ierr);
555   PetscFunctionReturn(0);
556 }
557 
558 #undef __FUNCT__
559 #define __FUNCT__ "PetscStrrstr"
560 /*@C
561    PetscStrrstr - Locates last occurance of string in another string
562 
563    Not Collective
564 
565    Input Parameters:
566 +  a - pointer to string
567 -  b - string to find
568 
569    Output Parameter:
570 .  tmp - location of occurance
571 
572    Level: intermediate
573 
574 @*/
575 PetscErrorCode PETSC_DLLEXPORT PetscStrrstr(const char a[],const char b[],char *tmp[])
576 {
577   const char *stmp = a, *ltmp = 0;
578 
579   PetscFunctionBegin;
580   while (stmp) {
581     stmp = (char *)strstr(stmp,b);
582     if (stmp) {ltmp = stmp;stmp++;}
583   }
584   *tmp = (char *)ltmp;
585   PetscFunctionReturn(0);
586 }
587 
588 #undef __FUNCT__
589 #define __FUNCT__ "PetscStrstr"
590 /*@C
591    PetscStrstr - Locates first occurance of string in another string
592 
593    Not Collective
594 
595    Input Parameters:
596 +  a - pointer to string
597 -  b - string to find
598 
599    Output Parameter:
600 .  tmp - location of occurance
601 
602    Level: intermediate
603 
604 @*/
605 PetscErrorCode PETSC_DLLEXPORT PetscStrstr(const char a[],const char b[],char *tmp[])
606 {
607   PetscFunctionBegin;
608   *tmp = (char *)strstr(a,b);
609   PetscFunctionReturn(0);
610 }
611 
612 #undef __FUNCT__
613 #define __FUNCT__ "PetscGetPetscDir"
614 /*@C
615    PetscGetPetscDir - Gets the directory PETSc is installed in
616 
617    Not Collective
618 
619    Output Parameter:
620 .  dir - the directory
621 
622    Level: developer
623 
624 @*/
625 PetscErrorCode PETSC_DLLEXPORT PetscGetPetscDir(const char *dir[])
626 {
627   PetscFunctionBegin;
628   *dir = PETSC_DIR;
629   PetscFunctionReturn(0);
630 }
631 
632 #undef __FUNCT__
633 #define __FUNCT__ "PetscStrreplace"
634 /*@C
635    PetscStrreplace - Replaces substrings in string with other substrings
636 
637    Not Collective
638 
639    Input Parameters:
640 +   comm - MPI_Comm of processors that are processing the string
641 .   aa - the string to look in
642 .   b - the resulting copy of a with replaced strings (b can be the same as a)
643 -   len - the length of b
644 
645    Notes:
646       Replaces   ${PETSC_ARCH},${PETSC_DIR},${PETSC_LIB_DIR},${DISPLAY},
647       ${HOMEDIRECTORY},${WORKINGDIRECTORY},${USERNAME} with appropriate values
648       as well as any environmental variables.
649 
650       Note: PETSC_LIB_DIR uses the environmental variable if it exists. PETSC_ARCH and PETSC_DIR use what
651       PETSc was built with and do not use environmental variables.
652 
653    Level: intermediate
654 
655 @*/
656 PetscErrorCode PETSC_DLLEXPORT PetscStrreplace(MPI_Comm comm,const char aa[],char b[],size_t len)
657 {
658   PetscErrorCode ierr;
659   int            i = 0;
660   size_t         l,l1,l2,l3;
661   char           *work,*par,*epar,env[1024],*tfree,*a = (char*)aa;
662   const char     *s[] = {"${PETSC_ARCH}","${PETSC_DIR}","${PETSC_LIB_DIR}","${DISPLAY}","${HOMEDIRECTORY}","${WORKINGDIRECTORY}","${USERNAME}",0};
663   const char     *r[] = {0,0,0,0,0,0,0,0};
664   PetscTruth     flag;
665 
666   PetscFunctionBegin;
667   if (!a || !b) SETERRQ(PETSC_ERR_ARG_NULL,"a and b strings must be nonnull");
668   if (aa == b) {
669     ierr    = PetscStrallocpy(aa,(char **)&a);CHKERRQ(ierr);
670   }
671   ierr = PetscMalloc(len*sizeof(char*),&work);CHKERRQ(ierr);
672 
673   /* get values for replaced variables */
674   ierr = PetscStrallocpy(PETSC_ARCH,(char**)&r[0]);CHKERRQ(ierr);
675   ierr = PetscStrallocpy(PETSC_DIR,(char**)&r[1]);CHKERRQ(ierr);
676   ierr = PetscStrallocpy(PETSC_LIB_DIR,(char**)&r[2]);CHKERRQ(ierr);
677   ierr = PetscMalloc(256*sizeof(char),&r[3]);CHKERRQ(ierr);
678   ierr = PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&r[4]);CHKERRQ(ierr);
679   ierr = PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&r[5]);CHKERRQ(ierr);
680   ierr = PetscMalloc(256*sizeof(char),&r[6]);CHKERRQ(ierr);
681   ierr = PetscGetDisplay((char*)r[3],256);CHKERRQ(ierr);
682   ierr = PetscGetHomeDirectory((char*)r[4],PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
683   ierr = PetscGetWorkingDirectory((char*)r[5],PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
684   ierr = PetscGetUserName((char*)r[6],256);CHKERRQ(ierr);
685 
686   /* replace that are in environment */
687   ierr = PetscOptionsGetenv(comm,"PETSC_LIB_DIR",env,1024,&flag);CHKERRQ(ierr);
688   if (flag) {
689     ierr = PetscStrallocpy(env,(char**)&r[2]);CHKERRQ(ierr);
690   }
691 
692   /* replace the requested strings */
693   ierr = PetscStrncpy(b,a,len);CHKERRQ(ierr);
694   while (s[i]) {
695     ierr = PetscStrlen(s[i],&l);CHKERRQ(ierr);
696     ierr = PetscStrstr(b,s[i],&par);CHKERRQ(ierr);
697     while (par) {
698       *par  =  0;
699       par  += l;
700 
701       ierr = PetscStrlen(b,&l1);CHKERRQ(ierr);
702       ierr = PetscStrlen(r[i],&l2);CHKERRQ(ierr);
703       ierr = PetscStrlen(par,&l3);CHKERRQ(ierr);
704       if (l1 + l2 + l3 >= len) {
705         SETERRQ(PETSC_ERR_ARG_SIZ,"b len is not long enough to hold new values");
706       }
707       ierr  = PetscStrcpy(work,b);CHKERRQ(ierr);
708       ierr  = PetscStrcat(work,r[i]);CHKERRQ(ierr);
709       ierr  = PetscStrcat(work,par);CHKERRQ(ierr);
710       ierr  = PetscStrncpy(b,work,len);CHKERRQ(ierr);
711       ierr  = PetscStrstr(b,s[i],&par);CHKERRQ(ierr);
712     }
713     i++;
714   }
715   i = 0;
716   while (r[i]) {
717     tfree = (char*)r[i];
718     ierr = PetscFree(tfree);CHKERRQ(ierr);
719     i++;
720   }
721 
722   /* look for any other ${xxx} strings to replace from environmental variables */
723   ierr = PetscStrstr(b,"${",&par);CHKERRQ(ierr);
724   while (par) {
725     *par = 0;
726     par += 2;
727     ierr  = PetscStrcpy(work,b);CHKERRQ(ierr);
728     ierr = PetscStrstr(par,"}",&epar);CHKERRQ(ierr);
729     *epar = 0;
730     epar += 1;
731     ierr = PetscOptionsGetenv(comm,par,env,256,&flag);CHKERRQ(ierr);
732     if (!flag) {
733       SETERRQ1(PETSC_ERR_ARG_WRONG,"Substitution string ${%s} not found as environmental variable",par);
734     }
735     ierr = PetscStrcat(work,env);CHKERRQ(ierr);
736     ierr = PetscStrcat(work,epar);CHKERRQ(ierr);
737     ierr = PetscStrcpy(b,work);CHKERRQ(ierr);
738     ierr = PetscStrstr(b,"${",&par);CHKERRQ(ierr);
739   }
740   ierr = PetscFree(work);CHKERRQ(ierr);
741   if (aa == b) {
742     ierr = PetscFree(a);CHKERRQ(ierr);
743   }
744   PetscFunctionReturn(0);
745 }
746 
747 /*MC
748    PetscStrfree - Frees a string (if it is not null)
749 
750    Not Collective
751 
752    Synopsis:
753    PetscErrorCode PetscStrfree(char *s)
754 
755    Input Parameter:
756 .  s - pointer to string
757 
758    Level: intermediate
759 
760   Concepts: string free
761 
762 .seealso: PetscStrncpy(), PetscStrcat(), PetscStrncat(), PetscStrallocpy()
763 
764 M*/
765