Example #1
0
/*! \brief
 * Prints a brief list of keywords (selection methods) available.
 *
 * \param[in] fp    Where to write the list.
 * \param[in] symtab  Symbol table to use to find available keywords.
 * \param[in] type  Only methods that return this type are printed.
 * \param[in] bMod  If false, \ref SMETH_MODIFIER methods are excluded, otherwise
 *     only them are printed.
 */
static void
print_keyword_list(FILE *fp, gmx_sel_symtab_t *symtab, e_selvalue_t type,
                   bool bMod)
{
    gmx_sel_symrec_t *symbol;

    symbol = _gmx_sel_first_symbol(symtab, SYMBOL_METHOD);
    while (symbol)
    {
        gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(symbol);
        bool                 bShow;
        bShow = (method->type == type)
            && ((bMod && (method->flags & SMETH_MODIFIER))
                || (!bMod && !(method->flags & SMETH_MODIFIER)));
        if (bShow)
        {
            fprintf(fp, " %c ",
                    (method->help.nlhelp > 0 && method->help.help) ? '*' : ' ');
            if (method->help.syntax)
            {
                fprintf(fp, "%s\n", method->help.syntax);
            }
            else
            {
                const char *symname = _gmx_sel_sym_name(symbol);

                fprintf(fp, "%s", symname);
                if (strcmp(symname, method->name) != 0)
                {
                    fprintf(fp, " (synonym for %s)", method->name);
                }
                fprintf(fp, "\n");
            }
        }
        symbol = _gmx_sel_next_symbol(symbol, SYMBOL_METHOD);
    }
}
Example #2
0
/*! \brief
 * Checks the validity of parameters.
 *
 * \param[in]     fp      File handle to use for diagnostic messages
 *   (can be NULL).
 * \param[in]     name    Name of the method (used for error messages).
 * \param[in]     nparams Number of parameters in \p param.
 * \param[in,out] param   Parameter array
 *   (only the \c flags field of gmx_boolean parameters may be modified).
 * \param[in]     symtab  Symbol table (used for checking overlaps).
 * \returns       TRUE if there are no problems with the parameters,
 *   FALSE otherwise.
 *
 * This function performs some checks common to both check_method() and
 * check_modifier().
 * The purpose of these checks is to ensure that the selection parser does not
 * need to check for the validity of the parameters at each turn, and to
 * report programming errors as early as possible.
 * If you remove a check, make sure that the parameter parser can handle the
 * resulting parameters.
 */
