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 the array 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 i, j, n, *lens, cnt = 0; 39 PetscBool flg = PETSC_FALSE; 40 41 if (!s) n = 0; 42 else n = 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) * 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 Parameters: 139 . s - 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 If `t` has previously been allocated then that memory is lost, you may need to `PetscStrArrayDestroy()` 148 the array before calling this routine. 149 150 .seealso: `PetscStrallocpy()`, `PetscStrArrayDestroy()`, `PetscStrNArrayallocpy()` 151 @*/ 152 PetscErrorCode PetscStrArrayallocpy(const char *const *list, char ***t) 153 { 154 PetscInt n = 0; 155 156 PetscFunctionBegin; 157 while (list[n++]) 158 ; 159 PetscCall(PetscMalloc1(n + 1, t)); 160 for (PetscInt i = 0; i < n; i++) PetscCall(PetscStrallocpy(list[i], (*t) + i)); 161 (*t)[n] = NULL; 162 PetscFunctionReturn(PETSC_SUCCESS); 163 } 164 165 /*@C 166 PetscStrArrayDestroy - Frees array of strings created with `PetscStrArrayallocpy()`. 167 168 Not Collective; No Fortran Support 169 170 Output Parameters: 171 . list - array of strings 172 173 Level: intermediate 174 175 .seealso: `PetscStrArrayallocpy()` 176 @*/ 177 PetscErrorCode PetscStrArrayDestroy(char ***list) 178 { 179 PetscInt n = 0; 180 181 PetscFunctionBegin; 182 if (!*list) PetscFunctionReturn(PETSC_SUCCESS); 183 while ((*list)[n]) { 184 PetscCall(PetscFree((*list)[n])); 185 ++n; 186 } 187 PetscCall(PetscFree(*list)); 188 PetscFunctionReturn(PETSC_SUCCESS); 189 } 190 191 /*@C 192 PetscStrNArrayallocpy - Allocates space to hold a copy of an array of strings then copies the strings 193 194 Not Collective; No Fortran Support 195 196 Input Parameters: 197 + n - the number of string entries 198 - s - pointer to array of strings 199 200 Output Parameter: 201 . t - the copied array string 202 203 Level: intermediate 204 205 .seealso: `PetscStrallocpy()`, `PetscStrArrayallocpy()`, `PetscStrNArrayDestroy()` 206 @*/ 207 PetscErrorCode PetscStrNArrayallocpy(PetscInt n, const char *const *list, char ***t) 208 { 209 PetscFunctionBegin; 210 PetscCall(PetscMalloc1(n, t)); 211 for (PetscInt i = 0; i < n; i++) PetscCall(PetscStrallocpy(list[i], (*t) + i)); 212 PetscFunctionReturn(PETSC_SUCCESS); 213 } 214 215 /*@C 216 PetscStrNArrayDestroy - Frees array of strings created with `PetscStrNArrayallocpy()`. 217 218 Not Collective; No Fortran Support 219 220 Output Parameters: 221 + n - number of string entries 222 - list - array of strings 223 224 Level: intermediate 225 226 .seealso: `PetscStrNArrayallocpy()`, `PetscStrArrayallocpy()` 227 @*/ 228 PetscErrorCode PetscStrNArrayDestroy(PetscInt n, char ***list) 229 { 230 PetscFunctionBegin; 231 if (!*list) PetscFunctionReturn(PETSC_SUCCESS); 232 for (PetscInt i = 0; i < n; i++) PetscCall(PetscFree((*list)[i])); 233 PetscCall(PetscFree(*list)); 234 PetscFunctionReturn(PETSC_SUCCESS); 235 } 236 237 /*@C 238 PetscBasename - returns a pointer to the last entry of a / or \ separated directory path 239 240 Not Collective; No Fortran Support 241 242 Input Parameter: 243 . a - pointer to string 244 245 Level: intermediate 246 247 .seealso: `PetscStrgrt()`, `PetscStrncmp()`, `PetscStrcasecmp()`, `PetscStrrchr()`, `PetscStrcmp()`, `PetscStrstr()`, 248 `PetscTokenCreate()`, `PetscStrToArray()`, `PetscStrInList()` 249 @*/ 250 const char *PetscBasename(const char a[]) 251 { 252 const char *ptr = NULL; 253 254 (void)PetscStrrchr(a, '/', (char **)&ptr); 255 if (ptr == a) { 256 if (PetscStrrchr(a, '\\', (char **)&ptr)) ptr = NULL; 257 } 258 return ptr; 259 } 260 261 /*@C 262 PetscStrcasecmp - Returns true if the two strings are the same 263 except possibly for case. 264 265 Not Collective; No Fortran Support 266 267 Input Parameters: 268 + a - pointer to first string 269 - b - pointer to second string 270 271 Output Parameter: 272 . flg - if the two strings are the same 273 274 Level: intermediate 275 276 Note: 277 `NULL` arguments are ok 278 279 .seealso: `PetscStrcmp()`, `PetscStrncmp()`, `PetscStrgrt()` 280 @*/ 281 PetscErrorCode PetscStrcasecmp(const char a[], const char b[], PetscBool *t) 282 { 283 int c; 284 285 PetscFunctionBegin; 286 PetscValidBoolPointer(t, 3); 287 if (!a && !b) c = 0; 288 else if (!a || !b) c = 1; 289 #if defined(PETSC_HAVE_STRCASECMP) 290 else c = strcasecmp(a, b); 291 #elif defined(PETSC_HAVE_STRICMP) 292 else c = stricmp(a, b); 293 #else 294 else { 295 char *aa, *bb; 296 297 PetscCall(PetscStrallocpy(a, &aa)); 298 PetscCall(PetscStrallocpy(b, &bb)); 299 PetscCall(PetscStrtolower(aa)); 300 PetscCall(PetscStrtolower(bb)); 301 PetscCall(PetscStrcmp(aa, bb, t)); 302 PetscCall(PetscFree(aa)); 303 PetscCall(PetscFree(bb)); 304 PetscFunctionReturn(PETSC_SUCCESS); 305 } 306 #endif 307 *t = c ? PETSC_FALSE : PETSC_TRUE; 308 PetscFunctionReturn(PETSC_SUCCESS); 309 } 310 311 /*@C 312 PetscStrendswithwhich - Determines if a string ends with one of several possible strings 313 314 Not Collective; No Fortran Support 315 316 Input Parameters: 317 + a - pointer to string 318 - bs - strings to end with (last entry must be `NULL`) 319 320 Output Parameter: 321 . cnt - the index of the string it ends with or the index of `NULL` 322 323 Level: intermediate 324 325 .seealso: `PetscStrbeginswithwhich()`, `PetscStrendswith()`, `PetscStrtoupper`, `PetscStrtolower()`, `PetscStrrchr()`, `PetscStrchr()`, 326 `PetscStrncmp()`, `PetscStrlen()`, `PetscStrncmp()`, `PetscStrcmp()` 327 @*/ 328 PetscErrorCode PetscStrendswithwhich(const char a[], const char *const *bs, PetscInt *cnt) 329 { 330 PetscFunctionBegin; 331 PetscValidPointer(bs, 2); 332 PetscValidIntPointer(cnt, 3); 333 *cnt = 0; 334 while (bs[*cnt]) { 335 PetscBool flg; 336 337 PetscCall(PetscStrendswith(a, bs[*cnt], &flg)); 338 if (flg) PetscFunctionReturn(PETSC_SUCCESS); 339 ++(*cnt); 340 } 341 PetscFunctionReturn(PETSC_SUCCESS); 342 } 343 344 struct _p_PetscToken { 345 char token; 346 char *array; 347 char *current; 348 }; 349 350 /*@C 351 PetscTokenFind - Locates next "token" in a `PetscToken` 352 353 Not Collective; No Fortran Support 354 355 Input Parameters: 356 . a - pointer to token 357 358 Output Parameter: 359 . result - location of occurrence, `NULL` if not found 360 361 Level: intermediate 362 363 Notes: 364 Treats all characters etc. inside a double quote " 365 as a single token. 366 367 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 368 second will return a `NULL` terminated y 369 370 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 371 372 .seealso: `PetscToken`, `PetscTokenCreate()`, `PetscTokenDestroy()` 373 @*/ 374 PetscErrorCode PetscTokenFind(PetscToken a, char *result[]) 375 { 376 char *ptr, token; 377 378 PetscFunctionBegin; 379 PetscValidPointer(a, 1); 380 PetscValidPointer(result, 2); 381 *result = ptr = a->current; 382 if (ptr && !*ptr) { 383 *result = NULL; 384 PetscFunctionReturn(PETSC_SUCCESS); 385 } 386 token = a->token; 387 if (ptr && (*ptr == '"')) { 388 token = '"'; 389 (*result)++; 390 ptr++; 391 } 392 while (ptr) { 393 if (*ptr == token) { 394 *ptr++ = 0; 395 while (*ptr == a->token) ptr++; 396 a->current = ptr; 397 break; 398 } 399 if (!*ptr) { 400 a->current = NULL; 401 break; 402 } 403 ptr++; 404 } 405 PetscFunctionReturn(PETSC_SUCCESS); 406 } 407 408 /*@C 409 PetscTokenCreate - Creates a `PetscToken` used to find tokens in a string 410 411 Not Collective; No Fortran Support 412 413 Input Parameters: 414 + string - the string to look in 415 - b - the separator character 416 417 Output Parameter: 418 . t - the token object 419 420 Level: intermediate 421 422 Note: 423 This version is different from the system version in that 424 it allows you to pass a read-only string into the function. 425 426 .seealso: `PetscToken`, `PetscTokenFind()`, `PetscTokenDestroy()` 427 @*/ 428 PetscErrorCode PetscTokenCreate(const char a[], char b, PetscToken *t) 429 { 430 PetscFunctionBegin; 431 PetscValidCharPointer(a, 1); 432 PetscValidPointer(t, 3); 433 PetscCall(PetscNew(t)); 434 PetscCall(PetscStrallocpy(a, &(*t)->array)); 435 436 (*t)->current = (*t)->array; 437 (*t)->token = b; 438 PetscFunctionReturn(PETSC_SUCCESS); 439 } 440 441 /*@C 442 PetscTokenDestroy - Destroys a `PetscToken` 443 444 Not Collective; No Fortran Support 445 446 Input Parameters: 447 . a - pointer to token 448 449 Level: intermediate 450 451 .seealso: `PetscToken`, `PetscTokenCreate()`, `PetscTokenFind()` 452 @*/ 453 PetscErrorCode PetscTokenDestroy(PetscToken *a) 454 { 455 PetscFunctionBegin; 456 if (!*a) PetscFunctionReturn(PETSC_SUCCESS); 457 PetscCall(PetscFree((*a)->array)); 458 PetscCall(PetscFree(*a)); 459 PetscFunctionReturn(PETSC_SUCCESS); 460 } 461 462 /*@C 463 PetscStrInList - search for a string in character-delimited list 464 465 Not Collective; No Fortran Support 466 467 Input Parameters: 468 + str - the string to look for 469 . list - the list to search in 470 - sep - the separator character 471 472 Output Parameter: 473 . found - whether `str` is in `list` 474 475 Level: intermediate 476 477 .seealso: `PetscTokenCreate()`, `PetscTokenFind()`, `PetscStrcmp()` 478 @*/ 479 PetscErrorCode PetscStrInList(const char str[], const char list[], char sep, PetscBool *found) 480 { 481 PetscToken token; 482 char *item; 483 484 PetscFunctionBegin; 485 PetscValidBoolPointer(found, 4); 486 *found = PETSC_FALSE; 487 PetscCall(PetscTokenCreate(list, sep, &token)); 488 PetscCall(PetscTokenFind(token, &item)); 489 while (item) { 490 PetscCall(PetscStrcmp(str, item, found)); 491 if (*found) break; 492 PetscCall(PetscTokenFind(token, &item)); 493 } 494 PetscCall(PetscTokenDestroy(&token)); 495 PetscFunctionReturn(PETSC_SUCCESS); 496 } 497 498 /*@C 499 PetscGetPetscDir - Gets the directory PETSc is installed in 500 501 Not Collective; No Fortran Support 502 503 Output Parameter: 504 . dir - the directory 505 506 Level: developer 507 508 @*/ 509 PetscErrorCode PetscGetPetscDir(const char *dir[]) 510 { 511 PetscFunctionBegin; 512 PetscValidPointer(dir, 1); 513 *dir = PETSC_DIR; 514 PetscFunctionReturn(PETSC_SUCCESS); 515 } 516 517 /*@C 518 PetscStrreplace - Replaces substrings in string with other substrings 519 520 Not Collective; No Fortran Support 521 522 Input Parameters: 523 + comm - `MPI_Comm` of processors that are processing the string 524 . aa - the string to look in 525 . b - the resulting copy of a with replaced strings (`b` can be the same as `a`) 526 - len - the length of `b` 527 528 Notes: 529 Replaces ${PETSC_ARCH},${PETSC_DIR},${PETSC_LIB_DIR},${DISPLAY}, 530 ${HOMEDIRECTORY},${WORKINGDIRECTORY},${USERNAME}, ${HOSTNAME} with appropriate values 531 as well as any environmental variables. 532 533 `PETSC_LIB_DIR` uses the environmental variable if it exists. `PETSC_ARCH` and `PETSC_DIR` use what 534 PETSc was built with and do not use environmental variables. 535 536 Level: developer 537 @*/ 538 PetscErrorCode PetscStrreplace(MPI_Comm comm, const char aa[], char b[], size_t len) 539 { 540 int i = 0; 541 size_t l, l1, l2, l3; 542 char *work, *par, *epar = NULL, env[1024], *tfree, *a = (char *)aa; 543 const char *s[] = {"${PETSC_ARCH}", "${PETSC_DIR}", "${PETSC_LIB_DIR}", "${DISPLAY}", "${HOMEDIRECTORY}", "${WORKINGDIRECTORY}", "${USERNAME}", "${HOSTNAME}", NULL}; 544 char *r[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; 545 PetscBool flag; 546 static size_t DISPLAY_LENGTH = 265, USER_LENGTH = 256, HOST_LENGTH = 256; 547 548 PetscFunctionBegin; 549 PetscValidCharPointer(aa, 2); 550 PetscValidCharPointer(b, 3); 551 if (aa == b) PetscCall(PetscStrallocpy(aa, (char **)&a)); 552 PetscCall(PetscMalloc1(len, &work)); 553 554 /* get values for replaced variables */ 555 PetscCall(PetscStrallocpy(PETSC_ARCH, &r[0])); 556 PetscCall(PetscStrallocpy(PETSC_DIR, &r[1])); 557 PetscCall(PetscStrallocpy(PETSC_LIB_DIR, &r[2])); 558 PetscCall(PetscMalloc1(DISPLAY_LENGTH, &r[3])); 559 PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN, &r[4])); 560 PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN, &r[5])); 561 PetscCall(PetscMalloc1(USER_LENGTH, &r[6])); 562 PetscCall(PetscMalloc1(HOST_LENGTH, &r[7])); 563 PetscCall(PetscGetDisplay(r[3], DISPLAY_LENGTH)); 564 PetscCall(PetscGetHomeDirectory(r[4], PETSC_MAX_PATH_LEN)); 565 PetscCall(PetscGetWorkingDirectory(r[5], PETSC_MAX_PATH_LEN)); 566 PetscCall(PetscGetUserName(r[6], USER_LENGTH)); 567 PetscCall(PetscGetHostName(r[7], HOST_LENGTH)); 568 569 /* replace that are in environment */ 570 PetscCall(PetscOptionsGetenv(comm, "PETSC_LIB_DIR", env, sizeof(env), &flag)); 571 if (flag) { 572 PetscCall(PetscFree(r[2])); 573 PetscCall(PetscStrallocpy(env, &r[2])); 574 } 575 576 /* replace the requested strings */ 577 PetscCall(PetscStrncpy(b, a, len)); 578 while (s[i]) { 579 PetscCall(PetscStrlen(s[i], &l)); 580 PetscCall(PetscStrstr(b, s[i], &par)); 581 while (par) { 582 *par = 0; 583 par += l; 584 585 PetscCall(PetscStrlen(b, &l1)); 586 PetscCall(PetscStrlen(r[i], &l2)); 587 PetscCall(PetscStrlen(par, &l3)); 588 PetscCheck(l1 + l2 + l3 < len, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "b len is not long enough to hold new values"); 589 PetscCall(PetscStrncpy(work, b, len)); 590 PetscCall(PetscStrlcat(work, r[i], len)); 591 PetscCall(PetscStrlcat(work, par, len)); 592 PetscCall(PetscStrncpy(b, work, len)); 593 PetscCall(PetscStrstr(b, s[i], &par)); 594 } 595 i++; 596 } 597 i = 0; 598 while (r[i]) { 599 tfree = (char *)r[i]; 600 PetscCall(PetscFree(tfree)); 601 i++; 602 } 603 604 /* look for any other ${xxx} strings to replace from environmental variables */ 605 PetscCall(PetscStrstr(b, "${", &par)); 606 while (par) { 607 *par = 0; 608 par += 2; 609 PetscCall(PetscStrncpy(work, b, len)); 610 PetscCall(PetscStrstr(par, "}", &epar)); 611 *epar = 0; 612 epar += 1; 613 PetscCall(PetscOptionsGetenv(comm, par, env, sizeof(env), &flag)); 614 PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Substitution string ${%s} not found as environmental variable", par); 615 PetscCall(PetscStrlcat(work, env, len)); 616 PetscCall(PetscStrlcat(work, epar, len)); 617 PetscCall(PetscStrncpy(b, work, len)); 618 PetscCall(PetscStrstr(b, "${", &par)); 619 } 620 PetscCall(PetscFree(work)); 621 if (aa == b) PetscCall(PetscFree(a)); 622 PetscFunctionReturn(PETSC_SUCCESS); 623 } 624 625 /*@C 626 PetscEListFind - searches list of strings for given string, using case insensitive matching 627 628 Not Collective; No Fortran Support 629 630 Input Parameters: 631 + n - number of strings in 632 . list - list of strings to search 633 - str - string to look for, empty string "" accepts default (first entry in list) 634 635 Output Parameters: 636 + value - index of matching string (if found) 637 - found - boolean indicating whether string was found (can be `NULL`) 638 639 Level: developer 640 641 .seealso: `PetscEnumFind()` 642 @*/ 643 PetscErrorCode PetscEListFind(PetscInt n, const char *const *list, const char *str, PetscInt *value, PetscBool *found) 644 { 645 PetscFunctionBegin; 646 if (found) { 647 PetscValidBoolPointer(found, 5); 648 *found = PETSC_FALSE; 649 } 650 for (PetscInt i = 0; i < n; ++i) { 651 PetscBool matched; 652 653 PetscCall(PetscStrcasecmp(str, list[i], &matched)); 654 if (matched || !str[0]) { 655 if (found) *found = PETSC_TRUE; 656 *value = i; 657 break; 658 } 659 } 660 PetscFunctionReturn(PETSC_SUCCESS); 661 } 662 663 /*@C 664 PetscEnumFind - searches enum list of strings for given string, using case insensitive matching 665 666 Not Collective; No Fortran Support 667 668 Input Parameters: 669 + enumlist - list of strings to search, followed by enum name, then enum prefix, then `NULL` 670 - str - string to look for 671 672 Output Parameters: 673 + value - index of matching string (if found) 674 - found - boolean indicating whether string was found (can be `NULL`) 675 676 Level: advanced 677 678 .seealso: `PetscEListFind()` 679 @*/ 680 PetscErrorCode PetscEnumFind(const char *const *enumlist, const char *str, PetscEnum *value, PetscBool *found) 681 { 682 PetscInt n = 0, evalue; 683 PetscBool efound; 684 685 PetscFunctionBegin; 686 PetscValidPointer(enumlist, 1); 687 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"); 688 PetscCheck(n >= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument must have at least two entries: typename and type prefix"); 689 n -= 3; /* drop enum name, prefix, and null termination */ 690 PetscCall(PetscEListFind(n, enumlist, str, &evalue, &efound)); 691 if (efound) { 692 PetscValidPointer(value, 3); 693 *value = (PetscEnum)evalue; 694 } 695 if (found) { 696 PetscValidBoolPointer(found, 4); 697 *found = efound; 698 } 699 PetscFunctionReturn(PETSC_SUCCESS); 700 } 701 702 /*@C 703 PetscCIFilename - returns the basename of a file name when the PETSc CI portable error output mode is enabled. 704 705 Not collective; No Fortran Support 706 707 Input Parameter: 708 . file - the file name 709 710 Level: developer 711 712 Note: 713 PETSc CI mode is a mode of running PETSc where output (both error and non-error) is made portable across all systems 714 so that comparisons of output between runs are easy to make. 715 716 This mode is used for all tests in the test harness, it applies to both debug and optimized builds. 717 718 Use the option `-petsc_ci` to turn on PETSc CI mode. It changes certain output in non-error situations to be portable for 719 all systems, mainly the output of options. It is passed to all PETSc programs automatically by the test harness. 720 721 Always uses the Unix / as the file separate even on Microsoft Windows systems 722 723 The option `-petsc_ci_portable_error_output` attempts to output the same error messages on all systems for the test harness. 724 In particular the output of filenames and line numbers in PETSc stacks. This is to allow (limited) checking of PETSc 725 error handling by the test harness. This options also causes PETSc to attempt to return an error code of 0 so that the test 726 harness can process the output for differences in the usual manner as for successful runs. It should be provided to the test 727 harness in the args: argument for specific examples. It will not necessarily produce portable output if different errors 728 (or no errors) occur on a subset of the MPI ranks. 729 730 .seealso: `PetscCILinenumber()` 731 @*/ 732 const char *PetscCIFilename(const char *file) 733 { 734 if (!PetscCIEnabledPortableErrorOutput) return file; 735 return PetscBasename(file); 736 } 737 738 /*@C 739 PetscCILinenumber - returns a line number except if `PetscCIEnablePortableErrorOutput` is set when it returns 0 740 741 Not Collective; No Fortran Support 742 743 Input Parameter: 744 . linenumber - the initial line number 745 746 Level: developer 747 748 Note: 749 See `PetscCIFilename()` for details on usage 750 751 .seealso: `PetscCIFilename()` 752 @*/ 753 int PetscCILinenumber(int linenumber) 754 { 755 if (!PetscCIEnabledPortableErrorOutput) return linenumber; 756 return 0; 757 } 758