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 the array
 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       i, j, n, *lens, cnt = 0;
 39:   PetscBool flg = PETSC_FALSE;

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

 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: .  s - 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:    If `t` has previously been allocated then that memory is lost, you may need to `PetscStrArrayDestroy()`
148:    the array before calling this routine.

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

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

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

168:    Not Collective; No Fortran Support

170:    Output Parameter:
171: .   list - array of strings

173:    Level: intermediate

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

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

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

194:    Not Collective; No Fortran Support

196:    Input Parameters:
197: +  n - the number of string entries
198: -  s - pointer to array of strings

200:    Output Parameter:
201: .  t - the copied array string

203:    Level: intermediate

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

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

218:    Not Collective; No Fortran Support

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

224:    Level: intermediate

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

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

240:    Not Collective; No Fortran Support

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

245:    Level: intermediate

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

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

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

265:    Not Collective; No Fortran Support

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

271:    Output Parameter:
272: .  flg - if the two strings are the same

274:    Level: intermediate

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

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

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

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

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

314:    Not Collective; No Fortran Support

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

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

323:    Level: intermediate

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

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

344: struct _p_PetscToken {
345:   char  token;
346:   char *array;
347:   char *current;
348: };

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

353:    Not Collective; No Fortran Support

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

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

361:    Level: intermediate

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

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

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

