Actual source code: yamlimpls.c
petsc-3.14.6 2021-03-30
1: #include <petsc/private/petscimpl.h>
2: #include <yaml.h>
4: enum storage_flags {VAR,VAL,SEQ}; /* "Store as" switch */
6: static PetscErrorCode PetscParseLayerYAML(PetscOptions options, yaml_document_t *doc, yaml_node_t *node)
7: {
8: char option[PETSC_MAX_PATH_LEN],prefix[PETSC_MAX_PATH_LEN];
9: yaml_node_pair_t *start, *top;
10: PetscErrorCode ierr;
13: PetscSNPrintf(option,PETSC_MAX_PATH_LEN,"%s"," ");
14: if (node->type != YAML_MAPPING_NODE) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unsupported yaml node type: expected mapping");
15: start = node->data.mapping.pairs.start;
16: top = node->data.mapping.pairs.top;
17: for (yaml_node_pair_t *pair = start; pair < top; pair++) {
18: int key_id = pair->key;
19: int value_id = pair->value;
20: yaml_node_t *key = NULL;
21: yaml_node_t *value = NULL;
23: key = yaml_document_get_node(doc, key_id);
24: if (!key) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_LIB, "Corrupt yaml document");
25: value = yaml_document_get_node(doc, value_id);
26: if (!value) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_LIB, "Corrupt yaml document");
27: if (key->type != YAML_SCALAR_NODE) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unsupported yaml node type: expected scalar");
28: if (value->type == YAML_SCALAR_NODE) {
29: PetscSNPrintf(option,PETSC_MAX_PATH_LEN,"-%s %s",(char *)(key->data.scalar.value),(char*)(value->data.scalar.value));
30: PetscOptionsInsertString(options, option);
31: } else if (value->type == YAML_MAPPING_NODE) {
32: PetscBool isMerge;
34: /* "<<" is the merge key: don't increment the prefix */
35: PetscStrcmp((char *)(key->data.scalar.value), "<<", &isMerge);
36: if (!isMerge) {
37: PetscSNPrintf(prefix,PETSC_MAX_PATH_LEN,"%s_",(char *)(key->data.scalar.value));
38: PetscOptionsPrefixPush(options, prefix);
39: }
40: PetscParseLayerYAML(options, doc, value);
41: if (!isMerge) {
42: PetscOptionsPrefixPop(options);
43: }
44: } else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unsupported yaml node tye: expected scalar or mapping");
45: }
46: return(0);
47: }
49: /*@C
50: PetscOptionsInsertStringYAML - Inserts YAML-formatted options into the database from a string
52: Logically Collective
54: Input Parameter:
55: + options - options object
56: - in_str - YAML-formatted string op options
58: Level: intermediate
60: .seealso: PetscOptionsSetValue(), PetscOptionsView(), PetscOptionsHasName(), PetscOptionsGetInt(),
61: PetscOptionsGetReal(), PetscOptionsGetString(), PetscOptionsGetIntArray(), PetscOptionsBool(),
62: PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
63: PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
64: PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
65: PetscOptionsFList(), PetscOptionsEList(), PetscOptionsInsertFile(), PetscOptionsInsertFileYAML()
66: @*/
67: PetscErrorCode PetscOptionsInsertStringYAML(PetscOptions options,const char in_str[])
68: {
70: size_t yamlLength;
71: yaml_parser_t parser;
72: yaml_document_t doc;
73: yaml_node_t *root = NULL;
76: PetscStrlen(in_str, &yamlLength);
77: if (!yaml_parser_initialize(&parser)){
78: SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_LIB,"YAML parser initialization error");
79: }
80: yaml_parser_set_input_string(&parser,(const unsigned char *) in_str,yamlLength);
81: if (!yaml_parser_load(&parser, &doc)) {
82: SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_LIB,"YAML parser loading error");
83: }
84: root = yaml_document_get_root_node(&doc);
85: if (root) {
86: PetscParseLayerYAML(options, &doc, root);
87: }
88: yaml_document_delete(&doc);
89: yaml_parser_delete(&parser);
90: return(0);
91: }
93: /*@C
95: PetscOptionsInsertFileYAML - Insert a YAML-formatted file in the option database
97: Collective
99: Input Parameter:
100: + comm - the processes that will share the options (usually PETSC_COMM_WORLD)
101: . file - name of file
102: - require - if PETSC_TRUE will generate an error if the file does not exist
104: Only a small subset of the YAML standard is implemented. Sequences are NOT supported;
105: aliases and the merge key "<<" are.
106: The algorithm recursively parses the yaml file, pushing and popping prefixes
107: and inserting key + values pairs using PetscOptionsInsertString().
109: PETSc will generate an error condition that stops the program if a YAML error
110: is detected, hence the user should check that the YAML file is valid before
111: supplying it, for instance at http://www.yamllint.com/ .
113: Inspired by https://stackoverflow.com/a/621451
115: Level: intermediate
117: .seealso: PetscOptionsSetValue(), PetscOptionsView(), PetscOptionsHasName(), PetscOptionsGetInt(),
118: PetscOptionsGetReal(), PetscOptionsGetString(), PetscOptionsGetIntArray(), PetscOptionsBool(),
119: PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
120: PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
121: PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
122: PetscOptionsFList(), PetscOptionsEList(), PetscOptionsInsertFile(), PetscOptionsInsertStringYAML()
123: @*/
124: PetscErrorCode PetscOptionsInsertFileYAML(MPI_Comm comm,const char file[],PetscBool require)
125: {
127: PetscMPIInt rank;
128: char fname[PETSC_MAX_PATH_LEN];
129: unsigned char *optionsStr;
130: int yamlLength;
131: FILE *source;
132: PetscInt offset;
133: size_t rd;
136: MPI_Comm_rank(comm,&rank);
137: if (!rank) {
138: PetscFixFilename(file,fname);
139: source = fopen(fname,"r");
140: if (source) {
141: fseek(source,0,SEEK_END);
142: yamlLength = ftell(source);
143: fseek(source,0,SEEK_SET);
144: PetscMalloc1(yamlLength+1,&optionsStr);
145: /* Read the content of the YAML file one char at a time; why does this read the file one byte at a time? */
146: for (offset = 0; offset < yamlLength; offset++) {
147: rd = fread(&(optionsStr[offset]), sizeof(unsigned char),1,source);
148: if (rd != sizeof(unsigned char)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to read entire YAML file: %s",file);
149: }
150: fclose(source);
151: optionsStr[yamlLength] = '\0';
152: } else if (require) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open YAML option file %s\n",fname);
153: MPI_Bcast(&yamlLength,1,MPI_INT,0,comm);
154: MPI_Bcast(optionsStr,yamlLength+1,MPI_UNSIGNED_CHAR,0,comm);
155: } else {
156: MPI_Bcast(&yamlLength,1,MPI_INT,0,comm);
157: PetscMalloc1(yamlLength+1,&optionsStr);
158: MPI_Bcast(optionsStr,yamlLength+1,MPI_UNSIGNED_CHAR,0,comm);
159: }
160: PetscOptionsInsertStringYAML(NULL, (const char *) optionsStr);
161: PetscFree(optionsStr);
162: return(0);
163: }