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