372: .seealso: `PetscToken`, `PetscTokenCreate()`, `PetscTokenDestroy()`
373: @*/
374: PetscErrorCode PetscTokenFind(PetscToken a, char *result[])
375: {
376:   char *ptr, token;

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

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

411:    Not Collective; No Fortran Support

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

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

420:    Level: intermediate

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

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

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

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

444:    Not Collective; No Fortran Support

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

449:    Level: intermediate

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

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

465:    Not Collective; No Fortran Support

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

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

475:    Level: intermediate

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

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

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

501:    Not Collective; No Fortran Support

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

506:    Level: developer

508: @*/
509: PetscErrorCode PetscGetPetscDir(const char *dir[])
510: {
511:   PetscFunctionBegin;
513:   *dir = PETSC_DIR;
514:   PetscFunctionReturn(PETSC_SUCCESS);
515: }

517: /*@C
518:    PetscStrreplace - Replaces substrings in string with other substrings

520:    Not Collective; No Fortran Support

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

528:    Level: developer

530:    Notes:
531:       Replaces ${PETSC_ARCH},${PETSC_DIR},${PETSC_LIB_DIR},${DISPLAY},
532:       ${HOMEDIRECTORY},${WORKINGDIRECTORY},${USERNAME}, ${HOSTNAME}, ${PETSC_MAKE} with appropriate values
533:       as well as any environmental variables.

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

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

549:   PetscFunctionBegin;
552:   if (aa == b) PetscCall(PetscStrallocpy(aa, (char **)&a));
553:   PetscCall(PetscMalloc1(len, &work));

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

571:   /* replace that are in environment */
572:   PetscCall(PetscOptionsGetenv(comm, "PETSC_LIB_DIR", env, sizeof(env), &flag));
573:   if (flag) {
574:     PetscCall(PetscFree(r[2]));
575:     PetscCall(PetscStrallocpy(env, &r[2]));
576:   }

578:   /* replace the requested strings */
579:   PetscCall(PetscStrncpy(b, a, len));
580:   while (s[i]) {
581:     PetscCall(PetscStrlen(s[i], &l));
582:     PetscCall(PetscStrstr(b, s[i], &par));
583:     while (par) {
584:       *par = 0;
585:       par += l;

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

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

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

630:    Not Collective; No Fortran Support

632:    Input Parameters:
633: +  n - number of strings in
634: .  list - list of strings to search
635: -  str - string to look for, empty string "" accepts default (first entry in list)

637:    Output Parameters:
638: +  value - index of matching string (if found)
639: -  found - boolean indicating whether string was found (can be `NULL`)

641:    Level: developer

643: .seealso: `PetscEnumFind()`
644: @*/
645: PetscErrorCode PetscEListFind(PetscInt n, const char *const *list, const char *str, PetscInt *value, PetscBool *found)
646: {
647:   PetscFunctionBegin;
648:   if (found) {
650:     *found = PETSC_FALSE;
651:   }
652:   for (PetscInt i = 0; i < n; ++i) {
653:     PetscBool matched;

655:     PetscCall(PetscStrcasecmp(str, list[i], &matched));
656:     if (matched || !str[0]) {
657:       if (found) *found = PETSC_TRUE;
658:       *value = i;
659:       break;
660:     }
661:   }
662:   PetscFunctionReturn(PETSC_SUCCESS);
663: }

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

668:    Not Collective; No Fortran Support

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

674:    Output Parameters:
675: +  value - index of matching string (if found)
676: -  found - boolean indicating whether string was found (can be `NULL`)

678:    Level: advanced

680: .seealso: `PetscEListFind()`
681: @*/
682: PetscErrorCode PetscEnumFind(const char *const *enumlist, const char *str, PetscEnum *value, PetscBool *found)
683: {
684:   PetscInt  n = 0, evalue;
685:   PetscBool efound;

687:   PetscFunctionBegin;
689:   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");
690:   PetscCheck(n >= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument must have at least two entries: typename and type prefix");
691:   n -= 3; /* drop enum name, prefix, and null termination */
692:   PetscCall(PetscEListFind(n, enumlist, str, &evalue, &efound));
693:   if (efound) {
695:     *value = (PetscEnum)evalue;
696:   }
697:   if (found) {
699:     *found = efound;
700:   }
701:   PetscFunctionReturn(PETSC_SUCCESS);
702: }

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

707:   Not Collective; No Fortran Support

709:   Input Parameter:
710: . file - the file name

712:   Level: developer

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

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

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

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

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

732: .seealso: `PetscCILinenumber()`
733: @*/
734: const char *PetscCIFilename(const char *file)
735: {
736:   if (!PetscCIEnabledPortableErrorOutput) return file;
737:   return PetscBasename(file);
738: }

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

743:   Not Collective; No Fortran Support

745:   Input Parameter:
746: . linenumber - the initial line number

748:   Level: developer

750:   Note:
751:   See `PetscCIFilename()` for details on usage

753: .seealso: `PetscCIFilename()`
754: @*/
755: int PetscCILinenumber(int linenumber)
756: {
757:   if (!PetscCIEnabledPortableErrorOutput) return linenumber;
758:   return 0;
759: }

761: /*@C
762:   PetscStrcat - Concatenates a string onto a given string

764:   Not Collective, No Fortran Support

766:   Input Parameters:
767: + s - string to be added to
768: - t - pointer to string to be added to end

770:   Level: deprecated (since 3.18.5)

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

775: .seealso: `PetscStrlcat()`
776: @*/
777: PetscErrorCode PetscStrcat(char s[], const char t[])
778: {
779:   PetscFunctionBegin;
780:   if (!t) PetscFunctionReturn(PETSC_SUCCESS);
782:   strcat(s, t);
783:   PetscFunctionReturn(PETSC_SUCCESS);
784: }

786: /*@C
787:   PetscStrcpy - Copies a string

789:   Not Collective, No Fortran Support

791:   Input Parameter:
792: . t - pointer to string

794:   Output Parameter:
795: . s - the copied string

797:   Level: deprecated (since 3.18.5)

799:   Notes:
800:   It is recommended you use `PetscStrncpy()` (equivalently `PetscArraycpy()` or
801:   `PetscMemcpy()`) instead of this routine.

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

805: .seealso: `PetscStrncpy()`
806: @*/
807: PetscErrorCode PetscStrcpy(char s[], const char t[])
808: {
809:   PetscFunctionBegin;
810:   if (t) {
813:     strcpy(s, t);
814:   } else if (s) {
815:     s[0] = '\0';
816:   }
817:   PetscFunctionReturn(PETSC_SUCCESS);
818: }