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