xref: /petsc/src/sys/utils/str.c (revision 26471541da5a976356ed03b94e7c320d3a98b2b3)
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 "petsc.h"                   /*I  "petsc.h"   I*/
9 #include "petscsys.h"
10 #if defined(PETSC_HAVE_STRING_H)
11 #include <string.h>
12 #endif
13 #if defined(PETSC_HAVE_STRINGS_H)
14 #include <strings.h>
15 #endif
16 #include "petscfix.h"
17 
18 #undef __FUNCT__
19 #define __FUNCT__ "PetscStrlen"
20 /*@C
21    PetscStrlen - Gets length of a string
22 
23    Not Collective
24 
25    Input Parameters:
26 .  s - pointer to string
27 
28    Output Parameter:
29 .  len - length in bytes
30 
31    Level: intermediate
32 
33    Note:
34    This routine is analogous to strlen().
35 
36    Null string returns a length of zero
37 
38   Concepts: string length
39 
40 @*/
41 PetscErrorCode PETSC_DLLEXPORT PetscStrlen(const char s[],size_t *len)
42 {
43   PetscFunctionBegin;
44   if (!s) {
45     *len = 0;
46   } else {
47     *len = strlen(s);
48   }
49   PetscFunctionReturn(0);
50 }
51 
52 #undef __FUNCT__
53 #define __FUNCT__ "PetscStrallocpy"
54 /*@C
55    PetscStrallocpy - Allocates space to hold a copy of a string then copies the string
56 
57    Not Collective
58 
59    Input Parameters:
60 .  s - pointer to string
61 
62    Output Parameter:
63 .  t - the copied string
64 
65    Level: intermediate
66 
67    Note:
68       Null string returns a new null string
69 
70   Concepts: string copy
71 
72 @*/
73 PetscErrorCode PETSC_DLLEXPORT PetscStrallocpy(const char s[],char *t[])
74 {
75   PetscErrorCode ierr;
76   size_t         len;
77   char           *tmp = 0;
78 
79   PetscFunctionBegin;
80   if (s) {
81     ierr = PetscStrlen(s,&len);CHKERRQ(ierr);
82     ierr = PetscMalloc((1+len)*sizeof(char),&tmp);CHKERRQ(ierr);
83     ierr = PetscStrcpy(tmp,s);CHKERRQ(ierr);
84   }
85   *t = tmp;
86   PetscFunctionReturn(0);
87 }
88 
89 #undef __FUNCT__
90 #define __FUNCT__ "PetscStrcpy"
91 /*@C
92    PetscStrcpy - Copies a string
93 
94    Not Collective
95 
96    Input Parameters:
97 .  t - pointer to string
98 
99    Output Parameter:
100 .  s - the copied string
101 
102    Level: intermediate
103 
104    Note:
105      Null string returns a string starting with zero
106 
107   Concepts: string copy
108 
109 .seealso: PetscStrncpy(), PetscStrcat(), PetscStrncat()
110 
111 @*/
112 PetscErrorCode PETSC_DLLEXPORT PetscStrcpy(char s[],const char t[])
113 {
114   PetscFunctionBegin;
115   if (t && !s) {
116     SETERRQ(PETSC_ERR_ARG_NULL,"Trying to copy string into null pointer");
117   }
118   if (t) {strcpy(s,t);}
119   else if (s) {s[0] = 0;}
120   PetscFunctionReturn(0);
121 }
122 
123 #undef __FUNCT__
124 #define __FUNCT__ "PetscStrncpy"
125 /*@C
126    PetscStrncpy - Copies a string up to a certain length
127 
128    Not Collective
129 
130    Input Parameters:
131 +  t - pointer to string
132 -  n - the length to copy
133 
134    Output Parameter:
135 .  s - the copied string
136 
137    Level: intermediate
138 
139    Note:
140      Null string returns a string starting with zero
141 
142   Concepts: string copy
143 
144 .seealso: PetscStrcpy(), PetscStrcat(), PetscStrncat()
145 
146 @*/
147 PetscErrorCode PETSC_DLLEXPORT PetscStrncpy(char s[],const char t[],size_t n)
148 {
149   PetscFunctionBegin;
150   if (t && !s) {
151     SETERRQ(PETSC_ERR_ARG_NULL,"Trying to copy string into null pointer");
152   }
153   if (t) {strncpy(s,t,n);}
154   else if (s) {s[0] = 0;}
155   PetscFunctionReturn(0);
156 }
157 
158 #undef __FUNCT__
159 #define __FUNCT__ "PetscStrcat"
160 /*@C
161    PetscStrcat - Concatenates a string onto a given string
162 
163    Not Collective
164 
165    Input Parameters:
166 +  s - string to be added to
167 -  t - pointer to string to be added to end
168 
169    Level: intermediate
170 
171   Concepts: string copy
172 
173 .seealso: PetscStrcpy(), PetscStrncpy(), PetscStrncat()
174 
175 @*/
176 PetscErrorCode PETSC_DLLEXPORT PetscStrcat(char s[],const char t[])
177 {
178   PetscFunctionBegin;
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    Level: intermediate
651 
652 @*/
653 PetscErrorCode PETSC_DLLEXPORT PetscStrreplace(MPI_Comm comm,const char aa[],char b[],size_t len)
654 {
655   PetscErrorCode ierr;
656   int            i = 0;
657   size_t         l,l1,l2,l3;
658   char           *work,*par,*epar,env[1024],*tfree,*a = (char*)aa;
659   const char     *s[] = {"${PETSC_ARCH}","${PETSC_DIR}","${PETSC_LIB_DIR}","${DISPLAY}","${HOMEDIRECTORY}","${WORKINGDIRECTORY}","${USERNAME}",0};
660   const char     *r[] = {0,0,0,0,0,0,0,0};
661   PetscTruth     flag;
662 
663   PetscFunctionBegin;
664   if (!a || !b) SETERRQ(PETSC_ERR_ARG_NULL,"a and b strings must be nonnull");
665   if (aa == b) {
666     ierr    = PetscStrallocpy(aa,(char **)&a);
667   }
668   ierr = PetscMalloc(len*sizeof(char*),&work);CHKERRQ(ierr);
669 
670   /* get values for replaced variables */
671   ierr = PetscStrallocpy(PETSC_ARCH,(char**)&r[0]);CHKERRQ(ierr);
672   ierr = PetscStrallocpy(PETSC_DIR,(char**)&r[1]);CHKERRQ(ierr);
673   ierr = PetscStrallocpy(PETSC_LIB_DIR,(char**)&r[2]);CHKERRQ(ierr);
674   ierr = PetscMalloc(256*sizeof(char),&r[3]);CHKERRQ(ierr);
675   ierr = PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&r[4]);CHKERRQ(ierr);
676   ierr = PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&r[5]);CHKERRQ(ierr);
677   ierr = PetscMalloc(256*sizeof(char),&r[6]);CHKERRQ(ierr);
678   ierr = PetscGetDisplay((char*)r[3],256);CHKERRQ(ierr);
679   ierr = PetscGetHomeDirectory((char*)r[4],PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
680   ierr = PetscGetWorkingDirectory((char*)r[5],PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
681   ierr = PetscGetUserName((char*)r[6],256);CHKERRQ(ierr);
682 
683   /* replace that are in environment */
684   ierr = PetscOptionsGetenv(comm,"PETSC_LIB_DIR",env,1024,&flag);CHKERRQ(ierr);
685   if (flag) {
686     ierr = PetscStrallocpy(env,(char**)&r[2]);CHKERRQ(ierr);
687   }
688 
689   /* replace the requested strings */
690   ierr = PetscStrncpy(b,a,len);CHKERRQ(ierr);
691   while (s[i]) {
692     ierr = PetscStrlen(s[i],&l);CHKERRQ(ierr);
693     ierr = PetscStrstr(b,s[i],&par);CHKERRQ(ierr);
694     while (par) {
695       *par  =  0;
696       par  += l;
697 
698       ierr = PetscStrlen(b,&l1);CHKERRQ(ierr);
699       ierr = PetscStrlen(r[i],&l2);CHKERRQ(ierr);
700       ierr = PetscStrlen(par,&l3);CHKERRQ(ierr);
701       if (l1 + l2 + l3 >= len) {
702         SETERRQ(PETSC_ERR_ARG_SIZ,"b len is not long enough to hold new values");
703       }
704       ierr  = PetscStrcpy(work,b);CHKERRQ(ierr);
705       ierr  = PetscStrcat(work,r[i]);CHKERRQ(ierr);
706       ierr  = PetscStrcat(work,par);CHKERRQ(ierr);
707       ierr  = PetscStrncpy(b,work,len);CHKERRQ(ierr);
708       ierr  = PetscStrstr(b,s[i],&par);CHKERRQ(ierr);
709     }
710     i++;
711   }
712   i = 0;
713   while (r[i]) {
714     tfree = (char*)r[i];
715     ierr = PetscFree(tfree);CHKERRQ(ierr);
716     i++;
717   }
718 
719   /* look for any other ${xxx} strings to replace from environmental variables */
720   ierr = PetscStrstr(b,"${",&par);CHKERRQ(ierr);
721   while (par) {
722     *par = 0;
723     par += 2;
724     ierr  = PetscStrcpy(work,b);CHKERRQ(ierr);
725     ierr = PetscStrstr(par,"}",&epar);CHKERRQ(ierr);
726     *epar = 0;
727     epar += 1;
728     ierr = PetscOptionsGetenv(comm,par,env,256,&flag);CHKERRQ(ierr);
729     if (!flag) {
730       SETERRQ1(PETSC_ERR_ARG_WRONG,"Substitution string ${%s} not found as environmental variable",par);
731     }
732     ierr = PetscStrcat(work,env);CHKERRQ(ierr);
733     ierr = PetscStrcat(work,epar);CHKERRQ(ierr);
734     ierr = PetscStrcpy(b,work);CHKERRQ(ierr);
735     ierr = PetscStrstr(b,"${",&par);CHKERRQ(ierr);
736   }
737   ierr = PetscFree(work);CHKERRQ(ierr);
738   if (aa == b) {
739     ierr = PetscFree(a);CHKERRQ(ierr);
740   }
741   PetscFunctionReturn(0);
742 }
743 
744 /*MC
745    PetscStrfree - Frees a string (if it is not null)
746 
747    Not Collective
748 
749    Synopsis:
750    PetscErrorCode PetscStrfree(char *s)
751 
752    Input Parameter:
753 .  s - pointer to string
754 
755    Level: intermediate
756 
757   Concepts: string free
758 
759 .seealso: PetscStrncpy(), PetscStrcat(), PetscStrncat(), PetscStrallocpy()
760 
761 M*/
762