xref: /petsc/src/sys/utils/str.c (revision a523d3127bc3ed18d68035dbf427fd8937089a6b)
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 #undef __FUNCT__
447 #define __FUNCT__ "PetscTokenFind"
448 /*@C
449    PetscTokenFind - Locates next "token" in a string
450 
451    Not Collective
452 
453    Input Parameters:
454 .  a - pointer to token
455 
456    Output Parameter:
457 .  result - location of occurance, PETSC_NULL if not found
458 
459    Notes:
460 
461      This version is different from the system version in that
462   it allows you to pass a read-only string into the function.
463 
464    Level: intermediate
465 
466 .seealso: PetscTokenCreate(), PetscTokenDestroy()
467 @*/
468 PetscErrorCode PETSC_DLLEXPORT PetscTokenFind(PetscToken *a,char *result[])
469 {
470   char *ptr = a->current;
471 
472   PetscFunctionBegin;
473   *result = a->current;
474   if (ptr && !*ptr) *result = 0;
475   while (ptr) {
476     if (*ptr == a->token) {
477       *ptr++ = 0;
478       while (*ptr == a->token) ptr++;
479       a->current = ptr;
480       break;
481     }
482     if (!*ptr) {
483       a->current = 0;
484       break;
485     }
486     ptr++;
487   }
488   PetscFunctionReturn(0);
489 }
490 
491 #undef __FUNCT__
492 #define __FUNCT__ "PetscTokenCreate"
493 /*@C
494    PetscTokenCreate - Creates a PetscToken used to find tokens in a string
495 
496    Not Collective
497 
498    Input Parameters:
499 +  string - the string to look in
500 -  token - the character to look for
501 
502    Output Parameter:
503 .  a - pointer to token
504 
505    Notes:
506 
507      This version is different from the system version in that
508   it allows you to pass a read-only string into the function.
509 
510    Level: intermediate
511 
512 .seealso: PetscTokenFind(), PetscTokenDestroy()
513 @*/
514 PetscErrorCode PETSC_DLLEXPORT PetscTokenCreate(const char a[],const char b,PetscToken **t)
515 {
516   PetscErrorCode ierr;
517 
518   PetscFunctionBegin;
519   ierr = PetscNew(PetscToken,t);CHKERRQ(ierr);
520   ierr = PetscStrallocpy(a,&(*t)->array);CHKERRQ(ierr);
521   (*t)->current = (*t)->array;
522   (*t)->token   = b;
523   PetscFunctionReturn(0);
524 }
525 
526 #undef __FUNCT__
527 #define __FUNCT__ "PetscTokenDestroy"
528 /*@C
529    PetscTokenDestroy - Destroys a PetscToken
530 
531    Not Collective
532 
533    Input Parameters:
534 .  a - pointer to token
535 
536    Level: intermediate
537 
538 .seealso: PetscTokenCreate(), PetscTokenFind()
539 @*/
540 PetscErrorCode PETSC_DLLEXPORT PetscTokenDestroy(PetscToken *a)
541 {
542   PetscErrorCode ierr;
543 
544   PetscFunctionBegin;
545   ierr = PetscFree(a->array);CHKERRQ(ierr);
546   ierr = PetscFree(a);CHKERRQ(ierr);
547   PetscFunctionReturn(0);
548 }
549 
550 #undef __FUNCT__
551 #define __FUNCT__ "PetscStrrstr"
552 /*@C
553    PetscStrrstr - Locates last occurance of string in another string
554 
555    Not Collective
556 
557    Input Parameters:
558 +  a - pointer to string
559 -  b - string to find
560 
561    Output Parameter:
562 .  tmp - location of occurance
563 
564    Level: intermediate
565 
566 @*/
567 PetscErrorCode PETSC_DLLEXPORT PetscStrrstr(const char a[],const char b[],char *tmp[])
568 {
569   const char *stmp = a, *ltmp = 0;
570 
571   PetscFunctionBegin;
572   while (stmp) {
573     stmp = (char *)strstr(stmp,b);
574     if (stmp) {ltmp = stmp;stmp++;}
575   }
576   *tmp = (char *)ltmp;
577   PetscFunctionReturn(0);
578 }
579 
580 #undef __FUNCT__
581 #define __FUNCT__ "PetscStrstr"
582 /*@C
583    PetscStrstr - Locates first occurance of string in another string
584 
585    Not Collective
586 
587    Input Parameters:
588 +  a - pointer to string
589 -  b - string to find
590 
591    Output Parameter:
592 .  tmp - location of occurance
593 
594    Level: intermediate
595 
596 @*/
597 PetscErrorCode PETSC_DLLEXPORT PetscStrstr(const char a[],const char b[],char *tmp[])
598 {
599   PetscFunctionBegin;
600   *tmp = (char *)strstr(a,b);
601   PetscFunctionReturn(0);
602 }
603 
604 #undef __FUNCT__
605 #define __FUNCT__ "PetscGetPetscDir"
606 /*@C
607    PetscGetPetscDir - Gets the directory PETSc is installed in
608 
609    Not Collective
610 
611    Output Parameter:
612 .  dir - the directory
613 
614    Level: developer
615 
616 @*/
617 PetscErrorCode PETSC_DLLEXPORT PetscGetPetscDir(const char *dir[])
618 {
619   PetscFunctionBegin;
620   *dir = PETSC_DIR;
621   PetscFunctionReturn(0);
622 }
623 
624 #undef __FUNCT__
625 #define __FUNCT__ "PetscStrreplace"
626 /*@C
627    PetscStrreplace - Replaces substrings in string with other substrings
628 
629    Not Collective
630 
631    Input Parameters:
632 +   comm - MPI_Comm of processors that are processing the string
633 .   aa - the string to look in
634 .   b - the resulting copy of a with replaced strings (b can be the same as a)
635 -   len - the length of b
636 
637    Notes:
638       Replaces   ${PETSC_ARCH},${PETSC_DIR},${PETSC_LIB_DIR},${DISPLAY},
639       ${HOMEDIRECTORY},${WORKINGDIRECTORY},${USERNAME} with appropriate values
640       as well as any environmental variables.
641 
642    Level: intermediate
643 
644 @*/
645 PetscErrorCode PETSC_DLLEXPORT PetscStrreplace(MPI_Comm comm,const char aa[],char b[],size_t len)
646 {
647   PetscErrorCode ierr;
648   int            i = 0;
649   size_t         l,l1,l2,l3;
650   char           *work,*par,*epar,env[1024],*tfree,*a = (char*)aa;
651   const char     *s[] = {"${PETSC_ARCH}","${PETSC_DIR}","${PETSC_LIB_DIR}","${DISPLAY}","${HOMEDIRECTORY}","${WORKINGDIRECTORY}","${USERNAME}",0};
652   const char     *r[] = {0,0,0,0,0,0,0,0};
653   PetscTruth     flag;
654 
655   PetscFunctionBegin;
656   if (!a || !b) SETERRQ(PETSC_ERR_ARG_NULL,"a and b strings must be nonnull");
657   if (aa == b) {
658     ierr    = PetscStrallocpy(aa,(char **)&a);
659   }
660   ierr = PetscMalloc(len*sizeof(char*),&work);CHKERRQ(ierr);
661 
662   /* get values for replaced variables */
663   ierr = PetscStrallocpy(PETSC_ARCH,(char**)&r[0]);CHKERRQ(ierr);
664   ierr = PetscStrallocpy(PETSC_DIR,(char**)&r[1]);CHKERRQ(ierr);
665   ierr = PetscStrallocpy(PETSC_LIB_DIR,(char**)&r[2]);CHKERRQ(ierr);
666   ierr = PetscMalloc(256*sizeof(char),&r[3]);CHKERRQ(ierr);
667   ierr = PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&r[4]);CHKERRQ(ierr);
668   ierr = PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&r[5]);CHKERRQ(ierr);
669   ierr = PetscMalloc(256*sizeof(char),&r[6]);CHKERRQ(ierr);
670   ierr = PetscGetDisplay((char*)r[3],256);CHKERRQ(ierr);
671   ierr = PetscGetHomeDirectory((char*)r[4],PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
672   ierr = PetscGetWorkingDirectory((char*)r[5],PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
673   ierr = PetscGetUserName((char*)r[6],256);CHKERRQ(ierr);
674 
675   /* replace that are in environment */
676   ierr = PetscOptionsGetenv(comm,"PETSC_LIB_DIR",env,1024,&flag);CHKERRQ(ierr);
677   if (flag) {
678     ierr = PetscStrallocpy(env,(char**)&r[2]);CHKERRQ(ierr);
679   }
680 
681   /* replace the requested strings */
682   ierr = PetscStrncpy(b,a,len);CHKERRQ(ierr);
683   while (s[i]) {
684     ierr = PetscStrlen(s[i],&l);CHKERRQ(ierr);
685     ierr = PetscStrstr(b,s[i],&par);CHKERRQ(ierr);
686     while (par) {
687       *par  =  0;
688       par  += l;
689 
690       ierr = PetscStrlen(b,&l1);CHKERRQ(ierr);
691       ierr = PetscStrlen(r[i],&l2);CHKERRQ(ierr);
692       ierr = PetscStrlen(par,&l3);CHKERRQ(ierr);
693       if (l1 + l2 + l3 >= len) {
694         SETERRQ(PETSC_ERR_ARG_SIZ,"b len is not long enough to hold new values");
695       }
696       ierr  = PetscStrcpy(work,b);CHKERRQ(ierr);
697       ierr  = PetscStrcat(work,r[i]);CHKERRQ(ierr);
698       ierr  = PetscStrcat(work,par);CHKERRQ(ierr);
699       ierr  = PetscStrncpy(b,work,len);CHKERRQ(ierr);
700       ierr  = PetscStrstr(b,s[i],&par);CHKERRQ(ierr);
701     }
702     i++;
703   }
704   i = 0;
705   while (r[i]) {
706     tfree = (char*)r[i];
707     ierr = PetscFree(tfree);CHKERRQ(ierr);
708     i++;
709   }
710 
711   /* look for any other ${xxx} strings to replace from environmental variables */
712   ierr = PetscStrstr(b,"${",&par);CHKERRQ(ierr);
713   while (par) {
714     *par = 0;
715     par += 2;
716     ierr  = PetscStrcpy(work,b);CHKERRQ(ierr);
717     ierr = PetscStrstr(par,"}",&epar);CHKERRQ(ierr);
718     *epar = 0;
719     epar += 1;
720     ierr = PetscOptionsGetenv(comm,par,env,256,&flag);CHKERRQ(ierr);
721     if (!flag) {
722       SETERRQ1(PETSC_ERR_ARG_WRONG,"Substitution string ${%s} not found as environmental variable",par);
723     }
724     ierr = PetscStrcat(work,env);CHKERRQ(ierr);
725     ierr = PetscStrcat(work,epar);CHKERRQ(ierr);
726     ierr = PetscStrcpy(b,work);CHKERRQ(ierr);
727     ierr = PetscStrstr(b,"${",&par);CHKERRQ(ierr);
728   }
729   ierr = PetscFree(work);CHKERRQ(ierr);
730   if (aa == b) {
731     ierr = PetscFree(a);CHKERRQ(ierr);
732   }
733   PetscFunctionReturn(0);
734 }
735 
736 /*MC
737    PetscStrfree - Frees a string (if it is not null)
738 
739    Not Collective
740 
741    Synopsis:
742    PetscErrorCode PetscStrfree(char *s)
743 
744    Input Parameter:
745 .  s - pointer to string
746 
747    Level: intermediate
748 
749   Concepts: string free
750 
751 .seealso: PetscStrncpy(), PetscStrcat(), PetscStrncat(), PetscStrallocpy()
752 
753 M*/
754