Actual source code: yamlimpls.c

petsc-3.12.5 2020-03-29
Report Typos and Errors
  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: }