Date: 2025-03-28T21:11: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 _p_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: .seealso: `PetscToken`, `PetscTokenCreate()`, `PetscTokenDestroy()`
    374: @*/
    375: PetscErrorCode PetscTokenFind(PetscToken a, char *result[])
    376: {
    377:   char *ptr, token;

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

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

    412:   Not Collective; No Fortran Support

    414:   Input Parameters:
    415: + a - the string to look in
    416: - b - the separator character

    418:   Output Parameter:
    419: . t - the token object

    421:   Level: intermediate

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

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

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

    442: /*@C
    443:   PetscTokenDestroy - Destroys a `PetscToken`

    445:   Not Collective; No Fortran Support

    447:   Input Parameter:
    448: . a - pointer to token

    450:   Level: intermediate

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

    463: /*@C
    464:   PetscStrInList - search for a string in character-delimited list

    466:   Not Collective; No Fortran Support

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

    473:   Output Parameter:
    474: . found - whether `str` is in `list`

    476:   Level: intermediate

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

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

    499: /*@C
    500:   PetscGetPetscDir - Gets the directory PETSc is installed in

    502:   Not Collective; No Fortran Support

    504:   Output Parameter:
    505: . dir - the directory

    507:   Level: developer

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

    519: /*@C
    520:   PetscStrreplace - Replaces substrings in string with other substrings

    522:   Not Collective; No Fortran Support

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

    530:   Level: developer

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

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

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

    555:   PetscFunctionBegin;
    556:   PetscAssertPointer(aa, 2);
    557:   PetscAssertPointer(b, 3);
    558:   if (aa == b) PetscCall(PetscStrallocpy(aa, (char **)&a));
    559:   PetscCall(PetscMalloc1(len, &work));

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

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

    584:   /* replace the requested strings */
    585:   PetscCall(PetscStrncpy(b, a, len));
    586:   while (s[i]) {
    587:     PetscCall(PetscStrlen(s[i], &l));
    588:     PetscCall(PetscStrstr(b, s[i], &par));
    589:     while (par) {
    590:       *par = 0;
    591:       par += l;

    593:       PetscCall(PetscStrlen(b, &l1));
    594:       PetscCall(PetscStrlen(r[i], &l2));
    595:       PetscCall(PetscStrlen(par, &l3));
    596:       PetscCheck(l1 + l2 + l3 < len, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "b len is not long enough to hold new values");
    597:       PetscCall(PetscStrncpy(work, b, len));
    598:       PetscCall(PetscStrlcat(work, r[i], len));
    599:       PetscCall(PetscStrlcat(work, par, len));
    600:       PetscCall(PetscStrncpy(b, work, len));
    601:       PetscCall(PetscStrstr(b, s[i], &par));
    602:     }
    603:     i++;
    604:   }
    605:   i = 0;
    606:   while (r[i]) {
    607:     tfree = (char *)r[i];
    608:     PetscCall(PetscFree(tfree));
    609:     i++;
    610:   }

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

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

    636:   Not Collective, No Fortran Support

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

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

    645:   Level: intermediate

    647: .seealso: `PetscStrcmp()`
    648: @*/
    649: PetscErrorCode PetscStrcmpAny(const char src[], PetscBool *match, const char cmp[], ...)
    650: {
    651:   va_list Argp;

    653:   PetscFunctionBegin;
    654:   PetscAssertPointer(match, 2);
    655:   *match = PETSC_FALSE;
    656:   if (!src) PetscFunctionReturn(PETSC_SUCCESS);
    657:   va_start(Argp, cmp);
    658:   while (cmp && cmp[0]) {
    659:     PetscBool found;
    660:     PetscCall(PetscStrcmp(src, cmp, &found));
    661:     if (found) {
    662:       *match = PETSC_TRUE;
    663:       break;
    664:     }
    665:     cmp = va_arg(Argp, const char *);
    666:   }
    667:   va_end(Argp);
    668:   PetscFunctionReturn(PETSC_SUCCESS);
    669: }

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

    674:   Not Collective; No Fortran Support

    676:   Input Parameters:
    677: + n    - number of strings in
    678: . list - list of strings to search
    679: - str  - string to look for, empty string "" accepts default (first entry in list)

    681:   Output Parameters:
    682: + value - index of matching string (if found)
    683: - found - boolean indicating whether string was found (can be `NULL`)

    685:   Level: developer

    687: .seealso: `PetscEnumFind()`
    688: @*/
    689: PetscErrorCode PetscEListFind(PetscInt n, const char *const *list, const char *str, PetscInt *value, PetscBool *found)
    690: {
    691:   PetscFunctionBegin;
    692:   if (found) {
    693:     PetscAssertPointer(found, 5);
    694:     *found = PETSC_FALSE;
    695:   }
    696:   for (PetscInt i = 0; i < n; ++i) {
    697:     PetscBool matched;

    699:     PetscCall(PetscStrcasecmp(str, list[i], &matched));
    700:     if (matched || !str[0]) {
    701:       if (found) *found = PETSC_TRUE;
    702:       *value = i;
    703:       break;
    704:     }
    705:   }
    706:   PetscFunctionReturn(PETSC_SUCCESS);
    707: }

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

    712:   Not Collective; No Fortran Support

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

    718:   Output Parameters:
    719: + value - index of matching string (if found)
    720: - found - boolean indicating whether string was found (can be `NULL`)

    722:   Level: advanced

    724: .seealso: `PetscEListFind()`
    725: @*/
    726: PetscErrorCode PetscEnumFind(const char *const *enumlist, const char *str, PetscEnum *value, PetscBool *found)
    727: {
    728:   PetscInt  n = 0, evalue;
    729:   PetscBool efound;

    731:   PetscFunctionBegin;
    732:   PetscAssertPointer(enumlist, 1);
    733:   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");
    734:   PetscCheck(n >= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument must have at least two entries: typename and type prefix");
    735:   n -= 3; /* drop enum name, prefix, and null termination */
    736:   PetscCall(PetscEListFind(n, enumlist, str, &evalue, &efound));
    737:   if (efound) {
    738:     PetscAssertPointer(value, 3);
    739:     *value = (PetscEnum)evalue;
    740:   }
    741:   if (found) {
    742:     PetscAssertPointer(found, 4);
    743:     *found = efound;
    744:   }
    745:   PetscFunctionReturn(PETSC_SUCCESS);
    746: }

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

    751:   Not Collective; No Fortran Support

    753:   Input Parameter:
    754: . file - the file name

    756:   Level: developer

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

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

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

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

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

    776: .seealso: `PetscCILinenumber()`
    777: @*/
    778: const char *PetscCIFilename(const char *file)
    779: {
    780:   if (!PetscCIEnabledPortableErrorOutput) return file;
    781:   return PetscBasename(file);
    782: }

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

    787:   Not Collective; No Fortran Support

    789:   Input Parameter:
    790: . linenumber - the initial line number

    792:   Level: developer

    794:   Note:
    795:   See `PetscCIFilename()` for details on usage

    797: .seealso: `PetscCIFilename()`
    798: @*/
    799: int PetscCILinenumber(int linenumber)
    800: {
    801:   if (!PetscCIEnabledPortableErrorOutput) return linenumber;
    802:   return 0;
    803: }

    805: /*@C
    806:   PetscStrcat - Concatenates a string onto a given string

    808:   Not Collective, No Fortran Support

    810:   Input Parameters:
    811: + s - string to be added to
    812: - t - pointer to string to be added to end

    814:   Level: deprecated (since 3.18.5)

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

    819: .seealso: `PetscStrlcat()`
    820: @*/
    821: PetscErrorCode PetscStrcat(char s[], const char t[])
    822: {
    823:   PetscFunctionBegin;
    824:   if (!t) PetscFunctionReturn(PETSC_SUCCESS);
    825:   PetscAssertPointer(s, 1);
    826:   strcat(s, t);
    827:   PetscFunctionReturn(PETSC_SUCCESS);
    828: }

    830: /*@C
    831:   PetscStrcpy - Copies a string

    833:   Not Collective, No Fortran Support

    835:   Input Parameter:
    836: . t - pointer to string

    838:   Output Parameter:
    839: . s - the copied string

    841:   Level: deprecated (since 3.18.5)

    843:   Notes:
    844:   It is recommended you use `PetscStrncpy()` (equivalently `PetscArraycpy()` or
    845:   `PetscMemcpy()`) instead of this routine.

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

    849: .seealso: `PetscStrncpy()`
    850: @*/
    851: PetscErrorCode PetscStrcpy(char s[], const char t[])
    852: {
    853:   PetscFunctionBegin;
    854:   if (t) {
    855:     PetscAssertPointer(s, 1);
    856:     PetscAssertPointer(t, 2);
    857:     strcpy(s, t);
    858:   } else if (s) {
    859:     s[0] = '\0';
    860:   }
    861:   PetscFunctionReturn(PETSC_SUCCESS);
    862: }