Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linenoise update #2307

Open
wants to merge 5 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/yanglint/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
if(WIN32)
if(WIN32 OR NOT ENABLE_YANGLINT_INTERACTIVE)
set(YANGLINT_INTERACTIVE OFF)
else()
set(YANGLINT_INTERACTIVE ON)
Expand Down
5 changes: 4 additions & 1 deletion tests/yanglint/interactive/ly.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ stty columns 720
# default setup for every unit test
variable ly_setup {
spawn $TUT
# turn off linenoise multiline.
ly_skip_warnings
# Searchpath is set, so modules can be loaded via the 'load' command.
ly_cmd "searchpath $::env(YANG_MODULES_DIR)"
Expand All @@ -32,7 +33,9 @@ variable ly_cleanup {
# Skip no dir and/or no history warnings and prompt.
proc ly_skip_warnings {} {
global prompt
expect -re "(YANGLINT.*)*$prompt" {}
expect -re "$prompt" {}
send -- "cli -s\r"
expect -re "\n$prompt" {}
}

# Send command 'cmd' to the process, expect error header and then check output string by 'pattern'.
Expand Down
6 changes: 5 additions & 1 deletion tools/lint/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ set(lintsrc
if(ENABLE_YANGLINT_INTERACTIVE)
set(lintsrc ${lintsrc}
main.c
cmd_cli.c
completion.c
configuration.c
linenoise/linenoise.c)
interactive_cmd.c
linenoise/linenoise.c
linenoise/utf8.c)
else()
set(lintsrc ${lintsrc}
interactive_cmd_off.c
main_ni_only.c)
endif()

Expand Down
37 changes: 36 additions & 1 deletion tools/lint/cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ typedef struct {
} COMMAND;

/**
* @brief The list of available commands.
* @brief The list of available commands for interactive and non-interactive mode.
*/
extern COMMAND commands[];

Expand All @@ -82,6 +82,18 @@ enum COMMAND_INDEX {
CMD_DEBUG
};

/**
* @brief The list of available commands only for interactive mode. Disjunct with ::commands.
*/
extern COMMAND interactive_cmd[];

/**
* @brief Index for global variable ::interactive_cmd.
*/
enum COMMAND_I_INDEX {
CMD_CLI = 0
};

/**
* @brief For each cmd, call the COMMAND.free_func in the variable 'commands'.
*/
Expand Down Expand Up @@ -391,4 +403,27 @@ int cmd_debug_store(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv);
int cmd_debug_setlog(struct ly_ctx *ctx, struct yl_opt *yo);
void cmd_debug_help(void);

/* cmd_cli.c */

/**
* @brief Setup cli.
*
* @param[in,out] ctx context for libyang.
* @param[in,out] yo context for yanglint.
* @param[in] posv Name of the cli mode.
* @return 0 on success.
*/
int cmd_cli_exec(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv);
void cmd_cli_help(void);

/**
* @copydoc cmd_add_opt
*/
int cmd_cli_opt(struct yl_opt *yo, const char *cmdline, char ***posv, int *posc);

/**
* @copydoc cmd_add_dep
*/
int cmd_cli_dep(struct yl_opt *yo, int posc);

#endif /* COMMANDS_H_ */
109 changes: 109 additions & 0 deletions tools/lint/cmd_cli.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* @file cli_verb.c
* @author Adam Piecek <[email protected]>
* @brief 'cli' command of the libyang's yanglint tool.
*
* Copyright (c) 2024-2024 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/

#include "cmd.h"

#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <strings.h>

#include "libyang.h"
#include "linenoise/linenoise.h"

#include "common.h"
#include "yl_opt.h"

#define LY_CLI_SINGLELINE 0x1

uint8_t cli_flags;

void
cmd_cli_help(void)
{
printf("Usage: cli [-s]\n"
" Settings for the command line interface.\n\n"
" -s, --toggle-singleline\n"
" The singleline settings toggles how the cli handles the overflow of typed text\n"
" across the screen. By default, it puts overflow text on a new line. But this\n"
" setting will make the text will scroll towards right to make room while\n"
" sending much less ANSI escape codes.\n");
}

int
cmd_cli_opt(struct yl_opt *yo, const char *cmdline, char ***posv, int *posc)
{
int rc = 0, argc = 0;
int opt, opt_index;
struct option options[] = {
{"toggle-singleline", no_argument, NULL, 's'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};

if ((rc = parse_cmdline(cmdline, &argc, &yo->argv))) {
return rc;
}

while ((opt = getopt_long(argc, yo->argv, interactive_cmd[CMD_CLI].optstring, options, &opt_index)) != -1) {
switch (opt) {
case 's':
yo->cli_flags |= LY_CLI_SINGLELINE;
break;
case 'h':
cmd_cli_help();
return 1;
default:
YLMSG_E("Unknown option.");
return 1;
}
}

*posv = &yo->argv[optind];
*posc = argc - optind;

return 0;
}

int
cmd_cli_dep(struct yl_opt *yo, int posc)
{
(void) yo;

if (posc != 0) {
YLMSG_E("Only options are expected.");
cmd_cli_help();
return 1;
}

return 0;
}

int
cmd_cli_exec(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv)
{
(void) ctx, (void) posv;

if (yo->cli_flags & LY_CLI_SINGLELINE) {
if (cli_flags & LY_CLI_SINGLELINE) {
cli_flags &= ~LY_CLI_SINGLELINE;
linenoiseSetMultiLine(1);
} else {
cli_flags |= LY_CLI_SINGLELINE;
linenoiseSetMultiLine(0);
}
}

return 0;
}
17 changes: 17 additions & 0 deletions tools/lint/cmd_help.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ print_generic_help(void)
printf(" %-15s %s\n", commands[i].name, commands[i].helpstring);
}
}
for (uint16_t i = 0; interactive_cmd[i].name; i++) {
if (interactive_cmd[i].helpstring != NULL) {
printf(" %-15s %s\n", interactive_cmd[i].name, interactive_cmd[i].helpstring);
}
}
}

