Date: 2026-03-01T05:25:14+00:00

Actual source code: str.c

      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>
      7: #if defined(PETSC_HAVE_STRINGS_H)
      8:   #include <strings.h> /* strcasecmp */
      9: #endif

     11: /*@C
     12:   PetscStrToArray - Separates a string by a character (for example ' ' or '\n') and creates an array of strings

     14:   Not Collective; No Fortran Support

     16:   Input Parameters:
     17: + s  - pointer to string
     18: - sp - separator character

     20:   Output Parameters:
     21: + argc - the number of entries in `args`
     22: - args - an array of the entries with a `NULL` at the end

     24:   Level: intermediate

     26:   Note:
     27:   This may be called before `PetscInitialize()` or after `PetscFinalize()`

     29:   Developer Notes:
     30:   Uses raw `malloc()` and does not call error handlers since this may be used before PETSc is initialized.

     32:   Used to generate `argc`, `args` arguments passed to `MPI_Init()`

     34: .seealso: `PetscStrToArrayDestroy()`, `PetscToken`, `PetscTokenCreate()`
     35: @*/
     36: PetscErrorCode PetscStrToArray(const char s[], char sp, int *argc, char ***args)
     37: {
     38:   int       n, i, j, *lens, cnt = 0;
     39:   PetscBool flg = PETSC_FALSE;

     41:   if (!s) n = 0;
     42:   else n = (int)strlen(s);
     43:   *argc = 0;
     44:   *args = NULL;
     45:   for (; n > 0; n--) { /* remove separator chars at the end - and will empty the string if all chars are separator chars */
     46:     if (s[n - 1] != sp) break;
     47:   }
     48:   if (!n) return PETSC_SUCCESS;
     49:   for (i = 0; i < n; i++) {
     50:     if (s[i] != sp) break;
     51:   }
     52:   for (; i < n + 1; i++) {
     53:     if ((s[i] == sp || s[i] == 0) && !flg) {
     54:       flg = PETSC_TRUE;
     55:       (*argc)++;
     56:     } else if (s[i] != sp) {
     57:       flg = PETSC_FALSE;
     58:     }
     59:   }
     60:   (*args) = (char **)malloc(((*argc) + 1) * sizeof(char *));
     61:   if (!*args) return PETSC_ERR_MEM;
     62:   lens = (int *)malloc(((*argc) + 1) * sizeof(int));
     63:   if (!lens) return PETSC_ERR_MEM;
     64:   for (i = 0; i < *argc; i++) lens[i] = 0;

     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:   }

     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;

     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: }

    110: /*@C
    111:   PetscStrToArrayDestroy - Frees array created with `PetscStrToArray()`.

    113:   Not Collective; No Fortran Support

    115:   Output Parameters:
    116: + argc - the number of arguments
    117: - args - the array of arguments

    119:   Level: intermediate

    121:   Note:
    122:   This may be called before `PetscInitialize()` or after `PetscFinalize()`

    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: }

    133: /*@C
    134:   PetscStrArrayallocpy - Allocates space to hold a copy of an array of strings then copies the strings

    136:   Not Collective; No Fortran Support

    138:   Input Parameter:
    139: . list - pointer to array of strings (final string is a `NULL`)

    141:   Output Parameter:
    142: . t - the copied array string

    144:   Level: intermediate

    146:   Note:
    147:   Use `PetscStrArrayDestroy()` to free the memory.

    149: .seealso: `PetscStrallocpy()`, `PetscStrArrayDestroy()`, `PetscStrNArrayallocpy()`
    150: @*/
    151: PetscErrorCode PetscStrArrayallocpy(const char *const *list, char ***t)
    152: {
    153:   PetscInt n = 0;

    155:   PetscFunctionBegin;
    156:   while (list[n++]);
    157:   PetscCall(PetscMalloc1(n + 1, t));
    158:   for (PetscInt i = 0; i < n; i++) PetscCall(PetscStrallocpy(list[i], (*t) + i));
    159:   (*t)[n] = NULL;
    160:   PetscFunctionReturn(PETSC_SUCCESS);
    161: }

    163: /*@C
    164:   PetscStrArrayDestroy - Frees array of strings created with `PetscStrArrayallocpy()`.

    166:   Not Collective; No Fortran Support

    168:   Output Parameter:
    169: . list - array of strings

    171:   Level: intermediate

    173: .seealso: `PetscStrArrayallocpy()`
    174: @*/
    175: PetscErrorCode PetscStrArrayDestroy(char ***list)
    176: {
    177:   PetscInt n = 0;

    179:   PetscFunctionBegin;
    180:   if (!*list) PetscFunctionReturn(PETSC_SUCCESS);
    181:   while ((*list)[n]) {
    182:     PetscCall(PetscFree((*list)[n]));
    183:     ++n;
    184:   }
    185:   PetscCall(PetscFree(*list));
    186:   PetscFunctionReturn(PETSC_SUCCESS);
    187: }

    189: /*@C
    190:   PetscStrNArrayallocpy - Allocates space to hold a copy of an array of strings then copies the strings

    192:   Not Collective; No Fortran Support

    194:   Input Parameters:
    195: + n    - the number of string entries
    196: - list - pointer to array of strings

    198:   Output Parameter:
    199: . t - the copied array string

    201:   Level: intermediate

    203:   Note:
    204:   Use `PetscStrNArrayDestroy()` to free the memory.

    206: .seealso: `PetscStrallocpy()`, `PetscStrArrayallocpy()`, `PetscStrNArrayDestroy()`
    207: @*/
    208: PetscErrorCode PetscStrNArrayallocpy(PetscInt n, const char *const *list, char ***t)
    209: {
    210:   PetscFunctionBegin;
    211:   PetscCall(PetscMalloc1(n, t));
    212:   for (PetscInt i = 0; i < n; i++) PetscCall(PetscStrallocpy(list[i], (*t) + i));
    213:   PetscFunctionReturn(PETSC_SUCCESS);
    214: }

    216: /*@C
    217:   PetscStrNArrayDestroy - Frees array of strings created with `PetscStrNArrayallocpy()`.

    219:   Not Collective; No Fortran Support

    221:   Output Parameters:
    222: + n    - number of string entries
    223: - list - array of strings

    225:   Level: intermediate

    227: .seealso: `PetscStrNArrayallocpy()`, `PetscStrArrayallocpy()`
    228: @*/
    229: PetscErrorCode PetscStrNArrayDestroy(PetscInt n, char ***list)
    230: {
    231:   PetscFunctionBegin;
    232:   if (!*list) PetscFunctionReturn(PETSC_SUCCESS);
    233:   for (PetscInt i = 0; i < n; i++) PetscCall(PetscFree((*list)[i]));
    234:   PetscCall(PetscFree(*list));
    235:   PetscFunctionReturn(PETSC_SUCCESS);
    236: }

    238: /*@C
    239:   PetscBasename - returns a pointer to the last entry of a / or \ separated directory path

    241:   Not Collective; No Fortran Support

    243:   Input Parameter:
    244: . a - pointer to string

    246:   Level: intermediate

    248: .seealso: `PetscStrgrt()`, `PetscStrncmp()`, `PetscStrcasecmp()`, `PetscStrrchr()`, `PetscStrcmp()`, `PetscStrstr()`,
    249:           `PetscTokenCreate()`, `PetscStrToArray()`, `PetscStrInList()`
    250: @*/
    251: const char *PetscBasename(const char a[])
    252: {
    253:   const char *ptr = NULL;

    255:   (void)PetscStrrchr(a, '/', (char **)&ptr);
    256:   if (ptr == a) {
    257:     if (PetscStrrchr(a, '\\', (char **)&ptr)) ptr = NULL;
    258:   }
    259:   return ptr;
    260: }

    262: /*@C
    263:   PetscStrcasecmp - Returns true if the two strings are the same
    264:   except possibly for case.

    266:   Not Collective; No Fortran Support

    268:   Input Parameters:
    269: + a - pointer to first string
    270: - b - pointer to second string

    272:   Output Parameter:
    273: . t - if the two strings are the same

    275:   Level: intermediate

    277:   Note:
    278:   `NULL` arguments are ok

    280: .seealso: `PetscStrcmp()`, `PetscStrncmp()`, `PetscStrgrt()`
    281: @*/
    282: PetscErrorCode PetscStrcasecmp(const char a[], const char b[], PetscBool *t)
    283: {
    284:   int c;

    286:   PetscFunctionBegin;
    287:   PetscAssertPointer(t, 3);
    288:   if (!a && !b) c = 0;
    289:   else if (!a || !b) c = 1;
    290: #if defined(PETSC_HAVE_STRCASECMP)
    291:   else c = strcasecmp(a, b);
    292: #elif defined(PETSC_HAVE_STRICMP)
    293:   else c = stricmp(a, b);
    294: #else
    295:   else {
    296:     char *aa, *bb;

    298:     PetscCall(PetscStrallocpy(a, &aa));
    299:     PetscCall(PetscStrallocpy(b, &bb));
    300:     PetscCall(PetscStrtolower(aa));
    301:     PetscCall(PetscStrtolower(bb));
    302:     PetscCall(PetscStrcmp(aa, bb, t));
    303:     PetscCall(PetscFree(aa));
    304:     PetscCall(PetscFree(bb));
    305:     PetscFunctionReturn(PETSC_SUCCESS);
    306:   }
    307: #endif
    308:   *t = c ? PETSC_FALSE : PETSC_TRUE;
    309:   PetscFunctionReturn(PETSC_SUCCESS);
    310: }

    312: /*@C
    313:   PetscStrendswithwhich - Determines if a string ends with one of several possible strings

    315:   Not Collective; No Fortran Support

    317:   Input Parameters:
    318: + a  - pointer to string
    319: - bs - strings to end with (last entry must be `NULL`)

    321:   Output Parameter:
    322: . cnt - the index of the string it ends with or the index of `NULL`

    324:   Level: intermediate

    326: .seealso: `PetscStrbeginswithwhich()`, `PetscStrendswith()`, `PetscStrtoupper`, `PetscStrtolower()`, `PetscStrrchr()`, `PetscStrchr()`,
    327:           `PetscStrncmp()`, `PetscStrlen()`, `PetscStrcmp()`
    328: @*/
    329: PetscErrorCode PetscStrendswithwhich(const char a[], const char *const *bs, PetscInt *cnt)
    330: {
    331:   PetscFunctionBegin;
    332:   PetscAssertPointer(bs, 2);
    333:   PetscAssertPointer(cnt, 3);
    334:   *cnt = 0;
    335:   while (bs[*cnt]) {
    336:     PetscBool flg;

    338:     PetscCall(PetscStrendswith(a, bs[*cnt], &flg));
    339:     if (flg) PetscFunctionReturn(PETSC_SUCCESS);
    340:     ++(*cnt);
    341:   }
    342:   PetscFunctionReturn(PETSC_SUCCESS);
    343: }

    345: struct _n_PetscToken {
    346:   char  token;
    347:   char *array;
    348:   char *current;
    349: };

    351: /*@C
    352:   PetscTokenFind - Locates next "token" in a `PetscToken`

    354:   Not Collective; No Fortran Support

    356:   Input Parameter:
    357: . a - pointer to token

    359:   Output Parameter:
    360: . result - location of occurrence, `NULL` if not found

    362:   Level: intermediate

    364:   Notes:
    365:   Treats all characters etc. inside a double quote "
    366:   as a single token.

    368:   For example if the separator character is + and the string is xxxx+y then the first fine will return a pointer to a `NULL` terminated xxxx and the
    369:   second will return a `NULL` terminated y

    371:   If the separator character is + and the string is xxxx then the first and only token found will be a pointer to a `NULL` terminated xxxx

    373:   Do not change or free the value of `result`

    375: .seealso: `PetscToken`, `PetscTokenCreate()`, `PetscTokenDestroy()`
    376: @*/
    377: PetscErrorCode PetscTokenFind(PetscToken a, const char *result[])
    378: {
    379:   char *ptr, token;

    381:   PetscFunctionBegin;
    382:   PetscAssertPointer(a, 1);
    383:   PetscAssertPointer(result, 2);
    384:   *result = ptr = a->current;
    385:   if (ptr && !*ptr) {
    386:     *result = NULL;
    387:     PetscFunctionReturn(PETSC_SUCCESS);
    388:   }
    389:   token = a->token;
    390:   if (ptr && (*ptr == '"')) {
    391:     token = '"';
    392:     (*result)++;
    393:     ptr++;
    394:   }
    395:   while (ptr) {
    396:     if (*ptr == token) {
    397:       *ptr++ = 0;
    398:       while (*ptr == a->token) ptr++;
    399:       a->current = ptr;
    400:       break;
    401:     }
    402:     if (!*ptr) {
    403:       a->current = NULL;
    404:       break;
    405:     }
    406:     ptr++;
    407:   }
    408:   PetscFunctionReturn(PETSC_SUCCESS);
    409: }

    411: /*@C
    412:   PetscTokenCreate - Creates a `PetscToken` used to find tokens in a string

    414:   Not Collective; No Fortran Support

    416:   Input Parameters:
    417: + a - the string to look in
    418: - b - the separator character

    420:   Output Parameter:
    421: . t - the token object

    423:   Level: intermediate

    425:   Note:
    426:   This version is different from the system version in that
    427:   it allows you to pass a read-only string into the function.

    429: .seealso: `PetscToken`, `PetscTokenFind()`, `PetscTokenDestroy()`
    430: @*/
    431: PetscErrorCode PetscTokenCreate(const char a[], char b, PetscToken *t)
    432: {
    433:   PetscFunctionBegin;
    434:   PetscAssertPointer(a, 1);
    435:   PetscAssertPointer(t, 3);
    436:   PetscCall(PetscNew(t));
    437:   PetscCall(PetscStrallocpy(a, &(*t)->array));

    439:   (*t)->current = (*t)->array;
    440:   (*t)->token   = b;
    441:   PetscFunctionReturn(PETSC_SUCCESS);
    442: }

    444: /*@C
    445:   PetscTokenDestroy - Destroys a `PetscToken`

    447:   Not Collective; No Fortran Support

    449:   Input Parameter:
    450: . a - pointer to token

    452:   Level: intermediate

    454: .seealso: `PetscToken`, `PetscTokenCreate()`, `PetscTokenFind()`
    455: @*/
    456: PetscErrorCode PetscTokenDestroy(PetscToken *a)
    457: {
    458:   PetscFunctionBegin;
    459:   if (!*a) PetscFunctionReturn(PETSC_SUCCESS);
    460:   PetscCall(PetscFree((*a)->array));
    461:   PetscCall(PetscFree(*a));
    462:   PetscFunctionReturn(PETSC_SUCCESS);
    463: }

    465: /*@C
    466:   PetscStrInList - search for a string in character-delimited list

    468:   Not Collective; No Fortran Support

    470:   Input Parameters:
    471: + str  - the string to look for
    472: . list - the list to search in
    473: - sep  - the separator character

    475:   Output Parameter:
    476: . found - whether `str` is in `list`

    478:   Level: intermediate

    480: .seealso: `PetscTokenCreate()`, `PetscTokenFind()`, `PetscStrcmp()`
    481: @*/
    482: PetscErrorCode PetscStrInList(const char str[], const char list[], char sep, PetscBool *found)
    483: {
    484:   PetscToken  token;
    485:   const char *item;

    487:   PetscFunctionBegin;
    488:   PetscAssertPointer(found, 4);
    489:   *found = PETSC_FALSE;
    490:   PetscCall(PetscTokenCreate(list, sep, &token));
    491:   PetscCall(PetscTokenFind(token, &item));
    492:   while (item) {
    493:     PetscCall(PetscStrcmp(str, item, found));
    494:     if (*found) break;
    495:     PetscCall(PetscTokenFind(token, &item));
    496:   }
    497:   PetscCall(PetscTokenDestroy(&token));
    498:   PetscFunctionReturn(PETSC_SUCCESS);
    499: }

    501: /*@C
    502:   PetscGetPetscDir - Gets the directory PETSc is installed in

    504:   Not Collective; No Fortran Support

    506:   Output Parameter:
    507: . dir - the directory

    509:   Level: developer

    511: .seealso: `PetscGetArchType()`
    512: @*/
    513: PetscErrorCode PetscGetPetscDir(const char *dir[])
    514: {
    515:   PetscFunctionBegin;
    516:   PetscAssertPointer(dir, 1);
    517:   *dir = PETSC_DIR;
    518:   PetscFunctionReturn(PETSC_SUCCESS);
    519: }

    521: /*@C
    522:   PetscStrreplace - Replaces substrings in string with other substrings

    524:   Not Collective; No Fortran Support

    526:   Input Parameters:
    527: + comm - `MPI_Comm` of processors that are processing the string
    528: . aa   - the string to look in
    529: . b    - the resulting copy of a with replaced strings (`b` can be the same as `a`)
    530: - len  - the length of `b`

    532:   Level: developer

    534:   Notes:
    535:   Replaces
    536: .vb
    537:     ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, ${DISPLAY},
    538:     ${HOMEDIRECTORY}, ${WORKINGDIRECTORY}, ${USERNAME}, ${HOSTNAME}, ${PETSC_MAKE}
    539: .ve
    540:   with appropriate values as well as any environmental variables.

    542:   `PETSC_LIB_DIR` uses the environmental variable if it exists. `PETSC_ARCH` and `PETSC_DIR` use what
    543:   PETSc was built with and do not use environmental variables.

    545: .seealso: `PetscStrcmp()`
    546: @*/
    547: PetscErrorCode PetscStrreplace(MPI_Comm comm, const char aa[], char b[], size_t len)
    548: {
    549:   int           i = 0;
    550:   size_t        l, l1, l2, l3;
    551:   char         *work, *par, *epar = NULL, env[1024], *tfree, *a = (char *)aa;
    552:   const char   *s[] = {"${PETSC_ARCH}", "${PETSC_DIR}", "${PETSC_LIB_DIR}", "${DISPLAY}", "${HOMEDIRECTORY}", "${WORKINGDIRECTORY}", "${USERNAME}", "${HOSTNAME}", "${PETSC_MAKE}", NULL};
    553:   char         *r[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
    554:   PetscBool     flag;
    555:   static size_t DISPLAY_LENGTH = 265, USER_LENGTH = 256, HOST_LENGTH = 256;

    557:   PetscFunctionBegin;
    558:   PetscAssertPointer(aa, 2);
    559:   PetscAssertPointer(b, 3);
    560:   if (aa == b) PetscCall(PetscStrallocpy(aa, &a));
    561:   PetscCall(PetscMalloc1(len, &work));

    563:   /* get values for replaced variables */
    564:   PetscCall(PetscStrallocpy(PETSC_ARCH, &r[0]));
    565:   PetscCall(PetscStrallocpy(PETSC_DIR, &r[1]));
    566:   PetscCall(PetscStrallocpy(PETSC_LIB_DIR, &r[2]));
    567:   PetscCall(PetscMalloc1(DISPLAY_LENGTH, &r[3]));
    568:   PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN, &r[4]));
    569:   PetscCall(PetscMalloc1(PETSC_MAX_PATH_LEN, &r[5]));
    570:   PetscCall(PetscMalloc1(USER_LENGTH, &r[6]));
    571:   PetscCall(PetscMalloc1(HOST_LENGTH, &r[7]));
    572:   PetscCall(PetscGetDisplay(r[3], DISPLAY_LENGTH));
    573:   PetscCall(PetscGetHomeDirectory(r[4], PETSC_MAX_PATH_LEN));
    574:   PetscCall(PetscGetWorkingDirectory(r[5], PETSC_MAX_PATH_LEN));
    575:   PetscCall(PetscGetUserName(r[6], USER_LENGTH));
    576:   PetscCall(PetscGetHostName(r[7], HOST_LENGTH));
    577:   PetscCall(PetscStrallocpy(PETSC_OMAKE, &r[8]));

    579:   /* replace that are in environment */
    580:   PetscCall(PetscOptionsGetenv(comm, "PETSC_LIB_DIR", env, sizeof(env), &flag));
    581:   if (flag) {
    582:     PetscCall(PetscFree(r[2]));
    583:     PetscCall(PetscStrallocpy(env, &r[2]));
    584:   }

    586:   /* replace the requested strings */
    587:   PetscCall(PetscStrncpy(b, a, len));
    588:   while (s[i]) {
    589:     PetscCall(PetscStrcmp(s[i], r[i], &flag));
    590:     if (flag) {
    591:       i++;
    592:       continue;
    593:     }
    594:     PetscCall(PetscStrlen(s[i], &l));
    595:     PetscCall(PetscStrstr(b, s[i], &par));
    596:     while (par) {
    597:       *par = 0;
    598:       par += l;

    600:       PetscCall(PetscStrlen(b, &l1));
    601:       PetscCall(PetscStrlen(r[i], &l2));
    602:       PetscCall(PetscStrlen(par, &l3));
    603:       PetscCheck(l1 + l2 + l3 < len, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "b len is not long enough to hold new values");
    604:       PetscCall(PetscStrncpy(work, b, len));
    605:       PetscCall(PetscStrlcat(work, r[i], len));
    606:       PetscCall(PetscStrlcat(work, par, len));
    607:       PetscCall(PetscStrncpy(b, work, len));
    608:       PetscCall(PetscStrstr(b, s[i], &par));
    609:     }
    610:     i++;
    611:   }
    612:   i = 0;
    613:   while (r[i]) {
    614:     tfree = r[i];
    615:     PetscCall(PetscFree(tfree));
    616:     i++;
    617:   }

    619:   /* look for any other ${xxx} strings to replace from environmental variables */
    620:   PetscCall(PetscStrstr(b, "${", &par));
    621:   while (par) {
    622:     *par = 0;
    623:     par += 2;
    624:     PetscCall(PetscStrncpy(work, b, len));
    625:     PetscCall(PetscStrstr(par, "}", &epar));
    626:     *epar = 0;
    627:     epar += 1;
    628:     PetscCall(PetscOptionsGetenv(comm, par, env, sizeof(env), &flag));
    629:     PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Substitution string ${%s} not found as environmental variable", par);
    630:     PetscCall(PetscStrlcat(work, env, len));
    631:     PetscCall(PetscStrlcat(work, epar, len));
    632:     PetscCall(PetscStrncpy(b, work, len));
    633:     PetscCall(PetscStrstr(b, "${", &par));
    634:   }
    635:   PetscCall(PetscFree(work));
    636:   if (aa == b) PetscCall(PetscFree(a));
    637:   PetscFunctionReturn(PETSC_SUCCESS);
    638: }

    640: /*@C
    641:   PetscStrcmpAny - Determines whether a string matches any of a list of strings.

    643:   Not Collective, No Fortran Support

    645:   Input Parameters:
    646: + src - pointer to input the string
    647: - cmp - list of non-null and non-empty strings to be compared against, pass the empty string "" to terminate the list

    649:   Output Parameter:
    650: . match - `PETSC_TRUE` if the input string matches any in the list, else `PETSC_FALSE`

    652:   Level: intermediate

    654: .seealso: `PetscStrcmp()`
    655: @*/
    656: PetscErrorCode PetscStrcmpAny(const char src[], PetscBool *match, const char cmp[], ...)
    657: {
    658:   va_list Argp;

    660:   PetscFunctionBegin;
    661:   PetscAssertPointer(match, 2);
    662:   *match = PETSC_FALSE;
    663:   if (!src) PetscFunctionReturn(PETSC_SUCCESS);
    664:   va_start(Argp, cmp);
    665:   while (cmp && cmp[0]) {
    666:     PetscBool found;
    667:     PetscCall(PetscStrcmp(src, cmp, &found));
    668:     if (found) {
    669:       *match = PETSC_TRUE;
    670:       break;
    671:     }
    672:     cmp = va_arg(Argp, const char *);
    673:   }
    674:   va_end(Argp);
    675:   PetscFunctionReturn(PETSC_SUCCESS);
    676: }

    678: /*@C
    679:   PetscEListFind - searches list of strings for given string, using case insensitive matching

    681:   Not Collective; No Fortran Support

    683:   Input Parameters:
    684: + n    - number of strings in
    685: . list - list of strings to search
    686: - str  - string to look for, empty string "" accepts default (first entry in list)

    688:   Output Parameters:
    689: + value - index of matching string (if found)
    690: - found - boolean indicating whether string was found (can be `NULL`)

    692:   Level: developer

    694: .seealso: `PetscEnumFind()`
    695: @*/
    696: PetscErrorCode PetscEListFind(PetscInt n, const char *const *list, const char *str, PetscInt *value, PetscBool *found)
    697: {
    698:   PetscFunctionBegin;
    699:   if (found) {
    700:     PetscAssertPointer(found, 5);
    701:     *found = PETSC_FALSE;
    702:   }
    703:   for (PetscInt i = 0; i < n; ++i) {
    704:     PetscBool matched;

    706:     PetscCall(PetscStrcasecmp(str, list[i], &matched));
    707:     if (matched || !str[0]) {
    708:       if (found) *found = PETSC_TRUE;
    709:       *value = i;
    710:       break;
    711:     }
    712:   }
    713:   PetscFunctionReturn(PETSC_SUCCESS);
    714: }

    716: /*@C
    717:   PetscEnumFind - searches enum list of strings for given string, using case insensitive matching

    719:   Not Collective; No Fortran Support

    721:   Input Parameters:
    722: + enumlist - list of strings to search, followed by enum name, then enum prefix, then `NULL`
    723: - str      - string to look for

    725:   Output Parameters:
    726: + value - index of matching string (if found)
    727: - found - boolean indicating whether string was found (can be `NULL`)

    729:   Level: advanced

    731: .seealso: `PetscEListFind()`
    732: @*/
    733: PetscErrorCode PetscEnumFind(const char *const *enumlist, const char *str, PetscEnum *value, PetscBool *found)
    734: {
    735:   PetscInt  n = 0, evalue;
    736:   PetscBool efound;

    738:   PetscFunctionBegin;
    739:   PetscAssertPointer(enumlist, 1);
    740:   while (enumlist[n++]) PetscCheck(n <= 50, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument appears to be wrong or have more than 50 entries");
    741:   PetscCheck(n >= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument must have at least two entries: typename and type prefix");
    742:   n -= 3; /* drop enum name, prefix, and null termination */
    743:   PetscCall(PetscEListFind(n, enumlist, str, &evalue, &efound));
    744:   if (efound) {
    745:     PetscAssertPointer(value, 3);
    746:     *value = (PetscEnum)evalue;
    747:   }
    748:   if (found) {
    749:     PetscAssertPointer(found, 4);
    750:     *found = efound;
    751:   }
    752:   PetscFunctionReturn(PETSC_SUCCESS);
    753: }

    755: /*@C
    756:   PetscCIFilename - returns the basename of a file name when the PETSc CI portable error output mode is enabled.

    758:   Not Collective; No Fortran Support

    760:   Input Parameter:
    761: . file - the file name

    763:   Level: developer

    765:   Note:
    766:   PETSc CI mode is a mode of running PETSc where output (both error and non-error) is made portable across all systems
    767:   so that comparisons of output between runs are easy to make.

    769:   This mode is used for all tests in the test harness, it applies to both debug and optimized builds.

    771:   Use the option `-petsc_ci` to turn on PETSc CI mode. It changes certain output in non-error situations to be portable for
    772:   all systems, mainly the output of options. It is passed to all PETSc programs automatically by the test harness.

    774:   Always uses the Unix / as the file separate even on Microsoft Windows systems

    776:   The option `-petsc_ci_portable_error_output` attempts to output the same error messages on all systems for the test harness.
    777:   In particular the output of filenames and line numbers in PETSc stacks. This is to allow (limited) checking of PETSc
    778:   error handling by the test harness. This options also causes PETSc to attempt to return an error code of 0 so that the test
    779:   harness can process the output for differences in the usual manner as for successful runs. It should be provided to the test
    780:   harness in the args: argument for specific examples. It will not necessarily produce portable output if different errors
    781:   (or no errors) occur on a subset of the MPI ranks.

    783: .seealso: `PetscCILinenumber()`
    784: @*/
    785: const char *PetscCIFilename(const char *file)
    786: {
    787:   if (!PetscCIEnabledPortableErrorOutput) return file;
    788:   return PetscBasename(file);
    789: }

    791: /*@C
    792:   PetscCILinenumber - returns a line number except if `PetscCIEnablePortableErrorOutput` is set when it returns 0

    794:   Not Collective; No Fortran Support

    796:   Input Parameter:
    797: . linenumber - the initial line number

    799:   Level: developer

    801:   Note:
    802:   See `PetscCIFilename()` for details on usage

    804: .seealso: `PetscCIFilename()`
    805: @*/
    806: int PetscCILinenumber(int linenumber)
    807: {
    808:   if (!PetscCIEnabledPortableErrorOutput) return linenumber;
    809:   return 0;
    810: }

    812: /*@C
    813:   PetscStrcat - Concatenates a string onto a given string

    815:   Not Collective, No Fortran Support

    817:   Input Parameters:
    818: + s - string to be added to
    819: - t - pointer to string to be added to end

    821:   Level: deprecated (since 3.18.5)

    823:   Notes:
    824:   It is recommended you use `PetscStrlcat()` instead of this routine.

    826: .seealso: `PetscStrlcat()`
    827: @*/
    828: PetscErrorCode PetscStrcat(char s[], const char t[])
    829: {
    830:   PetscFunctionBegin;
    831:   if (!t) PetscFunctionReturn(PETSC_SUCCESS);
    832:   PetscAssertPointer(s, 1);
    833:   strcat(s, t);
    834:   PetscFunctionReturn(PETSC_SUCCESS);
    835: }

    837: /*@C
    838:   PetscStrcpy - Copies a string

    840:   Not Collective, No Fortran Support

    842:   Input Parameter:
    843: . t - pointer to string

    845:   Output Parameter:
    846: . s - the copied string

    848:   Level: deprecated (since 3.18.5)

    850:   Notes:
    851:   It is recommended you use `PetscStrncpy()` (equivalently `PetscArraycpy()` or
    852:   `PetscMemcpy()`) instead of this routine.

    854:   `NULL` strings returns a string starting with zero.

    856: .seealso: `PetscStrncpy()`
    857: @*/
    858: PetscErrorCode PetscStrcpy(char s[], const char t[])
    859: {
    860:   PetscFunctionBegin;
    861:   if (t) {
    862:     PetscAssertPointer(s, 1);
    863:     PetscAssertPointer(t, 2);
    864:     strcpy(s, t);
    865:   } else if (s) {
    866:     s[0] = '\0';
    867:   }
    868:   PetscFunctionReturn(PETSC_SUCCESS);
    869: }