Exemple #1
0
/*
 * GCI_parsetree tries to interpret the type information of the first
 * generation. That are the branches "branch.return", "branch.1",
 * "branch.2", ... The value of "base" is such an identifier.
 * base must be a string large enough to hold the longest type variable name
 * which occurs in the tree including the branch name. This argument will
 * contain the variable's name which forces the error in case of an error.
 * The buffer is always modified.
 *
 * callback is described later. arg is passed to callback without further
 * interpretation.
 *
 * prefixChar is the prefix that must be used in front of stem names.
 *
 * The function loops over a type structure tree, the current node name is
 * placed in cb->buffer. We do a depth-first iteration. The callback function
 * is called at least for each type declaration. The callback is described
 * below the error codes.
 *
 * THE COMPLETE PARSING IS STOPPED IF THE callback RETURNS ANOTHER VALUE THAN
 * GCI_OK.
 *
 * THE GENERATED TYPES MAY HAVE ILLEGAL BIT SIZES. IT ISN'T CHECKED ALWAYS!
 *
 * Return values:
 * GCI_OK:              Everything is fine.
 *
 *                      In case of an error cb->buffer will contain the
 *                      variable's name where the problem raises first.
 *
 * GCI_MissingName:     A variable's name isn't set. This is the equivalence
 *                      for GCI_MissingValue in the type parsing step. The
 *                      system may or may not raise a NOVALUE condition instead
 *                      depending on the implementation.
 * GCI_BufferTooSmall:  The variable's name buffer cb->buffer can't hold the
 *                      complete variable's name or the type string exceeds
 *                      256 byte.
 * GCI_IllegalName:     The variables name in cb->buffer is illegal in terms of
 *                      Rexx. In general, the basename of GCI_paretree is
 *                      wrong.
 * GCI_RexxError:       An unexpected error is returned by the interpreter
 *                      while trying to access Rexx variables.
 * GCI_UnsupportedType: Wrong type of input, e.g. FLOAT31 or the empty string
 *                      in a type description string. Another reason is an
 *                      internal error since the default sizes for "unsigned"
 *                      and "integer" are not supported.
 * GCI_WrongInput:      Strange characters occur in the input string as the
 *                      bit size of the type.
 * GCI_NumberRange:     Number to small or big to fit into the desired type
 *                      with the desired destbyte-size. This applies to the
 *                      element count of an "ARRAY" or "CONTAINER" type size
 *                      or the bit size of the plain type.
 * GCI_NoBaseType:      The type won't fit the requirements for basic types.
 *
 * And there are numerous other possible errors returned by cb->callback.
 *
 *****************************************************************************
 *
 * Description of the callback:
 * This function will be called when a type string has been parsed. The
 * GCI_parseinfo structure is filled to allow the caller allocating enough
 * memory.
 *
 * depth is the current depth within the structure starting with 0. itemnumber
 * is the current number of the item within a structure starting with 1.
 * Arrays will have an item of 1, not more, not less. The item describes all
 * identical values in the array.
 * itemnumber will be 0 for the base element (of depth 0).
 *
 * itemnumber may be -1! This happens on containers and arrays after
 * processing the last subitem. This allows the callback to close the
 * current container and to do some final processing.
 *
 * arg is the copy of the arg parameter of GCI_parsetree. A hidden parameter
 * must be passed in arg (too) if it is needed.
 *
 * The caller of GCI_parsetree is responsible to understand additional
 * return codes of the callback.
 */
GCI_result GCI_parsetree( void *hidden,
                          GCI_str *base,
                          GCI_result (*callback)(int depth,
                                  int itemnumber,
                                  void *arg,
                                  const GCI_parseinfo *info),
                          void *arg,
                          const char *prefixChar )
{
    callblock cb;
    /*
     * All simple type values must fit into a static buffer.
     */
    char tmp[256];
    GCI_strOfCharBuffer( tmp );

    /*
     * We wrap the parameters in a block to prevent further parameters.
     * We use the given buffer for all further processing. We'll have the
     * errorneous string at once in that case.
     */
    cb.hidden = hidden;
    cb.buffer = base;
    cb.depth = 0;
    cb.callback = callback;
    cb.arg = arg;
    cb.tempbuf = str_tmp;
    cb.recurCount = 0;
    cb.prefixChar = prefixChar;

    return parse( &cb, 0 );
}
/*
 * Returns the translated function code from GCI_result to the code that
 * Regina shall return to the caller.
 * This function set the textual representation of an error code to that value
 * that will be accessed by RxFuncErrMsg() and sets the variable GCI_RC to
 * that value, too.
 *
 * dispo is either NULL (or the content is NULL) or contains the position of
 * the error within the structure. dispo's content will be deallocated.
 */