int
Expand All @@ -96,6 +101,18 @@ cmd_help_exec(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv)
break;
}
}
/* interactive-only command */
for (uint16_t i = 0; interactive_cmd[i].name; i++) {
if (strcmp(posv, interactive_cmd[i].name) == 0) {
match = 1;
if (interactive_cmd[i].help_func != NULL) {
interactive_cmd[i].help_func();
} else {
printf("%s: %s\n", posv, interactive_cmd[i].helpstring);
}
break;
}
}
if (!match) {
/* if unknown command specified, print the list of commands */
printf("Unknown command \'%s\'\n", posv);
Expand Down
115 changes: 90 additions & 25 deletions tools/lint/completion.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200809L /* strdup */

#include <dirent.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#include "libyang.h"

Expand All @@ -28,6 +30,70 @@
#include "compat.h"
#include "linenoise/linenoise.h"

/**
* @brief Fill path completion.
*
* @param[in] hint Path to directory.
* @param[in] lc For adding completions.
*/
static void
path_completion(const char *hint, linenoiseCompletions *lc)
{
const char *ptr;
char *full_path, *hint_ptr, match[FILENAME_MAX + 2];
DIR *dir;
struct dirent *ent;
struct stat st;

lc->path = 1;

ptr = strrchr(hint, '/');

/* new relative path */
if (ptr == NULL) {
full_path = malloc(2 + FILENAME_MAX + 1);
strcpy(full_path, "./");

ptr = hint;
} else {
full_path = malloc((int)(ptr - hint) + FILENAME_MAX + 1);
++ptr;
sprintf(full_path, "%.*s", (int)(ptr - hint), hint);

Check failure

Code scanning / CodeQL

Unbounded write Critical

This 'call to sprintf' with input from
buffer read by read
may overflow the destination.
This 'call to sprintf' with input from
buffer read by read
may overflow the destination.
This 'call to sprintf' with input from
buffer read by read
may overflow the destination.
This 'call to sprintf' with input from
buffer read by read
may overflow the destination.
This 'call to sprintf' with input from
string read by fgets
may overflow the destination.
This 'call to sprintf' with input from
string read by fgets
may overflow the destination.
This 'call to sprintf' with input from
buffer read by read
may overflow the destination.
This 'call to sprintf' with input from
buffer read by read
may overflow the destination.
This 'call to sprintf' with input from
buffer read by read
may overflow the destination.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a false-positive to me.

}
hint_ptr = full_path + strlen(full_path);

dir = opendir(full_path);
if (dir == NULL) {
free(full_path);
return;
}

while ((ent = readdir(dir))) {
if (ent->d_name[0] == '.') {
continue;
}

if (!strncmp(ptr, ent->d_name, strlen(ptr))) {
/* is it a directory? */
strcpy(hint_ptr, ent->d_name);
if (stat(full_path, &st)) {
/* skip this item */
continue;
}

strcpy(match, ent->d_name);
if (S_ISDIR(st.st_mode)) {
strcat(match, "/");
}

linenoiseAddCompletion(lc, match);
}
}

free(full_path);
closedir(dir);
}

/* from the main.c */
extern struct ly_ctx *ctx;

Expand Down Expand Up @@ -430,29 +496,28 @@
struct autocomplete {
enum COMMAND_INDEX ci; /**< command index to global variable 'commands' */
const char *opt; /**< optional option */
void (*ln_cb)(const char *, const char *, linenoiseCompletions *); /**< linenoise callback to call */
void (*yl_cb)(const char *, char ***, unsigned int *); /**< yanglint callback to call */
void (*yl_cb)(const char *, char ***, unsigned int *); /**< yanglint callback to call */
} ac[] = {
{CMD_ADD, NULL, linenoisePathCompletion, NULL},
{CMD_PRINT, "-f", NULL, get_print_format_arg},
{CMD_PRINT, "-P", NULL, get_schema_completion},
{CMD_PRINT, "-o", linenoisePathCompletion, NULL},
{CMD_PRINT, NULL, NULL, get_model_completion},
{CMD_SEARCHPATH, NULL, linenoisePathCompletion, NULL},
{CMD_EXTDATA, NULL, linenoisePathCompletion, NULL},
{CMD_CLEAR, "-Y", linenoisePathCompletion, NULL},
{CMD_DATA, "-t", NULL, get_data_type_arg},
{CMD_DATA, "-O", linenoisePathCompletion, NULL},
{CMD_DATA, "-R", linenoisePathCompletion, NULL},
{CMD_DATA, "-f", NULL, get_data_in_format_arg},
{CMD_DATA, "-F", NULL, get_data_in_format_arg},
{CMD_DATA, "-d", NULL, get_data_default_arg},
{CMD_DATA, "-o", linenoisePathCompletion, NULL},
{CMD_DATA, NULL, linenoisePathCompletion, NULL},
{CMD_LIST, NULL, NULL, get_list_format_arg},
{CMD_FEATURE, NULL, NULL, get_model_completion},
{CMD_VERB, NULL, NULL, get_verb_arg},
{CMD_DEBUG, NULL, NULL, get_debug_arg},
{CMD_ADD, NULL, NULL},
{CMD_PRINT, "-f", get_print_format_arg},
{CMD_PRINT, "-P", get_schema_completion},
{CMD_PRINT, "-o", NULL},
{CMD_PRINT, NULL, get_model_completion},
{CMD_SEARCHPATH, NULL, NULL},
{CMD_EXTDATA, NULL, NULL},
{CMD_CLEAR, "-Y", NULL},
{CMD_DATA, "-t", get_data_type_arg},
{CMD_DATA, "-O", NULL},
{CMD_DATA, "-R", NULL},
{CMD_DATA, "-f", get_data_in_format_arg},
{CMD_DATA, "-F", get_data_in_format_arg},
{CMD_DATA, "-d", get_data_default_arg},
{CMD_DATA, "-o", NULL},
{CMD_DATA, NULL, NULL},
{CMD_LIST, NULL, get_list_format_arg},
{CMD_FEATURE, NULL, get_model_completion},
{CMD_VERB, NULL, get_verb_arg},
{CMD_DEBUG, NULL, get_debug_arg},
};
size_t name_len;
const char *last, *name, *getoptstr;
Expand Down Expand Up @@ -490,10 +555,10 @@
}

/* callback */
if (ac[i].ln_cb) {
ac[i].ln_cb(buf, hint, lc);
} else {
if (ac[i].yl_cb) {
ac[i].yl_cb(hint, &matches, &match_count);
} else {
path_completion(hint, lc);
}
break;
}
Expand Down
Loading
Loading