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