Actual source code: yamlimpls.c

petsc-3.8.4 2018-03-24
Report Typos and Errors
  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: }