xref: /petsc/src/sys/objects/options.c (revision d5b43468fb8780a8feea140ccd6fa3e6a50411cc)
1 /* Define Feature test macros to make sure atoll is available (SVr4, POSIX.1-2001, 4.3BSD, C99), not in (C89 and POSIX.1-1996) */
2 #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for atoll() */
3 
4 /*
5    These routines simplify the use of command line, file options, etc., and are used to manipulate the options database.
6    This provides the low-level interface, the high level interface is in aoptions.c
7 
8    Some routines use regular malloc and free because it cannot know  what malloc is requested with the
9    options database until it has already processed the input.
10 */
11 
12 #include <petsc/private/petscimpl.h> /*I  "petscsys.h"   I*/
13 #include <petscviewer.h>
14 #include <ctype.h>
15 #if defined(PETSC_HAVE_MALLOC_H)
16   #include <malloc.h>
17 #endif
18 #if defined(PETSC_HAVE_STRINGS_H)
19   #include <strings.h> /* strcasecmp */
20 #endif
21 
22 #if defined(PETSC_HAVE_STRCASECMP)
23   #define PetscOptNameCmp(a, b) strcasecmp(a, b)
24 #elif defined(PETSC_HAVE_STRICMP)
25   #define PetscOptNameCmp(a, b) stricmp(a, b)
26 #else
27   #define PetscOptNameCmp(a, b) Error_strcasecmp_not_found
28 #endif
29 
30 #include <petsc/private/hashtable.h>
31 
32 /* This assumes ASCII encoding and ignores locale settings */
33 /* Using tolower() is about 2X slower in microbenchmarks   */
34 static inline int PetscToLower(int c)
35 {
36   return ((c >= 'A') & (c <= 'Z')) ? c + 'a' - 'A' : c;
37 }
38 
39 /* Bob Jenkins's one at a time hash function (case-insensitive) */
40 static inline unsigned int PetscOptHash(const char key[])
41 {
42   unsigned int hash = 0;
43   while (*key) {
44     hash += PetscToLower(*key++);
45     hash += hash << 10;
46     hash ^= hash >> 6;
47   }
48   hash += hash << 3;
49   hash ^= hash >> 11;
50   hash += hash << 15;
51   return hash;
52 }
53 
54 static inline int PetscOptEqual(const char a[], const char b[])
55 {
56   return !PetscOptNameCmp(a, b);
57 }
58 
59 KHASH_INIT(HO, kh_cstr_t, int, 1, PetscOptHash, PetscOptEqual)
60 
61 /*
62     This table holds all the options set by the user. For simplicity, we use a static size database
63 */
64 #define MAXOPTNAME         PETSC_MAX_OPTION_NAME
65 #define MAXOPTIONS         512
66 #define MAXALIASES         25
67 #define MAXPREFIXES        25
68 #define MAXOPTIONSMONITORS 5
69 
70 struct _n_PetscOptions {
71   PetscOptions previous;
72   int          N;                  /* number of options */
73   char        *names[MAXOPTIONS];  /* option names */
74   char        *values[MAXOPTIONS]; /* option values */
75   PetscBool    used[MAXOPTIONS];   /* flag option use */
76   PetscBool    precedentProcessed;
77 
78   /* Hash table */
79   khash_t(HO) *ht;
80 
81   /* Prefixes */
82   int  prefixind;
83   int  prefixstack[MAXPREFIXES];
84   char prefix[MAXOPTNAME];
85 
86   /* Aliases */
87   int   Naliases;             /* number or aliases */
88   char *aliases1[MAXALIASES]; /* aliased */
89   char *aliases2[MAXALIASES]; /* aliasee */
90 
91   /* Help */
92   PetscBool help;       /* flag whether "-help" is in the database */
93   PetscBool help_intro; /* flag whether "-help intro" is in the database */
94 
95   /* Monitors */
96   PetscBool monitorFromOptions, monitorCancel;
97   PetscErrorCode (*monitor[MAXOPTIONSMONITORS])(const char[], const char[], void *); /* returns control to user after */
98   PetscErrorCode (*monitordestroy[MAXOPTIONSMONITORS])(void **);                     /* */
99   void    *monitorcontext[MAXOPTIONSMONITORS];                                       /* to pass arbitrary user data into monitor */
100   PetscInt numbermonitors;                                                           /* to, for instance, detect options being set */
101 };
102 
103 static PetscOptions defaultoptions = NULL; /* the options database routines query this object for options */
104 
105 /* list of options which preceed others, i.e., are processed in PetscOptionsProcessPrecedentFlags() */
106 /* these options can only take boolean values, the code will crash if given a non-boolean value */
107 static const char *precedentOptions[] = {"-petsc_ci", "-options_monitor", "-options_monitor_cancel", "-help", "-skip_petscrc"};
108 enum PetscPrecedentOption {
109   PO_CI_ENABLE,
110   PO_OPTIONS_MONITOR,
111   PO_OPTIONS_MONITOR_CANCEL,
112   PO_HELP,
113   PO_SKIP_PETSCRC,
114   PO_NUM
115 };
116 
117 static PetscErrorCode PetscOptionsSetValue_Private(PetscOptions, const char[], const char[], int *);
118 
119 /*
120     Options events monitor
121 */
122 static PetscErrorCode PetscOptionsMonitor(PetscOptions options, const char name[], const char value[])
123 {
124   PetscFunctionBegin;
125   if (!value) value = "";
126   if (options->monitorFromOptions) PetscCall(PetscOptionsMonitorDefault(name, value, NULL));
127   for (PetscInt i = 0; i < options->numbermonitors; i++) PetscCall((*options->monitor[i])(name, value, options->monitorcontext[i]));
128   PetscFunctionReturn(0);
129 }
130 
131 /*@
132    PetscOptionsCreate - Creates an empty options database.
133 
134    Logically collective
135 
136    Output Parameter:
137 .  options - Options database object
138 
139    Level: advanced
140 
141    Note:
142    Though PETSc has a concept of multiple options database the current code uses a single default `PetscOptions` object
143 
144    Developer Notes:
145    We may want eventually to pass a `MPI_Comm` to determine the ownership of the object
146 
147    This object never got developed after being introduced, it is not clear that supporting multiple `PetscOptions` objects is useful
148 
149 .seealso: `PetscOptionsDestroy()`, `PetscOptionsPush()`, `PetscOptionsPop()`, `PetscOptionsInsert()`, `PetscOptionsSetValue()`
150 @*/
151 PetscErrorCode PetscOptionsCreate(PetscOptions *options)
152 {
153   PetscFunctionBegin;
154   PetscValidPointer(options, 1);
155   *options = (PetscOptions)calloc(1, sizeof(**options));
156   PetscCheck(*options, PETSC_COMM_SELF, PETSC_ERR_MEM, "Failed to allocate the options database");
157   PetscFunctionReturn(0);
158 }
159 
160 /*@
161     PetscOptionsDestroy - Destroys an option database.
162 
163     Logically collective on whatever communicator was associated with the call to `PetscOptionsCreate()`
164 
165   Input Parameter:
166 .  options - the `PetscOptions` object
167 
168    Level: advanced
169 
170 .seealso: `PetscOptionsInsert()`, `PetscOptionsPush()`, `PetscOptionsPop()`, `PetscOptionsInsert()`, `PetscOptionsSetValue()`
171 @*/
172 PetscErrorCode PetscOptionsDestroy(PetscOptions *options)
173 {
174   PetscFunctionBegin;
175   if (!*options) PetscFunctionReturn(0);
176   PetscCheck(!(*options)->previous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "You are destroying an option that has been used with PetscOptionsPush() but does not have a corresponding PetscOptionsPop()");
177   PetscCall(PetscOptionsClear(*options));
178   /* XXX what about monitors ? */
179   free(*options);
180   *options = NULL;
181   PetscFunctionReturn(0);
182 }
183 
184 /*
185     PetscOptionsCreateDefault - Creates the default global options database
186 */
187 PetscErrorCode PetscOptionsCreateDefault(void)
188 {
189   PetscFunctionBegin;
190   if (PetscUnlikely(!defaultoptions)) PetscCall(PetscOptionsCreate(&defaultoptions));
191   PetscFunctionReturn(0);
192 }
193 
194 /*@
195       PetscOptionsPush - Push a new `PetscOptions` object as the default provider of options
196                          Allows using different parts of a code to use different options databases
197 
198   Logically Collective
199 
200   Input Parameter:
201 .   opt - the options obtained with `PetscOptionsCreate()`
202 
203   Notes:
204   Use `PetscOptionsPop()` to return to the previous default options database
205 
206   The collectivity of this routine is complex; only the MPI ranks that call this routine will
207   have the affect of these options. If some processes that create objects call this routine and others do
208   not the code may fail in complicated ways because the same parallel solvers may incorrectly use different options
209   on different ranks.
210 
211   Developer Note:
212   Though this functionality has been provided it has never been used in PETSc and might be removed.
213 
214    Level: advanced
215 
216 .seealso: `PetscOptionsPop()`, `PetscOptionsCreate()`, `PetscOptionsInsert()`, `PetscOptionsSetValue()`, `PetscOptionsLeft()`
217 @*/
218 PetscErrorCode PetscOptionsPush(PetscOptions opt)
219 {
220   PetscFunctionBegin;
221   PetscCall(PetscOptionsCreateDefault());
222   opt->previous  = defaultoptions;
223   defaultoptions = opt;
224   PetscFunctionReturn(0);
225 }
226 
227 /*@
228       PetscOptionsPop - Pop the most recent `PetscOptionsPush() `to return to the previous default options
229 
230       Logically collective on whatever communicator was associated with the call to `PetscOptionsCreate()`
231 
232    Level: advanced
233 
234 .seealso: `PetscOptionsPop()`, `PetscOptionsCreate()`, `PetscOptionsInsert()`, `PetscOptionsSetValue()`, `PetscOptionsLeft()`
235 @*/
236 PetscErrorCode PetscOptionsPop(void)
237 {
238   PetscOptions current = defaultoptions;
239 
240   PetscFunctionBegin;
241   PetscCheck(defaultoptions, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing default options");
242   PetscCheck(defaultoptions->previous, PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscOptionsPop() called too many times");
243   defaultoptions    = defaultoptions->previous;
244   current->previous = NULL;
245   PetscFunctionReturn(0);
246 }
247 
248 /*
249     PetscOptionsDestroyDefault - Destroys the default global options database
250 */
251 PetscErrorCode PetscOptionsDestroyDefault(void)
252 {
253   PetscFunctionBegin;
254   if (!defaultoptions) PetscFunctionReturn(0);
255   /* Destroy any options that the user forgot to pop */
256   while (defaultoptions->previous) {
257     PetscOptions tmp = defaultoptions;
258 
259     PetscCall(PetscOptionsPop());
260     PetscCall(PetscOptionsDestroy(&tmp));
261   }
262   PetscCall(PetscOptionsDestroy(&defaultoptions));
263   PetscFunctionReturn(0);
264 }
265 
266 /*@C
267    PetscOptionsValidKey - PETSc Options database keys must begin with one or two dashes (-) followed by a letter.
268 
269    Not collective
270 
271    Input Parameter:
272 .  key - string to check if valid
273 
274    Output Parameter:
275 .  valid - `PETSC_TRUE` if a valid key
276 
277    Level: intermediate
278 @*/
279 PetscErrorCode PetscOptionsValidKey(const char key[], PetscBool *valid)
280 {
281   char *ptr;
282 
283   PetscFunctionBegin;
284   if (key) PetscValidCharPointer(key, 1);
285   PetscValidBoolPointer(valid, 2);
286   *valid = PETSC_FALSE;
287   if (!key) PetscFunctionReturn(0);
288   if (key[0] != '-') PetscFunctionReturn(0);
289   if (key[1] == '-') key++;
290   if (!isalpha((int)key[1])) PetscFunctionReturn(0);
291   (void)strtod(key, &ptr);
292   if (ptr != key && !(*ptr == '_' || isalnum((int)*ptr))) PetscFunctionReturn(0);
293   *valid = PETSC_TRUE;
294   PetscFunctionReturn(0);
295 }
296 
297 /*@C
298    PetscOptionsInsertString - Inserts options into the database from a string
299 
300    Logically Collective
301 
302    Input Parameters:
303 +  options - options object
304 -  in_str - string that contains options separated by blanks
305 
306    Level: intermediate
307 
308   The collectivity of this routine is complex; only the MPI ranks that call this routine will
309   have the affect of these options. If some processes that create objects call this routine and others do
310   not the code may fail in complicated ways because the same parallel solvers may incorrectly use different options
311   on different ranks.
312 
313    Contributed by Boyana Norris
314 
315 .seealso: `PetscOptionsSetValue()`, `PetscOptionsView()`, `PetscOptionsHasName()`, `PetscOptionsGetInt()`,
316           `PetscOptionsGetReal()`, `PetscOptionsGetString()`, `PetscOptionsGetIntArray()`, `PetscOptionsBool()`,
317           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
318           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
319           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
320           `PetscOptionsFList()`, `PetscOptionsEList()`, `PetscOptionsInsertFile()`
321 @*/
322 PetscErrorCode PetscOptionsInsertString(PetscOptions options, const char in_str[])
323 {
324   MPI_Comm   comm = PETSC_COMM_SELF;
325   char      *first, *second;
326   PetscToken token;
327 
328   PetscFunctionBegin;
329   PetscCall(PetscTokenCreate(in_str, ' ', &token));
330   PetscCall(PetscTokenFind(token, &first));
331   while (first) {
332     PetscBool isfile, isfileyaml, isstringyaml, ispush, ispop, key;
333     PetscCall(PetscStrcasecmp(first, "-options_file", &isfile));
334     PetscCall(PetscStrcasecmp(first, "-options_file_yaml", &isfileyaml));
335     PetscCall(PetscStrcasecmp(first, "-options_string_yaml", &isstringyaml));
336     PetscCall(PetscStrcasecmp(first, "-prefix_push", &ispush));
337     PetscCall(PetscStrcasecmp(first, "-prefix_pop", &ispop));
338     PetscCall(PetscOptionsValidKey(first, &key));
339     if (!key) {
340       PetscCall(PetscTokenFind(token, &first));
341     } else if (isfile) {
342       PetscCall(PetscTokenFind(token, &second));
343       PetscCall(PetscOptionsInsertFile(comm, options, second, PETSC_TRUE));
344       PetscCall(PetscTokenFind(token, &first));
345     } else if (isfileyaml) {
346       PetscCall(PetscTokenFind(token, &second));
347       PetscCall(PetscOptionsInsertFileYAML(comm, options, second, PETSC_TRUE));
348       PetscCall(PetscTokenFind(token, &first));
349     } else if (isstringyaml) {
350       PetscCall(PetscTokenFind(token, &second));
351       PetscCall(PetscOptionsInsertStringYAML(options, second));
352       PetscCall(PetscTokenFind(token, &first));
353     } else if (ispush) {
354       PetscCall(PetscTokenFind(token, &second));
355       PetscCall(PetscOptionsPrefixPush(options, second));
356       PetscCall(PetscTokenFind(token, &first));
357     } else if (ispop) {
358       PetscCall(PetscOptionsPrefixPop(options));
359       PetscCall(PetscTokenFind(token, &first));
360     } else {
361       PetscCall(PetscTokenFind(token, &second));
362       PetscCall(PetscOptionsValidKey(second, &key));
363       if (!key) {
364         PetscCall(PetscOptionsSetValue(options, first, second));
365         PetscCall(PetscTokenFind(token, &first));
366       } else {
367         PetscCall(PetscOptionsSetValue(options, first, NULL));
368         first = second;
369       }
370     }
371   }
372   PetscCall(PetscTokenDestroy(&token));
373   PetscFunctionReturn(0);
374 }
375 
376 /*
377     Returns a line (ended by a \n, \r or null character of any length. Result should be freed with free()
378 */
379 static char *Petscgetline(FILE *f)
380 {
381   size_t size = 0;
382   size_t len  = 0;
383   size_t last = 0;
384   char  *buf  = NULL;
385 
386   if (feof(f)) return NULL;
387   do {
388     size += 1024;                             /* BUFSIZ is defined as "the optimal read size for this platform" */
389     buf = (char *)realloc((void *)buf, size); /* realloc(NULL,n) is the same as malloc(n) */
390     /* Actually do the read. Note that fgets puts a terminal '\0' on the
391     end of the string, so we make sure we overwrite this */
392     if (!fgets(buf + len, 1024, f)) buf[len] = 0;
393     PetscStrlen(buf, &len);
394     last = len - 1;
395   } while (!feof(f) && buf[last] != '\n' && buf[last] != '\r');
396   if (len) return buf;
397   free(buf);
398   return NULL;
399 }
400 
401 static PetscErrorCode PetscOptionsFilename(MPI_Comm comm, const char file[], char filename[PETSC_MAX_PATH_LEN], PetscBool *yaml)
402 {
403   char fname[PETSC_MAX_PATH_LEN + 8], path[PETSC_MAX_PATH_LEN + 8], *tail;
404 
405   PetscFunctionBegin;
406   *yaml = PETSC_FALSE;
407   PetscCall(PetscStrreplace(comm, file, fname, sizeof(fname)));
408   PetscCall(PetscFixFilename(fname, path));
409   PetscCall(PetscStrendswith(path, ":yaml", yaml));
410   if (*yaml) {
411     PetscCall(PetscStrrchr(path, ':', &tail));
412     tail[-1] = 0; /* remove ":yaml" suffix from path */
413   }
414   PetscCall(PetscStrncpy(filename, path, PETSC_MAX_PATH_LEN));
415   /* check for standard YAML and JSON filename extensions */
416   if (!*yaml) PetscCall(PetscStrendswith(filename, ".yaml", yaml));
417   if (!*yaml) PetscCall(PetscStrendswith(filename, ".yml", yaml));
418   if (!*yaml) PetscCall(PetscStrendswith(filename, ".json", yaml));
419   if (!*yaml) { /* check file contents */
420     PetscMPIInt rank;
421     PetscCallMPI(MPI_Comm_rank(comm, &rank));
422     if (rank == 0) {
423       FILE *fh = fopen(filename, "r");
424       if (fh) {
425         char buf[6] = "";
426         if (fread(buf, 1, 6, fh) > 0) {
427           PetscCall(PetscStrncmp(buf, "%YAML ", 6, yaml));          /* check for '%YAML' tag */
428           if (!*yaml) PetscCall(PetscStrncmp(buf, "---", 3, yaml)); /* check for document start */
429         }
430         (void)fclose(fh);
431       }
432     }
433     PetscCallMPI(MPI_Bcast(yaml, 1, MPIU_BOOL, 0, comm));
434   }
435   PetscFunctionReturn(0);
436 }
437 
438 static PetscErrorCode PetscOptionsInsertFilePetsc(MPI_Comm comm, PetscOptions options, const char file[], PetscBool require)
439 {
440   char       *string, *vstring = NULL, *astring = NULL, *packed = NULL;
441   char       *tokens[4];
442   size_t      i, len, bytes;
443   FILE       *fd;
444   PetscToken  token = NULL;
445   int         err;
446   char       *cmatch;
447   const char  cmt  = '#';
448   PetscInt    line = 1;
449   PetscMPIInt rank, cnt = 0, acnt = 0, counts[2];
450   PetscBool   isdir, alias = PETSC_FALSE, valid;
451 
452   PetscFunctionBegin;
453   PetscCall(PetscMemzero(tokens, sizeof(tokens)));
454   PetscCallMPI(MPI_Comm_rank(comm, &rank));
455   if (rank == 0) {
456     char fpath[PETSC_MAX_PATH_LEN];
457     char fname[PETSC_MAX_PATH_LEN];
458 
459     PetscCall(PetscStrreplace(PETSC_COMM_SELF, file, fpath, sizeof(fpath)));
460     PetscCall(PetscFixFilename(fpath, fname));
461 
462     fd = fopen(fname, "r");
463     PetscCall(PetscTestDirectory(fname, 'r', &isdir));
464     PetscCheck(!isdir || !require, PETSC_COMM_SELF, PETSC_ERR_USER, "Specified options file %s is a directory", fname);
465     if (fd && !isdir) {
466       PetscSegBuffer vseg, aseg;
467       PetscCall(PetscSegBufferCreate(1, 4000, &vseg));
468       PetscCall(PetscSegBufferCreate(1, 2000, &aseg));
469 
470       /* the following line will not work when opening initial files (like .petscrc) since info is not yet set */
471       PetscCall(PetscInfo(NULL, "Opened options file %s\n", file));
472 
473       while ((string = Petscgetline(fd))) {
474         /* eliminate comments from each line */
475         PetscCall(PetscStrchr(string, cmt, &cmatch));
476         if (cmatch) *cmatch = 0;
477         PetscCall(PetscStrlen(string, &len));
478         /* replace tabs, ^M, \n with " " */
479         for (i = 0; i < len; i++) {
480           if (string[i] == '\t' || string[i] == '\r' || string[i] == '\n') string[i] = ' ';
481         }
482         PetscCall(PetscTokenCreate(string, ' ', &token));
483         PetscCall(PetscTokenFind(token, &tokens[0]));
484         if (!tokens[0]) {
485           goto destroy;
486         } else if (!tokens[0][0]) { /* if token 0 is empty (string begins with spaces), redo */
487           PetscCall(PetscTokenFind(token, &tokens[0]));
488         }
489         for (i = 1; i < 4; i++) PetscCall(PetscTokenFind(token, &tokens[i]));
490         if (!tokens[0]) {
491           goto destroy;
492         } else if (tokens[0][0] == '-') {
493           PetscCall(PetscOptionsValidKey(tokens[0], &valid));
494           PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error in options file %s line %" PetscInt_FMT ": invalid option %s", fname, line, tokens[0]);
495           PetscCall(PetscStrlen(tokens[0], &len));
496           PetscCall(PetscSegBufferGet(vseg, len + 1, &vstring));
497           PetscCall(PetscArraycpy(vstring, tokens[0], len));
498           vstring[len] = ' ';
499           if (tokens[1]) {
500             PetscCall(PetscOptionsValidKey(tokens[1], &valid));
501             PetscCheck(!valid, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error in options file %s line %" PetscInt_FMT ": cannot specify two options per line (%s %s)", fname, line, tokens[0], tokens[1]);
502             PetscCall(PetscStrlen(tokens[1], &len));
503             PetscCall(PetscSegBufferGet(vseg, len + 3, &vstring));
504             vstring[0] = '"';
505             PetscCall(PetscArraycpy(vstring + 1, tokens[1], len));
506             vstring[len + 1] = '"';
507             vstring[len + 2] = ' ';
508           }
509         } else {
510           PetscCall(PetscStrcasecmp(tokens[0], "alias", &alias));
511           if (alias) {
512             PetscCall(PetscOptionsValidKey(tokens[1], &valid));
513             PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error in options file %s line %" PetscInt_FMT ": invalid aliased option %s", fname, line, tokens[1]);
514             PetscCheck(tokens[2], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error in options file %s line %" PetscInt_FMT ": alias missing for %s", fname, line, tokens[1]);
515             PetscCall(PetscOptionsValidKey(tokens[2], &valid));
516             PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error in options file %s line %" PetscInt_FMT ": invalid aliasee option %s", fname, line, tokens[2]);
517             PetscCall(PetscStrlen(tokens[1], &len));
518             PetscCall(PetscSegBufferGet(aseg, len + 1, &astring));
519             PetscCall(PetscArraycpy(astring, tokens[1], len));
520             astring[len] = ' ';
521 
522             PetscCall(PetscStrlen(tokens[2], &len));
523             PetscCall(PetscSegBufferGet(aseg, len + 1, &astring));
524             PetscCall(PetscArraycpy(astring, tokens[2], len));
525             astring[len] = ' ';
526           } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown first token in options file %s line %" PetscInt_FMT ": %s", fname, line, tokens[0]);
527         }
528         {
529           const char *extraToken = alias ? tokens[3] : tokens[2];
530           PetscCheck(!extraToken, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error in options file %s line %" PetscInt_FMT ": extra token %s", fname, line, extraToken);
531         }
532       destroy:
533         free(string);
534         PetscCall(PetscTokenDestroy(&token));
535         alias = PETSC_FALSE;
536         line++;
537       }
538       err = fclose(fd);
539       PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file %s", fname);
540       PetscCall(PetscSegBufferGetSize(aseg, &bytes)); /* size without null termination */
541       PetscCall(PetscMPIIntCast(bytes, &acnt));
542       PetscCall(PetscSegBufferGet(aseg, 1, &astring));
543       astring[0] = 0;
544       PetscCall(PetscSegBufferGetSize(vseg, &bytes)); /* size without null termination */
545       PetscCall(PetscMPIIntCast(bytes, &cnt));
546       PetscCall(PetscSegBufferGet(vseg, 1, &vstring));
547       vstring[0] = 0;
548       PetscCall(PetscMalloc1(2 + acnt + cnt, &packed));
549       PetscCall(PetscSegBufferExtractTo(aseg, packed));
550       PetscCall(PetscSegBufferExtractTo(vseg, packed + acnt + 1));
551       PetscCall(PetscSegBufferDestroy(&aseg));
552       PetscCall(PetscSegBufferDestroy(&vseg));
553     } else PetscCheck(!require, PETSC_COMM_SELF, PETSC_ERR_USER, "Unable to open options file %s", fname);
554   }
555 
556   counts[0] = acnt;
557   counts[1] = cnt;
558   err       = MPI_Bcast(counts, 2, MPI_INT, 0, comm);
559   PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in first MPI collective call, could be caused by using an incorrect mpiexec or a network problem, it can be caused by having VPN running: see https://petsc.org/release/faq/");
560   acnt = counts[0];
561   cnt  = counts[1];
562   if (rank) PetscCall(PetscMalloc1(2 + acnt + cnt, &packed));
563   if (acnt || cnt) {
564     PetscCallMPI(MPI_Bcast(packed, 2 + acnt + cnt, MPI_CHAR, 0, comm));
565     astring = packed;
566     vstring = packed + acnt + 1;
567   }
568 
569   if (acnt) {
570     PetscCall(PetscTokenCreate(astring, ' ', &token));
571     PetscCall(PetscTokenFind(token, &tokens[0]));
572     while (tokens[0]) {
573       PetscCall(PetscTokenFind(token, &tokens[1]));
574       PetscCall(PetscOptionsSetAlias(options, tokens[0], tokens[1]));
575       PetscCall(PetscTokenFind(token, &tokens[0]));
576     }
577     PetscCall(PetscTokenDestroy(&token));
578   }
579 
580   if (cnt) PetscCall(PetscOptionsInsertString(options, vstring));
581   PetscCall(PetscFree(packed));
582   PetscFunctionReturn(0);
583 }
584 
585 /*@C
586      PetscOptionsInsertFile - Inserts options into the database from a file.
587 
588      Collective
589 
590   Input Parameters:
591 +   comm - the processes that will share the options (usually `PETSC_COMM_WORLD`)
592 .   options - options database, use NULL for default global database
593 .   file - name of file,
594            ".yml" and ".yaml" filename extensions are inserted as YAML options,
595            append ":yaml" to filename to force YAML options.
596 -   require - if `PETSC_TRUE` will generate an error if the file does not exist
597 
598   Notes:
599    Use  # for lines that are comments and which should be ignored.
600    Usually, instead of using this command, one should list the file name in the call to `PetscInitialize()`, this insures that certain options
601    such as -log_view or -malloc_debug are processed properly. This routine only sets options into the options database that will be processed by later
602    calls to XXXSetFromOptions() it should not be used for options listed under PetscInitialize().
603    The collectivity of this routine is complex; only the MPI ranks in comm will
604    have the affect of these options. If some processes that create objects call this routine and others do
605    not the code may fail in complicated ways because the same parallel solvers may incorrectly use different options
606    on different ranks.
607 
608   Level: developer
609 
610 .seealso: `PetscOptionsSetValue()`, `PetscOptionsView()`, `PetscOptionsHasName()`, `PetscOptionsGetInt()`,
611           `PetscOptionsGetReal()`, `PetscOptionsGetString()`, `PetscOptionsGetIntArray()`, `PetscOptionsBool()`,
612           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
613           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
614           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
615           `PetscOptionsFList()`, `PetscOptionsEList()`
616 @*/
617 PetscErrorCode PetscOptionsInsertFile(MPI_Comm comm, PetscOptions options, const char file[], PetscBool require)
618 {
619   char      filename[PETSC_MAX_PATH_LEN];
620   PetscBool yaml;
621 
622   PetscFunctionBegin;
623   PetscCall(PetscOptionsFilename(comm, file, filename, &yaml));
624   if (yaml) {
625     PetscCall(PetscOptionsInsertFileYAML(comm, options, filename, require));
626   } else {
627     PetscCall(PetscOptionsInsertFilePetsc(comm, options, filename, require));
628   }
629   PetscFunctionReturn(0);
630 }
631 
632 /*@C
633    PetscOptionsInsertArgs - Inserts options into the database from a array of strings
634 
635    Logically Collective
636 
637    Input Parameters:
638 +  options - options object
639 .  argc - the array length
640 -  args - the string array
641 
642    Level: intermediate
643 
644 .seealso: `PetscOptions`, `PetscOptionsInsertString()`, `PetscOptionsInsertFile()`
645 @*/
646 PetscErrorCode PetscOptionsInsertArgs(PetscOptions options, int argc, char *args[])
647 {
648   MPI_Comm     comm  = PETSC_COMM_WORLD;
649   int          left  = PetscMax(argc, 0);
650   char *const *eargs = args;
651 
652   PetscFunctionBegin;
653   while (left) {
654     PetscBool isfile, isfileyaml, isstringyaml, ispush, ispop, key;
655     PetscCall(PetscStrcasecmp(eargs[0], "-options_file", &isfile));
656     PetscCall(PetscStrcasecmp(eargs[0], "-options_file_yaml", &isfileyaml));
657     PetscCall(PetscStrcasecmp(eargs[0], "-options_string_yaml", &isstringyaml));
658     PetscCall(PetscStrcasecmp(eargs[0], "-prefix_push", &ispush));
659     PetscCall(PetscStrcasecmp(eargs[0], "-prefix_pop", &ispop));
660     PetscCall(PetscOptionsValidKey(eargs[0], &key));
661     if (!key) {
662       eargs++;
663       left--;
664     } else if (isfile) {
665       PetscCheck(left > 1 && eargs[1][0] != '-', PETSC_COMM_SELF, PETSC_ERR_USER, "Missing filename for -options_file filename option");
666       PetscCall(PetscOptionsInsertFile(comm, options, eargs[1], PETSC_TRUE));
667       eargs += 2;
668       left -= 2;
669     } else if (isfileyaml) {
670       PetscCheck(left > 1 && eargs[1][0] != '-', PETSC_COMM_SELF, PETSC_ERR_USER, "Missing filename for -options_file_yaml filename option");
671       PetscCall(PetscOptionsInsertFileYAML(comm, options, eargs[1], PETSC_TRUE));
672       eargs += 2;
673       left -= 2;
674     } else if (isstringyaml) {
675       PetscCheck(left > 1 && eargs[1][0] != '-', PETSC_COMM_SELF, PETSC_ERR_USER, "Missing string for -options_string_yaml string option");
676       PetscCall(PetscOptionsInsertStringYAML(options, eargs[1]));
677       eargs += 2;
678       left -= 2;
679     } else if (ispush) {
680       PetscCheck(left > 1, PETSC_COMM_SELF, PETSC_ERR_USER, "Missing prefix for -prefix_push option");
681       PetscCheck(eargs[1][0] != '-', PETSC_COMM_SELF, PETSC_ERR_USER, "Missing prefix for -prefix_push option (prefixes cannot start with '-')");
682       PetscCall(PetscOptionsPrefixPush(options, eargs[1]));
683       eargs += 2;
684       left -= 2;
685     } else if (ispop) {
686       PetscCall(PetscOptionsPrefixPop(options));
687       eargs++;
688       left--;
689     } else {
690       PetscBool nextiskey = PETSC_FALSE;
691       if (left >= 2) PetscCall(PetscOptionsValidKey(eargs[1], &nextiskey));
692       if (left < 2 || nextiskey) {
693         PetscCall(PetscOptionsSetValue(options, eargs[0], NULL));
694         eargs++;
695         left--;
696       } else {
697         PetscCall(PetscOptionsSetValue(options, eargs[0], eargs[1]));
698         eargs += 2;
699         left -= 2;
700       }
701     }
702   }
703   PetscFunctionReturn(0);
704 }
705 
706 static inline PetscErrorCode PetscOptionsStringToBoolIfSet_Private(enum PetscPrecedentOption opt, const char *val[], PetscBool set[], PetscBool *flg)
707 {
708   PetscFunctionBegin;
709   if (set[opt]) {
710     PetscCall(PetscOptionsStringToBool(val[opt], flg));
711   } else *flg = PETSC_FALSE;
712   PetscFunctionReturn(0);
713 }
714 
715 /* Process options with absolute precedence, these are only processed from the command line, not the environment or files */
716 static PetscErrorCode PetscOptionsProcessPrecedentFlags(PetscOptions options, int argc, char *args[], PetscBool *skip_petscrc, PetscBool *skip_petscrc_set)
717 {
718   const char *const *opt = precedentOptions;
719   const size_t       n   = PO_NUM;
720   size_t             o;
721   int                a;
722   const char       **val;
723   char             **cval;
724   PetscBool         *set, unneeded;
725 
726   PetscFunctionBegin;
727   PetscCall(PetscCalloc2(n, &cval, n, &set));
728   val = (const char **)cval;
729 
730   /* Look for options possibly set using PetscOptionsSetValue beforehand */
731   for (o = 0; o < n; o++) PetscCall(PetscOptionsFindPair(options, NULL, opt[o], &val[o], &set[o]));
732 
733   /* Loop through all args to collect last occurring value of each option */
734   for (a = 1; a < argc; a++) {
735     PetscBool valid, eq;
736 
737     PetscCall(PetscOptionsValidKey(args[a], &valid));
738     if (!valid) continue;
739     for (o = 0; o < n; o++) {
740       PetscCall(PetscStrcasecmp(args[a], opt[o], &eq));
741       if (eq) {
742         set[o] = PETSC_TRUE;
743         if (a == argc - 1 || !args[a + 1] || !args[a + 1][0] || args[a + 1][0] == '-') val[o] = NULL;
744         else val[o] = args[a + 1];
745         break;
746       }
747     }
748   }
749 
750   /* Process flags */
751   PetscCall(PetscStrcasecmp(val[PO_HELP], "intro", &options->help_intro));
752   if (options->help_intro) options->help = PETSC_TRUE;
753   else PetscCall(PetscOptionsStringToBoolIfSet_Private(PO_HELP, val, set, &options->help));
754   PetscCall(PetscOptionsStringToBoolIfSet_Private(PO_CI_ENABLE, val, set, &unneeded));
755   /* need to manage PO_CI_ENABLE option before the PetscOptionsMonitor is turned on, so its setting is not monitored */
756   if (set[PO_CI_ENABLE]) PetscCall(PetscOptionsSetValue_Private(options, opt[PO_CI_ENABLE], val[PO_CI_ENABLE], &a));
757   PetscCall(PetscOptionsStringToBoolIfSet_Private(PO_OPTIONS_MONITOR_CANCEL, val, set, &options->monitorCancel));
758   PetscCall(PetscOptionsStringToBoolIfSet_Private(PO_OPTIONS_MONITOR, val, set, &options->monitorFromOptions));
759   PetscCall(PetscOptionsStringToBoolIfSet_Private(PO_SKIP_PETSCRC, val, set, skip_petscrc));
760   *skip_petscrc_set = set[PO_SKIP_PETSCRC];
761 
762   /* Store precedent options in database and mark them as used */
763   for (o = 1; o < n; o++) {
764     if (set[o]) {
765       PetscCall(PetscOptionsSetValue_Private(options, opt[o], val[o], &a));
766       options->used[a] = PETSC_TRUE;
767     }
768   }
769   PetscCall(PetscFree2(cval, set));
770   options->precedentProcessed = PETSC_TRUE;
771   PetscFunctionReturn(0);
772 }
773 
774 static inline PetscErrorCode PetscOptionsSkipPrecedent(PetscOptions options, const char name[], PetscBool *flg)
775 {
776   PetscFunctionBegin;
777   PetscValidBoolPointer(flg, 3);
778   *flg = PETSC_FALSE;
779   if (options->precedentProcessed) {
780     for (int i = 0; i < PO_NUM; ++i) {
781       if (!PetscOptNameCmp(precedentOptions[i], name)) {
782         /* check if precedent option has been set already */
783         PetscCall(PetscOptionsFindPair(options, NULL, name, NULL, flg));
784         if (*flg) break;
785       }
786     }
787   }
788   PetscFunctionReturn(0);
789 }
790 
791 /*@C
792    PetscOptionsInsert - Inserts into the options database from the command line,
793                         the environmental variable and a file.
794 
795    Collective on `PETSC_COMM_WORLD`
796 
797    Input Parameters:
798 +  options - options database or NULL for the default global database
799 .  argc - count of number of command line arguments
800 .  args - the command line arguments
801 -  file - [optional] PETSc database file, append ":yaml" to filename to specify YAML options format.
802           Use NULL or empty string to not check for code specific file.
803           Also checks ~/.petscrc, .petscrc and petscrc.
804           Use -skip_petscrc in the code specific file (or command line) to skip ~/.petscrc, .petscrc and petscrc files.
805 
806    Options Database Keys:
807 +   -options_file <filename> - read options from a file
808 -   -options_file_yaml <filename> - read options from a YAML file
809 
810    Notes:
811    Since PetscOptionsInsert() is automatically called by `PetscInitialize()`,
812    the user does not typically need to call this routine. `PetscOptionsInsert()`
813    can be called several times, adding additional entries into the database.
814 
815    See `PetscInitialize()` for options related to option database monitoring.
816 
817    Level: advanced
818 
819 .seealso: `PetscOptionsDestroy()`, `PetscOptionsView()`, `PetscOptionsInsertString()`, `PetscOptionsInsertFile()`,
820           `PetscInitialize()`
821 @*/
822 PetscErrorCode PetscOptionsInsert(PetscOptions options, int *argc, char ***args, const char file[])
823 {
824   MPI_Comm    comm = PETSC_COMM_WORLD;
825   PetscMPIInt rank;
826   PetscBool   hasArgs     = (argc && *argc) ? PETSC_TRUE : PETSC_FALSE;
827   PetscBool   skipPetscrc = PETSC_FALSE, skipPetscrcSet = PETSC_FALSE;
828 
829   PetscFunctionBegin;
830   PetscCheck(!hasArgs || (args && *args), comm, PETSC_ERR_ARG_NULL, "*argc > 1 but *args not given");
831   PetscCallMPI(MPI_Comm_rank(comm, &rank));
832 
833   if (!options) {
834     PetscCall(PetscOptionsCreateDefault());
835     options = defaultoptions;
836   }
837   if (hasArgs) {
838     /* process options with absolute precedence */
839     PetscCall(PetscOptionsProcessPrecedentFlags(options, *argc, *args, &skipPetscrc, &skipPetscrcSet));
840     PetscCall(PetscOptionsGetBool(NULL, NULL, "-petsc_ci", &PetscCIEnabled, NULL));
841   }
842   if (file && file[0]) {
843     PetscCall(PetscOptionsInsertFile(comm, options, file, PETSC_TRUE));
844     /* if -skip_petscrc has not been set from command line, check whether it has been set in the file */
845     if (!skipPetscrcSet) PetscCall(PetscOptionsGetBool(options, NULL, "-skip_petscrc", &skipPetscrc, NULL));
846   }
847   if (!skipPetscrc) {
848     char filename[PETSC_MAX_PATH_LEN];
849     PetscCall(PetscGetHomeDirectory(filename, sizeof(filename)));
850     PetscCallMPI(MPI_Bcast(filename, (int)sizeof(filename), MPI_CHAR, 0, comm));
851     if (filename[0]) PetscCall(PetscStrcat(filename, "/.petscrc"));
852     PetscCall(PetscOptionsInsertFile(comm, options, filename, PETSC_FALSE));
853     PetscCall(PetscOptionsInsertFile(comm, options, ".petscrc", PETSC_FALSE));
854     PetscCall(PetscOptionsInsertFile(comm, options, "petscrc", PETSC_FALSE));
855   }
856 
857   /* insert environment options */
858   {
859     char  *eoptions = NULL;
860     size_t len      = 0;
861     if (rank == 0) {
862       eoptions = (char *)getenv("PETSC_OPTIONS");
863       PetscCall(PetscStrlen(eoptions, &len));
864     }
865     PetscCallMPI(MPI_Bcast(&len, 1, MPIU_SIZE_T, 0, comm));
866     if (len) {
867       if (rank) PetscCall(PetscMalloc1(len + 1, &eoptions));
868       PetscCallMPI(MPI_Bcast(eoptions, len, MPI_CHAR, 0, comm));
869       if (rank) eoptions[len] = 0;
870       PetscCall(PetscOptionsInsertString(options, eoptions));
871       if (rank) PetscCall(PetscFree(eoptions));
872     }
873   }
874 
875   /* insert YAML environment options */
876   {
877     char  *eoptions = NULL;
878     size_t len      = 0;
879     if (rank == 0) {
880       eoptions = (char *)getenv("PETSC_OPTIONS_YAML");
881       PetscCall(PetscStrlen(eoptions, &len));
882     }
883     PetscCallMPI(MPI_Bcast(&len, 1, MPIU_SIZE_T, 0, comm));
884     if (len) {
885       if (rank) PetscCall(PetscMalloc1(len + 1, &eoptions));
886       PetscCallMPI(MPI_Bcast(eoptions, len, MPI_CHAR, 0, comm));
887       if (rank) eoptions[len] = 0;
888       PetscCall(PetscOptionsInsertStringYAML(options, eoptions));
889       if (rank) PetscCall(PetscFree(eoptions));
890     }
891   }
892 
893   /* insert command line options here because they take precedence over arguments in petscrc/environment */
894   if (hasArgs) PetscCall(PetscOptionsInsertArgs(options, *argc - 1, *args + 1));
895   PetscCall(PetscOptionsGetBool(NULL, NULL, "-petsc_ci_portable_error_output", &PetscCIEnabledPortableErrorOutput, NULL));
896   PetscFunctionReturn(0);
897 }
898 
899 /* These options are not printed with PetscOptionsView() or PetscOptionsMonitor() when PetscCIEnabled is on */
900 /* TODO: get the list from the test harness, do not have it hardwired here. Maybe from gmakegentest.py */
901 static const char *PetscCIOptions[] = {
902   "malloc_debug",
903   "malloc_dump",
904   "malloc_test",
905   "nox",
906   "nox_warning",
907   "display",
908   "saws_port_auto_select",
909   "saws_port_auto_select_silent",
910   "vecscatter_mpi1",
911   "check_pointer_intensity",
912   "cuda_initialize",
913   "error_output_stdout",
914   "use_gpu_aware_mpi",
915   "checkfunctionlist",
916   "petsc_ci",
917   "petsc_ci_portable_error_output",
918 };
919 
920 static PetscBool PetscCIOption(const char *name)
921 {
922   PetscInt  idx;
923   PetscBool found;
924 
925   if (!PetscCIEnabled) return PETSC_FALSE;
926   PetscEListFind(PETSC_STATIC_ARRAY_LENGTH(PetscCIOptions), PetscCIOptions, name, &idx, &found);
927   return found;
928 }
929 
930 /*@C
931    PetscOptionsView - Prints the options that have been loaded. This is
932    useful for debugging purposes.
933 
934    Logically Collective on viewer
935 
936    Input Parameters:
937 +  options - options database, use NULL for default global database
938 -  viewer - must be an `PETSCVIEWERASCII` viewer
939 
940    Options Database Key:
941 .  -options_view - Activates `PetscOptionsView()` within `PetscFinalize()`
942 
943    Note:
944    Only the rank zero process of the `MPI_Comm` used to create view prints the option values. Other processes
945    may have different values but they are not printed.
946 
947    Level: advanced
948 
949 .seealso: `PetscOptionsAllUsed()`
950 @*/
951 PetscErrorCode PetscOptionsView(PetscOptions options, PetscViewer viewer)
952 {
953   PetscInt  i, N = 0;
954   PetscBool isascii;
955 
956   PetscFunctionBegin;
957   if (viewer) PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
958   options = options ? options : defaultoptions;
959   if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD;
960   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
961   PetscCheck(isascii, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Only supports ASCII viewer");
962 
963   for (i = 0; i < options->N; i++) {
964     if (PetscCIOption(options->names[i])) continue;
965     N++;
966   }
967 
968   if (!N) {
969     PetscCall(PetscViewerASCIIPrintf(viewer, "#No PETSc Option Table entries\n"));
970     PetscFunctionReturn(0);
971   }
972 
973   PetscCall(PetscViewerASCIIPrintf(viewer, "#PETSc Option Table entries:\n"));
974   for (i = 0; i < options->N; i++) {
975     if (PetscCIOption(options->names[i])) continue;
976     if (options->values[i]) {
977       PetscCall(PetscViewerASCIIPrintf(viewer, "-%s %s\n", options->names[i], options->values[i]));
978     } else {
979       PetscCall(PetscViewerASCIIPrintf(viewer, "-%s\n", options->names[i]));
980     }
981   }
982   PetscCall(PetscViewerASCIIPrintf(viewer, "#End of PETSc Option Table entries\n"));
983   PetscFunctionReturn(0);
984 }
985 
986 /*
987    Called by error handlers to print options used in run
988 */
989 PetscErrorCode PetscOptionsLeftError(void)
990 {
991   PetscInt i, nopt = 0;
992 
993   for (i = 0; i < defaultoptions->N; i++) {
994     if (!defaultoptions->used[i]) {
995       if (PetscCIOption(defaultoptions->names[i])) continue;
996       nopt++;
997     }
998   }
999   if (nopt) {
1000     (*PetscErrorPrintf)("WARNING! There are option(s) set that were not used! Could be the program crashed before they were used or a spelling mistake, etc!\n");
1001     for (i = 0; i < defaultoptions->N; i++) {
1002       if (!defaultoptions->used[i]) {
1003         if (PetscCIOption(defaultoptions->names[i])) continue;
1004         if (defaultoptions->values[i]) (*PetscErrorPrintf)("Option left: name:-%s value: %s\n", defaultoptions->names[i], defaultoptions->values[i]);
1005         else (*PetscErrorPrintf)("Option left: name:-%s (no value)\n", defaultoptions->names[i]);
1006       }
1007     }
1008   }
1009   return 0;
1010 }
1011 
1012 PETSC_EXTERN PetscErrorCode PetscOptionsViewError(void)
1013 {
1014   PetscInt     i, N = 0;
1015   PetscOptions options = defaultoptions;
1016 
1017   for (i = 0; i < options->N; i++) {
1018     if (PetscCIOption(options->names[i])) continue;
1019     N++;
1020   }
1021 
1022   if (N) {
1023     (*PetscErrorPrintf)("PETSc Option Table entries:\n");
1024   } else {
1025     (*PetscErrorPrintf)("No PETSc Option Table entries\n");
1026   }
1027   for (i = 0; i < options->N; i++) {
1028     if (PetscCIOption(options->names[i])) continue;
1029     if (options->values[i]) {
1030       (*PetscErrorPrintf)("-%s %s\n", options->names[i], options->values[i]);
1031     } else {
1032       (*PetscErrorPrintf)("-%s\n", options->names[i]);
1033     }
1034   }
1035   return 0;
1036 }
1037 
1038 /*@C
1039    PetscOptionsPrefixPush - Designate a prefix to be used by all options insertions to follow.
1040 
1041    Logically Collective
1042 
1043    Input Parameters:
1044 +  options - options database, or NULL for the default global database
1045 -  prefix - The string to append to the existing prefix
1046 
1047    Options Database Keys:
1048 +   -prefix_push <some_prefix_> - push the given prefix
1049 -   -prefix_pop - pop the last prefix
1050 
1051    Notes:
1052    It is common to use this in conjunction with -options_file as in
1053 
1054 $ -prefix_push system1_ -options_file system1rc -prefix_pop -prefix_push system2_ -options_file system2rc -prefix_pop
1055 
1056    where the files no longer require all options to be prefixed with -system2_.
1057 
1058    The collectivity of this routine is complex; only the MPI ranks that call this routine will
1059    have the affect of these options. If some processes that create objects call this routine and others do
1060    not the code may fail in complicated ways because the same parallel solvers may incorrectly use different options
1061    on different ranks.
1062 
1063    Level: advanced
1064 
1065 .seealso: `PetscOptionsPrefixPop()`, `PetscOptionsPush()`, `PetscOptionsPop()`, `PetscOptionsCreate()`, `PetscOptionsSetValue()`
1066 @*/
1067 PetscErrorCode PetscOptionsPrefixPush(PetscOptions options, const char prefix[])
1068 {
1069   size_t    n;
1070   PetscInt  start;
1071   char      key[MAXOPTNAME + 1];
1072   PetscBool valid;
1073 
1074   PetscFunctionBegin;
1075   PetscValidCharPointer(prefix, 2);
1076   options = options ? options : defaultoptions;
1077   PetscCheck(options->prefixind < MAXPREFIXES, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Maximum depth of prefix stack %d exceeded, recompile \n src/sys/objects/options.c with larger value for MAXPREFIXES", MAXPREFIXES);
1078   key[0] = '-'; /* keys must start with '-' */
1079   PetscCall(PetscStrncpy(key + 1, prefix, sizeof(key) - 1));
1080   PetscCall(PetscOptionsValidKey(key, &valid));
1081   if (!valid && options->prefixind > 0 && isdigit((int)prefix[0])) valid = PETSC_TRUE; /* If the prefix stack is not empty, make numbers a valid prefix */
1082   PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_USER, "Given prefix \"%s\" not valid (the first character must be a letter%s, do not include leading '-')", prefix, options->prefixind ? " or digit" : "");
1083   start = options->prefixind ? options->prefixstack[options->prefixind - 1] : 0;
1084   PetscCall(PetscStrlen(prefix, &n));
1085   PetscCheck(n + 1 <= sizeof(options->prefix) - start, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Maximum prefix length %zu exceeded", sizeof(options->prefix));
1086   PetscCall(PetscArraycpy(options->prefix + start, prefix, n + 1));
1087   options->prefixstack[options->prefixind++] = start + n;
1088   PetscFunctionReturn(0);
1089 }
1090 
1091 /*@C
1092    PetscOptionsPrefixPop - Remove the latest options prefix, see `PetscOptionsPrefixPush()` for details
1093 
1094    Logically Collective on the `MPI_Comm` used when called `PetscOptionsPrefixPush()`
1095 
1096   Input Parameter:
1097 .  options - options database, or NULL for the default global database
1098 
1099    Level: advanced
1100 
1101 .seealso: `PetscOptionsPrefixPush()`, `PetscOptionsPush()`, `PetscOptionsPop()`, `PetscOptionsCreate()`, `PetscOptionsSetValue()`
1102 @*/
1103 PetscErrorCode PetscOptionsPrefixPop(PetscOptions options)
1104 {
1105   PetscInt offset;
1106 
1107   PetscFunctionBegin;
1108   options = options ? options : defaultoptions;
1109   PetscCheck(options->prefixind >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "More prefixes popped than pushed");
1110   options->prefixind--;
1111   offset                  = options->prefixind ? options->prefixstack[options->prefixind - 1] : 0;
1112   options->prefix[offset] = 0;
1113   PetscFunctionReturn(0);
1114 }
1115 
1116 /*@C
1117     PetscOptionsClear - Removes all options form the database leaving it empty.
1118 
1119     Logically Collective
1120 
1121   Input Parameter:
1122 .  options - options database, use NULL for the default global database
1123 
1124    The collectivity of this routine is complex; only the MPI ranks that call this routine will
1125    have the affect of these options. If some processes that create objects call this routine and others do
1126    not the code may fail in complicated ways because the same parallel solvers may incorrectly use different options
1127    on different ranks.
1128 
1129    Level: developer
1130 
1131 .seealso: `PetscOptionsInsert()`
1132 @*/
1133 PetscErrorCode PetscOptionsClear(PetscOptions options)
1134 {
1135   PetscInt i;
1136 
1137   PetscFunctionBegin;
1138   options = options ? options : defaultoptions;
1139   if (!options) PetscFunctionReturn(0);
1140 
1141   for (i = 0; i < options->N; i++) {
1142     if (options->names[i]) free(options->names[i]);
1143     if (options->values[i]) free(options->values[i]);
1144   }
1145   options->N = 0;
1146 
1147   for (i = 0; i < options->Naliases; i++) {
1148     free(options->aliases1[i]);
1149     free(options->aliases2[i]);
1150   }
1151   options->Naliases = 0;
1152 
1153   /* destroy hash table */
1154   kh_destroy(HO, options->ht);
1155   options->ht = NULL;
1156 
1157   options->prefixind = 0;
1158   options->prefix[0] = 0;
1159   options->help      = PETSC_FALSE;
1160   PetscFunctionReturn(0);
1161 }
1162 
1163 /*@C
1164    PetscOptionsSetAlias - Makes a key and alias for another key
1165 
1166    Logically Collective
1167 
1168    Input Parameters:
1169 +  options - options database, or NULL for default global database
1170 .  newname - the alias
1171 -  oldname - the name that alias will refer to
1172 
1173    Level: advanced
1174 
1175    The collectivity of this routine is complex; only the MPI ranks that call this routine will
1176    have the affect of these options. If some processes that create objects call this routine and others do
1177    not the code may fail in complicated ways because the same parallel solvers may incorrectly use different options
1178    on different ranks.
1179 
1180 .seealso: `PetscOptionsGetInt()`, `PetscOptionsGetReal()`, `OptionsHasName()`,
1181           `PetscOptionsGetString()`, `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
1182           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
1183           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
1184           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
1185           `PetscOptionsFList()`, `PetscOptionsEList()`
1186 @*/
1187 PetscErrorCode PetscOptionsSetAlias(PetscOptions options, const char newname[], const char oldname[])
1188 {
1189   PetscInt  n;
1190   size_t    len;
1191   PetscBool valid;
1192 
1193   PetscFunctionBegin;
1194   PetscValidCharPointer(newname, 2);
1195   PetscValidCharPointer(oldname, 3);
1196   options = options ? options : defaultoptions;
1197   PetscCall(PetscOptionsValidKey(newname, &valid));
1198   PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid aliased option %s", newname);
1199   PetscCall(PetscOptionsValidKey(oldname, &valid));
1200   PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid aliasee option %s", oldname);
1201 
1202   n = options->Naliases;
1203   PetscCheck(n < MAXALIASES, PETSC_COMM_SELF, PETSC_ERR_MEM, "You have defined to many PETSc options aliases, limit %d recompile \n  src/sys/objects/options.c with larger value for MAXALIASES", MAXALIASES);
1204 
1205   newname++;
1206   oldname++;
1207   PetscCall(PetscStrlen(newname, &len));
1208   options->aliases1[n] = (char *)malloc((len + 1) * sizeof(char));
1209   PetscCall(PetscStrcpy(options->aliases1[n], newname));
1210   PetscCall(PetscStrlen(oldname, &len));
1211   options->aliases2[n] = (char *)malloc((len + 1) * sizeof(char));
1212   PetscCall(PetscStrcpy(options->aliases2[n], oldname));
1213   options->Naliases++;
1214   PetscFunctionReturn(0);
1215 }
1216 
1217 /*@C
1218    PetscOptionsSetValue - Sets an option name-value pair in the options
1219    database, overriding whatever is already present.
1220 
1221    Logically Collective
1222 
1223    Input Parameters:
1224 +  options - options database, use NULL for the default global database
1225 .  name - name of option, this SHOULD have the - prepended
1226 -  value - the option value (not used for all options, so can be NULL)
1227 
1228    Level: intermediate
1229 
1230    Note:
1231    This function can be called BEFORE `PetscInitialize()`
1232 
1233    The collectivity of this routine is complex; only the MPI ranks that call this routine will
1234    have the affect of these options. If some processes that create objects call this routine and others do
1235    not the code may fail in complicated ways because the same parallel solvers may incorrectly use different options
1236    on different ranks.
1237 
1238    Developers Note: Uses malloc() directly because PETSc may not be initialized yet.
1239 
1240 .seealso: `PetscOptionsInsert()`, `PetscOptionsClearValue()`
1241 @*/
1242 PetscErrorCode PetscOptionsSetValue(PetscOptions options, const char name[], const char value[])
1243 {
1244   PetscFunctionBegin;
1245   PetscCall(PetscOptionsSetValue_Private(options, name, value, NULL));
1246   PetscFunctionReturn(0);
1247 }
1248 
1249 static PetscErrorCode PetscOptionsSetValue_Private(PetscOptions options, const char name[], const char value[], int *pos)
1250 {
1251   size_t    len;
1252   int       N, n, i;
1253   char    **names;
1254   char      fullname[MAXOPTNAME] = "";
1255   PetscBool flg;
1256 
1257   PetscFunctionBegin;
1258   if (!options) {
1259     PetscCall(PetscOptionsCreateDefault());
1260     options = defaultoptions;
1261   }
1262   PetscCheck(name[0] == '-', PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "name %s must start with '-'", name);
1263 
1264   PetscCall(PetscOptionsSkipPrecedent(options, name, &flg));
1265   if (flg) PetscFunctionReturn(0);
1266 
1267   name++; /* skip starting dash */
1268 
1269   if (options->prefixind > 0) {
1270     strncpy(fullname, options->prefix, sizeof(fullname));
1271     fullname[sizeof(fullname) - 1] = 0;
1272     strncat(fullname, name, sizeof(fullname) - strlen(fullname) - 1);
1273     fullname[sizeof(fullname) - 1] = 0;
1274     name                           = fullname;
1275   }
1276 
1277   /* check against aliases */
1278   N = options->Naliases;
1279   for (i = 0; i < N; i++) {
1280     int result = PetscOptNameCmp(options->aliases1[i], name);
1281     if (!result) {
1282       name = options->aliases2[i];
1283       break;
1284     }
1285   }
1286 
1287   /* slow search */
1288   N = n = options->N;
1289   names = options->names;
1290   for (i = 0; i < N; i++) {
1291     int result = PetscOptNameCmp(names[i], name);
1292     if (!result) {
1293       n = i;
1294       goto setvalue;
1295     } else if (result > 0) {
1296       n = i;
1297       break;
1298     }
1299   }
1300   PetscCheck(N < MAXOPTIONS, PETSC_COMM_SELF, PETSC_ERR_MEM, "Number of options %d < max number of options %d, can not allocate enough space", N, MAXOPTIONS);
1301 
1302   /* shift remaining values up 1 */
1303   for (i = N; i > n; i--) {
1304     options->names[i]  = options->names[i - 1];
1305     options->values[i] = options->values[i - 1];
1306     options->used[i]   = options->used[i - 1];
1307   }
1308   options->names[n]  = NULL;
1309   options->values[n] = NULL;
1310   options->used[n]   = PETSC_FALSE;
1311   options->N++;
1312 
1313   /* destroy hash table */
1314   kh_destroy(HO, options->ht);
1315   options->ht = NULL;
1316 
1317   /* set new name */
1318   len               = strlen(name);
1319   options->names[n] = (char *)malloc((len + 1) * sizeof(char));
1320   PetscCheck(options->names[n], PETSC_COMM_SELF, PETSC_ERR_MEM, "Failed to allocate option name");
1321   strcpy(options->names[n], name);
1322 
1323 setvalue:
1324   /* set new value */
1325   if (options->values[n]) free(options->values[n]);
1326   len = value ? strlen(value) : 0;
1327   if (len) {
1328     options->values[n] = (char *)malloc((len + 1) * sizeof(char));
1329     if (!options->values[n]) return PETSC_ERR_MEM;
1330     strcpy(options->values[n], value);
1331   } else {
1332     options->values[n] = NULL;
1333   }
1334 
1335   /* handle -help so that it can be set from anywhere */
1336   if (!PetscOptNameCmp(name, "help")) {
1337     options->help       = PETSC_TRUE;
1338     options->help_intro = (value && !PetscOptNameCmp(value, "intro")) ? PETSC_TRUE : PETSC_FALSE;
1339     options->used[n]    = PETSC_TRUE;
1340   }
1341 
1342   PetscCall(PetscOptionsMonitor(options, name, value));
1343   if (pos) *pos = n;
1344   PetscFunctionReturn(0);
1345 }
1346 
1347 /*@C
1348    PetscOptionsClearValue - Clears an option name-value pair in the options
1349    database, overriding whatever is already present.
1350 
1351    Logically Collective
1352 
1353    Input Parameters:
1354 +  options - options database, use NULL for the default global database
1355 -  name - name of option, this SHOULD have the - prepended
1356 
1357    Level: intermediate
1358 
1359    Note:
1360    The collectivity of this routine is complex; only the MPI ranks that call this routine will
1361    have the affect of these options. If some processes that create objects call this routine and others do
1362    not the code may fail in complicated ways because the same parallel solvers may incorrectly use different options
1363    on different ranks.
1364 
1365 .seealso: `PetscOptionsInsert()`
1366 @*/
1367 PetscErrorCode PetscOptionsClearValue(PetscOptions options, const char name[])
1368 {
1369   int    N, n, i;
1370   char **names;
1371 
1372   PetscFunctionBegin;
1373   options = options ? options : defaultoptions;
1374   PetscCheck(name[0] == '-', PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Name must begin with '-': Instead %s", name);
1375   if (!PetscOptNameCmp(name, "-help")) options->help = options->help_intro = PETSC_FALSE;
1376 
1377   name++; /* skip starting dash */
1378 
1379   /* slow search */
1380   N = n = options->N;
1381   names = options->names;
1382   for (i = 0; i < N; i++) {
1383     int result = PetscOptNameCmp(names[i], name);
1384     if (!result) {
1385       n = i;
1386       break;
1387     } else if (result > 0) {
1388       n = N;
1389       break;
1390     }
1391   }
1392   if (n == N) PetscFunctionReturn(0); /* it was not present */
1393 
1394   /* remove name and value */
1395   if (options->names[n]) free(options->names[n]);
1396   if (options->values[n]) free(options->values[n]);
1397   /* shift remaining values down 1 */
1398   for (i = n; i < N - 1; i++) {
1399     options->names[i]  = options->names[i + 1];
1400     options->values[i] = options->values[i + 1];
1401     options->used[i]   = options->used[i + 1];
1402   }
1403   options->N--;
1404 
1405   /* destroy hash table */
1406   kh_destroy(HO, options->ht);
1407   options->ht = NULL;
1408 
1409   PetscCall(PetscOptionsMonitor(options, name, NULL));
1410   PetscFunctionReturn(0);
1411 }
1412 
1413 /*@C
1414    PetscOptionsFindPair - Gets an option name-value pair from the options database.
1415 
1416    Not Collective
1417 
1418    Input Parameters:
1419 +  options - options database, use NULL for the default global database
1420 .  pre - the string to prepend to the name or NULL, this SHOULD NOT have the "-" prepended
1421 -  name - name of option, this SHOULD have the "-" prepended
1422 
1423    Output Parameters:
1424 +  value - the option value (optional, not used for all options)
1425 -  set - whether the option is set (optional)
1426 
1427    Note:
1428    Each process may find different values or no value depending on how options were inserted into the database
1429 
1430    Level: developer
1431 
1432 .seealso: `PetscOptionsSetValue()`, `PetscOptionsClearValue()`
1433 @*/
1434 PetscErrorCode PetscOptionsFindPair(PetscOptions options, const char pre[], const char name[], const char *value[], PetscBool *set)
1435 {
1436   char      buf[MAXOPTNAME];
1437   PetscBool usehashtable = PETSC_TRUE;
1438   PetscBool matchnumbers = PETSC_TRUE;
1439 
1440   PetscFunctionBegin;
1441   options = options ? options : defaultoptions;
1442   PetscCheck(!pre || !PetscUnlikely(pre[0] == '-'), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Prefix cannot begin with '-': Instead %s", pre);
1443   PetscCheck(name[0] == '-', PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Name must begin with '-': Instead %s", name);
1444 
1445   name++; /* skip starting dash */
1446 
1447   /* append prefix to name, if prefix="foo_" and option='--bar", prefixed option is --foo_bar */
1448   if (pre && pre[0]) {
1449     char *ptr = buf;
1450     if (name[0] == '-') {
1451       *ptr++ = '-';
1452       name++;
1453     }
1454     PetscCall(PetscStrncpy(ptr, pre, buf + sizeof(buf) - ptr));
1455     PetscCall(PetscStrlcat(buf, name, sizeof(buf)));
1456     name = buf;
1457   }
1458 
1459   if (PetscDefined(USE_DEBUG)) {
1460     PetscBool valid;
1461     char      key[MAXOPTNAME + 1] = "-";
1462     PetscCall(PetscStrncpy(key + 1, name, sizeof(key) - 1));
1463     PetscCall(PetscOptionsValidKey(key, &valid));
1464     PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid option '%s' obtained from pre='%s' and name='%s'", key, pre ? pre : "", name);
1465   }
1466 
1467   if (!options->ht && usehashtable) {
1468     int          i, ret;
1469     khiter_t     it;
1470     khash_t(HO) *ht;
1471     ht = kh_init(HO);
1472     PetscCheck(ht, PETSC_COMM_SELF, PETSC_ERR_MEM, "Hash table allocation failed");
1473     ret = kh_resize(HO, ht, options->N * 2); /* twice the required size to reduce risk of collisions */
1474     PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_MEM, "Hash table allocation failed");
1475     for (i = 0; i < options->N; i++) {
1476       it = kh_put(HO, ht, options->names[i], &ret);
1477       PetscCheck(ret == 1, PETSC_COMM_SELF, PETSC_ERR_MEM, "Hash table allocation failed");
1478       kh_val(ht, it) = i;
1479     }
1480     options->ht = ht;
1481   }
1482 
1483   if (usehashtable) { /* fast search */
1484     khash_t(HO) *ht = options->ht;
1485     khiter_t     it = kh_get(HO, ht, name);
1486     if (it != kh_end(ht)) {
1487       int i            = kh_val(ht, it);
1488       options->used[i] = PETSC_TRUE;
1489       if (value) *value = options->values[i];
1490       if (set) *set = PETSC_TRUE;
1491       PetscFunctionReturn(0);
1492     }
1493   } else { /* slow search */
1494     int i, N = options->N;
1495     for (i = 0; i < N; i++) {
1496       int result = PetscOptNameCmp(options->names[i], name);
1497       if (!result) {
1498         options->used[i] = PETSC_TRUE;
1499         if (value) *value = options->values[i];
1500         if (set) *set = PETSC_TRUE;
1501         PetscFunctionReturn(0);
1502       } else if (result > 0) {
1503         break;
1504       }
1505     }
1506   }
1507 
1508   /*
1509    The following block slows down all lookups in the most frequent path (most lookups are unsuccessful).
1510    Maybe this special lookup mode should be enabled on request with a push/pop API.
1511    The feature of matching _%d_ used sparingly in the codebase.
1512    */
1513   if (matchnumbers) {
1514     int i, j, cnt = 0, locs[16], loce[16];
1515     /* determine the location and number of all _%d_ in the key */
1516     for (i = 0; name[i]; i++) {
1517       if (name[i] == '_') {
1518         for (j = i + 1; name[j]; j++) {
1519           if (name[j] >= '0' && name[j] <= '9') continue;
1520           if (name[j] == '_' && j > i + 1) { /* found a number */
1521             locs[cnt]   = i + 1;
1522             loce[cnt++] = j + 1;
1523           }
1524           i = j - 1;
1525           break;
1526         }
1527       }
1528     }
1529     for (i = 0; i < cnt; i++) {
1530       PetscBool found;
1531       char      opt[MAXOPTNAME + 1] = "-", tmp[MAXOPTNAME];
1532       PetscCall(PetscStrncpy(tmp, name, PetscMin((size_t)(locs[i] + 1), sizeof(tmp))));
1533       PetscCall(PetscStrlcat(opt, tmp, sizeof(opt)));
1534       PetscCall(PetscStrlcat(opt, name + loce[i], sizeof(opt)));
1535       PetscCall(PetscOptionsFindPair(options, NULL, opt, value, &found));
1536       if (found) {
1537         if (set) *set = PETSC_TRUE;
1538         PetscFunctionReturn(0);
1539       }
1540     }
1541   }
1542 
1543   if (set) *set = PETSC_FALSE;
1544   PetscFunctionReturn(0);
1545 }
1546 
1547 /* Check whether any option begins with pre+name */
1548 PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions options, const char pre[], const char name[], const char *value[], PetscBool *set)
1549 {
1550   char buf[MAXOPTNAME];
1551   int  numCnt = 0, locs[16], loce[16];
1552 
1553   PetscFunctionBegin;
1554   options = options ? options : defaultoptions;
1555   PetscCheck(!pre || pre[0] != '-', PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Prefix cannot begin with '-': Instead %s", pre);
1556   PetscCheck(name[0] == '-', PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Name must begin with '-': Instead %s", name);
1557 
1558   name++; /* skip starting dash */
1559 
1560   /* append prefix to name, if prefix="foo_" and option='--bar", prefixed option is --foo_bar */
1561   if (pre && pre[0]) {
1562     char *ptr = buf;
1563     if (name[0] == '-') {
1564       *ptr++ = '-';
1565       name++;
1566     }
1567     PetscCall(PetscStrncpy(ptr, pre, sizeof(buf) + (size_t)(ptr - buf)));
1568     PetscCall(PetscStrlcat(buf, name, sizeof(buf)));
1569     name = buf;
1570   }
1571 
1572   if (PetscDefined(USE_DEBUG)) {
1573     PetscBool valid;
1574     char      key[MAXOPTNAME + 1] = "-";
1575     PetscCall(PetscStrncpy(key + 1, name, sizeof(key) - 1));
1576     PetscCall(PetscOptionsValidKey(key, &valid));
1577     PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid option '%s' obtained from pre='%s' and name='%s'", key, pre ? pre : "", name);
1578   }
1579 
1580   /* determine the location and number of all _%d_ in the key */
1581   {
1582     int i, j;
1583     for (i = 0; name[i]; i++) {
1584       if (name[i] == '_') {
1585         for (j = i + 1; name[j]; j++) {
1586           if (name[j] >= '0' && name[j] <= '9') continue;
1587           if (name[j] == '_' && j > i + 1) { /* found a number */
1588             locs[numCnt]   = i + 1;
1589             loce[numCnt++] = j + 1;
1590           }
1591           i = j - 1;
1592           break;
1593         }
1594       }
1595     }
1596   }
1597 
1598   { /* slow search */
1599     int       c, i;
1600     size_t    len;
1601     PetscBool match;
1602 
1603     for (c = -1; c < numCnt; ++c) {
1604       char opt[MAXOPTNAME + 1] = "", tmp[MAXOPTNAME];
1605 
1606       if (c < 0) {
1607         PetscCall(PetscStrcpy(opt, name));
1608       } else {
1609         PetscCall(PetscStrncpy(tmp, name, PetscMin((size_t)(locs[c] + 1), sizeof(tmp))));
1610         PetscCall(PetscStrlcat(opt, tmp, sizeof(opt)));
1611         PetscCall(PetscStrlcat(opt, name + loce[c], sizeof(opt)));
1612       }
1613       PetscCall(PetscStrlen(opt, &len));
1614       for (i = 0; i < options->N; i++) {
1615         PetscCall(PetscStrncmp(options->names[i], opt, len, &match));
1616         if (match) {
1617           options->used[i] = PETSC_TRUE;
1618           if (value) *value = options->values[i];
1619           if (set) *set = PETSC_TRUE;
1620           PetscFunctionReturn(0);
1621         }
1622       }
1623     }
1624   }
1625 
1626   if (set) *set = PETSC_FALSE;
1627   PetscFunctionReturn(0);
1628 }
1629 
1630 /*@C
1631    PetscOptionsReject - Generates an error if a certain option is given.
1632 
1633    Not Collective
1634 
1635    Input Parameters:
1636 +  options - options database, use NULL for default global database
1637 .  pre - the option prefix (may be NULL)
1638 .  name - the option name one is seeking
1639 -  mess - error message (may be NULL)
1640 
1641    Level: advanced
1642 
1643 .seealso: `PetscOptionsGetInt()`, `PetscOptionsGetReal()`, `OptionsHasName()`,
1644           `PetscOptionsGetString()`, `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
1645           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
1646           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
1647           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
1648           `PetscOptionsFList()`, `PetscOptionsEList()`
1649 @*/
1650 PetscErrorCode PetscOptionsReject(PetscOptions options, const char pre[], const char name[], const char mess[])
1651 {
1652   PetscBool flag = PETSC_FALSE;
1653 
1654   PetscFunctionBegin;
1655   PetscCall(PetscOptionsHasName(options, pre, name, &flag));
1656   if (flag) {
1657     PetscCheck(!mess || !mess[0], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Program has disabled option: -%s%s with %s", pre ? pre : "", name + 1, mess);
1658     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Program has disabled option: -%s%s", pre ? pre : "", name + 1);
1659   }
1660   PetscFunctionReturn(0);
1661 }
1662 
1663 /*@C
1664    PetscOptionsHasHelp - Determines whether the "-help" option is in the database.
1665 
1666    Not Collective
1667 
1668    Input Parameter:
1669 .  options - options database, use NULL for default global database
1670 
1671    Output Parameter:
1672 .  set - `PETSC_TRUE` if found else `PETSC_FALSE`.
1673 
1674    Level: advanced
1675 
1676 .seealso: `PetscOptionsHasName()`
1677 @*/
1678 PetscErrorCode PetscOptionsHasHelp(PetscOptions options, PetscBool *set)
1679 {
1680   PetscFunctionBegin;
1681   PetscValidBoolPointer(set, 2);
1682   options = options ? options : defaultoptions;
1683   *set    = options->help;
1684   PetscFunctionReturn(0);
1685 }
1686 
1687 PetscErrorCode PetscOptionsHasHelpIntro_Internal(PetscOptions options, PetscBool *set)
1688 {
1689   PetscFunctionBegin;
1690   PetscValidBoolPointer(set, 2);
1691   options = options ? options : defaultoptions;
1692   *set    = options->help_intro;
1693   PetscFunctionReturn(0);
1694 }
1695 
1696 /*@C
1697    PetscOptionsHasName - Determines whether a certain option is given in the database. This returns true whether the option is a number, string or Boolean, even
1698                       if its value is set to false.
1699 
1700    Not Collective
1701 
1702    Input Parameters:
1703 +  options - options database, use NULL for default global database
1704 .  pre - string to prepend to the name or NULL
1705 -  name - the option one is seeking
1706 
1707    Output Parameter:
1708 .  set - `PETSC_TRUE` if found else `PETSC_FALSE`.
1709 
1710    Level: beginner
1711 
1712    Note:
1713    In many cases you probably want to use `PetscOptionsGetBool()` instead of calling this, to allowing toggling values.
1714 
1715 .seealso: `PetscOptionsGetInt()`, `PetscOptionsGetReal()`,
1716           `PetscOptionsGetString()`, `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
1717           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
1718           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
1719           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
1720           `PetscOptionsFList()`, `PetscOptionsEList()`
1721 @*/
1722 PetscErrorCode PetscOptionsHasName(PetscOptions options, const char pre[], const char name[], PetscBool *set)
1723 {
1724   const char *value;
1725   PetscBool   flag;
1726 
1727   PetscFunctionBegin;
1728   PetscCall(PetscOptionsFindPair(options, pre, name, &value, &flag));
1729   if (set) *set = flag;
1730   PetscFunctionReturn(0);
1731 }
1732 
1733 /*@C
1734    PetscOptionsGetAll - Lists all the options the program was run with in a single string.
1735 
1736    Not Collective
1737 
1738    Input Parameter:
1739 .  options - the options database, use NULL for the default global database
1740 
1741    Output Parameter:
1742 .  copts - pointer where string pointer is stored
1743 
1744    Notes:
1745     The array and each entry in the array should be freed with `PetscFree()`
1746 
1747     Each process may have different values depending on how the options were inserted into the database
1748 
1749    Level: advanced
1750 
1751 .seealso: `PetscOptionsAllUsed()`, `PetscOptionsView()`, `PetscOptionsPush()`, `PetscOptionsPop()`
1752 @*/
1753 PetscErrorCode PetscOptionsGetAll(PetscOptions options, char *copts[])
1754 {
1755   PetscInt i;
1756   size_t   len = 1, lent = 0;
1757   char    *coptions = NULL;
1758 
1759   PetscFunctionBegin;
1760   PetscValidPointer(copts, 2);
1761   options = options ? options : defaultoptions;
1762   /* count the length of the required string */
1763   for (i = 0; i < options->N; i++) {
1764     PetscCall(PetscStrlen(options->names[i], &lent));
1765     len += 2 + lent;
1766     if (options->values[i]) {
1767       PetscCall(PetscStrlen(options->values[i], &lent));
1768       len += 1 + lent;
1769     }
1770   }
1771   PetscCall(PetscMalloc1(len, &coptions));
1772   coptions[0] = 0;
1773   for (i = 0; i < options->N; i++) {
1774     PetscCall(PetscStrcat(coptions, "-"));
1775     PetscCall(PetscStrcat(coptions, options->names[i]));
1776     PetscCall(PetscStrcat(coptions, " "));
1777     if (options->values[i]) {
1778       PetscCall(PetscStrcat(coptions, options->values[i]));
1779       PetscCall(PetscStrcat(coptions, " "));
1780     }
1781   }
1782   *copts = coptions;
1783   PetscFunctionReturn(0);
1784 }
1785 
1786 /*@C
1787    PetscOptionsUsed - Indicates if PETSc has used a particular option set in the database
1788 
1789    Not Collective
1790 
1791    Input Parameters:
1792 +  options - options database, use NULL for default global database
1793 -  name - string name of option
1794 
1795    Output Parameter:
1796 .  used - `PETSC_TRUE` if the option was used, otherwise false, including if option was not found in options database
1797 
1798    Level: advanced
1799 
1800    Note:
1801    The value returned may be different on each process and depends on which options have been processed
1802    on the given process
1803 
1804 .seealso: `PetscOptionsView()`, `PetscOptionsLeft()`, `PetscOptionsAllUsed()`
1805 @*/
1806 PetscErrorCode PetscOptionsUsed(PetscOptions options, const char *name, PetscBool *used)
1807 {
1808   PetscInt i;
1809 
1810   PetscFunctionBegin;
1811   PetscValidCharPointer(name, 2);
1812   PetscValidBoolPointer(used, 3);
1813   options = options ? options : defaultoptions;
1814   *used   = PETSC_FALSE;
1815   for (i = 0; i < options->N; i++) {
1816     PetscCall(PetscStrcasecmp(options->names[i], name, used));
1817     if (*used) {
1818       *used = options->used[i];
1819       break;
1820     }
1821   }
1822   PetscFunctionReturn(0);
1823 }
1824 
1825 /*@
1826    PetscOptionsAllUsed - Returns a count of the number of options in the
1827    database that have never been selected.
1828 
1829    Not Collective
1830 
1831    Input Parameter:
1832 .  options - options database, use NULL for default global database
1833 
1834    Output Parameter:
1835 .  N - count of options not used
1836 
1837    Level: advanced
1838 
1839    Note:
1840    The value returned may be different on each process and depends on which options have been processed
1841    on the given process
1842 
1843 .seealso: `PetscOptionsView()`
1844 @*/
1845 PetscErrorCode PetscOptionsAllUsed(PetscOptions options, PetscInt *N)
1846 {
1847   PetscInt i, n = 0;
1848 
1849   PetscFunctionBegin;
1850   PetscValidIntPointer(N, 2);
1851   options = options ? options : defaultoptions;
1852   for (i = 0; i < options->N; i++) {
1853     if (!options->used[i]) n++;
1854   }
1855   *N = n;
1856   PetscFunctionReturn(0);
1857 }
1858 
1859 /*@
1860    PetscOptionsLeft - Prints to screen any options that were set and never used.
1861 
1862    Not Collective
1863 
1864    Input Parameter:
1865 .  options - options database; use NULL for default global database
1866 
1867    Options Database Key:
1868 .  -options_left - activates `PetscOptionsAllUsed()` within `PetscFinalize()`
1869 
1870    Notes:
1871       This is rarely used directly, it is called by `PetscFinalize()` in debug more or if -options_left
1872       is passed otherwise to help users determine possible mistakes in their usage of options. This
1873       only prints values on process zero of `PETSC_COMM_WORLD`.
1874 
1875       Other processes depending the objects
1876       used may have different options that are left unused.
1877 
1878    Level: advanced
1879 
1880 .seealso: `PetscOptionsAllUsed()`
1881 @*/
1882 PetscErrorCode PetscOptionsLeft(PetscOptions options)
1883 {
1884   PetscInt     i;
1885   PetscInt     cnt = 0;
1886   PetscOptions toptions;
1887 
1888   PetscFunctionBegin;
1889   toptions = options ? options : defaultoptions;
1890   for (i = 0; i < toptions->N; i++) {
1891     if (!toptions->used[i]) {
1892       if (PetscCIOption(toptions->names[i])) continue;
1893       if (toptions->values[i]) {
1894         PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Option left: name:-%s value: %s\n", toptions->names[i], toptions->values[i]));
1895       } else {
1896         PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Option left: name:-%s (no value)\n", toptions->names[i]));
1897       }
1898     }
1899   }
1900   if (!options) {
1901     toptions = defaultoptions;
1902     while (toptions->previous) {
1903       cnt++;
1904       toptions = toptions->previous;
1905     }
1906     if (cnt) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Option left: You may have forgotten some calls to PetscOptionsPop(),\n             PetscOptionsPop() has been called %" PetscInt_FMT " less times than PetscOptionsPush()\n", cnt));
1907   }
1908   PetscFunctionReturn(0);
1909 }
1910 
1911 /*@C
1912    PetscOptionsLeftGet - Returns all options that were set and never used.
1913 
1914    Not Collective
1915 
1916    Input Parameter:
1917 .  options - options database, use NULL for default global database
1918 
1919    Output Parameters:
1920 +  N - count of options not used
1921 .  names - names of options not used
1922 -  values - values of options not used
1923 
1924    Level: advanced
1925 
1926    Notes:
1927    Users should call `PetscOptionsLeftRestore()` to free the memory allocated in this routine
1928 
1929    The value returned may be different on each process and depends on which options have been processed
1930    on the given process
1931 
1932 .seealso: `PetscOptionsAllUsed()`, `PetscOptionsLeft()`
1933 @*/
1934 PetscErrorCode PetscOptionsLeftGet(PetscOptions options, PetscInt *N, char **names[], char **values[])
1935 {
1936   PetscInt i, n;
1937 
1938   PetscFunctionBegin;
1939   if (N) PetscValidIntPointer(N, 2);
1940   if (names) PetscValidPointer(names, 3);
1941   if (values) PetscValidPointer(values, 4);
1942   options = options ? options : defaultoptions;
1943 
1944   /* The number of unused PETSc options */
1945   n = 0;
1946   for (i = 0; i < options->N; i++) {
1947     if (PetscCIOption(options->names[i])) continue;
1948     if (!options->used[i]) n++;
1949   }
1950   if (N) *N = n;
1951   if (names) PetscCall(PetscMalloc1(n, names));
1952   if (values) PetscCall(PetscMalloc1(n, values));
1953 
1954   n = 0;
1955   if (names || values) {
1956     for (i = 0; i < options->N; i++) {
1957       if (!options->used[i]) {
1958         if (PetscCIOption(options->names[i])) continue;
1959         if (names) (*names)[n] = options->names[i];
1960         if (values) (*values)[n] = options->values[i];
1961         n++;
1962       }
1963     }
1964   }
1965   PetscFunctionReturn(0);
1966 }
1967 
1968 /*@C
1969    PetscOptionsLeftRestore - Free memory for the unused PETSc options obtained using `PetscOptionsLeftGet()`.
1970 
1971    Not Collective
1972 
1973    Input Parameters:
1974 +  options - options database, use NULL for default global database
1975 .  names - names of options not used
1976 -  values - values of options not used
1977 
1978    Level: advanced
1979 
1980 .seealso: `PetscOptionsAllUsed()`, `PetscOptionsLeft()`, `PetscOptionsLeftGet()`
1981 @*/
1982 PetscErrorCode PetscOptionsLeftRestore(PetscOptions options, PetscInt *N, char **names[], char **values[])
1983 {
1984   PetscFunctionBegin;
1985   if (N) PetscValidIntPointer(N, 2);
1986   if (names) PetscValidPointer(names, 3);
1987   if (values) PetscValidPointer(values, 4);
1988   if (N) *N = 0;
1989   if (names) PetscCall(PetscFree(*names));
1990   if (values) PetscCall(PetscFree(*values));
1991   PetscFunctionReturn(0);
1992 }
1993 
1994 /*@C
1995    PetscOptionsMonitorDefault - Print all options set value events using the supplied `PetscViewer`.
1996 
1997    Logically Collective on ctx
1998 
1999    Input Parameters:
2000 +  name  - option name string
2001 .  value - option value string
2002 -  ctx - an ASCII viewer or NULL
2003 
2004    Level: intermediate
2005 
2006    Notes:
2007      If ctx is NULL, `PetscPrintf()` is used.
2008      The first MPI rank in the `PetscViewer` viewer actually prints the values, other
2009      processes may have different values set
2010 
2011      If `PetscCIEnabled` then do not print the test harness options
2012 
2013 .seealso: `PetscOptionsMonitorSet()`
2014 @*/
2015 PetscErrorCode PetscOptionsMonitorDefault(const char name[], const char value[], void *ctx)
2016 {
2017   PetscFunctionBegin;
2018   if (PetscCIOption(name)) PetscFunctionReturn(0);
2019 
2020   if (ctx) {
2021     PetscViewer viewer = (PetscViewer)ctx;
2022     if (!value) {
2023       PetscCall(PetscViewerASCIIPrintf(viewer, "Removing option: %s\n", name));
2024     } else if (!value[0]) {
2025       PetscCall(PetscViewerASCIIPrintf(viewer, "Setting option: %s (no value)\n", name));
2026     } else {
2027       PetscCall(PetscViewerASCIIPrintf(viewer, "Setting option: %s = %s\n", name, value));
2028     }
2029   } else {
2030     MPI_Comm comm = PETSC_COMM_WORLD;
2031     if (!value) {
2032       PetscCall(PetscPrintf(comm, "Removing option: %s\n", name));
2033     } else if (!value[0]) {
2034       PetscCall(PetscPrintf(comm, "Setting option: %s (no value)\n", name));
2035     } else {
2036       PetscCall(PetscPrintf(comm, "Setting option: %s = %s\n", name, value));
2037     }
2038   }
2039   PetscFunctionReturn(0);
2040 }
2041 
2042 /*@C
2043    PetscOptionsMonitorSet - Sets an ADDITIONAL function to be called at every method that
2044    modified the PETSc options database.
2045 
2046    Not Collective
2047 
2048    Input Parameters:
2049 +  monitor - pointer to function (if this is NULL, it turns off monitoring
2050 .  mctx    - [optional] context for private data for the
2051              monitor routine (use NULL if no context is desired)
2052 -  monitordestroy - [optional] routine that frees monitor context
2053           (may be NULL)
2054 
2055    Calling Sequence of monitor:
2056 $     monitor (const char name[], const char value[], void *mctx)
2057 
2058 +  name - option name string
2059 .  value - option value string
2060 -  mctx  - optional monitoring context, as set by `PetscOptionsMonitorSet()`
2061 
2062    Options Database Keys:
2063    See `PetscInitialize()` for options related to option database monitoring.
2064 
2065    Notes:
2066    The default is to do nothing.  To print the name and value of options
2067    being inserted into the database, use `PetscOptionsMonitorDefault()` as the monitoring routine,
2068    with a null monitoring context.
2069 
2070    Several different monitoring routines may be set by calling
2071    `PetscOptionsMonitorSet()` multiple times; all will be called in the
2072    order in which they were set.
2073 
2074    Level: intermediate
2075 
2076 .seealso: `PetscOptionsMonitorDefault()`, `PetscInitialize()`
2077 @*/
2078 PetscErrorCode PetscOptionsMonitorSet(PetscErrorCode (*monitor)(const char name[], const char value[], void *), void *mctx, PetscErrorCode (*monitordestroy)(void **))
2079 {
2080   PetscOptions options = defaultoptions;
2081 
2082   PetscFunctionBegin;
2083   if (options->monitorCancel) PetscFunctionReturn(0);
2084   PetscCheck(options->numbermonitors < MAXOPTIONSMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many PetscOptions monitors set");
2085   options->monitor[options->numbermonitors]          = monitor;
2086   options->monitordestroy[options->numbermonitors]   = monitordestroy;
2087   options->monitorcontext[options->numbermonitors++] = (void *)mctx;
2088   PetscFunctionReturn(0);
2089 }
2090 
2091 /*
2092    PetscOptionsStringToBool - Converts string to PetscBool, handles cases like "yes", "no", "true", "false", "0", "1", "off", "on".
2093      Empty string is considered as true.
2094 */
2095 PetscErrorCode PetscOptionsStringToBool(const char value[], PetscBool *a)
2096 {
2097   PetscBool istrue, isfalse;
2098   size_t    len;
2099 
2100   PetscFunctionBegin;
2101   /* PetscStrlen() returns 0 for NULL or "" */
2102   PetscCall(PetscStrlen(value, &len));
2103   if (!len) {
2104     *a = PETSC_TRUE;
2105     PetscFunctionReturn(0);
2106   }
2107   PetscCall(PetscStrcasecmp(value, "TRUE", &istrue));
2108   if (istrue) {
2109     *a = PETSC_TRUE;
2110     PetscFunctionReturn(0);
2111   }
2112   PetscCall(PetscStrcasecmp(value, "YES", &istrue));
2113   if (istrue) {
2114     *a = PETSC_TRUE;
2115     PetscFunctionReturn(0);
2116   }
2117   PetscCall(PetscStrcasecmp(value, "1", &istrue));
2118   if (istrue) {
2119     *a = PETSC_TRUE;
2120     PetscFunctionReturn(0);
2121   }
2122   PetscCall(PetscStrcasecmp(value, "on", &istrue));
2123   if (istrue) {
2124     *a = PETSC_TRUE;
2125     PetscFunctionReturn(0);
2126   }
2127   PetscCall(PetscStrcasecmp(value, "FALSE", &isfalse));
2128   if (isfalse) {
2129     *a = PETSC_FALSE;
2130     PetscFunctionReturn(0);
2131   }
2132   PetscCall(PetscStrcasecmp(value, "NO", &isfalse));
2133   if (isfalse) {
2134     *a = PETSC_FALSE;
2135     PetscFunctionReturn(0);
2136   }
2137   PetscCall(PetscStrcasecmp(value, "0", &isfalse));
2138   if (isfalse) {
2139     *a = PETSC_FALSE;
2140     PetscFunctionReturn(0);
2141   }
2142   PetscCall(PetscStrcasecmp(value, "off", &isfalse));
2143   if (isfalse) {
2144     *a = PETSC_FALSE;
2145     PetscFunctionReturn(0);
2146   }
2147   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown logical value: %s", value);
2148 }
2149 
2150 /*
2151    PetscOptionsStringToInt - Converts a string to an integer value. Handles special cases such as "default" and "decide"
2152 */
2153 PetscErrorCode PetscOptionsStringToInt(const char name[], PetscInt *a)
2154 {
2155   size_t    len;
2156   PetscBool decide, tdefault, mouse;
2157 
2158   PetscFunctionBegin;
2159   PetscCall(PetscStrlen(name, &len));
2160   PetscCheck(len, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "character string of length zero has no numerical value");
2161 
2162   PetscCall(PetscStrcasecmp(name, "PETSC_DEFAULT", &tdefault));
2163   if (!tdefault) PetscCall(PetscStrcasecmp(name, "DEFAULT", &tdefault));
2164   PetscCall(PetscStrcasecmp(name, "PETSC_DECIDE", &decide));
2165   if (!decide) PetscCall(PetscStrcasecmp(name, "DECIDE", &decide));
2166   PetscCall(PetscStrcasecmp(name, "mouse", &mouse));
2167 
2168   if (tdefault) *a = PETSC_DEFAULT;
2169   else if (decide) *a = PETSC_DECIDE;
2170   else if (mouse) *a = -1;
2171   else {
2172     char *endptr;
2173     long  strtolval;
2174 
2175     strtolval = strtol(name, &endptr, 10);
2176     PetscCheck((size_t)(endptr - name) == len, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input string %s has no integer value (do not include . in it)", name);
2177 
2178 #if defined(PETSC_USE_64BIT_INDICES) && defined(PETSC_HAVE_ATOLL)
2179     (void)strtolval;
2180     *a = atoll(name);
2181 #elif defined(PETSC_USE_64BIT_INDICES) && defined(PETSC_HAVE___INT64)
2182     (void)strtolval;
2183     *a = _atoi64(name);
2184 #else
2185     *a = (PetscInt)strtolval;
2186 #endif
2187   }
2188   PetscFunctionReturn(0);
2189 }
2190 
2191 #if defined(PETSC_USE_REAL___FLOAT128)
2192   #include <quadmath.h>
2193 #endif
2194 
2195 static PetscErrorCode PetscStrtod(const char name[], PetscReal *a, char **endptr)
2196 {
2197   PetscFunctionBegin;
2198 #if defined(PETSC_USE_REAL___FLOAT128)
2199   *a = strtoflt128(name, endptr);
2200 #else
2201   *a = (PetscReal)strtod(name, endptr);
2202 #endif
2203   PetscFunctionReturn(0);
2204 }
2205 
2206 static PetscErrorCode PetscStrtoz(const char name[], PetscScalar *a, char **endptr, PetscBool *isImaginary)
2207 {
2208   PetscBool hasi = PETSC_FALSE;
2209   char     *ptr;
2210   PetscReal strtoval;
2211 
2212   PetscFunctionBegin;
2213   PetscCall(PetscStrtod(name, &strtoval, &ptr));
2214   if (ptr == name) {
2215     strtoval = 1.;
2216     hasi     = PETSC_TRUE;
2217     if (name[0] == 'i') {
2218       ptr++;
2219     } else if (name[0] == '+' && name[1] == 'i') {
2220       ptr += 2;
2221     } else if (name[0] == '-' && name[1] == 'i') {
2222       strtoval = -1.;
2223       ptr += 2;
2224     }
2225   } else if (*ptr == 'i') {
2226     hasi = PETSC_TRUE;
2227     ptr++;
2228   }
2229   *endptr      = ptr;
2230   *isImaginary = hasi;
2231   if (hasi) {
2232 #if !defined(PETSC_USE_COMPLEX)
2233     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input string %s contains imaginary but complex not supported ", name);
2234 #else
2235     *a = PetscCMPLX(0., strtoval);
2236 #endif
2237   } else {
2238     *a = strtoval;
2239   }
2240   PetscFunctionReturn(0);
2241 }
2242 
2243 /*
2244    Converts a string to PetscReal value. Handles special cases like "default" and "decide"
2245 */
2246 PetscErrorCode PetscOptionsStringToReal(const char name[], PetscReal *a)
2247 {
2248   size_t    len;
2249   PetscBool match;
2250   char     *endptr;
2251 
2252   PetscFunctionBegin;
2253   PetscCall(PetscStrlen(name, &len));
2254   PetscCheck(len, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "String of length zero has no numerical value");
2255 
2256   PetscCall(PetscStrcasecmp(name, "PETSC_DEFAULT", &match));
2257   if (!match) PetscCall(PetscStrcasecmp(name, "DEFAULT", &match));
2258   if (match) {
2259     *a = PETSC_DEFAULT;
2260     PetscFunctionReturn(0);
2261   }
2262 
2263   PetscCall(PetscStrcasecmp(name, "PETSC_DECIDE", &match));
2264   if (!match) PetscCall(PetscStrcasecmp(name, "DECIDE", &match));
2265   if (match) {
2266     *a = PETSC_DECIDE;
2267     PetscFunctionReturn(0);
2268   }
2269 
2270   PetscCall(PetscStrtod(name, a, &endptr));
2271   PetscCheck((size_t)(endptr - name) == len, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input string %s has no numeric value", name);
2272   PetscFunctionReturn(0);
2273 }
2274 
2275 PetscErrorCode PetscOptionsStringToScalar(const char name[], PetscScalar *a)
2276 {
2277   PetscBool   imag1;
2278   size_t      len;
2279   PetscScalar val = 0.;
2280   char       *ptr = NULL;
2281 
2282   PetscFunctionBegin;
2283   PetscCall(PetscStrlen(name, &len));
2284   PetscCheck(len, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "character string of length zero has no numerical value");
2285   PetscCall(PetscStrtoz(name, &val, &ptr, &imag1));
2286 #if defined(PETSC_USE_COMPLEX)
2287   if ((size_t)(ptr - name) < len) {
2288     PetscBool   imag2;
2289     PetscScalar val2;
2290 
2291     PetscCall(PetscStrtoz(ptr, &val2, &ptr, &imag2));
2292     if (imag1) PetscCheck(imag2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input string %s: must specify imaginary component second", name);
2293     val = PetscCMPLX(PetscRealPart(val), PetscImaginaryPart(val2));
2294   }
2295 #endif
2296   PetscCheck((size_t)(ptr - name) == len, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input string %s has no numeric value ", name);
2297   *a = val;
2298   PetscFunctionReturn(0);
2299 }
2300 
2301 /*@C
2302    PetscOptionsGetBool - Gets the Logical (true or false) value for a particular
2303             option in the database.
2304 
2305    Not Collective
2306 
2307    Input Parameters:
2308 +  options - options database, use NULL for default global database
2309 .  pre - the string to prepend to the name or NULL
2310 -  name - the option one is seeking
2311 
2312    Output Parameters:
2313 +  ivalue - the logical value to return
2314 -  set - `PETSC_TRUE`  if found, else `PETSC_FALSE`
2315 
2316    Level: beginner
2317 
2318    Notes:
2319        TRUE, true, YES, yes, nostring, and 1 all translate to `PETSC_TRUE`
2320        FALSE, false, NO, no, and 0 all translate to `PETSC_FALSE`
2321 
2322       If the option is given, but no value is provided, then ivalue and set are both given the value `PETSC_TRUE`. That is -requested_bool
2323      is equivalent to -requested_bool true
2324 
2325        If the user does not supply the option at all ivalue is NOT changed. Thus
2326      you should ALWAYS initialize the ivalue if you access it without first checking if the set flag is true.
2327 
2328 .seealso: `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
2329           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsGetInt()`, `PetscOptionsBool()`,
2330           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
2331           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
2332           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
2333           `PetscOptionsFList()`, `PetscOptionsEList()`
2334 @*/
2335 PetscErrorCode PetscOptionsGetBool(PetscOptions options, const char pre[], const char name[], PetscBool *ivalue, PetscBool *set)
2336 {
2337   const char *value;
2338   PetscBool   flag;
2339 
2340   PetscFunctionBegin;
2341   PetscValidCharPointer(name, 3);
2342   if (ivalue) PetscValidBoolPointer(ivalue, 4);
2343   PetscCall(PetscOptionsFindPair(options, pre, name, &value, &flag));
2344   if (flag) {
2345     if (set) *set = PETSC_TRUE;
2346     PetscCall(PetscOptionsStringToBool(value, &flag));
2347     if (ivalue) *ivalue = flag;
2348   } else {
2349     if (set) *set = PETSC_FALSE;
2350   }
2351   PetscFunctionReturn(0);
2352 }
2353 
2354 /*@C
2355    PetscOptionsGetEList - Puts a list of option values that a single one may be selected from
2356 
2357    Not Collective
2358 
2359    Input Parameters:
2360 +  options - options database, use NULL for default global database
2361 .  pre - the string to prepend to the name or NULL
2362 .  opt - option name
2363 .  list - the possible choices (one of these must be selected, anything else is invalid)
2364 -  ntext - number of choices
2365 
2366    Output Parameters:
2367 +  value - the index of the value to return (defaults to zero if the option name is given but no choice is listed)
2368 -  set - `PETSC_TRUE` if found, else `PETSC_FALSE`
2369 
2370    Level: intermediate
2371 
2372    Notes:
2373     If the user does not supply the option value is NOT changed. Thus
2374      you should ALWAYS initialize the ivalue if you access it without first checking if the set flag is true.
2375 
2376    See `PetscOptionsFList()` for when the choices are given in a `PetscFunctionList`
2377 
2378 .seealso: `PetscOptionsGetInt()`, `PetscOptionsGetReal()`,
2379           `PetscOptionsHasName()`, `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
2380           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
2381           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
2382           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
2383           `PetscOptionsFList()`, `PetscOptionsEList()`
2384 @*/
2385 PetscErrorCode PetscOptionsGetEList(PetscOptions options, const char pre[], const char opt[], const char *const *list, PetscInt ntext, PetscInt *value, PetscBool *set)
2386 {
2387   size_t    alen, len = 0, tlen = 0;
2388   char     *svalue;
2389   PetscBool aset, flg = PETSC_FALSE;
2390   PetscInt  i;
2391 
2392   PetscFunctionBegin;
2393   PetscValidCharPointer(opt, 3);
2394   for (i = 0; i < ntext; i++) {
2395     PetscCall(PetscStrlen(list[i], &alen));
2396     if (alen > len) len = alen;
2397     tlen += len + 1;
2398   }
2399   len += 5; /* a little extra space for user mistypes */
2400   PetscCall(PetscMalloc1(len, &svalue));
2401   PetscCall(PetscOptionsGetString(options, pre, opt, svalue, len, &aset));
2402   if (aset) {
2403     PetscCall(PetscEListFind(ntext, list, svalue, value, &flg));
2404     if (!flg) {
2405       char *avail, *pavl;
2406 
2407       PetscCall(PetscMalloc1(tlen, &avail));
2408       pavl = avail;
2409       for (i = 0; i < ntext; i++) {
2410         PetscCall(PetscStrlen(list[i], &alen));
2411         PetscCall(PetscStrcpy(pavl, list[i]));
2412         pavl += alen;
2413         PetscCall(PetscStrcpy(pavl, " "));
2414         pavl += 1;
2415       }
2416       PetscCall(PetscStrtolower(avail));
2417       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_USER, "Unknown option %s for -%s%s. Available options: %s", svalue, pre ? pre : "", opt + 1, avail);
2418     }
2419     if (set) *set = PETSC_TRUE;
2420   } else if (set) *set = PETSC_FALSE;
2421   PetscCall(PetscFree(svalue));
2422   PetscFunctionReturn(0);
2423 }
2424 
2425 /*@C
2426    PetscOptionsGetEnum - Gets the enum value for a particular option in the database.
2427 
2428    Not Collective
2429 
2430    Input Parameters:
2431 +  options - options database, use NULL for default global database
2432 .  pre - option prefix or NULL
2433 .  opt - option name
2434 -  list - array containing the list of choices, followed by the enum name, followed by the enum prefix, followed by a null
2435 
2436    Output Parameters:
2437 +  value - the  value to return
2438 -  set - `PETSC_TRUE` if found, else `PETSC_FALSE`
2439 
2440    Level: beginner
2441 
2442    Notes:
2443     If the user does not supply the option value is NOT changed. Thus
2444      you should ALWAYS initialize the ivalue if you access it without first checking if the set flag is true.
2445 
2446           List is usually something like `PCASMTypes` or some other predefined list of enum names
2447 
2448 .seealso: `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, `PetscOptionsGetInt()`,
2449           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
2450           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
2451           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
2452           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
2453           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
2454           `PetscOptionsFList()`, `PetscOptionsEList()`, `PetscOptionsGetEList()`, `PetscOptionsEnum()`
2455 @*/
2456 PetscErrorCode PetscOptionsGetEnum(PetscOptions options, const char pre[], const char opt[], const char *const *list, PetscEnum *value, PetscBool *set)
2457 {
2458   PetscInt  ntext = 0, tval;
2459   PetscBool fset;
2460 
2461   PetscFunctionBegin;
2462   PetscValidCharPointer(opt, 3);
2463   while (list[ntext++]) PetscCheck(ntext <= 50, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument appears to be wrong or have more than 50 entries");
2464   PetscCheck(ntext >= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument must have at least two entries: typename and type prefix");
2465   ntext -= 3;
2466   PetscCall(PetscOptionsGetEList(options, pre, opt, list, ntext, &tval, &fset));
2467   /* with PETSC_USE_64BIT_INDICES sizeof(PetscInt) != sizeof(PetscEnum) */
2468   if (fset) *value = (PetscEnum)tval;
2469   if (set) *set = fset;
2470   PetscFunctionReturn(0);
2471 }
2472 
2473 /*@C
2474    PetscOptionsGetInt - Gets the integer value for a particular option in the database.
2475 
2476    Not Collective
2477 
2478    Input Parameters:
2479 +  options - options database, use NULL for default global database
2480 .  pre - the string to prepend to the name or NULL
2481 -  name - the option one is seeking
2482 
2483    Output Parameters:
2484 +  ivalue - the integer value to return
2485 -  set - `PETSC_TRUE` if found, else `PETSC_FALSE`
2486 
2487    Level: beginner
2488 
2489    Notes:
2490    If the user does not supply the option ivalue is NOT changed. Thus
2491    you should ALWAYS initialize the ivalue if you access it without first checking if the set flag is true.
2492 
2493 .seealso: `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
2494           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
2495           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
2496           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
2497           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
2498           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
2499           `PetscOptionsFList()`, `PetscOptionsEList()`
2500 @*/
2501 PetscErrorCode PetscOptionsGetInt(PetscOptions options, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
2502 {
2503   const char *value;
2504   PetscBool   flag;
2505 
2506   PetscFunctionBegin;
2507   PetscValidCharPointer(name, 3);
2508   PetscValidIntPointer(ivalue, 4);
2509   PetscCall(PetscOptionsFindPair(options, pre, name, &value, &flag));
2510   if (flag) {
2511     if (!value) {
2512       if (set) *set = PETSC_FALSE;
2513     } else {
2514       if (set) *set = PETSC_TRUE;
2515       PetscCall(PetscOptionsStringToInt(value, ivalue));
2516     }
2517   } else {
2518     if (set) *set = PETSC_FALSE;
2519   }
2520   PetscFunctionReturn(0);
2521 }
2522 
2523 /*@C
2524    PetscOptionsGetReal - Gets the double precision value for a particular
2525    option in the database.
2526 
2527    Not Collective
2528 
2529    Input Parameters:
2530 +  options - options database, use NULL for default global database
2531 .  pre - string to prepend to each name or NULL
2532 -  name - the option one is seeking
2533 
2534    Output Parameters:
2535 +  dvalue - the double value to return
2536 -  set - `PETSC_TRUE` if found, `PETSC_FALSE` if not found
2537 
2538    Note:
2539     If the user does not supply the option dvalue is NOT changed. Thus
2540      you should ALWAYS initialize the ivalue if you access it without first checking if the set flag is true.
2541 
2542    Level: beginner
2543 
2544 .seealso: `PetscOptionsGetInt()`, `PetscOptionsHasName()`,
2545           `PetscOptionsGetString()`, `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
2546           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
2547           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
2548           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
2549           `PetscOptionsFList()`, `PetscOptionsEList()`
2550 @*/
2551 PetscErrorCode PetscOptionsGetReal(PetscOptions options, const char pre[], const char name[], PetscReal *dvalue, PetscBool *set)
2552 {
2553   const char *value;
2554   PetscBool   flag;
2555 
2556   PetscFunctionBegin;
2557   PetscValidCharPointer(name, 3);
2558   PetscValidRealPointer(dvalue, 4);
2559   PetscCall(PetscOptionsFindPair(options, pre, name, &value, &flag));
2560   if (flag) {
2561     if (!value) {
2562       if (set) *set = PETSC_FALSE;
2563     } else {
2564       if (set) *set = PETSC_TRUE;
2565       PetscCall(PetscOptionsStringToReal(value, dvalue));
2566     }
2567   } else {
2568     if (set) *set = PETSC_FALSE;
2569   }
2570   PetscFunctionReturn(0);
2571 }
2572 
2573 /*@C
2574    PetscOptionsGetScalar - Gets the scalar value for a particular
2575    option in the database.
2576 
2577    Not Collective
2578 
2579    Input Parameters:
2580 +  options - options database, use NULL for default global database
2581 .  pre - string to prepend to each name or NULL
2582 -  name - the option one is seeking
2583 
2584    Output Parameters:
2585 +  dvalue - the double value to return
2586 -  set - `PETSC_TRUE` if found, else `PETSC_FALSE`
2587 
2588    Level: beginner
2589 
2590    Usage:
2591    A complex number 2+3i must be specified with NO spaces
2592 
2593    Note:
2594     If the user does not supply the option dvalue is NOT changed. Thus
2595      you should ALWAYS initialize the ivalue if you access it without first checking if the set flag is true.
2596 
2597 .seealso: `PetscOptionsGetInt()`, `PetscOptionsHasName()`,
2598           `PetscOptionsGetString()`, `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
2599           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
2600           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
2601           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
2602           `PetscOptionsFList()`, `PetscOptionsEList()`
2603 @*/
2604 PetscErrorCode PetscOptionsGetScalar(PetscOptions options, const char pre[], const char name[], PetscScalar *dvalue, PetscBool *set)
2605 {
2606   const char *value;
2607   PetscBool   flag;
2608 
2609   PetscFunctionBegin;
2610   PetscValidCharPointer(name, 3);
2611   PetscValidScalarPointer(dvalue, 4);
2612   PetscCall(PetscOptionsFindPair(options, pre, name, &value, &flag));
2613   if (flag) {
2614     if (!value) {
2615       if (set) *set = PETSC_FALSE;
2616     } else {
2617 #if !defined(PETSC_USE_COMPLEX)
2618       PetscCall(PetscOptionsStringToReal(value, dvalue));
2619 #else
2620       PetscCall(PetscOptionsStringToScalar(value, dvalue));
2621 #endif
2622       if (set) *set = PETSC_TRUE;
2623     }
2624   } else { /* flag */
2625     if (set) *set = PETSC_FALSE;
2626   }
2627   PetscFunctionReturn(0);
2628 }
2629 
2630 /*@C
2631    PetscOptionsGetString - Gets the string value for a particular option in
2632    the database.
2633 
2634    Not Collective
2635 
2636    Input Parameters:
2637 +  options - options database, use NULL for default global database
2638 .  pre - string to prepend to name or NULL
2639 .  name - the option one is seeking
2640 -  len - maximum length of the string including null termination
2641 
2642    Output Parameters:
2643 +  string - location to copy string
2644 -  set - `PETSC_TRUE` if found, else `PETSC_FALSE`
2645 
2646    Level: beginner
2647 
2648    Fortran Note:
2649    The Fortran interface is slightly different from the C/C++
2650    interface (len is not used).  Sample usage in Fortran follows
2651 .vb
2652       character *20    string
2653       PetscErrorCode   ierr
2654       PetscBool        set
2655       call PetscOptionsGetString(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,'-s',string,set,ierr)
2656 .ve
2657 
2658    Note:
2659     if the option is given but no string is provided then an empty string is returned and set is given the value of `PETSC_TRUE`
2660 
2661            If the user does not use the option then the string is not changed. Thus
2662            you should ALWAYS initialize the string if you access it without first checking if the set flag is true.
2663 
2664       Even if the user provided no string (for example -optionname -someotheroption) the flag is set to PETSC_TRUE (and the string is fulled with nulls).
2665 
2666 .seealso: `PetscOptionsGetInt()`, `PetscOptionsGetReal()`,
2667           `PetscOptionsHasName()`, `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
2668           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
2669           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
2670           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
2671           `PetscOptionsFList()`, `PetscOptionsEList()`
2672 @*/
2673 PetscErrorCode PetscOptionsGetString(PetscOptions options, const char pre[], const char name[], char string[], size_t len, PetscBool *set)
2674 {
2675   const char *value;
2676   PetscBool   flag;
2677 
2678   PetscFunctionBegin;
2679   PetscValidCharPointer(name, 3);
2680   PetscValidCharPointer(string, 4);
2681   PetscCall(PetscOptionsFindPair(options, pre, name, &value, &flag));
2682   if (!flag) {
2683     if (set) *set = PETSC_FALSE;
2684   } else {
2685     if (set) *set = PETSC_TRUE;
2686     if (value) PetscCall(PetscStrncpy(string, value, len));
2687     else PetscCall(PetscArrayzero(string, len));
2688   }
2689   PetscFunctionReturn(0);
2690 }
2691 
2692 char *PetscOptionsGetStringMatlab(PetscOptions options, const char pre[], const char name[])
2693 {
2694   const char *value;
2695   PetscBool   flag;
2696 
2697   PetscFunctionBegin;
2698   if (PetscOptionsFindPair(options, pre, name, &value, &flag)) PetscFunctionReturn(NULL);
2699   if (flag) PetscFunctionReturn((char *)value);
2700   PetscFunctionReturn(NULL);
2701 }
2702 
2703 /*@C
2704   PetscOptionsGetBoolArray - Gets an array of Logical (true or false) values for a particular
2705   option in the database.  The values must be separated with commas with no intervening spaces.
2706 
2707   Not Collective
2708 
2709   Input Parameters:
2710 + options - options database, use NULL for default global database
2711 . pre - string to prepend to each name or NULL
2712 - name - the option one is seeking
2713 
2714   Output Parameters:
2715 + dvalue - the integer values to return
2716 . nmax - On input maximum number of values to retrieve, on output the actual number of values retrieved
2717 - set - `PETSC_TRUE` if found, else `PETSC_FALSE`
2718 
2719   Level: beginner
2720 
2721   Note:
2722   TRUE, true, YES, yes, nostring, and 1 all translate to PETSC_TRUE. FALSE, false, NO, no, and 0 all translate to PETSC_FALSE
2723 
2724 .seealso: `PetscOptionsGetInt()`, `PetscOptionsHasName()`,
2725           `PetscOptionsGetString()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
2726           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
2727           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
2728           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
2729           `PetscOptionsFList()`, `PetscOptionsEList()`
2730 @*/
2731 PetscErrorCode PetscOptionsGetBoolArray(PetscOptions options, const char pre[], const char name[], PetscBool dvalue[], PetscInt *nmax, PetscBool *set)
2732 {
2733   const char *svalue;
2734   char       *value;
2735   PetscInt    n = 0;
2736   PetscBool   flag;
2737   PetscToken  token;
2738 
2739   PetscFunctionBegin;
2740   PetscValidCharPointer(name, 3);
2741   PetscValidBoolPointer(dvalue, 4);
2742   PetscValidIntPointer(nmax, 5);
2743 
2744   PetscCall(PetscOptionsFindPair(options, pre, name, &svalue, &flag));
2745   if (!flag || !svalue) {
2746     if (set) *set = PETSC_FALSE;
2747     *nmax = 0;
2748     PetscFunctionReturn(0);
2749   }
2750   if (set) *set = PETSC_TRUE;
2751   PetscCall(PetscTokenCreate(svalue, ',', &token));
2752   PetscCall(PetscTokenFind(token, &value));
2753   while (value && n < *nmax) {
2754     PetscCall(PetscOptionsStringToBool(value, dvalue));
2755     PetscCall(PetscTokenFind(token, &value));
2756     dvalue++;
2757     n++;
2758   }
2759   PetscCall(PetscTokenDestroy(&token));
2760   *nmax = n;
2761   PetscFunctionReturn(0);
2762 }
2763 
2764 /*@C
2765   PetscOptionsGetEnumArray - Gets an array of enum values for a particular option in the database.
2766 
2767   Not Collective
2768 
2769   Input Parameters:
2770 + options - options database, use NULL for default global database
2771 . pre - option prefix or NULL
2772 . name - option name
2773 - list - array containing the list of choices, followed by the enum name, followed by the enum prefix, followed by a null
2774 
2775   Output Parameters:
2776 + ivalue - the  enum values to return
2777 . nmax - On input maximum number of values to retrieve, on output the actual number of values retrieved
2778 - set - `PETSC_TRUE` if found, else `PETSC_FALSE`
2779 
2780   Level: beginner
2781 
2782   Notes:
2783   The array must be passed as a comma separated list.
2784 
2785   There must be no intervening spaces between the values.
2786 
2787   list is usually something like `PCASMTypes` or some other predefined list of enum names.
2788 
2789 .seealso: `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, `PetscOptionsGetInt()`,
2790           `PetscOptionsGetEnum()`, `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
2791           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`, `PetscOptionsName()`,
2792           `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`, `PetscOptionsStringArray()`, `PetscOptionsRealArray()`,
2793           `PetscOptionsScalar()`, `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
2794           `PetscOptionsFList()`, `PetscOptionsEList()`, `PetscOptionsGetEList()`, `PetscOptionsEnum()`
2795 @*/
2796 PetscErrorCode PetscOptionsGetEnumArray(PetscOptions options, const char pre[], const char name[], const char *const *list, PetscEnum ivalue[], PetscInt *nmax, PetscBool *set)
2797 {
2798   const char *svalue;
2799   char       *value;
2800   PetscInt    n = 0;
2801   PetscEnum   evalue;
2802   PetscBool   flag;
2803   PetscToken  token;
2804 
2805   PetscFunctionBegin;
2806   PetscValidCharPointer(name, 3);
2807   PetscValidPointer(list, 4);
2808   PetscValidPointer(ivalue, 5);
2809   PetscValidIntPointer(nmax, 6);
2810 
2811   PetscCall(PetscOptionsFindPair(options, pre, name, &svalue, &flag));
2812   if (!flag || !svalue) {
2813     if (set) *set = PETSC_FALSE;
2814     *nmax = 0;
2815     PetscFunctionReturn(0);
2816   }
2817   if (set) *set = PETSC_TRUE;
2818   PetscCall(PetscTokenCreate(svalue, ',', &token));
2819   PetscCall(PetscTokenFind(token, &value));
2820   while (value && n < *nmax) {
2821     PetscCall(PetscEnumFind(list, value, &evalue, &flag));
2822     PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_USER, "Unknown enum value '%s' for -%s%s", svalue, pre ? pre : "", name + 1);
2823     ivalue[n++] = evalue;
2824     PetscCall(PetscTokenFind(token, &value));
2825   }
2826   PetscCall(PetscTokenDestroy(&token));
2827   *nmax = n;
2828   PetscFunctionReturn(0);
2829 }
2830 
2831 /*@C
2832   PetscOptionsGetIntArray - Gets an array of integer values for a particular option in the database.
2833 
2834   Not Collective
2835 
2836   Input Parameters:
2837 + options - options database, use NULL for default global database
2838 . pre - string to prepend to each name or NULL
2839 - name - the option one is seeking
2840 
2841   Output Parameters:
2842 + ivalue - the integer values to return
2843 . nmax - On input maximum number of values to retrieve, on output the actual number of values retrieved
2844 - set - `PETSC_TRUE` if found, else `PETSC_FALSE`
2845 
2846   Level: beginner
2847 
2848   Notes:
2849   The array can be passed as
2850 +  a comma separated list -                                 0,1,2,3,4,5,6,7
2851 .  a range (start\-end+1) -                                 0-8
2852 .  a range with given increment (start\-end+1:inc) -        0-7:2
2853 -  a combination of values and ranges separated by commas - 0,1-8,8-15:2
2854 
2855   There must be no intervening spaces between the values.
2856 
2857 .seealso: `PetscOptionsGetInt()`, `PetscOptionsHasName()`,
2858           `PetscOptionsGetString()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
2859           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
2860           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
2861           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
2862           `PetscOptionsFList()`, `PetscOptionsEList()`
2863 @*/
2864 PetscErrorCode PetscOptionsGetIntArray(PetscOptions options, const char pre[], const char name[], PetscInt ivalue[], PetscInt *nmax, PetscBool *set)
2865 {
2866   const char *svalue;
2867   char       *value;
2868   PetscInt    n = 0, i, j, start, end, inc, nvalues;
2869   size_t      len;
2870   PetscBool   flag, foundrange;
2871   PetscToken  token;
2872 
2873   PetscFunctionBegin;
2874   PetscValidCharPointer(name, 3);
2875   PetscValidIntPointer(ivalue, 4);
2876   PetscValidIntPointer(nmax, 5);
2877 
2878   PetscCall(PetscOptionsFindPair(options, pre, name, &svalue, &flag));
2879   if (!flag || !svalue) {
2880     if (set) *set = PETSC_FALSE;
2881     *nmax = 0;
2882     PetscFunctionReturn(0);
2883   }
2884   if (set) *set = PETSC_TRUE;
2885   PetscCall(PetscTokenCreate(svalue, ',', &token));
2886   PetscCall(PetscTokenFind(token, &value));
2887   while (value && n < *nmax) {
2888     /* look for form  d-D where d and D are integers */
2889     foundrange = PETSC_FALSE;
2890     PetscCall(PetscStrlen(value, &len));
2891     if (value[0] == '-') i = 2;
2892     else i = 1;
2893     for (; i < (int)len; i++) {
2894       if (value[i] == '-') {
2895         PetscCheck(i != (int)len - 1, PETSC_COMM_SELF, PETSC_ERR_USER, "Error in %" PetscInt_FMT "-th array entry %s", n, value);
2896         value[i] = 0;
2897 
2898         PetscCall(PetscOptionsStringToInt(value, &start));
2899         inc = 1;
2900         j   = i + 1;
2901         for (; j < (int)len; j++) {
2902           if (value[j] == ':') {
2903             value[j] = 0;
2904 
2905             PetscCall(PetscOptionsStringToInt(value + j + 1, &inc));
2906             PetscCheck(inc > 0, PETSC_COMM_SELF, PETSC_ERR_USER, "Error in %" PetscInt_FMT "-th array entry,%s cannot have negative increment", n, value + j + 1);
2907             break;
2908           }
2909         }
2910         PetscCall(PetscOptionsStringToInt(value + i + 1, &end));
2911         PetscCheck(end > start, PETSC_COMM_SELF, PETSC_ERR_USER, "Error in %" PetscInt_FMT "-th array entry, %s-%s cannot have decreasing list", n, value, value + i + 1);
2912         nvalues = (end - start) / inc + (end - start) % inc;
2913         PetscCheck(n + nvalues <= *nmax, PETSC_COMM_SELF, PETSC_ERR_USER, "Error in %" PetscInt_FMT "-th array entry, not enough space left in array (%" PetscInt_FMT ") to contain entire range from %" PetscInt_FMT " to %" PetscInt_FMT, n, *nmax - n, start, end);
2914         for (; start < end; start += inc) {
2915           *ivalue = start;
2916           ivalue++;
2917           n++;
2918         }
2919         foundrange = PETSC_TRUE;
2920         break;
2921       }
2922     }
2923     if (!foundrange) {
2924       PetscCall(PetscOptionsStringToInt(value, ivalue));
2925       ivalue++;
2926       n++;
2927     }
2928     PetscCall(PetscTokenFind(token, &value));
2929   }
2930   PetscCall(PetscTokenDestroy(&token));
2931   *nmax = n;
2932   PetscFunctionReturn(0);
2933 }
2934 
2935 /*@C
2936   PetscOptionsGetRealArray - Gets an array of double precision values for a
2937   particular option in the database.  The values must be separated with commas with no intervening spaces.
2938 
2939   Not Collective
2940 
2941   Input Parameters:
2942 + options - options database, use NULL for default global database
2943 . pre - string to prepend to each name or NULL
2944 - name - the option one is seeking
2945 
2946   Output Parameters:
2947 + dvalue - the double values to return
2948 . nmax - On input maximum number of values to retrieve, on output the actual number of values retrieved
2949 - set - `PETSC_TRUE` if found, else `PETSC_FALSE`
2950 
2951   Level: beginner
2952 
2953 .seealso: `PetscOptionsGetInt()`, `PetscOptionsHasName()`,
2954           `PetscOptionsGetString()`, `PetscOptionsGetIntArray()`, `PetscOptionsBool()`,
2955           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
2956           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
2957           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
2958           `PetscOptionsFList()`, `PetscOptionsEList()`
2959 @*/
2960 PetscErrorCode PetscOptionsGetRealArray(PetscOptions options, const char pre[], const char name[], PetscReal dvalue[], PetscInt *nmax, PetscBool *set)
2961 {
2962   const char *svalue;
2963   char       *value;
2964   PetscInt    n = 0;
2965   PetscBool   flag;
2966   PetscToken  token;
2967 
2968   PetscFunctionBegin;
2969   PetscValidCharPointer(name, 3);
2970   PetscValidRealPointer(dvalue, 4);
2971   PetscValidIntPointer(nmax, 5);
2972 
2973   PetscCall(PetscOptionsFindPair(options, pre, name, &svalue, &flag));
2974   if (!flag || !svalue) {
2975     if (set) *set = PETSC_FALSE;
2976     *nmax = 0;
2977     PetscFunctionReturn(0);
2978   }
2979   if (set) *set = PETSC_TRUE;
2980   PetscCall(PetscTokenCreate(svalue, ',', &token));
2981   PetscCall(PetscTokenFind(token, &value));
2982   while (value && n < *nmax) {
2983     PetscCall(PetscOptionsStringToReal(value, dvalue++));
2984     PetscCall(PetscTokenFind(token, &value));
2985     n++;
2986   }
2987   PetscCall(PetscTokenDestroy(&token));
2988   *nmax = n;
2989   PetscFunctionReturn(0);
2990 }
2991 
2992 /*@C
2993   PetscOptionsGetScalarArray - Gets an array of scalars for a
2994   particular option in the database.  The values must be separated with commas with no intervening spaces.
2995 
2996   Not Collective
2997 
2998   Input Parameters:
2999 + options - options database, use NULL for default global database
3000 . pre - string to prepend to each name or NULL
3001 - name - the option one is seeking
3002 
3003   Output Parameters:
3004 + dvalue - the scalar values to return
3005 . nmax - On input maximum number of values to retrieve, on output the actual number of values retrieved
3006 - set - `PETSC_TRUE` if found, else `PETSC_FALSE`
3007 
3008   Level: beginner
3009 
3010 .seealso: `PetscOptionsGetInt()`, `PetscOptionsHasName()`,
3011           `PetscOptionsGetString()`, `PetscOptionsGetIntArray()`, `PetscOptionsBool()`,
3012           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
3013           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
3014           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
3015           `PetscOptionsFList()`, `PetscOptionsEList()`
3016 @*/
3017 PetscErrorCode PetscOptionsGetScalarArray(PetscOptions options, const char pre[], const char name[], PetscScalar dvalue[], PetscInt *nmax, PetscBool *set)
3018 {
3019   const char *svalue;
3020   char       *value;
3021   PetscInt    n = 0;
3022   PetscBool   flag;
3023   PetscToken  token;
3024 
3025   PetscFunctionBegin;
3026   PetscValidCharPointer(name, 3);
3027   PetscValidScalarPointer(dvalue, 4);
3028   PetscValidIntPointer(nmax, 5);
3029 
3030   PetscCall(PetscOptionsFindPair(options, pre, name, &svalue, &flag));
3031   if (!flag || !svalue) {
3032     if (set) *set = PETSC_FALSE;
3033     *nmax = 0;
3034     PetscFunctionReturn(0);
3035   }
3036   if (set) *set = PETSC_TRUE;
3037   PetscCall(PetscTokenCreate(svalue, ',', &token));
3038   PetscCall(PetscTokenFind(token, &value));
3039   while (value && n < *nmax) {
3040     PetscCall(PetscOptionsStringToScalar(value, dvalue++));
3041     PetscCall(PetscTokenFind(token, &value));
3042     n++;
3043   }
3044   PetscCall(PetscTokenDestroy(&token));
3045   *nmax = n;
3046   PetscFunctionReturn(0);
3047 }
3048 
3049 /*@C
3050   PetscOptionsGetStringArray - Gets an array of string values for a particular
3051   option in the database. The values must be separated with commas with no intervening spaces.
3052 
3053   Not Collective
3054 
3055   Input Parameters:
3056 + options - options database, use NULL for default global database
3057 . pre - string to prepend to name or NULL
3058 - name - the option one is seeking
3059 
3060   Output Parameters:
3061 + strings - location to copy strings
3062 . nmax - On input maximum number of strings, on output the actual number of strings found
3063 - set - `PETSC_TRUE` if found, else `PETSC_FALSE`
3064 
3065   Level: beginner
3066 
3067   Notes:
3068   The nmax parameter is used for both input and output.
3069 
3070   The user should pass in an array of pointers to char, to hold all the
3071   strings returned by this function.
3072 
3073   The user is responsible for deallocating the strings that are
3074   returned. The Fortran interface for this routine is not supported.
3075 
3076 .seealso: `PetscOptionsGetInt()`, `PetscOptionsGetReal()`,
3077           `PetscOptionsHasName()`, `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
3078           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
3079           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
3080           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
3081           `PetscOptionsFList()`, `PetscOptionsEList()`
3082 @*/
3083 PetscErrorCode PetscOptionsGetStringArray(PetscOptions options, const char pre[], const char name[], char *strings[], PetscInt *nmax, PetscBool *set)
3084 {
3085   const char *svalue;
3086   char       *value;
3087   PetscInt    n = 0;
3088   PetscBool   flag;
3089   PetscToken  token;
3090 
3091   PetscFunctionBegin;
3092   PetscValidCharPointer(name, 3);
3093   PetscValidPointer(strings, 4);
3094   PetscValidIntPointer(nmax, 5);
3095 
3096   PetscCall(PetscOptionsFindPair(options, pre, name, &svalue, &flag));
3097   if (!flag || !svalue) {
3098     if (set) *set = PETSC_FALSE;
3099     *nmax = 0;
3100     PetscFunctionReturn(0);
3101   }
3102   if (set) *set = PETSC_TRUE;
3103   PetscCall(PetscTokenCreate(svalue, ',', &token));
3104   PetscCall(PetscTokenFind(token, &value));
3105   while (value && n < *nmax) {
3106     PetscCall(PetscStrallocpy(value, &strings[n]));
3107     PetscCall(PetscTokenFind(token, &value));
3108     n++;
3109   }
3110   PetscCall(PetscTokenDestroy(&token));
3111   *nmax = n;
3112   PetscFunctionReturn(0);
3113 }
3114 
3115 /*@C
3116    PetscOptionsDeprecated - mark an option as deprecated, optionally replacing it with a new one
3117 
3118    Prints a deprecation warning, unless an option is supplied to suppress.
3119 
3120    Logically Collective
3121 
3122    Input Parameters:
3123 +  pre - string to prepend to name or NULL
3124 .  oldname - the old, deprecated option
3125 .  newname - the new option, or NULL if option is purely removed
3126 .  version - a string describing the version of first deprecation, e.g. "3.9"
3127 -  info - additional information string, or NULL.
3128 
3129    Options Database Key:
3130 . -options_suppress_deprecated_warnings - do not print deprecation warnings
3131 
3132    Notes:
3133    Must be called between `PetscOptionsBegin()` (or `PetscObjectOptionsBegin()`) and `PetscOptionsEnd()`.
3134    Only the proces of rank zero that owns the `PetscOptionsItems` are argument (managed by `PetscOptionsBegin()` or
3135    `PetscObjectOptionsBegin()` prints the information
3136    If newname is provided, the old option is replaced. Otherwise, it remains
3137    in the options database.
3138    If an option is not replaced, the info argument should be used to advise the user
3139    on how to proceed.
3140    There is a limit on the length of the warning printed, so very long strings
3141    provided as info may be truncated.
3142 
3143    Level: developer
3144 
3145 .seealso: `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsScalar()`, `PetscOptionsBool()`, `PetscOptionsString()`, `PetscOptionsSetValue()`
3146 @*/
3147 PetscErrorCode PetscOptionsDeprecated_Private(PetscOptionItems *PetscOptionsObject, const char oldname[], const char newname[], const char version[], const char info[])
3148 {
3149   PetscBool         found, quiet;
3150   const char       *value;
3151   const char *const quietopt = "-options_suppress_deprecated_warnings";
3152   char              msg[4096];
3153   char             *prefix  = NULL;
3154   PetscOptions      options = NULL;
3155   MPI_Comm          comm    = PETSC_COMM_SELF;
3156 
3157   PetscFunctionBegin;
3158   PetscValidCharPointer(oldname, 2);
3159   PetscValidCharPointer(version, 4);
3160   if (PetscOptionsObject) {
3161     prefix  = PetscOptionsObject->prefix;
3162     options = PetscOptionsObject->options;
3163     comm    = PetscOptionsObject->comm;
3164   }
3165   PetscCall(PetscOptionsFindPair(options, prefix, oldname, &value, &found));
3166   if (found) {
3167     if (newname) {
3168       if (prefix) PetscCall(PetscOptionsPrefixPush(options, prefix));
3169       PetscCall(PetscOptionsSetValue(options, newname, value));
3170       if (prefix) PetscCall(PetscOptionsPrefixPop(options));
3171       PetscCall(PetscOptionsClearValue(options, oldname));
3172     }
3173     quiet = PETSC_FALSE;
3174     PetscCall(PetscOptionsGetBool(options, NULL, quietopt, &quiet, NULL));
3175     if (!quiet) {
3176       PetscCall(PetscStrcpy(msg, "** PETSc DEPRECATION WARNING ** : the option "));
3177       PetscCall(PetscStrcat(msg, oldname));
3178       PetscCall(PetscStrcat(msg, " is deprecated as of version "));
3179       PetscCall(PetscStrcat(msg, version));
3180       PetscCall(PetscStrcat(msg, " and will be removed in a future release."));
3181       if (newname) {
3182         PetscCall(PetscStrcat(msg, " Please use the option "));
3183         PetscCall(PetscStrcat(msg, newname));
3184         PetscCall(PetscStrcat(msg, " instead."));
3185       }
3186       if (info) {
3187         PetscCall(PetscStrcat(msg, " "));
3188         PetscCall(PetscStrcat(msg, info));
3189       }
3190       PetscCall(PetscStrcat(msg, " (Silence this warning with "));
3191       PetscCall(PetscStrcat(msg, quietopt));
3192       PetscCall(PetscStrcat(msg, ")\n"));
3193       PetscCall(PetscPrintf(comm, "%s", msg));
3194     }
3195   }
3196   PetscFunctionReturn(0);
3197 }
3198