xref: /petsc/src/sys/utils/str.c (revision 4df4a32cb8db0b7b88394c85cd73c68458309a1d)
1 /*
2     We define the string operations here. The reason we just do not use
3   the standard string routines in the PETSc code is that on some machines
4   they are broken or have the wrong prototypes.
5 */
6 #include <petsc/private/petscimpl.h> /*I  "petscsys.h"   I*/
7 #if defined(PETSC_HAVE_STRINGS_H)
8   #include <strings.h> /* strcasecmp */
9 #endif
10 
11 /*@C
12   PetscStrToArray - Separates a string by a character (for example ' ' or '\n') and creates an array of strings
13 
14   Not Collective; No Fortran Support
15 
16   Input Parameters:
17 + s  - pointer to string
18 - sp - separator character
19 
20   Output Parameters:
21 + argc - the number of entries in `args`
22 - args - an array of the entries with a `NULL` at the end
23 
24   Level: intermediate
25 
26   Note:
27   This may be called before `PetscInitialize()` or after `PetscFinalize()`
28 
29   Developer Notes:
30   Uses raw `malloc()` and does not call error handlers since this may be used before PETSc is initialized.
31 
32   Used to generate `argc`, `args` arguments passed to `MPI_Init()`
33 
34 .seealso: `PetscStrToArrayDestroy()`, `PetscToken`, `PetscTokenCreate()`
35 @*/
36 PetscErrorCode PetscStrToArray(const char s[], char sp, int *argc, char ***args)
37 {
38   int       n, i, j, *lens, cnt = 0;
39   PetscBool flg = PETSC_FALSE;
40 
41   if (!s) n = 0;
42   else n = (int)strlen(s);
43   *argc = 0;
44   *args = NULL;
45   for (; n > 0; n--) { /* remove separator chars at the end - and will empty the string if all chars are separator chars */
46     if (s[n - 1] != sp) break;
47   }
48   if (!n) return PETSC_SUCCESS;
49   for (i = 0; i < n; i++) {
50     if (s[i] != sp) break;
51   }
52   for (; i < n + 1; i++) {
53     if ((s[i] == sp || s[i] == 0) && !flg) {
54       flg = PETSC_TRUE;
55       (*argc)++;
56     } else if (s[i] != sp) {
57       flg = PETSC_FALSE;
58     }
59   }
60   (*args) = (char **)malloc(((*argc) + 1) * sizeof(char *));
61   if (!*args) return PETSC_ERR_MEM;
62   lens = (int *)malloc(((*argc) + 1) * sizeof(int));
63   if (!lens) return PETSC_ERR_MEM;
64   for (i = 0; i < *argc; i++) lens[i] = 0;
65 
66   *argc = 0;
67   for (i = 0; i < n; i++) {
68     if (s[i] != sp) break;
69   }
70   for (; i < n + 1; i++) {
71     if ((s[i] == sp || s[i] == 0) && !flg) {
72       flg = PETSC_TRUE;
73       (*argc)++;
74     } else if (s[i] != sp) {
75       lens[*argc]++;
76       flg = PETSC_FALSE;
77     }
78   }
79 
80   for (i = 0; i < *argc; i++) {
81     (*args)[i] = (char *)malloc((lens[i] + 1) * sizeof(char));
82     if (!(*args)[i]) {
83       free(lens);
84       for (j = 0; j < i; j++) free((*args)[j]);
85       free(*args);
86       return PETSC_ERR_MEM;
87     }
88   }
89   free(lens);
90   (*args)[*argc] = NULL;
91 
92   *argc = 0;
93   for (i = 0; i < n; i++) {
94     if (s[i] != sp) break;
95   }
96   for (; i < n + 1; i++) {
97     if ((s[i] == sp || s[i] == 0) && !flg) {
98       flg                   = PETSC_TRUE;
99       (*args)[*argc][cnt++] = 0;
100       (*argc)++;
101       cnt = 0;
102     } else if (s[i] != sp && s[i] != 0) {
103       (*args)[*argc][cnt++] = s[i];
104       flg                   = PETSC_FALSE;
105     }
106   }
107   return PETSC_SUCCESS;
108 }
109 
110 /*@C
111   PetscStrToArrayDestroy - Frees array created with `PetscStrToArray()`.
112 
113   Not Collective; No Fortran Support
114 
115   Output Parameters:
116 + argc - the number of arguments
117 - args - the array of arguments
118 
119   Level: intermediate
120 
121   Note:
122   This may be called before `PetscInitialize()` or after `PetscFinalize()`
123 
124 .seealso: `PetscStrToArray()`
125 @*/
126 PetscErrorCode PetscStrToArrayDestroy(int argc, char **args)
127 {
128   for (int i = 0; i < argc; ++i) free(args[i]);
129   if (args) free(args);
130   return PETSC_SUCCESS;
131 }
132 
133 /*@C
134   PetscStrArrayallocpy - Allocates space to hold a copy of an array of strings then copies the strings
135 
136   Not Collective; No Fortran Support
137 
138   Input Parameter:
139 . list - pointer to array of strings (final string is a `NULL`)
140 
141   Output Parameter:
142 . t - the copied array string
143 
144   Level: intermediate
145 
146   Note:
147   Use `PetscStrArrayDestroy()` to free the memory.
148 
149 .seealso: `PetscStrallocpy()`, `PetscStrArrayDestroy()`, `PetscStrNArrayallocpy()`
150 @*/
151 PetscErrorCode PetscStrArrayallocpy(const char *const *list, char ***t)
152 {
153   PetscInt n = 0;
154 
155   PetscFunctionBegin;
156   while (list[n++]);
157   PetscCall(PetscMalloc1(n + 1, t));
158   for (PetscInt i = 0; i < n; i++) PetscCall(PetscStrallocpy(list[i], (*t) + i));
159   (*t)[n] = NULL;
160   PetscFunctionReturn(PETSC_SUCCESS);
161 }
162 
163 /*@C
164   PetscStrArrayDestroy - Frees array of strings created with `PetscStrArrayallocpy()`.
165 
166   Not Collective; No Fortran Support
167 
168   Output Parameter:
169 . list - array of strings
170 
171   Level: intermediate
172 
173 .seealso: `PetscStrArrayallocpy()`
174 @*/
175 PetscErrorCode PetscStrArrayDestroy(char ***list)
176 {
177   PetscInt n = 0;
178 
179   PetscFunctionBegin;
180   if (!*list) PetscFunctionReturn(PETSC_SUCCESS);
181   while ((*list)[n]) {
182     PetscCall(PetscFree((*list)[n]));
183     ++n;
184   }
185   PetscCall(PetscFree(*list));
186   PetscFunctionReturn(PETSC_SUCCESS);
187 }
188 
189 /*@C
190   PetscStrNArrayallocpy - Allocates space to hold a copy of an array of strings then copies the strings
191 
192   Not Collective; No Fortran Support
193 
194   Input Parameters:
195 + n    - the number of string entries
196 - list - pointer to array of strings
197 
198   Output Parameter:
199 . t - the copied array string
200 
201   Level: intermediate
202 
203   Note:
204   Use `PetscStrNArrayDestroy()` to free the memory.
205 
206 .seealso: `PetscStrallocpy()`, `PetscStrArrayallocpy()`, `PetscStrNArrayDestroy()`
207 @*/
208 PetscErrorCode PetscStrNArrayallocpy(PetscInt n, const char *const *list, char ***t)
209 {
210   PetscFunctionBegin;
211   PetscCall(PetscMalloc1(n, t));
212   for (PetscInt i = 0; i < n; i++) PetscCall(PetscStrallocpy(list[i], (*t) + i));
213   PetscFunctionReturn(PETSC_SUCCESS);
214 }
215 
216 /*@C
217   PetscStrNArrayDestroy - Frees array of strings created with `PetscStrNArrayallocpy()`.
218 
219   Not Collective; No Fortran Support
220 
221   Output Parameters:
222 + n    - number of string entries
223 - list - array of strings
224 
225   Level: intermediate
226 
227 .seealso: `PetscStrNArrayallocpy()`, `PetscStrArrayallocpy()`
228 @*/
229 PetscErrorCode PetscStrNArrayDestroy(PetscInt n, char ***list)
230 {
231   PetscFunctionBegin;
232   if (!*list) PetscFunctionReturn(PETSC_SUCCESS);
233   for (PetscInt i = 0; i < n; i++) PetscCall(PetscFree((*list)[i]));
234   PetscCall(PetscFree(*list));
235   PetscFunctionReturn(PETSC_SUCCESS);
236 }
237 
238 /*@C
239   PetscBasename - returns a pointer to the last entry of a / or \ separated directory path
240 
241   Not Collective; No Fortran Support
242 
243   Input Parameter:
244 . a - pointer to string
245 
246   Level: intermediate
247 
248 .seealso: `PetscStrgrt()`, `PetscStrncmp()`, `PetscStrcasecmp()`, `PetscStrrchr()`, `PetscStrcmp()`, `PetscStrstr()`,
249           `PetscTokenCreate()`, `PetscStrToArray()`, `PetscStrInList()`
250 @*/
251 const char *PetscBasename(const char a[])
252 {
253   const char *ptr = NULL;
254 
255   (void)PetscStrrchr(a, '/', (char **)&ptr);
256   if (ptr == a) {
257     if (PetscStrrchr(a, '\\', (char **)&ptr)) ptr = NULL;
258   }
259   return ptr;
260 }
261 
262 /*@C
263   PetscStrcasecmp - Returns true if the two strings are the same
264   except possibly for case.
265 
266   Not Collective; No Fortran Support
267 
268   Input Parameters:
269 + a - pointer to first string
270 - b - pointer to second string
271 
272   Output Parameter:
273 . t - if the two strings are the same
274 
275   Level: intermediate
276 
277   Note:
278   `NULL` arguments are ok
279 
280 .seealso: `PetscStrcmp()`, `PetscStrncmp()`, `PetscStrgrt()`
281 @*/
282 PetscErrorCode PetscStrcasecmp(const char a[], const char b[], PetscBool *t)
283 {
284   int c;
285 
286   PetscFunctionBegin;
287   PetscAssertPointer(t, 3);
288   if (!a && !b) c = 0;
289   else if (!a || !b) c = 1;
290 #if defined(PETSC_HAVE_STRCASECMP)
291   else c = strcasecmp(a, b);
292 #elif defined(PETSC_HAVE_STRICMP)
293   else c = stricmp(a, b);
294 #else
295   else {
296     char *aa, *bb;
297 
298     PetscCall(PetscStrallocpy(a, &aa));
299     PetscCall(PetscStrallocpy(b, &bb));
300     PetscCall(PetscStrtolower(aa));
301     PetscCall(PetscStrtolower(bb));
302     PetscCall(PetscStrcmp(aa, bb, t));
303     PetscCall(PetscFree(aa));
304     PetscCall(PetscFree(bb));
305     PetscFunctionReturn(PETSC_SUCCESS);
306   }
307 #endif
308   *t = c ? PETSC_FALSE : PETSC_TRUE;
309   PetscFunctionReturn(PETSC_SUCCESS);
310 }
311 
312 /*@C
313   PetscStrendswithwhich - Determines if a string ends with one of several possible strings
314 
315   Not Collective; No Fortran Support
316 
317   Input Parameters:
318 + a  - pointer to string
319 - bs - strings to end with (last entry must be `NULL`)
320 
321   Output Parameter:
322 . cnt - the index of the string it ends with or the index of `NULL`
323 
324   Level: intermediate
325 
326 .seealso: `PetscStrbeginswithwhich()`, `PetscStrendswith()`, `PetscStrtoupper`, `PetscStrtolower()`, `PetscStrrchr()`, `PetscStrchr()`,
327           `PetscStrncmp()`, `PetscStrlen()`, `PetscStrcmp()`
328 @*/
329 PetscErrorCode PetscStrendswithwhich(const char a[], const char *const *bs, PetscInt *cnt)
330 {
331   PetscFunctionBegin;
332   PetscAssertPointer(bs, 2);
333   PetscAssertPointer(cnt, 3);
334   *cnt = 0;
335   while (bs[*cnt]) {
336     PetscBool flg;
337 
338     PetscCall(PetscStrendswith(a, bs[*cnt], &flg));
339     if (flg) PetscFunctionReturn(PETSC_SUCCESS);
340     ++(*cnt);
341   }
342   PetscFunctionReturn(PETSC_SUCCESS);
343 }
344 
345 struct _p_PetscToken {
346   char  token;
347   char *array;
348   char *current;
349 };
350 
351 /*@C
352   PetscTokenFind - Locates next "token" in a `PetscToken`
353 
354   Not Collective; No Fortran Support
355 
356   Input Parameter:
357 . a - pointer to token
358 
359   Output Parameter:
360 . result - location of occurrence, `NULL` if not found
361 
362   Level: intermediate
363 
364   Notes:
365   Treats all characters etc. inside a double quote "
366   as a single token.
367 
368   For example if the separator character is + and the string is xxxx+y then the first fine will return a pointer to a `NULL` terminated xxxx and the
369   second will return a `NULL` terminated y
370 
371   If the separator character is + and the string is xxxx then the first and only token found will be a pointer to a `NULL` terminated xxxx
372 
373 .seealso: `PetscToken`, `PetscTokenCreate()`, `PetscTokenDestroy()`
374 @*/
375 PetscErrorCode PetscTokenFind(PetscToken a, char *result[])
376 {
377   char *ptr, token;
378 
379   PetscFunctionBegin;
380   PetscAssertPointer(a, 1);
381   PetscAssertPointer(result, 2);
382   *result = ptr = a->current;
383   if (ptr && !*ptr) {
384     *result = NULL;
385     PetscFunctionReturn(PETSC_SUCCESS);
386   }
387   token = a->token;
388   if (ptr && (*ptr == '"')) {
389     token = '"';
390     (*result)++;
391     ptr++;
392   }
393   while (ptr) {
394     if (*ptr == token) {
395       *ptr++ = 0;
396       while (*ptr == a->token) ptr++;
397       a->current = ptr;
398       break;
399     }
400     if (!*ptr) {
401       a->current = NULL;
402       break;
403     }
404     ptr++;
405   }
406   PetscFunctionReturn(PETSC_SUCCESS);
407 }
408 
409 /*@C
410   PetscTokenCreate - Creates a `PetscToken` used to find tokens in a string
411 
412   Not Collective; No Fortran Support
413 
414   Input Parameters:
415 + a - the string to look in
416 - b - the separator character
417 
418   Output Parameter:
419 . t - the token object
420 
421   Level: intermediate
422 
423   Note:
424   This version is different from the system version in that
425   it allows you to pass a read-only string into the function.
426 
427 .seealso: `PetscToken`, `PetscTokenFind()`, `PetscTokenDestroy()`
428 @*/
429 PetscErrorCode PetscTokenCreate(const char a[], char b, PetscToken *t)
430 {
431   PetscFunctionBegin;
432   PetscAssertPointer(a, 1);
433   PetscAssertPointer(t, 3);
434   PetscCall(PetscNew(t));
435   PetscCall(PetscStrallocpy(a, &(*t)->array));
436 
437   (*t)->current = (*t)->array;
438   (*t)->token   = b;
439   PetscFunctionReturn(PETSC_SUCCESS);
440 }
441 
442 /*@C
443   PetscTokenDestroy - Destroys a `PetscToken`
444 
445   Not Collective; No Fortran Support
446 
447   Input Parameter:
448 . a - pointer to token
449 
450   Level: intermediate
451 
452 .seealso: `PetscToken`, `PetscTokenCreate()`, `PetscTokenFind()`
453 @*/
454 PetscErrorCode PetscTokenDestroy(PetscToken *a)
455 {
456   PetscFunctionBegin;
457   if (!*a) PetscFunctionReturn(PETSC_SUCCESS);
458   PetscCall(PetscFree((*a)->array));
459   PetscCall(PetscFree(*a));
460   PetscFunctionReturn(PETSC_SUCCESS);
461 }
462 
463 /*@C
464   PetscStrInList - search for a string in character-delimited list
465 
466   Not Collective; No Fortran Support
467 
468   Input Parameters:
469 + str  - the string to look for
470 . list - the list to search in
471 - sep  - the separator character
472 
473   Output Parameter:
474 . found - whether `str` is in `list`
475 
476   Level: intermediate
477 
478 .seealso: `PetscTokenCreate()`, `PetscTokenFind()`, `PetscStrcmp()`
479 @*/
480 PetscErrorCode PetscStrInList(const char str[], const char list[], char sep, PetscBool *found)
481 {
482   PetscToken token;
483   char      *item;
484 
485   PetscFunctionBegin;
486   PetscAssertPointer(found, 4);
487   *found = PETSC_FALSE;
488   PetscCall(PetscTokenCreate(list, sep, &token));
489   PetscCall(PetscTokenFind(token, &item));
490   while (item) {
491     PetscCall(PetscStrcmp(str, item, found));
492     if (*found) break;
493     PetscCall(PetscTokenFind(token, &item));
494   }
495   PetscCall(PetscTokenDestroy(&token));
496   PetscFunctionReturn(PETSC_SUCCESS);
497 }
498 
499 /*@C
500   PetscGetPetscDir - Gets the directory PETSc is installed in
501 
502   Not Collective; No Fortran Support
503 
504   Output Parameter:
505 . dir - the directory
506 
507   Level: developer
508 
509 .seealso: `PetscGetArchType()`
510 @*/
511 PetscErrorCode PetscGetPetscDir(const char *dir[])
512 {
513   PetscFunctionBegin;
514   PetscAssertPointer(dir, 1);
515   *dir = PETSC_DIR;
516   PetscFunctionReturn(PETSC_SUCCESS);
517 }
518 
519 /*@C
520   PetscStrreplace - Replaces substrings in string with other substrings
521 
522   Not Collective; No Fortran Support
523 
524   Input Parameters:
525 + comm - `MPI_Comm` of processors that are processing the string
526 . aa   - the string to look in
527 . b    - the resulting copy of a with replaced strings (`b` can be the same as `a`)
528 - len  - the length of `b`
529 
530   Level: developer
531 
532   Notes:
533   Replaces
534 .vb
535     ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, ${DISPLAY},
536     ${HOMEDIRECTORY}, ${WORKINGDIRECTORY}, ${USERNAME}, ${HOSTNAME}, ${PETSC_MAKE}
537 .ve
538   with appropriate values as well as any environmental variables.
539 
540   `PETSC_LIB_DIR` uses the environmental variable if it exists. `PETSC_ARCH` and `PETSC_DIR` use what
541   PETSc was built with and do not use environmental variables.
542 
543 .seealso: `PetscStrcmp()`
544 @*/
545 PetscErrorCode PetscStrreplace(MPI_Comm comm, const char aa[], char b[], size_t len)
546 {
547   int           i = 0;
548   size_t        l, l1, l2, l3;
549   char         *work, *par, *epar = NULL, env[1024], *tfree, *a = (char *)aa;
550   const char   *s[] = {"${PETSC_ARCH}", "${PETSC_DIR}", "${PETSC_LIB_DIR}", "${DISPLAY}", "${HOMEDIRECTORY}", "${WORKINGDIRECTORY}", "${USERNAME}", "${HOSTNAME}", "${PETSC_MAKE}", NULL};
551   char         *r[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
552   PetscBool     flag;
553   static size_t DISPLAY_LENGTH = 265, USER_LENGTH = 256, HOST_LENGTH = 256;
554 
555   PetscFunctionBegin;
556   PetscAssertPointer(aa, 2);
557   PetscAssertPointer(b, 3);
558   if (aa == b) PetscCall(PetscStrallocpy(aa, &a));
559   PetscCall(PetscMalloc1(len, &work));
560 
561   /* get values for replaced variables */
562   PetscCall(PetscStrallocpy(PETSC_ARCH, &r[0]));
563   PetscCall(PetscStrallocpy(PETSC_DIR, &r[1]));
564   PetscCall(PetscStrallocpy(PETSC_LIB_DIR, &r[2]));
565   PetscCall(PetscMalloc1(DISPLAY_LENGTH, &r[3]));
566   PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN, &r[4]));
567   PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN, &r[5]));
568   PetscCall(PetscMalloc1(USER_LENGTH, &r[6]));
569   PetscCall(PetscMalloc1(HOST_LENGTH, &r[7]));
570   PetscCall(PetscGetDisplay(r[3], DISPLAY_LENGTH));
571   PetscCall(PetscGetHomeDirectory(r[4], PETSC_MAX_PATH_LEN));
572   PetscCall(PetscGetWorkingDirectory(r[5], PETSC_MAX_PATH_LEN));
573   PetscCall(PetscGetUserName(r[6], USER_LENGTH));
574   PetscCall(PetscGetHostName(r[7], HOST_LENGTH));
575   PetscCall(PetscStrallocpy(PETSC_OMAKE, &r[8]));
576 
577   /* replace that are in environment */
578   PetscCall(PetscOptionsGetenv(comm, "PETSC_LIB_DIR", env, sizeof(env), &flag));
579   if (flag) {
580     PetscCall(PetscFree(r[2]));
581     PetscCall(PetscStrallocpy(env, &r[2]));
582   }
583 
584   /* replace the requested strings */
585   PetscCall(PetscStrncpy(b, a, len));
586   while (s[i]) {
587     PetscCall(PetscStrlen(s[i], &l));
588     PetscCall(PetscStrstr(b, s[i], &par));
589     while (par) {
590       *par = 0;
591       par += l;
592 
593       PetscCall(PetscStrlen(b, &l1));
594       PetscCall(PetscStrlen(r[i], &l2));
595       PetscCall(PetscStrlen(par, &l3));
596       PetscCheck(l1 + l2 + l3 < len, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "b len is not long enough to hold new values");
597       PetscCall(PetscStrncpy(work, b, len));
598       PetscCall(PetscStrlcat(work, r[i], len));
599       PetscCall(PetscStrlcat(work, par, len));
600       PetscCall(PetscStrncpy(b, work, len));
601       PetscCall(PetscStrstr(b, s[i], &par));
602     }
603     i++;
604   }
605   i = 0;
606   while (r[i]) {
607     tfree = r[i];
608     PetscCall(PetscFree(tfree));
609     i++;
610   }
611 
612   /* look for any other ${xxx} strings to replace from environmental variables */
613   PetscCall(PetscStrstr(b, "${", &par));
614   while (par) {
615     *par = 0;
616     par += 2;
617     PetscCall(PetscStrncpy(work, b, len));
618     PetscCall(PetscStrstr(par, "}", &epar));
619     *epar = 0;
620     epar += 1;
621     PetscCall(PetscOptionsGetenv(comm, par, env, sizeof(env), &flag));
622     PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Substitution string ${%s} not found as environmental variable", par);
623     PetscCall(PetscStrlcat(work, env, len));
624     PetscCall(PetscStrlcat(work, epar, len));
625     PetscCall(PetscStrncpy(b, work, len));
626     PetscCall(PetscStrstr(b, "${", &par));
627   }
628   PetscCall(PetscFree(work));
629   if (aa == b) PetscCall(PetscFree(a));
630   PetscFunctionReturn(PETSC_SUCCESS);
631 }
632 
633 /*@C
634   PetscStrcmpAny - Determines whether a string matches any of a list of strings.
635 
636   Not Collective, No Fortran Support
637 
638   Input Parameters:
639 + src - pointer to input the string
640 - cmp - list of non-null and non-empty strings to be compared against, pass the empty string "" to terminate the list
641 
642   Output Parameter:
643 . match - `PETSC_TRUE` if the input string matches any in the list, else `PETSC_FALSE`
644 
645   Level: intermediate
646 
647 .seealso: `PetscStrcmp()`
648 @*/
649 PetscErrorCode PetscStrcmpAny(const char src[], PetscBool *match, const char cmp[], ...)
650 {
651   va_list Argp;
652 
653   PetscFunctionBegin;
654   PetscAssertPointer(match, 2);
655   *match = PETSC_FALSE;
656   if (!src) PetscFunctionReturn(PETSC_SUCCESS);
657   va_start(Argp, cmp);
658   while (cmp && cmp[0]) {
659     PetscBool found;
660     PetscCall(PetscStrcmp(src, cmp, &found));
661     if (found) {
662       *match = PETSC_TRUE;
663       break;
664     }
665     cmp = va_arg(Argp, const char *);
666   }
667   va_end(Argp);
668   PetscFunctionReturn(PETSC_SUCCESS);
669 }
670 
671 /*@C
672   PetscEListFind - searches list of strings for given string, using case insensitive matching
673 
674   Not Collective; No Fortran Support
675 
676   Input Parameters:
677 + n    - number of strings in
678 . list - list of strings to search
679 - str  - string to look for, empty string "" accepts default (first entry in list)
680 
681   Output Parameters:
682 + value - index of matching string (if found)
683 - found - boolean indicating whether string was found (can be `NULL`)
684 
685   Level: developer
686 
687 .seealso: `PetscEnumFind()`
688 @*/
689 PetscErrorCode PetscEListFind(PetscInt n, const char *const *list, const char *str, PetscInt *value, PetscBool *found)
690 {
691   PetscFunctionBegin;
692   if (found) {
693     PetscAssertPointer(found, 5);
694     *found = PETSC_FALSE;
695   }
696   for (PetscInt i = 0; i < n; ++i) {
697     PetscBool matched;
698 
699     PetscCall(PetscStrcasecmp(str, list[i], &matched));
700     if (matched || !str[0]) {
701       if (found) *found = PETSC_TRUE;
702       *value = i;
703       break;
704     }
705   }
706   PetscFunctionReturn(PETSC_SUCCESS);
707 }
708 
709 /*@C
710   PetscEnumFind - searches enum list of strings for given string, using case insensitive matching
711 
712   Not Collective; No Fortran Support
713 
714   Input Parameters:
715 + enumlist - list of strings to search, followed by enum name, then enum prefix, then `NULL`
716 - str      - string to look for
717 
718   Output Parameters:
719 + value - index of matching string (if found)
720 - found - boolean indicating whether string was found (can be `NULL`)
721 
722   Level: advanced
723 
724 .seealso: `PetscEListFind()`
725 @*/
726 PetscErrorCode PetscEnumFind(const char *const *enumlist, const char *str, PetscEnum *value, PetscBool *found)
727 {
728   PetscInt  n = 0, evalue;
729   PetscBool efound;
730 
731   PetscFunctionBegin;
732   PetscAssertPointer(enumlist, 1);
733   while (enumlist[n++]) PetscCheck(n <= 50, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument appears to be wrong or have more than 50 entries");
734   PetscCheck(n >= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument must have at least two entries: typename and type prefix");
735   n -= 3; /* drop enum name, prefix, and null termination */
736   PetscCall(PetscEListFind(n, enumlist, str, &evalue, &efound));
737   if (efound) {
738     PetscAssertPointer(value, 3);
739     *value = (PetscEnum)evalue;
740   }
741   if (found) {
742     PetscAssertPointer(found, 4);
743     *found = efound;
744   }
745   PetscFunctionReturn(PETSC_SUCCESS);
746 }
747 
748 /*@C
749   PetscCIFilename - returns the basename of a file name when the PETSc CI portable error output mode is enabled.
750 
751   Not Collective; No Fortran Support
752 
753   Input Parameter:
754 . file - the file name
755 
756   Level: developer
757 
758   Note:
759   PETSc CI mode is a mode of running PETSc where output (both error and non-error) is made portable across all systems
760   so that comparisons of output between runs are easy to make.
761 
762   This mode is used for all tests in the test harness, it applies to both debug and optimized builds.
763 
764   Use the option `-petsc_ci` to turn on PETSc CI mode. It changes certain output in non-error situations to be portable for
765   all systems, mainly the output of options. It is passed to all PETSc programs automatically by the test harness.
766 
767   Always uses the Unix / as the file separate even on Microsoft Windows systems
768 
769   The option `-petsc_ci_portable_error_output` attempts to output the same error messages on all systems for the test harness.
770   In particular the output of filenames and line numbers in PETSc stacks. This is to allow (limited) checking of PETSc
771   error handling by the test harness. This options also causes PETSc to attempt to return an error code of 0 so that the test
772   harness can process the output for differences in the usual manner as for successful runs. It should be provided to the test
773   harness in the args: argument for specific examples. It will not necessarily produce portable output if different errors
774   (or no errors) occur on a subset of the MPI ranks.
775 
776 .seealso: `PetscCILinenumber()`
777 @*/
778 const char *PetscCIFilename(const char *file)
779 {
780   if (!PetscCIEnabledPortableErrorOutput) return file;
781   return PetscBasename(file);
782 }
783 
784 /*@C
785   PetscCILinenumber - returns a line number except if `PetscCIEnablePortableErrorOutput` is set when it returns 0
786 
787   Not Collective; No Fortran Support
788 
789   Input Parameter:
790 . linenumber - the initial line number
791 
792   Level: developer
793 
794   Note:
795   See `PetscCIFilename()` for details on usage
796 
797 .seealso: `PetscCIFilename()`
798 @*/
799 int PetscCILinenumber(int linenumber)
800 {
801   if (!PetscCIEnabledPortableErrorOutput) return linenumber;
802   return 0;
803 }
804 
805 /*@C
806   PetscStrcat - Concatenates a string onto a given string
807 
808   Not Collective, No Fortran Support
809 
810   Input Parameters:
811 + s - string to be added to
812 - t - pointer to string to be added to end
813 
814   Level: deprecated (since 3.18.5)
815 
816   Notes:
817   It is recommended you use `PetscStrlcat()` instead of this routine.
818 
819 .seealso: `PetscStrlcat()`
820 @*/
821 PetscErrorCode PetscStrcat(char s[], const char t[])
822 {
823   PetscFunctionBegin;
824   if (!t) PetscFunctionReturn(PETSC_SUCCESS);
825   PetscAssertPointer(s, 1);
826   strcat(s, t);
827   PetscFunctionReturn(PETSC_SUCCESS);
828 }
829 
830 /*@C
831   PetscStrcpy - Copies a string
832 
833   Not Collective, No Fortran Support
834 
835   Input Parameter:
836 . t - pointer to string
837 
838   Output Parameter:
839 . s - the copied string
840 
841   Level: deprecated (since 3.18.5)
842 
843   Notes:
844   It is recommended you use `PetscStrncpy()` (equivalently `PetscArraycpy()` or
845   `PetscMemcpy()`) instead of this routine.
846 
847   `NULL` strings returns a string starting with zero.
848 
849 .seealso: `PetscStrncpy()`
850 @*/
851 PetscErrorCode PetscStrcpy(char s[], const char t[])
852 {
853   PetscFunctionBegin;
854   if (t) {
855     PetscAssertPointer(s, 1);
856     PetscAssertPointer(t, 2);
857     strcpy(s, t);
858   } else if (s) {
859     s[0] = '\0';
860   }
861   PetscFunctionReturn(PETSC_SUCCESS);
862 }
863