static int GCIcode2ReginaFuncCode( tsd_t *TSD,
                                   GCI_result rc,
                                   GCI_str *dispo,
                                   int forceError )
{
   GCI_str description, fullinfo, *fi = NULL, *out;
   volatile char *tmpDispo, *tmpFull = NULL, *tmpBest;
   streng *h;
   char GCI_RC[7];
   GCI_strOfCharBuffer(GCI_RC);

   GCI_strcats( &str_GCI_RC, "GCI_RC" );
   GCI_describe( &description, rc );

   if ( ( dispo != NULL ) && ( GCI_content( dispo ) == NULL ) )
      dispo = NULL;

   if ( ( dispo != NULL ) && ( rc != GCI_OK ) )
   {
      if ( GCI_stralloc( TSD, &fullinfo, GCI_strlen( dispo ) +
                                         GCI_strlen( &description ) +
                                         3 ) == GCI_OK )
      {
         fi = &fullinfo;
         GCI_strcpy( fi, &description );
         GCI_strcats( fi, ": " );
         GCI_strcat( fi, dispo );
      }
   }

   out = ( fi != NULL ) ? fi : &description;
   GCI_writeRexx( TSD, &str_GCI_RC, out, 0 );

   if ( ( rc == GCI_OK ) && !forceError )
   {
      if ( dispo != NULL )
         GCI_strfree( TSD, dispo );
      if ( fi != NULL )
         GCI_strfree( TSD, fi );
      return 0;
   }

   h = streng_of( TSD, &description );
   tmpDispo = tmpstr_of( TSD, h );
   Free_stringTSD( h );

   if ( fi != NULL )
   {
      h = streng_of( TSD, fi );
      tmpFull = tmpstr_of( TSD, h );
      Free_stringTSD( h );
   }

   if ( dispo != NULL )
      GCI_strfree( TSD, dispo );
   if ( fi != NULL )
      GCI_strfree( TSD, fi );

   /*
    * We have two temporary strings describing the error condition.
    * All stuff we have to deallocate is deallocated. Let's go.
    */
   tmpBest = ( tmpFull != NULL ) ? tmpFull : tmpDispo;
   set_err_message( TSD, (char *) tmpBest, "" );

   switch ( rc )
   {
      case GCI_NoMemory:
         exiterror( ERR_STORAGE_EXHAUSTED, 0 );

      case GCI_WrongInput:
         exiterror( ERR_INCORRECT_CALL, 980, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_NumberRange:
         exiterror( ERR_INCORRECT_CALL, 981, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_StringRange:
         exiterror( ERR_INCORRECT_CALL, 982, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_UnsupportedType:
         if ( !forceError )
            return 71; /* RXFUNC_BADTYPE + 1 */
         exiterror( ERR_INCORRECT_CALL, 983, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_UnsupportedNumber:
         exiterror( ERR_INCORRECT_CALL, 984, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_BufferTooSmall:
         exiterror( ERR_INCORRECT_CALL, 985, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_MissingName:
         exiterror( ERR_INCORRECT_CALL, 986, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_MissingValue:
         exiterror( ERR_INCORRECT_CALL, 987, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_IllegalName:
         exiterror( ERR_INCORRECT_CALL, 988, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_RexxError:
         exiterror( ERR_INCORRECT_CALL, 989, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_NoBaseType:
         exiterror( ERR_INCORRECT_CALL, 990, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_SyntaxError:
         exiterror( ERR_INCORRECT_CALL, 991, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_ArgStackOverflow:
         exiterror( ERR_INCORRECT_CALL, 992, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_NestingOverflow:
         exiterror( ERR_INCORRECT_CALL, 993, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      default:
         break;
   }
   exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, tmpBest );
   return 0; /* Keep the compiler happy */
}