Actual source code: yamlimpls.c
petsc-3.12.5 2020-03-29
1: #include <petsc/private/petscimpl.h>
2: #include <yaml.h>
4: enum storage_flags {VAR,VAL,SEQ}; /* "Store as" switch */
6: static PetscErrorCode PetscParseLayerYAML(yaml_parser_t *parser,int *lvl)
7: {
8: yaml_event_t event;
9: int storage = VAR; /* mapping cannot start with VAL definition w/o VAR key */
10: char key[PETSC_MAX_PATH_LEN],option[PETSC_MAX_PATH_LEN],prefix[PETSC_MAX_PATH_LEN];
11: PetscErrorCode ierr;
14: PetscSNPrintf(option,PETSC_MAX_PATH_LEN,"%s"," ");
15: do {
16: if(!yaml_parser_parse(parser,&event)){
17: SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_LIB,"YAML parse error (for instance, improper indentation)");
18: }
19: /* Parse value either as a new leaf in the mapping */
20: /* or as a leaf value (one of them, in case it's a sequence) */
21: switch (event.type) {
22: case YAML_SCALAR_EVENT:
23: if (storage) {
24: PetscSNPrintf(option,PETSC_MAX_PATH_LEN,"-%s %s",key,(char*)event.data.scalar.value);
25: PetscOptionsInsertString(NULL,option);
26: } else {
27: PetscStrncpy(key,(char*)event.data.scalar.value,event.data.scalar.length+1);
28: }
29: storage ^= VAL; /* Flip VAR/VAL switch for the next event */
30: break;
31: case YAML_SEQUENCE_START_EVENT:
32: /* Sequence - all the following scalars will be appended to the last_leaf */
33: storage = SEQ;
34: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP ,"Unable to open YAML option file: sequences not supported");
35: yaml_event_delete(&event);
36: break;
37: case YAML_SEQUENCE_END_EVENT:
38: storage = VAR;
39: yaml_event_delete(&event);
40: break;
41: case YAML_MAPPING_START_EVENT:
42: PetscSNPrintf(prefix,PETSC_MAX_PATH_LEN,"%s_",key);
43: if (*lvl > 0) {
44: PetscOptionsPrefixPush(NULL,prefix);
45: }
46: (*lvl)++;
47: PetscParseLayerYAML(parser,lvl);
48: (*lvl)--;
49: if (*lvl > 0) {
50: PetscOptionsPrefixPop(NULL);
51: }
52: storage ^= VAL; /* Flip VAR/VAL, w/o touching SEQ */
53: yaml_event_delete(&event);
54: break;
55: default:
56: break;
57: }
58: }
59: while ((event.type != YAML_MAPPING_END_EVENT) && (event.type != YAML_STREAM_END_EVENT));
60: return(0);
61: }
63: /*C
65: PetscOptionsInsertFileYAML - Insert a YAML-formatted file in the option database
67: Collective
69: Input Parameter:
70: + comm - the processes that will share the options (usually PETSC_COMM_WORLD)
71: . file - name of file
72: - require - if PETSC_TRUE will generate an error if the file does not exist
74: Only a small subset of the YAML standard is implemented. Sequences and alias
75: are NOT supported.
76: The algorithm recursively parses the yaml file, pushing and popping prefixes
77: and inserting key + values pairs using PetscOptionsInsertString().
79: PETSc will generate an error condition that stops the program if a YAML error
80: is detected, hence the user should check that the YAML file is valid before
81: supplying it, for instance at http://www.yamllint.com/ .
83: Inspired by https://stackoverflow.com/a/621451
85: Level: intermediate
87: .seealso: PetscOptionsSetValue(), PetscOptionsView(), PetscOptionsHasName(), PetscOptionsGetInt(),
88: PetscOptionsGetReal(), PetscOptionsGetString(), PetscOptionsGetIntArray(), PetscOptionsBool(),
89: PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
90: PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
91: PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
92: PetscOptionsFList(), PetscOptionsEList(), PetscOptionsInsertFile()
93: C*/
94: PetscErrorCode PetscOptionsInsertFileYAML(MPI_Comm comm,const char file[],PetscBool require)
95: {
97: PetscMPIInt rank;
98: char fname[PETSC_MAX_PATH_LEN];
99: unsigned char *optionsStr;
100: int yamlLength;
101: yaml_parser_t parser;
102: int lvl=0;
103: FILE *source;
104: PetscInt offset;
105: size_t rd;
108: MPI_Comm_rank(comm,&rank);
109: if (!rank) {
110: PetscFixFilename(file,fname);
111: source = fopen(fname,"r");
112: if (source) {
113: fseek(source,0,SEEK_END);
114: yamlLength = ftell(source);
115: fseek(source,0,SEEK_SET);
116: PetscMalloc1(yamlLength+1,&optionsStr);
117: /* Read the content of the YAML file one char at a time; why does this read the file one byte at a time? */
118: for (offset = 0; offset < yamlLength; offset++) {
119: rd = fread(&(optionsStr[offset]), sizeof(unsigned char),1,source);
120: if (rd != sizeof(unsigned char)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to read entire YAML file: %s",file);
121: }
122: fclose(source);
123: optionsStr[yamlLength] = '\0';
124: } else if (require) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open YAML option file %s\n",fname);
125: MPI_Bcast(&yamlLength,1,MPI_INT,0,comm);
126: MPI_Bcast(optionsStr,yamlLength+1,MPI_UNSIGNED_CHAR,0,comm);
127: } else {
128: MPI_Bcast(&yamlLength,1,MPI_INT,0,comm);
129: PetscMalloc1(yamlLength+1,&optionsStr);
130: MPI_Bcast(optionsStr,yamlLength+1,MPI_UNSIGNED_CHAR,0,comm);
131: }
132: if(!yaml_parser_initialize(&parser)){
133: SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_LIB,"YAML parser initialization error");
134: }
135: yaml_parser_set_input_string(&parser,optionsStr,(size_t) yamlLength);
136: PetscParseLayerYAML(&parser,&lvl);
137: yaml_parser_delete(&parser);
138: PetscFree(optionsStr);
139: return(0);
140: }