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