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 @*/
PetscStrToArray(const char s[],char sp,int * argc,char *** args)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 @*/
PetscStrToArrayDestroy(int argc,char ** args)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 @*/
PetscStrArrayallocpy(const char * const * list,char *** t)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 @*/
PetscStrArrayDestroy(char *** list)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 @*/
PetscStrNArrayallocpy(PetscInt n,const char * const * list,char *** t)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 @*/
PetscStrNArrayDestroy(PetscInt n,char *** list)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 @*/
PetscBasename(const char a[])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 @*/
PetscStrcasecmp(const char a[],const char b[],PetscBool * t)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 @*/
PetscStrendswithwhich(const char a[],const char * const * bs,PetscInt * cnt)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 _n_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 Do not change or free the value of `result`
374
375 .seealso: `PetscToken`, `PetscTokenCreate()`, `PetscTokenDestroy()`
376 @*/
PetscTokenFind(PetscToken a,const char * result[])377 PetscErrorCode PetscTokenFind(PetscToken a, const char *result[])
378 {
379 char *ptr, token;
380
381 PetscFunctionBegin;
382 PetscAssertPointer(a, 1);
383 PetscAssertPointer(result, 2);
384 *result = ptr = a->current;
385 if (ptr && !*ptr) {
386 *result = NULL;
387 PetscFunctionReturn(PETSC_SUCCESS);
388 }
389 token = a->token;
390 if (ptr && (*ptr == '"')) {
391 token = '"';
392 (*result)++;
393 ptr++;
394 }
395 while (ptr) {
396 if (*ptr == token) {
397 *ptr++ = 0;
398 while (*ptr == a->token) ptr++;
399 a->current = ptr;
400 break;
401 }
402 if (!*ptr) {
403 a->current = NULL;
404 break;
405 }
406 ptr++;
407 }
408 PetscFunctionReturn(PETSC_SUCCESS);
409 }
410
411 /*@C
412 PetscTokenCreate - Creates a `PetscToken` used to find tokens in a string
413
414 Not Collective; No Fortran Support
415
416 Input Parameters:
417 + a - the string to look in
418 - b - the separator character
419
420 Output Parameter:
421 . t - the token object
422
423 Level: intermediate
424
425 Note:
426 This version is different from the system version in that
427 it allows you to pass a read-only string into the function.
428
429 .seealso: `PetscToken`, `PetscTokenFind()`, `PetscTokenDestroy()`
430 @*/
PetscTokenCreate(const char a[],char b,PetscToken * t)431 PetscErrorCode PetscTokenCreate(const char a[], char b, PetscToken *t)
432 {
433 PetscFunctionBegin;
434 PetscAssertPointer(a, 1);
435 PetscAssertPointer(t, 3);
436 PetscCall(PetscNew(t));
437 PetscCall(PetscStrallocpy(a, &(*t)->array));
438
439 (*t)->current = (*t)->array;
440 (*t)->token = b;
441 PetscFunctionReturn(PETSC_SUCCESS);
442 }
443
444 /*@C
445 PetscTokenDestroy - Destroys a `PetscToken`
446
447 Not Collective; No Fortran Support
448
449 Input Parameter:
450 . a - pointer to token
451
452 Level: intermediate
453
454 .seealso: `PetscToken`, `PetscTokenCreate()`, `PetscTokenFind()`
455 @*/
PetscTokenDestroy(PetscToken * a)456 PetscErrorCode PetscTokenDestroy(PetscToken *a)
457 {
458 PetscFunctionBegin;
459 if (!*a) PetscFunctionReturn(PETSC_SUCCESS);
460 PetscCall(PetscFree((*a)->array));
461 PetscCall(PetscFree(*a));
462 PetscFunctionReturn(PETSC_SUCCESS);
463 }
464
465 /*@C
466 PetscStrInList - search for a string in character-delimited list
467
468 Not Collective; No Fortran Support
469
470 Input Parameters:
471 + str - the string to look for
472 . list - the list to search in
473 - sep - the separator character
474
475 Output Parameter:
476 . found - whether `str` is in `list`
477
478 Level: intermediate
479
480 .seealso: `PetscTokenCreate()`, `PetscTokenFind()`, `PetscStrcmp()`
481 @*/
PetscStrInList(const char str[],const char list[],char sep,PetscBool * found)482 PetscErrorCode PetscStrInList(const char str[], const char list[], char sep, PetscBool *found)
483 {
484 PetscToken token;
485 const char *item;
486
487 PetscFunctionBegin;
488 PetscAssertPointer(found, 4);
489 *found = PETSC_FALSE;
490 PetscCall(PetscTokenCreate(list, sep, &token));
491 PetscCall(PetscTokenFind(token, &item));
492 while (item) {
493 PetscCall(PetscStrcmp(str, item, found));
494 if (*found) break;
495 PetscCall(PetscTokenFind(token, &item));
496 }
497 PetscCall(PetscTokenDestroy(&token));
498 PetscFunctionReturn(PETSC_SUCCESS);
499 }
500
501 /*@C
502 PetscGetPetscDir - Gets the directory PETSc is installed in
503
504 Not Collective; No Fortran Support
505
506 Output Parameter:
507 . dir - the directory
508
509 Level: developer
510
511 .seealso: `PetscGetArchType()`
512 @*/
PetscGetPetscDir(const char * dir[])513 PetscErrorCode PetscGetPetscDir(const char *dir[])
514 {
515 PetscFunctionBegin;
516 PetscAssertPointer(dir, 1);
517 *dir = PETSC_DIR;
518 PetscFunctionReturn(PETSC_SUCCESS);
519 }
520
521 /*@C
522 PetscStrreplace - Replaces substrings in string with other substrings
523
524 Not Collective; No Fortran Support
525
526 Input Parameters:
527 + comm - `MPI_Comm` of processors that are processing the string
528 . aa - the string to look in
529 . b - the resulting copy of a with replaced strings (`b` can be the same as `a`)
530 - len - the length of `b`
531
532 Level: developer
533
534 Notes:
535 Replaces
536 .vb
537 ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, ${DISPLAY},
538 ${HOMEDIRECTORY}, ${WORKINGDIRECTORY}, ${USERNAME}, ${HOSTNAME}, ${PETSC_MAKE}
539 .ve
540 with appropriate values as well as any environmental variables.
541
542 `PETSC_LIB_DIR` uses the environmental variable if it exists. `PETSC_ARCH` and `PETSC_DIR` use what
543 PETSc was built with and do not use environmental variables.
544
545 .seealso: `PetscStrcmp()`
546 @*/
PetscStrreplace(MPI_Comm comm,const char aa[],char b[],size_t len)547 PetscErrorCode PetscStrreplace(MPI_Comm comm, const char aa[], char b[], size_t len)
548 {
549 int i = 0;
550 size_t l, l1, l2, l3;
551 char *work, *par, *epar = NULL, env[1024], *tfree, *a = (char *)aa;
552 const char *s[] = {"${PETSC_ARCH}", "${PETSC_DIR}", "${PETSC_LIB_DIR}", "${DISPLAY}", "${HOMEDIRECTORY}", "${WORKINGDIRECTORY}", "${USERNAME}", "${HOSTNAME}", "${PETSC_MAKE}", NULL};
553 char *r[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
554 PetscBool flag;
555 static size_t DISPLAY_LENGTH = 265, USER_LENGTH = 256, HOST_LENGTH = 256;
556
557 PetscFunctionBegin;
558 PetscAssertPointer(aa, 2);
559 PetscAssertPointer(b, 3);
560 if (aa == b) PetscCall(PetscStrallocpy(aa, &a));
561 PetscCall(PetscMalloc1(len, &work));
562
563 /* get values for replaced variables */
564 PetscCall(PetscStrallocpy(PETSC_ARCH, &r[0]));
565 PetscCall(PetscStrallocpy(PETSC_DIR, &r[1]));
566 PetscCall(PetscStrallocpy(PETSC_LIB_DIR, &r[2]));
567 PetscCall(PetscMalloc1(DISPLAY_LENGTH, &r[3]));
568 PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN, &r[4]));
569 PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN, &r[5]));
570 PetscCall(PetscMalloc1(USER_LENGTH, &r[6]));
571 PetscCall(PetscMalloc1(HOST_LENGTH, &r[7]));
572 PetscCall(PetscGetDisplay(r[3], DISPLAY_LENGTH));
573 PetscCall(PetscGetHomeDirectory(r[4], PETSC_MAX_PATH_LEN));
574 PetscCall(PetscGetWorkingDirectory(r[5], PETSC_MAX_PATH_LEN));
575 PetscCall(PetscGetUserName(r[6], USER_LENGTH));
576 PetscCall(PetscGetHostName(r[7], HOST_LENGTH));
577 PetscCall(PetscStrallocpy(PETSC_OMAKE, &r[8]));
578
579 /* replace that are in environment */
580 PetscCall(PetscOptionsGetenv(comm, "PETSC_LIB_DIR", env, sizeof(env), &flag));
581 if (flag) {
582 PetscCall(PetscFree(r[2]));
583 PetscCall(PetscStrallocpy(env, &r[2]));
584 }
585
586 /* replace the requested strings */
587 PetscCall(PetscStrncpy(b, a, len));
588 while (s[i]) {
589 PetscCall(PetscStrcmp(s[i], r[i], &flag));
590 if (flag) {
591 i++;
592 continue;
593 }
594 PetscCall(PetscStrlen(s[i], &l));
595 PetscCall(PetscStrstr(b, s[i], &par));
596 while (par) {
597 *par = 0;
598 par += l;
599
600 PetscCall(PetscStrlen(b, &l1));
601 PetscCall(PetscStrlen(r[i], &l2));
602 PetscCall(PetscStrlen(par, &l3));
603 PetscCheck(l1 + l2 + l3 < len, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "b len is not long enough to hold new values");
604 PetscCall(PetscStrncpy(work, b, len));
605 PetscCall(PetscStrlcat(work, r[i], len));
606 PetscCall(PetscStrlcat(work, par, len));
607 PetscCall(PetscStrncpy(b, work, len));
608 PetscCall(PetscStrstr(b, s[i], &par));
609 }
610 i++;
611 }
612 i = 0;
613 while (r[i]) {
614 tfree = r[i];
615 PetscCall(PetscFree(tfree));
616 i++;
617 }
618
619 /* look for any other ${xxx} strings to replace from environmental variables */
620 PetscCall(PetscStrstr(b, "${", &par));
621 while (par) {
622 *par = 0;
623 par += 2;
624 PetscCall(PetscStrncpy(work, b, len));
625 PetscCall(PetscStrstr(par, "}", &epar));
626 *epar = 0;
627 epar += 1;
628 PetscCall(PetscOptionsGetenv(comm, par, env, sizeof(env), &flag));
629 PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Substitution string ${%s} not found as environmental variable", par);
630 PetscCall(PetscStrlcat(work, env, len));
631 PetscCall(PetscStrlcat(work, epar, len));
632 PetscCall(PetscStrncpy(b, work, len));
633 PetscCall(PetscStrstr(b, "${", &par));
634 }
635 PetscCall(PetscFree(work));
636 if (aa == b) PetscCall(PetscFree(a));
637 PetscFunctionReturn(PETSC_SUCCESS);
638 }
639
640 /*@C
641 PetscStrcmpAny - Determines whether a string matches any of a list of strings.
642
643 Not Collective, No Fortran Support
644
645 Input Parameters:
646 + src - pointer to input the string
647 - cmp - list of non-null and non-empty strings to be compared against, pass the empty string "" to terminate the list
648
649 Output Parameter:
650 . match - `PETSC_TRUE` if the input string matches any in the list, else `PETSC_FALSE`
651
652 Level: intermediate
653
654 .seealso: `PetscStrcmp()`
655 @*/
PetscStrcmpAny(const char src[],PetscBool * match,const char cmp[],...)656 PetscErrorCode PetscStrcmpAny(const char src[], PetscBool *match, const char cmp[], ...)
657 {
658 va_list Argp;
659
660 PetscFunctionBegin;
661 PetscAssertPointer(match, 2);
662 *match = PETSC_FALSE;
663 if (!src) PetscFunctionReturn(PETSC_SUCCESS);
664 va_start(Argp, cmp);
665 while (cmp && cmp[0]) {
666 PetscBool found;
667 PetscCall(PetscStrcmp(src, cmp, &found));
668 if (found) {
669 *match = PETSC_TRUE;
670 break;
671 }
672 cmp = va_arg(Argp, const char *);
673 }
674 va_end(Argp);
675 PetscFunctionReturn(PETSC_SUCCESS);
676 }
677
678 /*@C
679 PetscEListFind - searches list of strings for given string, using case insensitive matching
680
681 Not Collective; No Fortran Support
682
683 Input Parameters:
684 + n - number of strings in
685 . list - list of strings to search
686 - str - string to look for, empty string "" accepts default (first entry in list)
687
688 Output Parameters:
689 + value - index of matching string (if found)
690 - found - boolean indicating whether string was found (can be `NULL`)
691
692 Level: developer
693
694 .seealso: `PetscEnumFind()`
695 @*/
PetscEListFind(PetscInt n,const char * const * list,const char * str,PetscInt * value,PetscBool * found)696 PetscErrorCode PetscEListFind(PetscInt n, const char *const *list, const char *str, PetscInt *value, PetscBool *found)
697 {
698 PetscFunctionBegin;
699 if (found) {
700 PetscAssertPointer(found, 5);
701 *found = PETSC_FALSE;
702 }
703 for (PetscInt i = 0; i < n; ++i) {
704 PetscBool matched;
705
706 PetscCall(PetscStrcasecmp(str, list[i], &matched));
707 if (matched || !str[0]) {
708 if (found) *found = PETSC_TRUE;
709 *value = i;
710 break;
711 }
712 }
713 PetscFunctionReturn(PETSC_SUCCESS);
714 }
715
716 /*@C
717 PetscEnumFind - searches enum list of strings for given string, using case insensitive matching
718
719 Not Collective; No Fortran Support
720
721 Input Parameters:
722 + enumlist - list of strings to search, followed by enum name, then enum prefix, then `NULL`
723 - str - string to look for
724
725 Output Parameters:
726 + value - index of matching string (if found)
727 - found - boolean indicating whether string was found (can be `NULL`)
728
729 Level: advanced
730
731 .seealso: `PetscEListFind()`
732 @*/
PetscEnumFind(const char * const * enumlist,const char * str,PetscEnum * value,PetscBool * found)733 PetscErrorCode PetscEnumFind(const char *const *enumlist, const char *str, PetscEnum *value, PetscBool *found)
734 {
735 PetscInt n = 0, evalue;
736 PetscBool efound;
737
738 PetscFunctionBegin;
739 PetscAssertPointer(enumlist, 1);
740 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");
741 PetscCheck(n >= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument must have at least two entries: typename and type prefix");
742 n -= 3; /* drop enum name, prefix, and null termination */
743 PetscCall(PetscEListFind(n, enumlist, str, &evalue, &efound));
744 if (efound) {
745 PetscAssertPointer(value, 3);
746 *value = (PetscEnum)evalue;
747 }
748 if (found) {
749 PetscAssertPointer(found, 4);
750 *found = efound;
751 }
752 PetscFunctionReturn(PETSC_SUCCESS);
753 }
754
755 /*@C
756 PetscCIFilename - returns the basename of a file name when the PETSc CI portable error output mode is enabled.
757
758 Not Collective; No Fortran Support
759
760 Input Parameter:
761 . file - the file name
762
763 Level: developer
764
765 Note:
766 PETSc CI mode is a mode of running PETSc where output (both error and non-error) is made portable across all systems
767 so that comparisons of output between runs are easy to make.
768
769 This mode is used for all tests in the test harness, it applies to both debug and optimized builds.
770
771 Use the option `-petsc_ci` to turn on PETSc CI mode. It changes certain output in non-error situations to be portable for
772 all systems, mainly the output of options. It is passed to all PETSc programs automatically by the test harness.
773
774 Always uses the Unix / as the file separate even on Microsoft Windows systems
775
776 The option `-petsc_ci_portable_error_output` attempts to output the same error messages on all systems for the test harness.
777 In particular the output of filenames and line numbers in PETSc stacks. This is to allow (limited) checking of PETSc
778 error handling by the test harness. This options also causes PETSc to attempt to return an error code of 0 so that the test
779 harness can process the output for differences in the usual manner as for successful runs. It should be provided to the test
780 harness in the args: argument for specific examples. It will not necessarily produce portable output if different errors
781 (or no errors) occur on a subset of the MPI ranks.
782
783 .seealso: `PetscCILinenumber()`
784 @*/
PetscCIFilename(const char * file)785 const char *PetscCIFilename(const char *file)
786 {
787 if (!PetscCIEnabledPortableErrorOutput) return file;
788 return PetscBasename(file);
789 }
790
791 /*@C
792 PetscCILinenumber - returns a line number except if `PetscCIEnablePortableErrorOutput` is set when it returns 0
793
794 Not Collective; No Fortran Support
795
796 Input Parameter:
797 . linenumber - the initial line number
798
799 Level: developer
800
801 Note:
802 See `PetscCIFilename()` for details on usage
803
804 .seealso: `PetscCIFilename()`
805 @*/
PetscCILinenumber(int linenumber)806 int PetscCILinenumber(int linenumber)
807 {
808 if (!PetscCIEnabledPortableErrorOutput) return linenumber;
809 return 0;
810 }
811
812 /*@C
813 PetscStrcat - Concatenates a string onto a given string
814
815 Not Collective, No Fortran Support
816
817 Input Parameters:
818 + s - string to be added to
819 - t - pointer to string to be added to end
820
821 Level: deprecated (since 3.18.5)
822
823 Notes:
824 It is recommended you use `PetscStrlcat()` instead of this routine.
825
826 .seealso: `PetscStrlcat()`
827 @*/
PetscStrcat(char s[],const char t[])828 PetscErrorCode PetscStrcat(char s[], const char t[])
829 {
830 PetscFunctionBegin;
831 if (!t) PetscFunctionReturn(PETSC_SUCCESS);
832 PetscAssertPointer(s, 1);
833 strcat(s, t);
834 PetscFunctionReturn(PETSC_SUCCESS);
835 }
836
837 /*@C
838 PetscStrcpy - Copies a string
839
840 Not Collective, No Fortran Support
841
842 Input Parameter:
843 . t - pointer to string
844
845 Output Parameter:
846 . s - the copied string
847
848 Level: deprecated (since 3.18.5)
849
850 Notes:
851 It is recommended you use `PetscStrncpy()` (equivalently `PetscArraycpy()` or
852 `PetscMemcpy()`) instead of this routine.
853
854 `NULL` strings returns a string starting with zero.
855
856 .seealso: `PetscStrncpy()`
857 @*/
PetscStrcpy(char s[],const char t[])858 PetscErrorCode PetscStrcpy(char s[], const char t[])
859 {
860 PetscFunctionBegin;
861 if (t) {
862 PetscAssertPointer(s, 1);
863 PetscAssertPointer(t, 2);
864 strcpy(s, t);
865 } else if (s) {
866 s[0] = '\0';
867 }
868 PetscFunctionReturn(PETSC_SUCCESS);
869 }
870