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(PetscStrlen(s[i], &l));
590:     PetscCall(PetscStrstr(b, s[i], &par));
591:     while (par) {
592:       *par = 0;
593:       par += l;

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

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

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

638:   Not Collective, No Fortran Support

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

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

647:   Level: intermediate

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

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

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

676:   Not Collective; No Fortran Support

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

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

687:   Level: developer

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

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

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

714:   Not Collective; No Fortran Support

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

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

724:   Level: advanced

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

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

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

753:   Not Collective; No Fortran Support

755:   Input Parameter:
756: . file - the file name

758:   Level: developer

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

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

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

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

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

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

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

789:   Not Collective; No Fortran Support

791:   Input Parameter:
792: . linenumber - the initial line number

794:   Level: developer

796:   Note:
797:   See `PetscCIFilename()` for details on usage

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

807: /*@C
808:   PetscStrcat - Concatenates a string onto a given string

810:   Not Collective, No Fortran Support

812:   Input Parameters:
813: + s - string to be added to
814: - t - pointer to string to be added to end

816:   Level: deprecated (since 3.18.5)

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

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

832: /*@C
833:   PetscStrcpy - Copies a string

835:   Not Collective, No Fortran Support

837:   Input Parameter:
838: . t - pointer to string

840:   Output Parameter:
841: . s - the copied string

843:   Level: deprecated (since 3.18.5)

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

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

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