/*! * \param[in] topic Topic for which help was requested, or NULL for general * help. * \param[in] scanner Scanner data structure. * * \p topic is freed by this function. */ void _gmx_sel_handle_help_cmd(const SelectionParserValueListPointer &topic, yyscan_t scanner) { gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner); if (sc->rootHelp.get() == NULL) { sc->rootHelp = gmx::createSelectionHelpTopic(); } gmx::HelpWriterContext context(&gmx::File::standardError(), gmx::eHelpOutputFormat_Console); gmx::HelpManager manager(*sc->rootHelp, context); try { SelectionParserValueList::const_iterator value; for (value = topic->begin(); value != topic->end(); ++value) { manager.enterTopic(value->stringValue()); } } catch (const gmx::InvalidInputError &ex) { fprintf(stderr, "%s\n", ex.what()); return; } manager.writeCurrentTopic(); }
/*! \brief * Parses the values for a parameter that takes a constant number of values. * * \param[in] values List of values. * \param param Parameter to parse. * \param root Selection element to which child expressions are added. * \param[in] scanner Scanner data structure. * * For integer ranges, the sequence of numbers from the first to second value * is stored, each as a separate value. */ static void parse_values_std(const SelectionParserValueList &values, gmx_ana_selparam_t *param, const SelectionTreeElementPointer &root, void *scanner) { int i, j; bool bDynamic; /* Handle atom-valued parameters */ if (param->flags & SPAR_ATOMVAL) { if (values.size() > 1) { GMX_THROW(InvalidInputError( "Only a single value or a single expression is " "supported in this context")); } if (values.front().hasExpressionValue()) { SelectionTreeElementPointer child = add_child(root, param, values.front().expr, scanner); child->flags |= SEL_ALLOCVAL; if (child->v.type != GROUP_VALUE && (child->flags & SEL_ATOMVAL)) { /* Rest of the initialization is done during compilation in * init_method(). */ /* TODO: Positions are not correctly handled */ param->val.nr = -1; if (param->nvalptr) { *param->nvalptr = -1; } return; } param->flags &= ~SPAR_ATOMVAL; param->val.nr = 1; if (param->nvalptr) { *param->nvalptr = 1; } param->nvalptr = NULL; if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE || param->val.type == STR_VALUE) { _gmx_selvalue_reserve(¶m->val, 1); } set_expr_value_store(child, param, 0, scanner); return; } /* If we reach here, proceed with normal parameter handling */ param->val.nr = 1; if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE || param->val.type == STR_VALUE) { _gmx_selvalue_reserve(¶m->val, 1); } param->flags &= ~SPAR_ATOMVAL; param->flags &= ~SPAR_DYNAMIC; } i = 0; bDynamic = false; SelectionParserValueList::const_iterator value; for (value = values.begin(); value != values.end() && i < param->val.nr; ++value) { GMX_RELEASE_ASSERT(value->type == param->val.type, "Invalid value type (should have been caught earlier)"); if (value->hasExpressionValue()) { SelectionTreeElementPointer child = add_child(root, param, value->expr, scanner); set_expr_value_store(child, param, i, scanner); if (child->flags & SEL_DYNAMIC) { bDynamic = true; } } else { /* Value is not an expression */ switch (value->type) { case INT_VALUE: { bool bTooManyValues; if (value->u.i.i1 <= value->u.i.i2) { for (j = value->u.i.i1; j <= value->u.i.i2 && i < param->val.nr; ++j) { param->val.u.i[i++] = j; } bTooManyValues = (j != value->u.i.i2 + 1); } else { for (j = value->u.i.i1; j >= value->u.i.i2 && i < param->val.nr; --j) { param->val.u.i[i++] = j; } bTooManyValues = (j != value->u.i.i2 - 1); } if (bTooManyValues) { std::string text(_gmx_sel_lexer_get_text(scanner, value->location())); std::string message = formatString("Range ('%s') produces more values than is " "accepted in this context", text.c_str()); GMX_THROW(InvalidInputError(message)); } --i; break; } case REAL_VALUE: if (value->u.r.r1 != value->u.r.r2) { std::string text(_gmx_sel_lexer_get_text(scanner, value->location())); std::string message = formatString("Real range ('%s') is not supported in this context", text.c_str()); GMX_THROW(InvalidInputError(message)); } param->val.u.r[i] = value->u.r.r1; break; case STR_VALUE: param->val.u.s[i] = gmx_strdup(value->stringValue().c_str()); break; case POS_VALUE: gmx_ana_pos_init_const(¶m->val.u.p[i], value->u.x); break; case NO_VALUE: case GROUP_VALUE: GMX_THROW(InternalError("Invalid non-expression value type")); } } ++i; } if (value != values.end()) { std::string message = formatString("Too many values provided, expected %d", param->val.nr); GMX_THROW(InvalidInputError(message)); } if (i < param->val.nr) { std::string message = formatString("Too few values provided, expected %d", param->val.nr); GMX_THROW(InvalidInputError(message)); } if (!bDynamic) { param->flags &= ~SPAR_DYNAMIC; } if (param->nvalptr) { *param->nvalptr = param->val.nr; } param->nvalptr = NULL; }
/*! \brief * Parses the values for a parameter that takes a variable number of values. * * \param[in] values List of values. * \param param Parameter to parse. * \param root Selection element to which child expressions are added. * \param[in] scanner Scanner data structure. * * For integer ranges, the sequence of numbers from the first to second value * is stored, each as a separate value. */ static void parse_values_varnum(const SelectionParserValueList &values, gmx_ana_selparam_t *param, const SelectionTreeElementPointer &root, void *scanner) { int i, j; param->flags &= ~SPAR_DYNAMIC; /* Compute number of values, considering also integer ranges. */ int valueCount = static_cast<int>(values.size()); if (param->val.type == INT_VALUE) { SelectionParserValueList::const_iterator value; for (value = values.begin(); value != values.end(); ++value) { if (value->type == INT_VALUE && !value->hasExpressionValue()) { valueCount += abs(value->u.i.i2 - value->u.i.i1); } } } /* Check that the value type is actually implemented */ if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE && param->val.type != STR_VALUE && param->val.type != POS_VALUE) { GMX_THROW(InternalError("Variable-count value type not implemented")); } /* Reserve appropriate amount of memory */ if (param->val.type == POS_VALUE) { gmx_ana_pos_reserve(param->val.u.p, valueCount, 0); gmx_ana_indexmap_init(¶m->val.u.p->m, NULL, NULL, INDEX_UNKNOWN); gmx_ana_pos_set_nr(param->val.u.p, valueCount); } else { _gmx_selvalue_reserve(¶m->val, valueCount); } /* Create a dummy child element to store the string values. * This element is responsible for freeing the values, but carries no * other function. */ if (param->val.type == STR_VALUE) { SelectionTreeElementPointer child( new SelectionTreeElement(SEL_CONST, SelectionLocation::createEmpty())); _gmx_selelem_set_vtype(child, STR_VALUE); child->setName(param->name); child->flags &= ~SEL_ALLOCVAL; child->flags |= SEL_FLAGSSET | SEL_VARNUMVAL | SEL_ALLOCDATA; child->v.nr = valueCount; _gmx_selvalue_setstore(&child->v, param->val.u.s); /* Because the child is not group-valued, the u union is not used * for anything, so we can abuse it by storing the parameter value * as place_child() expects, but this is really ugly... */ child->u.param = param; place_child(root, child, param); } param->val.nr = valueCount; i = 0; SelectionParserValueList::const_iterator value; for (value = values.begin(); value != values.end(); ++value) { GMX_RELEASE_ASSERT(value->type == param->val.type, "Invalid value type (should have been caught earlier)"); if (value->hasExpressionValue()) { std::string text(_gmx_sel_lexer_get_text(scanner, value->location())); std::string message("Selection expressions are not supported in this " "context when multiple values are provided"); InvalidInputError ex(message); ex.prependContext(formatString("Invalid expression '%s'", text.c_str())); GMX_THROW(ex); } switch (param->val.type) { case INT_VALUE: if (value->u.i.i1 <= value->u.i.i2) { for (j = value->u.i.i1; j <= value->u.i.i2; ++j) { param->val.u.i[i++] = j; } } else { for (j = value->u.i.i1; j >= value->u.i.i2; --j) { param->val.u.i[i++] = j; } } break; case REAL_VALUE: if (value->u.r.r1 != value->u.r.r2) { std::string text(_gmx_sel_lexer_get_text(scanner, value->location())); std::string message = formatString("Real range ('%s') is not supported in this context", text.c_str()); InvalidInputError ex(message); GMX_THROW(ex); } param->val.u.r[i++] = value->u.r.r1; break; case STR_VALUE: param->val.u.s[i++] = gmx_strdup(value->stringValue().c_str()); break; case POS_VALUE: copy_rvec(value->u.x, param->val.u.p->x[i++]); break; default: /* Should not be reached */ GMX_RELEASE_ASSERT(false, "Variable-count value type not implemented"); } } GMX_RELEASE_ASSERT(i == valueCount, "Inconsistent value count wrt. the actual value population"); if (param->nvalptr) { *param->nvalptr = param->val.nr; } param->nvalptr = NULL; }