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 */ 7 #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/ 8 #if defined(PETSC_HAVE_STRINGS_H) 9 #include <strings.h> /* strcasecmp */ 10 #endif 11 12 /*@C 13 PetscStrToArray - Separates a string by a character (for example ' ' or '\n') and creates an array of strings 14 15 Not Collective 16 17 Input Parameters: 18 + s - pointer to string 19 - sp - separator character 20 21 Output Parameters: 22 + argc - the number of entries in the array 23 - args - an array of the entries with a null at the end 24 25 Level: intermediate 26 27 Notes: 28 this may be called before PetscInitialize() or after PetscFinalize() 29 30 Not for use in Fortran 31 32 Developer Notes: 33 Using raw malloc() and does not call error handlers since this may be used before PETSc is initialized. Used 34 to generate argc, args arguments passed to MPI_Init() 35 36 .seealso: `PetscStrToArrayDestroy()`, `PetscToken`, `PetscTokenCreate()` 37 38 @*/ 39 PetscErrorCode PetscStrToArray(const char s[], char sp, int *argc, char ***args) { 40 int i, j, n, *lens, cnt = 0; 41 PetscBool flg = PETSC_FALSE; 42 43 if (!s) n = 0; 44 else n = strlen(s); 45 *argc = 0; 46 *args = NULL; 47 for (; n > 0; n--) { /* remove separator chars at the end - and will empty the string if all chars are separator chars */ 48 if (s[n - 1] != sp) break; 49 } 50 if (!n) return 0; 51 for (i = 0; i < n; i++) { 52 if (s[i] != sp) break; 53 } 54 for (; i < n + 1; i++) { 55 if ((s[i] == sp || s[i] == 0) && !flg) { 56 flg = PETSC_TRUE; 57 (*argc)++; 58 } else if (s[i] != sp) { 59 flg = PETSC_FALSE; 60 } 61 } 62 (*args) = (char **)malloc(((*argc) + 1) * sizeof(char *)); 63 if (!*args) return PETSC_ERR_MEM; 64 lens = (int *)malloc((*argc) * sizeof(int)); 65 if (!lens) return PETSC_ERR_MEM; 66 for (i = 0; i < *argc; i++) lens[i] = 0; 67 68 *argc = 0; 69 for (i = 0; i < n; i++) { 70 if (s[i] != sp) break; 71 } 72 for (; i < n + 1; i++) { 73 if ((s[i] == sp || s[i] == 0) && !flg) { 74 flg = PETSC_TRUE; 75 (*argc)++; 76 } else if (s[i] != sp) { 77 lens[*argc]++; 78 flg = PETSC_FALSE; 79 } 80 } 81 82 for (i = 0; i < *argc; i++) { 83 (*args)[i] = (char *)malloc((lens[i] + 1) * sizeof(char)); 84 if (!(*args)[i]) { 85 free(lens); 86 for (j = 0; j < i; j++) free((*args)[j]); 87 free(*args); 88 return PETSC_ERR_MEM; 89 } 90 } 91 free(lens); 92 (*args)[*argc] = NULL; 93 94 *argc = 0; 95 for (i = 0; i < n; i++) { 96 if (s[i] != sp) break; 97 } 98 for (; i < n + 1; i++) { 99 if ((s[i] == sp || s[i] == 0) && !flg) { 100 flg = PETSC_TRUE; 101 (*args)[*argc][cnt++] = 0; 102 (*argc)++; 103 cnt = 0; 104 } else if (s[i] != sp && s[i] != 0) { 105 (*args)[*argc][cnt++] = s[i]; 106 flg = PETSC_FALSE; 107 } 108 } 109 return 0; 110 } 111 112 /*@C 113 PetscStrToArrayDestroy - Frees array created with PetscStrToArray(). 114 115 Not Collective 116 117 Output Parameters: 118 + argc - the number of arguments 119 - args - the array of arguments 120 121 Level: intermediate 122 123 Notes: 124 This may be called before PetscInitialize() or after PetscFinalize() 125 126 Not for use in Fortran 127 128 .seealso: `PetscStrToArray()` 129 130 @*/ 131 PetscErrorCode PetscStrToArrayDestroy(int argc, char **args) { 132 for (int i = 0; i < argc; ++i) free(args[i]); 133 if (args) free(args); 134 return 0; 135 } 136 137 /*@C 138 PetscStrlen - Gets length of a string 139 140 Not Collective 141 142 Input Parameters: 143 . s - pointer to string 144 145 Output Parameter: 146 . len - length in bytes 147 148 Level: intermediate 149 150 Note: 151 This routine is analogous to strlen(). 152 153 Null string returns a length of zero 154 155 Not for use in Fortran 156 157 @*/ 158 PetscErrorCode PetscStrlen(const char s[], size_t *len) { 159 PetscFunctionBegin; 160 *len = s ? strlen(s) : 0; 161 PetscFunctionReturn(0); 162 } 163 164 /*@C 165 PetscStrallocpy - Allocates space to hold a copy of a string then copies the string 166 167 Not Collective 168 169 Input Parameters: 170 . s - pointer to string 171 172 Output Parameter: 173 . t - the copied string 174 175 Level: intermediate 176 177 Note: 178 Null string returns a new null string 179 180 Not for use in Fortran 181 182 Warning: If t has previously been allocated then that memory is lost, you may need to PetscFree() 183 the array before calling this routine. 184 185 .seealso: `PetscStrArrayallocpy()`, `PetscStrcpy()`, `PetscStrNArrayallocpy()` 186 187 @*/ 188 PetscErrorCode PetscStrallocpy(const char s[], char *t[]) { 189 char *tmp = NULL; 190 191 PetscFunctionBegin; 192 if (s) { 193 size_t len; 194 195 PetscCall(PetscStrlen(s, &len)); 196 PetscCall(PetscMalloc1(1 + len, &tmp)); 197 PetscCall(PetscStrcpy(tmp, s)); 198 } 199 *t = tmp; 200 PetscFunctionReturn(0); 201 } 202 203 /*@C 204 PetscStrArrayallocpy - Allocates space to hold a copy of an array of strings then copies the strings 205 206 Not Collective 207 208 Input Parameters: 209 . s - pointer to array of strings (final string is a null) 210 211 Output Parameter: 212 . t - the copied array string 213 214 Level: intermediate 215 216 Note: 217 Not for use in Fortran 218 219 Warning: If t has previously been allocated then that memory is lost, you may need to PetscStrArrayDestroy() 220 the array before calling this routine. 221 222 .seealso: `PetscStrallocpy()`, `PetscStrArrayDestroy()`, `PetscStrNArrayallocpy()` 223 224 @*/ 225 PetscErrorCode PetscStrArrayallocpy(const char *const *list, char ***t) { 226 PetscInt n = 0; 227 228 PetscFunctionBegin; 229 while (list[n++]) 230 ; 231 PetscCall(PetscMalloc1(n + 1, t)); 232 for (PetscInt i = 0; i < n; i++) PetscCall(PetscStrallocpy(list[i], (*t) + i)); 233 (*t)[n] = NULL; 234 PetscFunctionReturn(0); 235 } 236 237 /*@C 238 PetscStrArrayDestroy - Frees array of strings created with PetscStrArrayallocpy(). 239 240 Not Collective 241 242 Output Parameters: 243 . list - array of strings 244 245 Level: intermediate 246 247 Notes: 248 Not for use in Fortran 249 250 .seealso: `PetscStrArrayallocpy()` 251 252 @*/ 253 PetscErrorCode PetscStrArrayDestroy(char ***list) { 254 PetscInt n = 0; 255 256 PetscFunctionBegin; 257 if (!*list) PetscFunctionReturn(0); 258 while ((*list)[n]) { 259 PetscCall(PetscFree((*list)[n])); 260 ++n; 261 } 262 PetscCall(PetscFree(*list)); 263 PetscFunctionReturn(0); 264 } 265 266 /*@C 267 PetscStrNArrayallocpy - Allocates space to hold a copy of an array of strings then copies the strings 268 269 Not Collective 270 271 Input Parameters: 272 + n - the number of string entries 273 - s - pointer to array of strings 274 275 Output Parameter: 276 . t - the copied array string 277 278 Level: intermediate 279 280 Note: 281 Not for use in Fortran 282 283 .seealso: `PetscStrallocpy()`, `PetscStrArrayallocpy()`, `PetscStrNArrayDestroy()` 284 285 @*/ 286 PetscErrorCode PetscStrNArrayallocpy(PetscInt n, const char *const *list, char ***t) { 287 PetscFunctionBegin; 288 PetscCall(PetscMalloc1(n, t)); 289 for (PetscInt i = 0; i < n; i++) PetscCall(PetscStrallocpy(list[i], (*t) + i)); 290 PetscFunctionReturn(0); 291 } 292 293 /*@C 294 PetscStrNArrayDestroy - Frees array of strings created with PetscStrArrayallocpy(). 295 296 Not Collective 297 298 Output Parameters: 299 + n - number of string entries 300 - list - array of strings 301 302 Level: intermediate 303 304 Notes: 305 Not for use in Fortran 306 307 .seealso: `PetscStrArrayallocpy()` 308 309 @*/ 310 PetscErrorCode PetscStrNArrayDestroy(PetscInt n, char ***list) { 311 PetscFunctionBegin; 312 if (!*list) PetscFunctionReturn(0); 313 for (PetscInt i = 0; i < n; i++) PetscCall(PetscFree((*list)[i])); 314 PetscCall(PetscFree(*list)); 315 PetscFunctionReturn(0); 316 } 317 318 /*@C 319 PetscStrcpy - Copies a string 320 321 Not Collective 322 323 Input Parameters: 324 . t - pointer to string 325 326 Output Parameter: 327 . s - the copied string 328 329 Level: intermediate 330 331 Notes: 332 Null string returns a string starting with zero 333 334 Not for use in Fortran 335 336 It is recommended you use PetscStrncpy() instead of this routine 337 338 .seealso: `PetscStrncpy()`, `PetscStrcat()`, `PetscStrlcat()` 339 340 @*/ 341 342 PetscErrorCode PetscStrcpy(char s[], const char t[]) { 343 PetscFunctionBegin; 344 if (t) { 345 PetscValidCharPointer(s, 1); 346 PetscValidCharPointer(t, 2); 347 strcpy(s, t); 348 } else if (s) s[0] = 0; 349 PetscFunctionReturn(0); 350 } 351 352 /*@C 353 PetscStrncpy - Copies a string up to a certain length 354 355 Not Collective 356 357 Input Parameters: 358 + t - pointer to string 359 - n - the length to copy 360 361 Output Parameter: 362 . s - the copied string 363 364 Level: intermediate 365 366 Note: 367 Null string returns a string starting with zero 368 369 If the string that is being copied is of length n or larger then the entire string is not 370 copied and the final location of s is set to NULL. This is different then the behavior of 371 strncpy() which leaves s non-terminated if there is not room for the entire string. 372 373 Developers Note: Should this be PetscStrlcpy() to reflect its behavior which is like strlcpy() not strncpy() 374 375 .seealso: `PetscStrcpy()`, `PetscStrcat()`, `PetscStrlcat()` 376 377 @*/ 378 PetscErrorCode PetscStrncpy(char s[], const char t[], size_t n) { 379 PetscFunctionBegin; 380 if (s) PetscCheck(n, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Requires an output string of length at least 1 to hold the termination character"); 381 if (t) { 382 PetscValidCharPointer(s, 1); 383 if (n > 1) { 384 strncpy(s, t, n - 1); 385 s[n - 1] = '\0'; 386 } else { 387 s[0] = '\0'; 388 } 389 } else if (s) s[0] = 0; 390 PetscFunctionReturn(0); 391 } 392 393 /*@C 394 PetscStrcat - Concatenates a string onto a given string 395 396 Not Collective 397 398 Input Parameters: 399 + s - string to be added to 400 - t - pointer to string to be added to end 401 402 Level: intermediate 403 404 Notes: 405 Not for use in Fortran 406 407 It is recommended you use PetscStrlcat() instead of this routine 408 409 .seealso: `PetscStrcpy()`, `PetscStrncpy()`, `PetscStrlcat()` 410 411 @*/ 412 PetscErrorCode PetscStrcat(char s[], const char t[]) { 413 PetscFunctionBegin; 414 if (!t) PetscFunctionReturn(0); 415 PetscValidCharPointer(s, 1); 416 PetscValidCharPointer(t, 2); 417 strcat(s, t); 418 PetscFunctionReturn(0); 419 } 420 421 /*@C 422 PetscStrlcat - Concatenates a string onto a given string, up to a given length 423 424 Not Collective 425 426 Input Parameters: 427 + s - pointer to string to be added to at end 428 . t - string to be added 429 - n - length of the original allocated string 430 431 Level: intermediate 432 433 Notes: 434 Not for use in Fortran 435 436 Unlike the system call strncat(), the length passed in is the length of the 437 original allocated space, not the length of the left-over space. This is 438 similar to the BSD system call strlcat(). 439 440 .seealso: `PetscStrcpy()`, `PetscStrncpy()`, `PetscStrcat()` 441 442 @*/ 443 PetscErrorCode PetscStrlcat(char s[], const char t[], size_t n) { 444 size_t len; 445 446 PetscFunctionBegin; 447 if (!t) PetscFunctionReturn(0); 448 PetscValidCharPointer(s, 1); 449 PetscValidCharPointer(t, 2); 450 PetscCheck(n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "String buffer length must be positive"); 451 PetscCall(PetscStrlen(t, &len)); 452 strncat(s, t, n - len); 453 s[n - 1] = 0; 454 PetscFunctionReturn(0); 455 } 456 457 void PetscStrcmpNoError(const char a[], const char b[], PetscBool *flg) { 458 if (!a && !b) *flg = PETSC_TRUE; 459 else if (!a || !b) *flg = PETSC_FALSE; 460 else *flg = strcmp(a, b) ? PETSC_FALSE : PETSC_TRUE; 461 } 462 463 /*@C 464 PetscBasename - returns a pointer to the last entry of a / or \ seperated directory path 465 466 Not Collective 467 468 Input Parameter: 469 . a - pointer to string 470 471 Level: intermediate 472 473 Notes: 474 Not for use in Fortran 475 476 Works for both Unix and Windows path separators 477 478 .seealso: `PetscStrgrt()`, `PetscStrncmp()`, `PetscStrcasecmp()`, `PetscStrrchr()`,`PetscStrcmp()`,`PetscStrstr()`, 479 `PetscTokenCreate()`, `PetscStrToArray()`, `PetscStrInList()` 480 @*/ 481 const char *PetscBasename(const char a[]) { 482 const char *ptr; 483 484 if (PetscStrrchr(a, '/', (char **)&ptr)) ptr = NULL; 485 if (ptr == a) { 486 if (PetscStrrchr(a, '\\', (char **)&ptr)) ptr = NULL; 487 } 488 return ptr; 489 } 490 491 /*@C 492 PetscStrcmp - Compares two strings, 493 494 Not Collective 495 496 Input Parameters: 497 + a - pointer to string first string 498 - b - pointer to second string 499 500 Output Parameter: 501 . flg - PETSC_TRUE if the two strings are equal 502 503 Level: intermediate 504 505 Notes: 506 Not for use in Fortran 507 508 .seealso: `PetscStrgrt()`, `PetscStrncmp()`, `PetscStrcasecmp()` 509 @*/ 510 PetscErrorCode PetscStrcmp(const char a[], const char b[], PetscBool *flg) { 511 PetscFunctionBegin; 512 PetscValidBoolPointer(flg, 3); 513 if (!a && !b) *flg = PETSC_TRUE; 514 else if (!a || !b) *flg = PETSC_FALSE; 515 else *flg = (PetscBool)!strcmp(a, b); 516 PetscFunctionReturn(0); 517 } 518 519 /*@C 520 PetscStrgrt - If first string is greater than the second 521 522 Not Collective 523 524 Input Parameters: 525 + a - pointer to first string 526 - b - pointer to second string 527 528 Output Parameter: 529 . flg - if the first string is greater 530 531 Notes: 532 Null arguments are ok, a null string is considered smaller than 533 all others 534 535 Not for use in Fortran 536 537 Level: intermediate 538 539 .seealso: `PetscStrcmp()`, `PetscStrncmp()`, `PetscStrcasecmp()` 540 541 @*/ 542 PetscErrorCode PetscStrgrt(const char a[], const char b[], PetscBool *t) { 543 PetscFunctionBegin; 544 PetscValidBoolPointer(t, 3); 545 if (!a && !b) *t = PETSC_FALSE; 546 else if (a && !b) *t = PETSC_TRUE; 547 else if (!a && b) *t = PETSC_FALSE; 548 else { 549 PetscValidCharPointer(a, 1); 550 PetscValidCharPointer(b, 2); 551 *t = strcmp(a, b) > 0 ? PETSC_TRUE : PETSC_FALSE; 552 } 553 PetscFunctionReturn(0); 554 } 555 556 /*@C 557 PetscStrcasecmp - Returns true if the two strings are the same 558 except possibly for case. 559 560 Not Collective 561 562 Input Parameters: 563 + a - pointer to first string 564 - b - pointer to second string 565 566 Output Parameter: 567 . flg - if the two strings are the same 568 569 Notes: 570 Null arguments are ok 571 572 Not for use in Fortran 573 574 Level: intermediate 575 576 .seealso: `PetscStrcmp()`, `PetscStrncmp()`, `PetscStrgrt()` 577 578 @*/ 579 PetscErrorCode PetscStrcasecmp(const char a[], const char b[], PetscBool *t) { 580 int c; 581 582 PetscFunctionBegin; 583 PetscValidBoolPointer(t, 3); 584 if (!a && !b) c = 0; 585 else if (!a || !b) c = 1; 586 #if defined(PETSC_HAVE_STRCASECMP) 587 else c = strcasecmp(a, b); 588 #elif defined(PETSC_HAVE_STRICMP) 589 else c = stricmp(a, b); 590 #else 591 else { 592 char *aa, *bb; 593 PetscCall(PetscStrallocpy(a, &aa)); 594 PetscCall(PetscStrallocpy(b, &bb)); 595 PetscCall(PetscStrtolower(aa)); 596 PetscCall(PetscStrtolower(bb)); 597 PetscCall(PetscStrcmp(aa, bb, t)); 598 PetscCall(PetscFree(aa)); 599 PetscCall(PetscFree(bb)); 600 PetscFunctionReturn(0); 601 } 602 #endif 603 *t = c ? PETSC_FALSE : PETSC_TRUE; 604 PetscFunctionReturn(0); 605 } 606 607 /*@C 608 PetscStrncmp - Compares two strings, up to a certain length 609 610 Not Collective 611 612 Input Parameters: 613 + a - pointer to first string 614 . b - pointer to second string 615 - n - length to compare up to 616 617 Output Parameter: 618 . t - if the two strings are equal 619 620 Level: intermediate 621 622 Notes: 623 Not for use in Fortran 624 625 .seealso: `PetscStrgrt()`, `PetscStrcmp()`, `PetscStrcasecmp()` 626 627 @*/ 628 PetscErrorCode PetscStrncmp(const char a[], const char b[], size_t n, PetscBool *t) { 629 PetscFunctionBegin; 630 if (n) { 631 PetscValidCharPointer(a, 1); 632 PetscValidCharPointer(b, 2); 633 } 634 PetscValidBoolPointer(t, 4); 635 *t = strncmp(a, b, n) ? PETSC_FALSE : PETSC_TRUE; 636 PetscFunctionReturn(0); 637 } 638 639 /*@C 640 PetscStrchr - Locates first occurrence of a character in a string 641 642 Not Collective 643 644 Input Parameters: 645 + a - pointer to string 646 - b - character 647 648 Output Parameter: 649 . c - location of occurrence, NULL if not found 650 651 Level: intermediate 652 653 Notes: 654 Not for use in Fortran 655 656 @*/ 657 PetscErrorCode PetscStrchr(const char a[], char b, char *c[]) { 658 PetscFunctionBegin; 659 PetscValidCharPointer(a, 1); 660 PetscValidPointer(c, 3); 661 *c = (char *)strchr(a, b); 662 PetscFunctionReturn(0); 663 } 664 665 /*@C 666 PetscStrrchr - Locates one location past the last occurrence of a character in a string, 667 if the character is not found then returns entire string 668 669 Not Collective 670 671 Input Parameters: 672 + a - pointer to string 673 - b - character 674 675 Output Parameter: 676 . tmp - location of occurrence, a if not found 677 678 Level: intermediate 679 680 Notes: 681 Not for use in Fortran 682 683 @*/ 684 PetscErrorCode PetscStrrchr(const char a[], char b, char *tmp[]) { 685 PetscFunctionBegin; 686 PetscValidCharPointer(a, 1); 687 PetscValidPointer(tmp, 3); 688 *tmp = (char *)strrchr(a, b); 689 if (!*tmp) *tmp = (char *)a; 690 else *tmp = *tmp + 1; 691 PetscFunctionReturn(0); 692 } 693 694 /*@C 695 PetscStrtolower - Converts string to lower case 696 697 Not Collective 698 699 Input Parameters: 700 . a - pointer to string 701 702 Level: intermediate 703 704 Notes: 705 Not for use in Fortran 706 707 @*/ 708 PetscErrorCode PetscStrtolower(char a[]) { 709 PetscFunctionBegin; 710 PetscValidCharPointer(a, 1); 711 while (*a) { 712 if (*a >= 'A' && *a <= 'Z') *a += 'a' - 'A'; 713 a++; 714 } 715 PetscFunctionReturn(0); 716 } 717 718 /*@C 719 PetscStrtoupper - Converts string to upper case 720 721 Not Collective 722 723 Input Parameters: 724 . a - pointer to string 725 726 Level: intermediate 727 728 Notes: 729 Not for use in Fortran 730 731 @*/ 732 PetscErrorCode PetscStrtoupper(char a[]) { 733 PetscFunctionBegin; 734 PetscValidCharPointer(a, 1); 735 while (*a) { 736 if (*a >= 'a' && *a <= 'z') *a += 'A' - 'a'; 737 a++; 738 } 739 PetscFunctionReturn(0); 740 } 741 742 /*@C 743 PetscStrendswith - Determines if a string ends with a certain string 744 745 Not Collective 746 747 Input Parameters: 748 + a - pointer to string 749 - b - string to endwith 750 751 Output Parameter: 752 . flg - PETSC_TRUE or PETSC_FALSE 753 754 Notes: 755 Not for use in Fortran 756 757 Level: intermediate 758 759 @*/ 760 PetscErrorCode PetscStrendswith(const char a[], const char b[], PetscBool *flg) { 761 char *test; 762 763 PetscFunctionBegin; 764 PetscValidBoolPointer(flg, 3); 765 *flg = PETSC_FALSE; 766 PetscCall(PetscStrrstr(a, b, &test)); 767 if (test) { 768 size_t na, nb; 769 770 PetscCall(PetscStrlen(a, &na)); 771 PetscCall(PetscStrlen(b, &nb)); 772 if (a + na - nb == test) *flg = PETSC_TRUE; 773 } 774 PetscFunctionReturn(0); 775 } 776 777 /*@C 778 PetscStrbeginswith - Determines if a string begins with a certain string 779 780 Not Collective 781 782 Input Parameters: 783 + a - pointer to string 784 - b - string to begin with 785 786 Output Parameter: 787 . flg - PETSC_TRUE or PETSC_FALSE 788 789 Notes: 790 Not for use in Fortran 791 792 Level: intermediate 793 794 .seealso: `PetscStrendswithwhich()`, `PetscStrendswith()`, `PetscStrtoupper`, `PetscStrtolower()`, `PetscStrrchr()`, `PetscStrchr()`, 795 `PetscStrncmp()`, `PetscStrlen()`, `PetscStrncmp()`, `PetscStrcmp()` 796 797 @*/ 798 PetscErrorCode PetscStrbeginswith(const char a[], const char b[], PetscBool *flg) { 799 char *test; 800 801 PetscFunctionBegin; 802 PetscValidCharPointer(a, 1); 803 PetscValidCharPointer(b, 2); 804 PetscValidBoolPointer(flg, 3); 805 *flg = PETSC_FALSE; 806 PetscCall(PetscStrrstr(a, b, &test)); 807 if (test && (test == a)) *flg = PETSC_TRUE; 808 PetscFunctionReturn(0); 809 } 810 811 /*@C 812 PetscStrendswithwhich - Determines if a string ends with one of several possible strings 813 814 Not Collective 815 816 Input Parameters: 817 + a - pointer to string 818 - bs - strings to end with (last entry must be NULL) 819 820 Output Parameter: 821 . cnt - the index of the string it ends with or the index of NULL 822 823 Notes: 824 Not for use in Fortran 825 826 Level: intermediate 827 828 @*/ 829 PetscErrorCode PetscStrendswithwhich(const char a[], const char *const *bs, PetscInt *cnt) { 830 PetscFunctionBegin; 831 PetscValidPointer(bs, 2); 832 PetscValidIntPointer(cnt, 3); 833 *cnt = 0; 834 while (bs[*cnt]) { 835 PetscBool flg; 836 837 PetscCall(PetscStrendswith(a, bs[*cnt], &flg)); 838 if (flg) PetscFunctionReturn(0); 839 ++(*cnt); 840 } 841 PetscFunctionReturn(0); 842 } 843 844 /*@C 845 PetscStrrstr - Locates last occurrence of string in another string 846 847 Not Collective 848 849 Input Parameters: 850 + a - pointer to string 851 - b - string to find 852 853 Output Parameter: 854 . tmp - location of occurrence 855 856 Notes: 857 Not for use in Fortran 858 859 Level: intermediate 860 861 @*/ 862 PetscErrorCode PetscStrrstr(const char a[], const char b[], char *tmp[]) { 863 const char *ltmp = NULL; 864 865 PetscFunctionBegin; 866 PetscValidCharPointer(a, 1); 867 PetscValidCharPointer(b, 2); 868 PetscValidPointer(tmp, 3); 869 while (a) { 870 a = (char *)strstr(a, b); 871 if (a) ltmp = a++; 872 } 873 *tmp = (char *)ltmp; 874 PetscFunctionReturn(0); 875 } 876 877 /*@C 878 PetscStrstr - Locates first occurrence of string in another string 879 880 Not Collective 881 882 Input Parameters: 883 + haystack - string to search 884 - needle - string to find 885 886 Output Parameter: 887 . tmp - location of occurrence, is a NULL if the string is not found 888 889 Notes: 890 Not for use in Fortran 891 892 Level: intermediate 893 894 @*/ 895 PetscErrorCode PetscStrstr(const char haystack[], const char needle[], char *tmp[]) { 896 PetscFunctionBegin; 897 PetscValidCharPointer(haystack, 1); 898 PetscValidCharPointer(needle, 2); 899 PetscValidPointer(tmp, 3); 900 *tmp = (char *)strstr(haystack, needle); 901 PetscFunctionReturn(0); 902 } 903 904 struct _p_PetscToken { 905 char token; 906 char *array; 907 char *current; 908 }; 909 910 /*@C 911 PetscTokenFind - Locates next "token" in a string 912 913 Not Collective 914 915 Input Parameters: 916 . a - pointer to token 917 918 Output Parameter: 919 . result - location of occurrence, NULL if not found 920 921 Notes: 922 923 This version is different from the system version in that 924 it allows you to pass a read-only string into the function. 925 926 This version also treats all characters etc. inside a double quote " 927 as a single token. 928 929 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 930 second will return a null terminated y 931 932 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 933 934 Not for use in Fortran 935 936 Level: intermediate 937 938 .seealso: `PetscTokenCreate()`, `PetscTokenDestroy()` 939 @*/ 940 PetscErrorCode PetscTokenFind(PetscToken a, char *result[]) { 941 char *ptr, token; 942 943 PetscFunctionBegin; 944 PetscValidPointer(a, 1); 945 PetscValidPointer(result, 2); 946 *result = ptr = a->current; 947 if (ptr && !*ptr) { 948 *result = NULL; 949 PetscFunctionReturn(0); 950 } 951 token = a->token; 952 if (ptr && (*ptr == '"')) { 953 token = '"'; 954 (*result)++; 955 ptr++; 956 } 957 while (ptr) { 958 if (*ptr == token) { 959 *ptr++ = 0; 960 while (*ptr == a->token) ptr++; 961 a->current = ptr; 962 break; 963 } 964 if (!*ptr) { 965 a->current = NULL; 966 break; 967 } 968 ptr++; 969 } 970 PetscFunctionReturn(0); 971 } 972 973 /*@C 974 PetscTokenCreate - Creates a PetscToken used to find tokens in a string 975 976 Not Collective 977 978 Input Parameters: 979 + string - the string to look in 980 - b - the separator character 981 982 Output Parameter: 983 . t- the token object 984 985 Notes: 986 987 This version is different from the system version in that 988 it allows you to pass a read-only string into the function. 989 990 Not for use in Fortran 991 992 Level: intermediate 993 994 .seealso: `PetscTokenFind()`, `PetscTokenDestroy()` 995 @*/ 996 PetscErrorCode PetscTokenCreate(const char a[], const char b, PetscToken *t) { 997 PetscFunctionBegin; 998 PetscValidCharPointer(a, 1); 999 PetscValidPointer(t, 3); 1000 PetscCall(PetscNew(t)); 1001 PetscCall(PetscStrallocpy(a, &(*t)->array)); 1002 1003 (*t)->current = (*t)->array; 1004 (*t)->token = b; 1005 PetscFunctionReturn(0); 1006 } 1007 1008 /*@C 1009 PetscTokenDestroy - Destroys a PetscToken 1010 1011 Not Collective 1012 1013 Input Parameters: 1014 . a - pointer to token 1015 1016 Level: intermediate 1017 1018 Notes: 1019 Not for use in Fortran 1020 1021 .seealso: `PetscTokenCreate()`, `PetscTokenFind()` 1022 @*/ 1023 PetscErrorCode PetscTokenDestroy(PetscToken *a) { 1024 PetscFunctionBegin; 1025 if (!*a) PetscFunctionReturn(0); 1026 PetscCall(PetscFree((*a)->array)); 1027 PetscCall(PetscFree(*a)); 1028 PetscFunctionReturn(0); 1029 } 1030 1031 /*@C 1032 PetscStrInList - search string in character-delimited list 1033 1034 Not Collective 1035 1036 Input Parameters: 1037 + str - the string to look for 1038 . list - the list to search in 1039 - sep - the separator character 1040 1041 Output Parameter: 1042 . found - whether str is in list 1043 1044 Level: intermediate 1045 1046 Notes: 1047 Not for use in Fortran 1048 1049 .seealso: `PetscTokenCreate()`, `PetscTokenFind()`, `PetscStrcmp()` 1050 @*/ 1051 PetscErrorCode PetscStrInList(const char str[], const char list[], char sep, PetscBool *found) { 1052 PetscToken token; 1053 char *item; 1054 1055 PetscFunctionBegin; 1056 PetscValidBoolPointer(found, 4); 1057 *found = PETSC_FALSE; 1058 PetscCall(PetscTokenCreate(list, sep, &token)); 1059 PetscCall(PetscTokenFind(token, &item)); 1060 while (item) { 1061 PetscCall(PetscStrcmp(str, item, found)); 1062 if (*found) break; 1063 PetscCall(PetscTokenFind(token, &item)); 1064 } 1065 PetscCall(PetscTokenDestroy(&token)); 1066 PetscFunctionReturn(0); 1067 } 1068 1069 /*@C 1070 PetscGetPetscDir - Gets the directory PETSc is installed in 1071 1072 Not Collective 1073 1074 Output Parameter: 1075 . dir - the directory 1076 1077 Level: developer 1078 1079 Notes: 1080 Not for use in Fortran 1081 1082 @*/ 1083 PetscErrorCode PetscGetPetscDir(const char *dir[]) { 1084 PetscFunctionBegin; 1085 PetscValidPointer(dir, 1); 1086 *dir = PETSC_DIR; 1087 PetscFunctionReturn(0); 1088 } 1089 1090 /*@C 1091 PetscStrreplace - Replaces substrings in string with other substrings 1092 1093 Not Collective 1094 1095 Input Parameters: 1096 + comm - MPI_Comm of processors that are processing the string 1097 . aa - the string to look in 1098 . b - the resulting copy of a with replaced strings (b can be the same as a) 1099 - len - the length of b 1100 1101 Notes: 1102 Replaces ${PETSC_ARCH},${PETSC_DIR},${PETSC_LIB_DIR},${DISPLAY}, 1103 ${HOMEDIRECTORY},${WORKINGDIRECTORY},${USERNAME}, ${HOSTNAME} with appropriate values 1104 as well as any environmental variables. 1105 1106 PETSC_LIB_DIR uses the environmental variable if it exists. PETSC_ARCH and PETSC_DIR use what 1107 PETSc was built with and do not use environmental variables. 1108 1109 Not for use in Fortran 1110 1111 Level: intermediate 1112 1113 @*/ 1114 PetscErrorCode PetscStrreplace(MPI_Comm comm, const char aa[], char b[], size_t len) { 1115 int i = 0; 1116 size_t l, l1, l2, l3; 1117 char *work, *par, *epar, env[1024], *tfree, *a = (char *)aa; 1118 const char *s[] = {"${PETSC_ARCH}", "${PETSC_DIR}", "${PETSC_LIB_DIR}", "${DISPLAY}", "${HOMEDIRECTORY}", "${WORKINGDIRECTORY}", "${USERNAME}", "${HOSTNAME}", NULL}; 1119 char *r[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; 1120 PetscBool flag; 1121 static size_t DISPLAY_LENGTH = 265, USER_LENGTH = 256, HOST_LENGTH = 256; 1122 1123 PetscFunctionBegin; 1124 PetscValidCharPointer(aa, 2); 1125 PetscValidCharPointer(b, 3); 1126 if (aa == b) PetscCall(PetscStrallocpy(aa, (char **)&a)); 1127 PetscCall(PetscMalloc1(len, &work)); 1128 1129 /* get values for replaced variables */ 1130 PetscCall(PetscStrallocpy(PETSC_ARCH, &r[0])); 1131 PetscCall(PetscStrallocpy(PETSC_DIR, &r[1])); 1132 PetscCall(PetscStrallocpy(PETSC_LIB_DIR, &r[2])); 1133 PetscCall(PetscMalloc1(DISPLAY_LENGTH, &r[3])); 1134 PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN, &r[4])); 1135 PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN, &r[5])); 1136 PetscCall(PetscMalloc1(USER_LENGTH, &r[6])); 1137 PetscCall(PetscMalloc1(HOST_LENGTH, &r[7])); 1138 PetscCall(PetscGetDisplay(r[3], DISPLAY_LENGTH)); 1139 PetscCall(PetscGetHomeDirectory(r[4], PETSC_MAX_PATH_LEN)); 1140 PetscCall(PetscGetWorkingDirectory(r[5], PETSC_MAX_PATH_LEN)); 1141 PetscCall(PetscGetUserName(r[6], USER_LENGTH)); 1142 PetscCall(PetscGetHostName(r[7], HOST_LENGTH)); 1143 1144 /* replace that are in environment */ 1145 PetscCall(PetscOptionsGetenv(comm, "PETSC_LIB_DIR", env, sizeof(env), &flag)); 1146 if (flag) { 1147 PetscCall(PetscFree(r[2])); 1148 PetscCall(PetscStrallocpy(env, &r[2])); 1149 } 1150 1151 /* replace the requested strings */ 1152 PetscCall(PetscStrncpy(b, a, len)); 1153 while (s[i]) { 1154 PetscCall(PetscStrlen(s[i], &l)); 1155 PetscCall(PetscStrstr(b, s[i], &par)); 1156 while (par) { 1157 *par = 0; 1158 par += l; 1159 1160 PetscCall(PetscStrlen(b, &l1)); 1161 PetscCall(PetscStrlen(r[i], &l2)); 1162 PetscCall(PetscStrlen(par, &l3)); 1163 PetscCheck(l1 + l2 + l3 < len, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "b len is not long enough to hold new values"); 1164 PetscCall(PetscStrncpy(work, b, len)); 1165 PetscCall(PetscStrlcat(work, r[i], len)); 1166 PetscCall(PetscStrlcat(work, par, len)); 1167 PetscCall(PetscStrncpy(b, work, len)); 1168 PetscCall(PetscStrstr(b, s[i], &par)); 1169 } 1170 i++; 1171 } 1172 i = 0; 1173 while (r[i]) { 1174 tfree = (char *)r[i]; 1175 PetscCall(PetscFree(tfree)); 1176 i++; 1177 } 1178 1179 /* look for any other ${xxx} strings to replace from environmental variables */ 1180 PetscCall(PetscStrstr(b, "${", &par)); 1181 while (par) { 1182 *par = 0; 1183 par += 2; 1184 PetscCall(PetscStrncpy(work, b, len)); 1185 PetscCall(PetscStrstr(par, "}", &epar)); 1186 *epar = 0; 1187 epar += 1; 1188 PetscCall(PetscOptionsGetenv(comm, par, env, sizeof(env), &flag)); 1189 PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Substitution string ${%s} not found as environmental variable", par); 1190 PetscCall(PetscStrlcat(work, env, len)); 1191 PetscCall(PetscStrlcat(work, epar, len)); 1192 PetscCall(PetscStrncpy(b, work, len)); 1193 PetscCall(PetscStrstr(b, "${", &par)); 1194 } 1195 PetscCall(PetscFree(work)); 1196 if (aa == b) PetscCall(PetscFree(a)); 1197 PetscFunctionReturn(0); 1198 } 1199 1200 /*@C 1201 PetscEListFind - searches list of strings for given string, using case insensitive matching 1202 1203 Not Collective 1204 1205 Input Parameters: 1206 + n - number of strings in 1207 . list - list of strings to search 1208 - str - string to look for, empty string "" accepts default (first entry in list) 1209 1210 Output Parameters: 1211 + value - index of matching string (if found) 1212 - found - boolean indicating whether string was found (can be NULL) 1213 1214 Notes: 1215 Not for use in Fortran 1216 1217 Level: advanced 1218 @*/ 1219 PetscErrorCode PetscEListFind(PetscInt n, const char *const *list, const char *str, PetscInt *value, PetscBool *found) { 1220 PetscFunctionBegin; 1221 if (found) { 1222 PetscValidBoolPointer(found, 5); 1223 *found = PETSC_FALSE; 1224 } 1225 for (PetscInt i = 0; i < n; ++i) { 1226 PetscBool matched; 1227 1228 PetscCall(PetscStrcasecmp(str, list[i], &matched)); 1229 if (matched || !str[0]) { 1230 if (found) *found = PETSC_TRUE; 1231 *value = i; 1232 break; 1233 } 1234 } 1235 PetscFunctionReturn(0); 1236 } 1237 1238 /*@C 1239 PetscEnumFind - searches enum list of strings for given string, using case insensitive matching 1240 1241 Not Collective 1242 1243 Input Parameters: 1244 + enumlist - list of strings to search, followed by enum name, then enum prefix, then NUL 1245 - str - string to look for 1246 1247 Output Parameters: 1248 + value - index of matching string (if found) 1249 - found - boolean indicating whether string was found (can be NULL) 1250 1251 Notes: 1252 Not for use in Fortran 1253 1254 Level: advanced 1255 @*/ 1256 PetscErrorCode PetscEnumFind(const char *const *enumlist, const char *str, PetscEnum *value, PetscBool *found) { 1257 PetscInt n = 0, evalue; 1258 PetscBool efound; 1259 1260 PetscFunctionBegin; 1261 PetscValidPointer(enumlist, 1); 1262 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"); 1263 PetscCheck(n >= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument must have at least two entries: typename and type prefix"); 1264 n -= 3; /* drop enum name, prefix, and null termination */ 1265 PetscCall(PetscEListFind(n, enumlist, str, &evalue, &efound)); 1266 if (efound) { 1267 PetscValidPointer(value, 3); 1268 *value = (PetscEnum)evalue; 1269 } 1270 if (found) { 1271 PetscValidBoolPointer(found, 4); 1272 *found = efound; 1273 } 1274 PetscFunctionReturn(0); 1275 } 1276 1277 /*@C 1278 PetscCIFilename - returns the basename of a file name when the PETSc CI portable error output mode is enabled. 1279 1280 Not collective 1281 1282 Input Parameter: 1283 . file - the file name 1284 1285 Note: 1286 PETSc CI mode is a mode of running PETSc where output (both error and non-error) is made portable across all systems 1287 so that comparisons of output between runs are easy to make. 1288 1289 This mode is used for all tests in the test harness, it applies to both debug and optimized builds. 1290 1291 Use the option -petsc_ci to turn on PETSc CI mode. It changes certain output in non-error situations to be portable for 1292 all systems, mainly the output of options. It is passed to all PETSc programs automatically by the test harness. 1293 1294 Always uses the Unix / as the file separate even on Microsoft Windows systems 1295 1296 The option -petsc_ci_portable_error_output attempts to output the same error messages on all systems for the test harness. 1297 In particular the output of filenames and line numbers in PETSc stacks. This is to allow (limited) checking of PETSc 1298 error handling by the test harness. This options also causes PETSc to attempt to return an error code of 0 so that the test 1299 harness can process the output for differences in the usual manner as for successful runs. It should be provided to the test 1300 harness in the args: argument for specific examples. It will not neccessarily produce portable output if different errors 1301 (or no errors) occur on a subset of the MPI ranks. 1302 1303 Level: developer 1304 1305 .seealso: `PetscCILinenumber()` 1306 1307 @*/ 1308 const char *PetscCIFilename(const char *file) { 1309 if (!PetscCIEnabledPortableErrorOutput) return file; 1310 return PetscBasename(file); 1311 } 1312 1313 /*@C 1314 PetscCILinenumber - returns a line number except if PetscCIEnablePortableErrorOutput) is set when it returns 0 1315 1316 Not collective 1317 1318 Input Parameter: 1319 . linenumber - the initial line number 1320 1321 Note: 1322 See `PetscCIFilename()` for details on usage 1323 1324 Level: developer 1325 1326 .seealso: `PetscCIFilename()` 1327 1328 @*/ 1329 int PetscCILinenumber(int linenumber) { 1330 if (!PetscCIEnabledPortableErrorOutput) return linenumber; 1331 return 0; 1332 } 1333