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