Actual source code: yamlimpls.c
petsc-3.10.5 2019-03-28
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: 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: }