Actual source code: yamlimpls.c

petsc-3.7.7 2017-09-25
Report Typos and Errors
  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: }