static gmx_bool
check_params(FILE *fp, const char *name, int nparams, gmx_ana_selparam_t param[],
             gmx_sel_symtab_t *symtab)
{
    gmx_bool              bOk = TRUE;
    gmx_sel_symrec_t     *sym;
    int                   i, j;

    if (nparams > 0 && !param)
    {
        report_error(fp, name, "error: missing parameter data");
        return FALSE;
    }
    if (nparams == 0 && param)
    {
        report_error(fp, name, "warning: parameter data unused because nparams=0");
    }
    /* Check each parameter */
    for (i = 0; i < nparams; ++i)
    {
        /* Check that there is at most one NULL name, in the beginning */
        if (param[i].name == NULL && i > 0)
        {
            report_error(fp, name, "error: NULL parameter should be the first one");
            bOk = FALSE;
            continue;
        }
        /* Check for duplicates */
        for (j = 0; j < i; ++j)
        {
            if (param[j].name == NULL)
            {
                continue;
            }
            if (!gmx_strcasecmp(param[i].name, param[j].name))
            {
                report_error(fp, name, "error: duplicate parameter name '%s'", param[i].name);
                bOk = FALSE;
                break;
            }
        }
        /* Check flags */
        if (param[i].flags & SPAR_SET)
        {
            report_param_error(fp, name, param[i].name, "warning: flag SPAR_SET is set");
            param[i].flags &= ~SPAR_SET;
        }
        if (param[i].flags & SPAR_RANGES)
        {
            if (param[i].val.type != INT_VALUE && param[i].val.type != REAL_VALUE)
            {
                report_param_error(fp, name, param[i].name, "error: SPAR_RANGES cannot be set for a non-numeric parameter");
                bOk = FALSE;
            }
            if (param[i].flags & SPAR_DYNAMIC)
            {
                report_param_error(fp, name, param[i].name, "warning: SPAR_DYNAMIC does not have effect with SPAR_RANGES");
                param[i].flags &= ~SPAR_DYNAMIC;
            }
            if (!(param[i].flags & SPAR_VARNUM) && param[i].val.nr != 1)
            {
                report_param_error(fp, name, param[i].name, "error: range should take either one or an arbitrary number of values");
                bOk = FALSE;
            }
            if (param[i].flags & SPAR_ATOMVAL)
            {
                report_param_error(fp, name, param[i].name, "error: SPAR_RANGES and SPAR_ATOMVAL both set");
                bOk = FALSE;
            }
        }
        if ((param[i].flags & SPAR_VARNUM) && (param[i].flags & SPAR_ATOMVAL))
        {
            report_param_error(fp, name, param[i].name, "error: SPAR_VARNUM and SPAR_ATOMVAL both set");
            bOk = FALSE;
        }
        if (param[i].flags & SPAR_ENUMVAL)
        {
            if (param[i].val.type != STR_VALUE)
            {
                report_param_error(fp, name, param[i].name, "error: SPAR_ENUMVAL can only be set for string parameters");
                bOk = FALSE;
            }
            if (param[i].val.nr != 1)
            {
                report_param_error(fp, name, param[i].name, "error: SPAR_ENUMVAL parameters should take exactly one value");
                bOk = FALSE;
            }
            if (param[i].flags & (SPAR_DYNAMIC | SPAR_VARNUM | SPAR_ATOMVAL))
            {
                report_param_error(fp, name, param[i].name, "error: only SPAR_OPTIONAL supported with SPAR_ENUMVAL");
                bOk = FALSE;
            }
        }
        /* Check gmx_boolean parameters */
        if (param[i].val.type == NO_VALUE)
        {
            if (param[i].val.nr != 0)
            {
                report_param_error(fp, name, param[i].name, "error: number of values should be zero for gmx_boolean parameters");
                bOk = FALSE;
            }
            /* The gmx_boolean parameters should always be optional, so set the
             * flag for convenience. */
            param[i].flags |= SPAR_OPTIONAL;
            /* Any other flags should not be specified */
            if (param[i].flags & ~SPAR_OPTIONAL)
            {
                report_param_error(fp, name, param[i].name, "error: gmx_boolean parameter should not have any flags set");
                bOk = FALSE;
            }
        }
        /* Check val.nr */
        if (param[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL))
        {
            if (param[i].val.nr != -1)
            {
                report_param_error(fp, name, param[i].name, "warning: val.nr is not -1 although SPAR_VARNUM/SPAR_ATOMVAL is set");
            }
            param[i].val.nr = -1;
        }
        else if (param[i].val.type != NO_VALUE)
        {
            if (param[i].val.nr <= 0)
            {
                report_param_error(fp, name, param[i].name, "error: val.nr <= 0");
                bOk = FALSE;
            }
        }
        /* Check that the value pointer is NULL */
        if (param[i].nvalptr != NULL)
        {
            report_param_error(fp, name, param[i].name, "warning: nvalptr is set");
        }
        if (param[i].val.u.ptr != NULL && !(param[i].flags & SPAR_ENUMVAL))
        {
            report_param_error(fp, name, param[i].name, "warning: value pointer is set");
        }
        /* Check that the name contains only valid characters */
        if (param[i].name == NULL)
        {
            continue;
        }
        if (!isalpha(param[i].name[0]))
        {
            report_param_error(fp, name, param[i].name, "error: name does not begin with a letter");
            bOk = FALSE;
            continue;
        }
        for (j = 1; param[i].name[j] != 0; ++j)
        {
            if (param[i].name[j] != '_' && !isalnum(param[i].name[j]))
            {
                report_param_error(fp, name, param[i].name, "error: name contains non-alphanumeric characters");
                bOk = FALSE;
                break;
            }
        }
        if (param[i].name[j] != 0)
        {
            continue;
        }
        /* Check that the name does not conflict with a method */
        if (_gmx_sel_find_symbol(symtab, param[i].name, TRUE))
        {
            report_param_error(fp, name, param[i].name, "error: name conflicts with another method or a keyword");
            bOk = FALSE;
        }
    } /* End of parameter loop */
      /* Check parameters of existing methods */
    sym = _gmx_sel_first_symbol(symtab, SYMBOL_METHOD);
    while (sym)
    {
        gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(sym);
        gmx_ana_selparam_t  *param  =
            gmx_ana_selmethod_find_param(name, method);
        if (param)
        {
            report_param_error(fp, method->name, param->name, "error: name conflicts with another method or a keyword");
            bOk = FALSE;
        }
        sym = _gmx_sel_next_symbol(sym, SYMBOL_METHOD);
    }
    return bOk;
}
Example #3
0
/*!
 * \param[in]  fp      Where to write the help.
 * \param[in]  symtab  Symbol table to use to find available keywords.
 * \param[in]  topic Topic to print help on, or NULL for general help.
 *
 * \p symtab is used to get information on which keywords are available in the
 * present context.
 */
