Blame tools/lint/completion.c

Packit 8fb591
/**
Packit 8fb591
 * @file completion.c
Packit 8fb591
 * @author Michal Vasko <mvasko@cesnet.cz>
Packit 8fb591
 * @brief libyang's yanglint tool auto completion
Packit 8fb591
 *
Packit 8fb591
 * Copyright (c) 2015 CESNET, z.s.p.o.
Packit 8fb591
 *
Packit 8fb591
 * This source code is licensed under BSD 3-Clause License (the "License").
Packit 8fb591
 * You may not use this file except in compliance with the License.
Packit 8fb591
 * You may obtain a copy of the License at
Packit 8fb591
 *
Packit 8fb591
 *     https://opensource.org/licenses/BSD-3-Clause
Packit 8fb591
 */
Packit 8fb591
Packit 8fb591
#include <stdlib.h>
Packit 8fb591
#include <stdio.h>
Packit 8fb591
#include <sys/types.h>
Packit 8fb591
#include <dirent.h>
Packit 8fb591
#include <errno.h>
Packit 8fb591
#include <string.h>
Packit 8fb591
Packit 8fb591
#include "commands.h"
Packit 8fb591
#include "../../linenoise/linenoise.h"
Packit 8fb591
#include "libyang.h"
Packit 8fb591
Packit 8fb591
extern struct ly_ctx *ctx;
Packit 8fb591
Packit 8fb591
static void
Packit 8fb591
get_cmd_completion(const char *hint, char ***matches, unsigned int *match_count)
Packit 8fb591
{
Packit 8fb591
    int i;
Packit 8fb591
    void *p;
Packit 8fb591
Packit 8fb591
    *match_count = 0;
Packit 8fb591
    *matches = NULL;
Packit 8fb591
Packit 8fb591
    for (i = 0; commands[i].name; i++) {
Packit 8fb591
        if (!strncmp(hint, commands[i].name, strlen(hint))) {
Packit 8fb591
            ++(*match_count);
Packit 8fb591
            p = realloc(*matches, *match_count * sizeof **matches);
Packit 8fb591
            if (!p) {
Packit 8fb591
                fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
Packit 8fb591
                return;
Packit 8fb591
            }
Packit 8fb591
            *matches = p;
Packit 8fb591
            (*matches)[*match_count-1] = strdup(commands[i].name);
Packit 8fb591
        }
Packit 8fb591
    }
Packit 8fb591
}
Packit 8fb591
Packit 8fb591
static int
Packit 8fb591
last_is_opt(const char *hint)
Packit 8fb591
{
Packit 8fb591
    const char *ptr;
Packit 8fb591
Packit 8fb591
    /* last is option */
Packit 8fb591
    if (hint[0] == '-') {
Packit 8fb591
        return 1;
Packit 8fb591
    }
Packit 8fb591
Packit 8fb591
    do {
Packit 8fb591
        --hint;
Packit 8fb591
    } while (hint[0] == ' ');
Packit 8fb591
Packit 8fb591
    /* last is option argument */
Packit 8fb591
    ptr = strrchr(hint, ' ');
Packit 8fb591
    if (ptr) {
Packit 8fb591
        ++ptr;
Packit 8fb591
        if (ptr[0] == '-') {
Packit 8fb591
            return 1;
Packit 8fb591
        }
Packit 8fb591
    }
Packit 8fb591
Packit 8fb591
    return 0;
Packit 8fb591
}
Packit 8fb591
Packit 8fb591
static void
Packit 8fb591
get_model_completion(const char *hint, char ***matches, unsigned int *match_count)
Packit 8fb591
{
Packit 8fb591
    int i;
Packit 8fb591
    uint32_t idx = 0;
Packit 8fb591
    const struct lys_module *module;
Packit 8fb591
    void *p;
Packit 8fb591
Packit 8fb591
    *match_count = 0;
Packit 8fb591
    *matches = NULL;
Packit 8fb591
Packit 8fb591
    while ((module = ly_ctx_get_module_iter(ctx, &idx))) {
Packit 8fb591
        if (!strncmp(hint, module->name, strlen(hint))) {
Packit 8fb591
            ++(*match_count);
Packit 8fb591
            p = realloc(*matches, *match_count * sizeof **matches);
Packit 8fb591
            if (!p) {
Packit 8fb591
                fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
Packit 8fb591
                return;
Packit 8fb591
            }
Packit 8fb591
            *matches = p;
Packit 8fb591
            (*matches)[*match_count-1] = strdup(module->name);
Packit 8fb591
        }
Packit 8fb591
Packit 8fb591
        for (i = 0; i < module->inc_size; ++i) {
Packit 8fb591
            if (!strncmp(hint, module->inc[i].submodule->name, strlen(hint))) {
Packit 8fb591
                ++(*match_count);
Packit 8fb591
                p = realloc(*matches, *match_count * sizeof **matches);
Packit 8fb591
                if (!p) {
Packit 8fb591
                    fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
Packit 8fb591
                    return;
Packit 8fb591
                }
Packit 8fb591
                *matches = p;
Packit 8fb591
                (*matches)[*match_count-1] = strdup(module->inc[i].submodule->name);
Packit 8fb591
            }
Packit 8fb591
        }
Packit 8fb591
    }
Packit 8fb591
}
Packit 8fb591
Packit 8fb591
void
Packit 8fb591
complete_cmd(const char *buf, const char *hint, linenoiseCompletions *lc)
Packit 8fb591
{
Packit 8fb591
    char **matches = NULL;
Packit 8fb591
    unsigned int match_count = 0, i;
Packit 8fb591
Packit 8fb591
    if (!strncmp(buf, "add ", 4)) {
Packit 8fb591
        linenoisePathCompletion(buf, hint, lc);
Packit 8fb591
    } else if ((!strncmp(buf, "searchpath ", 11) || !strncmp(buf, "data ", 5)
Packit 8fb591
            || !strncmp(buf, "config ", 7) || !strncmp(buf, "filter ", 7)
Packit 8fb591
            || !strncmp(buf, "xpath ", 6) || !strncmp(buf, "clear ", 6)) && !last_is_opt(hint)) {
Packit 8fb591
        linenoisePathCompletion(buf, hint, lc);
Packit 8fb591
    } else if ((!strncmp(buf, "print ", 6) || !strncmp(buf, "feature ", 8)) && !last_is_opt(hint)) {
Packit 8fb591
        get_model_completion(hint, &matches, &match_count);
Packit 8fb591
    } else if (!strchr(buf, ' ') && hint[0]) {
Packit 8fb591
        get_cmd_completion(hint, &matches, &match_count);
Packit 8fb591
    }
Packit 8fb591
Packit 8fb591
    for (i = 0; i < match_count; ++i) {
Packit 8fb591
        linenoiseAddCompletion(lc, matches[i]);
Packit 8fb591
        free(matches[i]);
Packit 8fb591
    }
Packit 8fb591
    free(matches);
Packit 8fb591
}