void
_gmx_sel_print_help(FILE *fp, gmx_sel_symtab_t *symtab, const char *topic)
{
    const t_selection_help_item *item = NULL;
    size_t i;

    /* Find the item for the topic */
    if (!topic)
    {
        item = &helpitems[0];
    }
    else if (strcmp(topic, "all") == 0)
    {
        for (i = 0; i < asize(helpitems); ++i)
        {
            item = &helpitems[i];
            _gmx_sel_print_help(fp, symtab, item->topic);
            if (i != asize(helpitems) - 1)
            {
                fprintf(fp, "\n\n");
            }
        }
        return;
    }
    else
    {
        for (i = 1; i < asize(helpitems); ++i)
        {
            if (strncmp(helpitems[i].topic, topic, strlen(topic)) == 0)
            {
                item = &helpitems[i];
                break;
            }
        }
    }
    /* If the topic is not found, check the available methods.
     * If they don't provide any help either, tell the user and exit. */
    if (!item)
    {
        gmx_sel_symrec_t *symbol;

        symbol = _gmx_sel_first_symbol(symtab, SYMBOL_METHOD);
        while (symbol)
        {
            gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(symbol);
            if (method->help.nlhelp > 0 && method->help.help
                && strncmp(method->name, topic, strlen(topic)) == 0)
            {
                print_tty_formatted(fp, method->help.nlhelp,
                        method->help.help, 0, NULL, NULL, false);
                return;
            }
            symbol = _gmx_sel_next_symbol(symbol, SYMBOL_METHOD);
        }

        fprintf(fp, "No help available for '%s'.\n", topic);
        return;
    }
    /* Print the help */
    print_tty_formatted(fp, item->nl, item->text, 0, NULL, NULL, false);
    /* Special handling of certain pages */
    if (!topic)
    {
        int len = 0;

        /* Print the subtopics on the main page */
        fprintf(fp, "\nAvailable subtopics:\n");
        for (i = 1; i < asize(helpitems); ++i)
        {
            int len1 = strlen(helpitems[i].topic) + 2;

            len += len1;
            if (len > 79)
            {
                fprintf(fp, "\n");
                len = len1;
            }
            fprintf(fp, "  %s", helpitems[i].topic);
        }
        fprintf(fp, "\n");
    }
    else if (strcmp(item->topic, "keywords") == 0)
    {
        /* Print the list of keywords */
        fprintf(fp, "\nKeywords that select atoms by an integer property:\n");
        fprintf(fp, "(use in expressions or like \"atomnr 1 to 5 7 9\")\n");
        print_keyword_list(fp, symtab, INT_VALUE, false);

        fprintf(fp, "\nKeywords that select atoms by a numeric property:\n");
        fprintf(fp, "(use in expressions or like \"occupancy 0.5 to 1\")\n");
        print_keyword_list(fp, symtab, REAL_VALUE, false);

        fprintf(fp, "\nKeywords that select atoms by a string property:\n");
        fprintf(fp, "(use like \"name PATTERN [PATTERN] ...\")\n");
        print_keyword_list(fp, symtab, STR_VALUE, false);

        fprintf(fp, "\nAdditional keywords that directly select atoms:\n");
        print_keyword_list(fp, symtab, GROUP_VALUE, false);

        fprintf(fp, "\nKeywords that directly evaluate to positions:\n");
        fprintf(fp, "(see also \"help positions\")\n");
        print_keyword_list(fp, symtab, POS_VALUE, false);

        fprintf(fp, "\nAdditional keywords:\n");
        print_keyword_list(fp, symtab, POS_VALUE, true);
        print_keyword_list(fp, symtab, NO_VALUE, true);
    }
}