temporary use old version of console component with old linenoise

This commit is contained in:
Данила Горнушко 2023-11-22 20:43:11 +03:00
parent 3b9c168a3b
commit e17520f632
34 changed files with 4729 additions and 6455 deletions

View file

@ -1,24 +0,0 @@
set(argtable_srcs argtable3/arg_cmd.c
argtable3/arg_date.c
argtable3/arg_dbl.c
argtable3/arg_dstr.c
argtable3/arg_end.c
argtable3/arg_file.c
argtable3/arg_hashtable.c
argtable3/arg_int.c
argtable3/arg_lit.c
argtable3/arg_rem.c
argtable3/arg_rex.c
argtable3/arg_str.c
argtable3/arg_utils.c
argtable3/argtable3.c)
idf_component_register(SRCS "commands.c"
"esp_console_repl.c"
"split_argv.c"
"linenoise/linenoise.c"
${argtable_srcs}
INCLUDE_DIRS "."
REQUIRES vfs
PRIV_REQUIRES driver)

View file

@ -24,144 +24,3 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
FreeBSD getopt library
======================
Copyright (c) 2000 The NetBSD Foundation, Inc.
All rights reserved.
This code is derived from software contributed to The NetBSD Foundation
by Dieter Baron and Thomas Klausner.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Tcl library
===========
This software is copyrighted by the Regents of the University of
California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
Corporation and other parties. The following terms apply to all files
associated with the software unless explicitly disclaimed in
individual files.
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
GOVERNMENT USE: If you are acquiring this software on behalf of the
U.S. government, the Government shall have only "Restricted Rights"
in the software and related documentation as defined in the Federal
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
are acquiring the software on behalf of the Department of Defense, the
software shall be classified as "Commercial Computer Software" and the
Government shall have only "Restricted Rights" as defined in Clause
252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the
authors grant the U.S. Government and others acting in its behalf
permission to use and distribute the software in accordance with the
terms specified in this license.
C Hash Table library
====================
Copyright (c) 2002, Christopher Clark
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the original author; nor the names of any contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The Better String library
=========================
Copyright (c) 2014, Paul Hsieh
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of bstrlib nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,285 +0,0 @@
/*
* SPDX-FileCopyrightText: 2013-2019 Tom G. Huang
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_cmd: Provides the sub-command mechanism
*
* This file is part of the argtable3 library.
*
* Copyright (C) 2013-2019 Tom G. Huang
* <tomghuang@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#define MAX_MODULE_VERSION_SIZE 128
static arg_hashtable_t* s_hashtable = NULL;
static char* s_module_name = NULL;
static int s_mod_ver_major = 0;
static int s_mod_ver_minor = 0;
static int s_mod_ver_patch = 0;
static char* s_mod_ver_tag = NULL;
static char* s_mod_ver = NULL;
void arg_set_module_name(const char* name) {
size_t slen;
xfree(s_module_name);
slen = strlen(name);
s_module_name = (char*)xmalloc(slen + 1);
memset(s_module_name, 0, slen + 1);
#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
strncpy_s(s_module_name, slen + 1, name, slen);
#else
memcpy(s_module_name, name, slen);
#endif
}
void arg_set_module_version(int major, int minor, int patch, const char* tag) {
size_t slen_tag, slen_ds;
arg_dstr_t ds;
s_mod_ver_major = major;
s_mod_ver_minor = minor;
s_mod_ver_patch = patch;
xfree(s_mod_ver_tag);
slen_tag = strlen(tag);
s_mod_ver_tag = (char*)xmalloc(slen_tag + 1);
memset(s_mod_ver_tag, 0, slen_tag + 1);
#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
strncpy_s(s_mod_ver_tag, slen_tag + 1, tag, slen_tag);
#else
memcpy(s_mod_ver_tag, tag, slen_tag);
#endif
ds = arg_dstr_create();
arg_dstr_catf(ds, "%d.", s_mod_ver_major);
arg_dstr_catf(ds, "%d.", s_mod_ver_minor);
arg_dstr_catf(ds, "%d.", s_mod_ver_patch);
arg_dstr_cat(ds, s_mod_ver_tag);
xfree(s_mod_ver);
slen_ds = strlen(arg_dstr_cstr(ds));
s_mod_ver = (char*)xmalloc(slen_ds + 1);
memset(s_mod_ver, 0, slen_ds + 1);
#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
strncpy_s(s_mod_ver, slen_ds + 1, arg_dstr_cstr(ds), slen_ds);
#else
memcpy(s_mod_ver, arg_dstr_cstr(ds), slen_ds);
#endif
arg_dstr_destroy(ds);
}
static unsigned int hash_key(const void* key) {
const char* str = (const char*)key;
int c;
unsigned int hash = 5381;
while ((c = *str++) != 0)
hash = ((hash << 5) + hash) + (unsigned int)c; /* hash * 33 + c */
return hash;
}
static int equal_keys(const void* key1, const void* key2) {
char* k1 = (char*)key1;
char* k2 = (char*)key2;
return (0 == strcmp(k1, k2));
}
void arg_cmd_init(void) {
s_hashtable = arg_hashtable_create(32, hash_key, equal_keys);
}
void arg_cmd_uninit(void) {
arg_hashtable_destroy(s_hashtable, 1);
}
void arg_cmd_register(const char* name, arg_cmdfn* proc, const char* description) {
arg_cmd_info_t* cmd_info;
size_t slen_name;
void* k;
assert(strlen(name) < ARG_CMD_NAME_LEN);
assert(strlen(description) < ARG_CMD_DESCRIPTION_LEN);
/* Check if the command already exists. */
/* If the command exists, replace the existing command. */
/* If the command doesn't exist, insert the command. */
cmd_info = (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, name);
if (cmd_info) {
arg_hashtable_remove(s_hashtable, name);
cmd_info = NULL;
}
cmd_info = (arg_cmd_info_t*)xmalloc(sizeof(arg_cmd_info_t));
memset(cmd_info, 0, sizeof(arg_cmd_info_t));
#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
strncpy_s(cmd_info->name, ARG_CMD_NAME_LEN, name, strlen(name));
strncpy_s(cmd_info->description, ARG_CMD_DESCRIPTION_LEN, description, strlen(description));
#else
memcpy(cmd_info->name, name, strlen(name));
memcpy(cmd_info->description, description, strlen(description));
#endif
cmd_info->proc = proc;
slen_name = strlen(name);
k = xmalloc(slen_name + 1);
memset(k, 0, slen_name + 1);
#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
strncpy_s((char*)k, slen_name + 1, name, slen_name);
#else
memcpy((char*)k, name, slen_name);
#endif
arg_hashtable_insert(s_hashtable, k, cmd_info);
}
void arg_cmd_unregister(const char* name) {
arg_hashtable_remove(s_hashtable, name);
}
int arg_cmd_dispatch(const char* name, int argc, char* argv[], arg_dstr_t res) {
arg_cmd_info_t* cmd_info = arg_cmd_info(name);
assert(cmd_info != NULL);
assert(cmd_info->proc != NULL);
return cmd_info->proc(argc, argv, res);
}
arg_cmd_info_t* arg_cmd_info(const char* name) {
return (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, name);
}
unsigned int arg_cmd_count(void) {
return arg_hashtable_count(s_hashtable);
}
arg_cmd_itr_t arg_cmd_itr_create(void) {
return (arg_cmd_itr_t)arg_hashtable_itr_create(s_hashtable);
}
int arg_cmd_itr_advance(arg_cmd_itr_t itr) {
return arg_hashtable_itr_advance((arg_hashtable_itr_t*)itr);
}
char* arg_cmd_itr_key(arg_cmd_itr_t itr) {
return (char*)arg_hashtable_itr_key((arg_hashtable_itr_t*)itr);
}
arg_cmd_info_t* arg_cmd_itr_value(arg_cmd_itr_t itr) {
return (arg_cmd_info_t*)arg_hashtable_itr_value((arg_hashtable_itr_t*)itr);
}
void arg_cmd_itr_destroy(arg_cmd_itr_t itr) {
arg_hashtable_itr_destroy((arg_hashtable_itr_t*)itr);
}
int arg_cmd_itr_search(arg_cmd_itr_t itr, void* k) {
return arg_hashtable_itr_search((arg_hashtable_itr_t*)itr, s_hashtable, k);
}
static const char* module_name(void) {
if (s_module_name == NULL || strlen(s_module_name) == 0)
return "<name>";
return s_module_name;
}
static const char* module_version(void) {
if (s_mod_ver == NULL || strlen(s_mod_ver) == 0)
return "0.0.0.0";
return s_mod_ver;
}
void arg_make_get_help_msg(arg_dstr_t res) {
arg_dstr_catf(res, "%s v%s\n", module_name(), module_version());
arg_dstr_catf(res, "Please type '%s help' to get more information.\n", module_name());
}
void arg_make_help_msg(arg_dstr_t ds, char* cmd_name, void** argtable) {
arg_cmd_info_t* cmd_info = (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, cmd_name);
if (cmd_info) {
arg_dstr_catf(ds, "%s: %s\n", cmd_name, cmd_info->description);
}
arg_dstr_cat(ds, "Usage:\n");
arg_dstr_catf(ds, " %s", module_name());
arg_print_syntaxv_ds(ds, argtable, "\n \nAvailable options:\n");
arg_print_glossary_ds(ds, argtable, " %-23s %s\n");
arg_dstr_cat(ds, "\n");
}
void arg_make_syntax_err_msg(arg_dstr_t ds, void** argtable, struct arg_end* end) {
arg_print_errors_ds(ds, end, module_name());
arg_dstr_cat(ds, "Usage: \n");
arg_dstr_catf(ds, " %s", module_name());
arg_print_syntaxv_ds(ds, argtable, "\n");
arg_dstr_cat(ds, "\n");
}
int arg_make_syntax_err_help_msg(arg_dstr_t ds, char* name, int help, int nerrors, void** argtable, struct arg_end* end, int* exitcode) {
/* help handling
* note: '-h|--help' takes precedence over error reporting
*/
if (help > 0) {
arg_make_help_msg(ds, name, argtable);
*exitcode = EXIT_SUCCESS;
return 1;
}
/* syntax error handling */
if (nerrors > 0) {
arg_make_syntax_err_msg(ds, argtable, end);
*exitcode = EXIT_FAILURE;
return 1;
}
return 0;
}

View file

@ -1,575 +0,0 @@
/*
* SPDX-FileCopyrightText: 1998-2001,2003-2011,2013 Stewart Heitmann
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_date: Implements the date command-line option
*
* This file is part of the argtable3 library.
*
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
* <sheitmann@users.sourceforge.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <stdlib.h>
#include <string.h>
char* arg_strptime(const char* buf, const char* fmt, struct tm* tm);
static void arg_date_resetfn(struct arg_date* parent) {
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
parent->count = 0;
}
static int arg_date_scanfn(struct arg_date* parent, const char* argval) {
int errorcode = 0;
if (parent->count == parent->hdr.maxcount) {
errorcode = ARG_ERR_MAXCOUNT;
} else if (!argval) {
/* no argument value was given, leave parent->tmval[] unaltered but still count it */
parent->count++;
} else {
const char* pend;
struct tm tm = parent->tmval[parent->count];
/* parse the given argument value, store result in parent->tmval[] */
pend = arg_strptime(argval, parent->format, &tm);
if (pend && pend[0] == '\0')
parent->tmval[parent->count++] = tm;
else
errorcode = ARG_ERR_BADDATE;
}
ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
return errorcode;
}
static int arg_date_checkfn(struct arg_date* parent) {
int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
return errorcode;
}
static void arg_date_errorfn(struct arg_date* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
const char* shortopts = parent->hdr.shortopts;
const char* longopts = parent->hdr.longopts;
const char* datatype = parent->hdr.datatype;
/* make argval NULL safe */
argval = argval ? argval : "";
arg_dstr_catf(ds, "%s: ", progname);
switch (errorcode) {
case ARG_ERR_MINCOUNT:
arg_dstr_cat(ds, "missing option ");
arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
break;
case ARG_ERR_MAXCOUNT:
arg_dstr_cat(ds, "excess option ");
arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
break;
case ARG_ERR_BADDATE: {
struct tm tm;
char buff[200];
arg_dstr_catf(ds, "illegal timestamp format \"%s\"\n", argval);
memset(&tm, 0, sizeof(tm));
arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm);
strftime(buff, sizeof(buff), parent->format, &tm);
arg_dstr_catf(ds, "correct format is \"%s\"\n", buff);
break;
}
}
}
struct arg_date* arg_date0(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary) {
return arg_daten(shortopts, longopts, format, datatype, 0, 1, glossary);
}
struct arg_date* arg_date1(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary) {
return arg_daten(shortopts, longopts, format, datatype, 1, 1, glossary);
}
struct arg_date*
arg_daten(const char* shortopts, const char* longopts, const char* format, const char* datatype, int mincount, int maxcount, const char* glossary) {
size_t nbytes;
struct arg_date* result;
/* foolproof things by ensuring maxcount is not less than mincount */
maxcount = (maxcount < mincount) ? mincount : maxcount;
/* default time format is the national date format for the locale */
if (!format)
format = "%x";
nbytes = sizeof(struct arg_date) /* storage for struct arg_date */
+ (size_t)maxcount * sizeof(struct tm); /* storage for tmval[maxcount] array */
/* allocate storage for the arg_date struct + tmval[] array. */
/* we use calloc because we want the tmval[] array zero filled. */
result = (struct arg_date*)xcalloc(1, nbytes);
/* init the arg_hdr struct */
result->hdr.flag = ARG_HASVALUE;
result->hdr.shortopts = shortopts;
result->hdr.longopts = longopts;
result->hdr.datatype = datatype ? datatype : format;
result->hdr.glossary = glossary;
result->hdr.mincount = mincount;
result->hdr.maxcount = maxcount;
result->hdr.parent = result;
result->hdr.resetfn = (arg_resetfn*)arg_date_resetfn;
result->hdr.scanfn = (arg_scanfn*)arg_date_scanfn;
result->hdr.checkfn = (arg_checkfn*)arg_date_checkfn;
result->hdr.errorfn = (arg_errorfn*)arg_date_errorfn;
/* store the tmval[maxcount] array immediately after the arg_date struct */
result->tmval = (struct tm*)(result + 1);
/* init the remaining arg_date member variables */
result->count = 0;
result->format = format;
ARG_TRACE(("arg_daten() returns %p\n", result));
return result;
}
/*-
* Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code was contributed to The NetBSD Foundation by Klaus Klein.
* Heavily optimised by David Laight
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <ctype.h>
#include <string.h>
#include <time.h>
/*
* We do not implement alternate representations. However, we always
* check whether a given modifier is allowed for a certain conversion.
*/
#define ALT_E 0x01
#define ALT_O 0x02
#define LEGAL_ALT(x) \
{ \
if (alt_format & ~(x)) \
return (0); \
}
#define TM_YEAR_BASE (1900)
static int conv_num(const char**, int*, int, int);
static const char* day[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
static const char* abday[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
static const char* mon[12] = {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"};
static const char* abmon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
static const char* am_pm[2] = {"AM", "PM"};
static int arg_strcasecmp(const char* s1, const char* s2) {
const unsigned char* us1 = (const unsigned char*)s1;
const unsigned char* us2 = (const unsigned char*)s2;
while (tolower(*us1) == tolower(*us2++))
if (*us1++ == '\0')
return 0;
return tolower(*us1) - tolower(*--us2);
}
static int arg_strncasecmp(const char* s1, const char* s2, size_t n) {
if (n != 0) {
const unsigned char* us1 = (const unsigned char*)s1;
const unsigned char* us2 = (const unsigned char*)s2;
do {
if (tolower(*us1) != tolower(*us2++))
return tolower(*us1) - tolower(*--us2);
if (*us1++ == '\0')
break;
} while (--n != 0);
}
return 0;
}
char* arg_strptime(const char* buf, const char* fmt, struct tm* tm) {
char c;
const char* bp;
size_t len = 0;
int alt_format, i, split_year = 0;
bp = buf;
while ((c = *fmt) != '\0') {
/* Clear `alternate' modifier prior to new conversion. */
alt_format = 0;
/* Eat up white-space. */
if (isspace(c)) {
while (isspace((int)(*bp)))
bp++;
fmt++;
continue;
}
if ((c = *fmt++) != '%')
goto literal;
again:
switch (c = *fmt++) {
case '%': /* "%%" is converted to "%". */
literal:
if (c != *bp++)
return (0);
break;
/*
* "Alternative" modifiers. Just set the appropriate flag
* and start over again.
*/
case 'E': /* "%E?" alternative conversion modifier. */
LEGAL_ALT(0);
alt_format |= ALT_E;
goto again;
case 'O': /* "%O?" alternative conversion modifier. */
LEGAL_ALT(0);
alt_format |= ALT_O;
goto again;
/*
* "Complex" conversion rules, implemented through recursion.
*/
case 'c': /* Date and time, using the locale's format. */
LEGAL_ALT(ALT_E);
bp = arg_strptime(bp, "%x %X", tm);
if (!bp)
return (0);
break;
case 'D': /* The date as "%m/%d/%y". */
LEGAL_ALT(0);
bp = arg_strptime(bp, "%m/%d/%y", tm);
if (!bp)
return (0);
break;
case 'R': /* The time as "%H:%M". */
LEGAL_ALT(0);
bp = arg_strptime(bp, "%H:%M", tm);
if (!bp)
return (0);
break;
case 'r': /* The time in 12-hour clock representation. */
LEGAL_ALT(0);
bp = arg_strptime(bp, "%I:%M:%S %p", tm);
if (!bp)
return (0);
break;
case 'T': /* The time as "%H:%M:%S". */
LEGAL_ALT(0);
bp = arg_strptime(bp, "%H:%M:%S", tm);
if (!bp)
return (0);
break;
case 'X': /* The time, using the locale's format. */
LEGAL_ALT(ALT_E);
bp = arg_strptime(bp, "%H:%M:%S", tm);
if (!bp)
return (0);
break;
case 'x': /* The date, using the locale's format. */
LEGAL_ALT(ALT_E);
bp = arg_strptime(bp, "%m/%d/%y", tm);
if (!bp)
return (0);
break;
/*
* "Elementary" conversion rules.
*/
case 'A': /* The day of week, using the locale's form. */
case 'a':
LEGAL_ALT(0);
for (i = 0; i < 7; i++) {
/* Full name. */
len = strlen(day[i]);
if (arg_strncasecmp(day[i], bp, len) == 0)
break;
/* Abbreviated name. */
len = strlen(abday[i]);
if (arg_strncasecmp(abday[i], bp, len) == 0)
break;
}
/* Nothing matched. */
if (i == 7)
return (0);
tm->tm_wday = i;
bp += len;
break;
case 'B': /* The month, using the locale's form. */
case 'b':
case 'h':
LEGAL_ALT(0);
for (i = 0; i < 12; i++) {
/* Full name. */
len = strlen(mon[i]);
if (arg_strncasecmp(mon[i], bp, len) == 0)
break;
/* Abbreviated name. */
len = strlen(abmon[i]);
if (arg_strncasecmp(abmon[i], bp, len) == 0)
break;
}
/* Nothing matched. */
if (i == 12)
return (0);
tm->tm_mon = i;
bp += len;
break;
case 'C': /* The century number. */
LEGAL_ALT(ALT_E);
if (!(conv_num(&bp, &i, 0, 99)))
return (0);
if (split_year) {
tm->tm_year = (tm->tm_year % 100) + (i * 100);
} else {
tm->tm_year = i * 100;
split_year = 1;
}
break;
case 'd': /* The day of month. */
case 'e':
LEGAL_ALT(ALT_O);
if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
return (0);
break;
case 'k': /* The hour (24-hour clock representation). */
LEGAL_ALT(0);
/* FALLTHROUGH */
case 'H':
LEGAL_ALT(ALT_O);
if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
return (0);
break;
case 'l': /* The hour (12-hour clock representation). */
LEGAL_ALT(0);
/* FALLTHROUGH */
case 'I':
LEGAL_ALT(ALT_O);
if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
return (0);
if (tm->tm_hour == 12)
tm->tm_hour = 0;
break;
case 'j': /* The day of year. */
LEGAL_ALT(0);
if (!(conv_num(&bp, &i, 1, 366)))
return (0);
tm->tm_yday = i - 1;
break;
case 'M': /* The minute. */
LEGAL_ALT(ALT_O);
if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
return (0);
break;
case 'm': /* The month. */
LEGAL_ALT(ALT_O);
if (!(conv_num(&bp, &i, 1, 12)))
return (0);
tm->tm_mon = i - 1;
break;
case 'p': /* The locale's equivalent of AM/PM. */
LEGAL_ALT(0);
/* AM? */
if (arg_strcasecmp(am_pm[0], bp) == 0) {
if (tm->tm_hour > 11)
return (0);
bp += strlen(am_pm[0]);
break;
}
/* PM? */
else if (arg_strcasecmp(am_pm[1], bp) == 0) {
if (tm->tm_hour > 11)
return (0);
tm->tm_hour += 12;
bp += strlen(am_pm[1]);
break;
}
/* Nothing matched. */
return (0);
case 'S': /* The seconds. */
LEGAL_ALT(ALT_O);
if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
return (0);
break;
case 'U': /* The week of year, beginning on sunday. */
case 'W': /* The week of year, beginning on monday. */
LEGAL_ALT(ALT_O);
/*
* XXX This is bogus, as we can not assume any valid
* information present in the tm structure at this
* point to calculate a real value, so just check the
* range for now.
*/
if (!(conv_num(&bp, &i, 0, 53)))
return (0);
break;
case 'w': /* The day of week, beginning on sunday. */
LEGAL_ALT(ALT_O);
if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
return (0);
break;
case 'Y': /* The year. */
LEGAL_ALT(ALT_E);
if (!(conv_num(&bp, &i, 0, 9999)))
return (0);
tm->tm_year = i - TM_YEAR_BASE;
break;
case 'y': /* The year within 100 years of the epoch. */
LEGAL_ALT(ALT_E | ALT_O);
if (!(conv_num(&bp, &i, 0, 99)))
return (0);
if (split_year) {
tm->tm_year = ((tm->tm_year / 100) * 100) + i;
break;
}
split_year = 1;
if (i <= 68)
tm->tm_year = i + 2000 - TM_YEAR_BASE;
else
tm->tm_year = i + 1900 - TM_YEAR_BASE;
break;
/*
* Miscellaneous conversions.
*/
case 'n': /* Any kind of white-space. */
case 't':
LEGAL_ALT(0);
while (isspace((int)(*bp)))
bp++;
break;
default: /* Unknown/unsupported conversion. */
return (0);
}
}
/* LINTED functional specification */
return ((char*)bp);
}
static int conv_num(const char** buf, int* dest, int llim, int ulim) {
int result = 0;
/* The limit also determines the number of valid digits. */
int rulim = ulim;
if (**buf < '0' || **buf > '9')
return (0);
do {
result *= 10;
result += *(*buf)++ - '0';
rulim /= 10;
} while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
if (result < llim || result > ulim)
return (0);
*dest = result;
return (1);
}

View file

@ -1,164 +0,0 @@
/*
* SPDX-FileCopyrightText: 1998-2001,2003-2011,2013 Stewart Heitmann
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_dbl: Implements the double command-line option
*
* This file is part of the argtable3 library.
*
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
* <sheitmann@users.sourceforge.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <stdlib.h>
static void arg_dbl_resetfn(struct arg_dbl* parent) {
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
parent->count = 0;
}
static int arg_dbl_scanfn(struct arg_dbl* parent, const char* argval) {
int errorcode = 0;
if (parent->count == parent->hdr.maxcount) {
/* maximum number of arguments exceeded */
errorcode = ARG_ERR_MAXCOUNT;
} else if (!argval) {
/* a valid argument with no argument value was given. */
/* This happens when an optional argument value was invoked. */
/* leave parent argument value unaltered but still count the argument. */
parent->count++;
} else {
double val;
char* end;
/* extract double from argval into val */
val = strtod(argval, &end);
/* if success then store result in parent->dval[] array otherwise return error*/
if (*end == 0)
parent->dval[parent->count++] = val;
else
errorcode = ARG_ERR_BADDOUBLE;
}
ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
return errorcode;
}
static int arg_dbl_checkfn(struct arg_dbl* parent) {
int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
return errorcode;
}
static void arg_dbl_errorfn(struct arg_dbl* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
const char* shortopts = parent->hdr.shortopts;
const char* longopts = parent->hdr.longopts;
const char* datatype = parent->hdr.datatype;
/* make argval NULL safe */
argval = argval ? argval : "";
arg_dstr_catf(ds, "%s: ", progname);
switch (errorcode) {
case ARG_ERR_MINCOUNT:
arg_dstr_cat(ds, "missing option ");
arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
break;
case ARG_ERR_MAXCOUNT:
arg_dstr_cat(ds, "excess option ");
arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
break;
case ARG_ERR_BADDOUBLE:
arg_dstr_catf(ds, "invalid argument \"%s\" to option ", argval);
arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
break;
}
}
struct arg_dbl* arg_dbl0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
return arg_dbln(shortopts, longopts, datatype, 0, 1, glossary);
}
struct arg_dbl* arg_dbl1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
return arg_dbln(shortopts, longopts, datatype, 1, 1, glossary);
}
struct arg_dbl* arg_dbln(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {
size_t nbytes;
struct arg_dbl* result;
size_t addr;
size_t rem;
/* foolproof things by ensuring maxcount is not less than mincount */
maxcount = (maxcount < mincount) ? mincount : maxcount;
nbytes = sizeof(struct arg_dbl) /* storage for struct arg_dbl */
+ (size_t)(maxcount + 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */
result = (struct arg_dbl*)xmalloc(nbytes);
/* init the arg_hdr struct */
result->hdr.flag = ARG_HASVALUE;
result->hdr.shortopts = shortopts;
result->hdr.longopts = longopts;
result->hdr.datatype = datatype ? datatype : "<double>";
result->hdr.glossary = glossary;
result->hdr.mincount = mincount;
result->hdr.maxcount = maxcount;
result->hdr.parent = result;
result->hdr.resetfn = (arg_resetfn*)arg_dbl_resetfn;
result->hdr.scanfn = (arg_scanfn*)arg_dbl_scanfn;
result->hdr.checkfn = (arg_checkfn*)arg_dbl_checkfn;
result->hdr.errorfn = (arg_errorfn*)arg_dbl_errorfn;
/* Store the dval[maxcount] array on the first double boundary that
* immediately follows the arg_dbl struct. We do the memory alignment
* purely for SPARC and Motorola systems. They require floats and
* doubles to be aligned on natural boundaries.
*/
addr = (size_t)(result + 1);
rem = addr % sizeof(double);
result->dval = (double*)(addr + sizeof(double) - rem);
ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr, result->dval, (int)sizeof(double), (int)rem));
result->count = 0;
ARG_TRACE(("arg_dbln() returns %p\n", result));
return result;
}

View file

@ -1,344 +0,0 @@
/*
* SPDX-FileCopyrightText: 2013-2019 Tom G. Huang
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_dstr: Implements the dynamic string utilities
*
* This file is part of the argtable3 library.
*
* Copyright (C) 2013-2019 Tom G. Huang
* <tomghuang@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
#define START_VSNBUFF 16
/*
* This dynamic string module is adapted from TclResult.c in the Tcl library.
* Here is the copyright notice from the library:
*
* This software is copyrighted by the Regents of the University of
* California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
* Corporation and other parties. The following terms apply to all files
* associated with the software unless explicitly disclaimed in
* individual files.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice is included verbatim in any distributions. No written agreement,
* license, or royalty fee is required for any of the authorized uses.
* Modifications to this software may be copyrighted by their authors
* and need not follow the licensing terms described here, provided that
* the new terms are clearly indicated on the first page of each file where
* they apply.
*
* IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
* FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
* DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
* IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
* NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
* MODIFICATIONS.
*
* GOVERNMENT USE: If you are acquiring this software on behalf of the
* U.S. government, the Government shall have only "Restricted Rights"
* in the software and related documentation as defined in the Federal
* Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
* are acquiring the software on behalf of the Department of Defense, the
* software shall be classified as "Commercial Computer Software" and the
* Government shall have only "Restricted Rights" as defined in Clause
* 252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the
* authors grant the U.S. Government and others acting in its behalf
* permission to use and distribute the software in accordance with the
* terms specified in this license.
*/
typedef struct _internal_arg_dstr {
char* data;
arg_dstr_freefn* free_proc;
char sbuf[ARG_DSTR_SIZE + 1];
char* append_data;
int append_data_size;
int append_used;
} _internal_arg_dstr_t;
static void setup_append_buf(arg_dstr_t res, int newSpace);
arg_dstr_t arg_dstr_create(void) {
_internal_arg_dstr_t* h = (_internal_arg_dstr_t*)xmalloc(sizeof(_internal_arg_dstr_t));
memset(h, 0, sizeof(_internal_arg_dstr_t));
h->sbuf[0] = 0;
h->data = h->sbuf;
h->free_proc = ARG_DSTR_STATIC;
return h;
}
void arg_dstr_destroy(arg_dstr_t ds) {
if (ds == NULL)
return;
arg_dstr_reset(ds);
xfree(ds);
return;
}
void arg_dstr_set(arg_dstr_t ds, char* str, arg_dstr_freefn* free_proc) {
int length;
register arg_dstr_freefn* old_free_proc = ds->free_proc;
char* old_result = ds->data;
if (str == NULL) {
ds->sbuf[0] = 0;
ds->data = ds->sbuf;
ds->free_proc = ARG_DSTR_STATIC;
} else if (free_proc == ARG_DSTR_VOLATILE) {
length = (int)strlen(str);
if (length > ARG_DSTR_SIZE) {
ds->data = (char*)xmalloc((unsigned)length + 1);
ds->free_proc = ARG_DSTR_DYNAMIC;
} else {
ds->data = ds->sbuf;
ds->free_proc = ARG_DSTR_STATIC;
}
strcpy(ds->data, str);
} else {
ds->data = str;
ds->free_proc = free_proc;
}
/*
* If the old result was dynamically-allocated, free it up. Do it here,
* rather than at the beginning, in case the new result value was part of
* the old result value.
*/
if ((old_free_proc != 0) && (old_result != ds->data)) {
if (old_free_proc == ARG_DSTR_DYNAMIC) {
xfree(old_result);
} else {
(*old_free_proc)(old_result);
}
}
if ((ds->append_data != NULL) && (ds->append_data_size > 0)) {
xfree(ds->append_data);
ds->append_data = NULL;
ds->append_data_size = 0;
}
}
char* arg_dstr_cstr(arg_dstr_t ds) /* Interpreter whose result to return. */
{
return ds->data;
}
void arg_dstr_cat(arg_dstr_t ds, const char* str) {
setup_append_buf(ds, (int)strlen(str) + 1);
memcpy(ds->data + strlen(ds->data), str, strlen(str));
}
void arg_dstr_catc(arg_dstr_t ds, char c) {
setup_append_buf(ds, 2);
memcpy(ds->data + strlen(ds->data), &c, 1);
}
/*
* The logic of the `arg_dstr_catf` function is adapted from the `bformat`
* function in The Better String Library by Paul Hsieh. Here is the copyright
* notice from the library:
*
* Copyright (c) 2014, Paul Hsieh
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of bstrlib nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
void arg_dstr_catf(arg_dstr_t ds, const char* fmt, ...) {
va_list arglist;
char* buff;
int n, r;
size_t slen;
if (fmt == NULL)
return;
/* Since the length is not determinable beforehand, a search is
performed using the truncating "vsnprintf" call (to avoid buffer
overflows) on increasing potential sizes for the output result. */
if ((n = (int)(2 * strlen(fmt))) < START_VSNBUFF)
n = START_VSNBUFF;
buff = (char*)xmalloc((size_t)(n + 2));
memset(buff, 0, (size_t)(n + 2));
for (;;) {
va_start(arglist, fmt);
r = vsnprintf(buff, (size_t)(n + 1), fmt, arglist);
va_end(arglist);
slen = strlen(buff);
if (slen < (size_t)n)
break;
if (r > n)
n = r;
else
n += n;
xfree(buff);
buff = (char*)xmalloc((size_t)(n + 2));
memset(buff, 0, (size_t)(n + 2));
}
arg_dstr_cat(ds, buff);
xfree(buff);
}
static void setup_append_buf(arg_dstr_t ds, int new_space) {
int total_space;
/*
* Make the append buffer larger, if that's necessary, then copy the
* data into the append buffer and make the append buffer the official
* data.
*/
if (ds->data != ds->append_data) {
/*
* If the buffer is too big, then free it up so we go back to a
* smaller buffer. This avoids tying up memory forever after a large
* operation.
*/
if (ds->append_data_size > 500) {
xfree(ds->append_data);
ds->append_data = NULL;
ds->append_data_size = 0;
}
ds->append_used = (int)strlen(ds->data);
} else if (ds->data[ds->append_used] != 0) {
/*
* Most likely someone has modified a result created by
* arg_dstr_cat et al. so that it has a different size. Just
* recompute the size.
*/
ds->append_used = (int)strlen(ds->data);
}
total_space = new_space + ds->append_used;
if (total_space >= ds->append_data_size) {
char* newbuf;
if (total_space < 100) {
total_space = 200;
} else {
total_space *= 2;
}
newbuf = (char*)xmalloc((unsigned)total_space);
memset(newbuf, 0, (size_t)total_space);
strcpy(newbuf, ds->data);
if (ds->append_data != NULL) {
xfree(ds->append_data);
}
ds->append_data = newbuf;
ds->append_data_size = total_space;
} else if (ds->data != ds->append_data) {
strcpy(ds->append_data, ds->data);
}
arg_dstr_free(ds);
ds->data = ds->append_data;
}
void arg_dstr_free(arg_dstr_t ds) {
if (ds->free_proc != NULL) {
if (ds->free_proc == ARG_DSTR_DYNAMIC) {
xfree(ds->data);
} else {
(*ds->free_proc)(ds->data);
}
ds->free_proc = NULL;
}
}
void arg_dstr_reset(arg_dstr_t ds) {
arg_dstr_free(ds);
if ((ds->append_data != NULL) && (ds->append_data_size > 0)) {
xfree(ds->append_data);
ds->append_data = NULL;
ds->append_data_size = 0;
}
ds->data = ds->sbuf;
ds->sbuf[0] = 0;
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif

View file

@ -1,135 +0,0 @@
/*
* SPDX-FileCopyrightText: 1998-2001,2003-2011,2013 Stewart Heitmann
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_end: Implements the error handling utilities
*
* This file is part of the argtable3 library.
*
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
* <sheitmann@users.sourceforge.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <stdlib.h>
static void arg_end_resetfn(struct arg_end* parent) {
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
parent->count = 0;
}
static void arg_end_errorfn(void* parent, arg_dstr_t ds, int error, const char* argval, const char* progname) {
/* suppress unreferenced formal parameter warning */
(void)parent;
progname = progname ? progname : "";
argval = argval ? argval : "";
arg_dstr_catf(ds, "%s: ", progname);
switch (error) {
case ARG_ELIMIT:
arg_dstr_cat(ds, "too many errors to display");
break;
case ARG_EMALLOC:
arg_dstr_cat(ds, "insufficient memory");
break;
case ARG_ENOMATCH:
arg_dstr_catf(ds, "unexpected argument \"%s\"", argval);
break;
case ARG_EMISSARG:
arg_dstr_catf(ds, "option \"%s\" requires an argument", argval);
break;
case ARG_ELONGOPT:
arg_dstr_catf(ds, "invalid option \"%s\"", argval);
break;
default:
arg_dstr_catf(ds, "invalid option \"-%c\"", error);
break;
}
arg_dstr_cat(ds, "\n");
}
struct arg_end* arg_end(int maxcount) {
size_t nbytes;
struct arg_end* result;
nbytes = sizeof(struct arg_end) + (size_t)maxcount * sizeof(int) /* storage for int error[maxcount] array*/
+ (size_t)maxcount * sizeof(void*) /* storage for void* parent[maxcount] array */
+ (size_t)maxcount * sizeof(char*); /* storage for char* argval[maxcount] array */
result = (struct arg_end*)xmalloc(nbytes);
/* init the arg_hdr struct */
result->hdr.flag = ARG_TERMINATOR;
result->hdr.shortopts = NULL;
result->hdr.longopts = NULL;
result->hdr.datatype = NULL;
result->hdr.glossary = NULL;
result->hdr.mincount = 1;
result->hdr.maxcount = maxcount;
result->hdr.parent = result;
result->hdr.resetfn = (arg_resetfn*)arg_end_resetfn;
result->hdr.scanfn = NULL;
result->hdr.checkfn = NULL;
result->hdr.errorfn = (arg_errorfn*)arg_end_errorfn;
/* store error[maxcount] array immediately after struct arg_end */
result->error = (int*)(result + 1);
/* store parent[maxcount] array immediately after error[] array */
result->parent = (void**)(result->error + maxcount);
/* store argval[maxcount] array immediately after parent[] array */
result->argval = (const char**)(result->parent + maxcount);
ARG_TRACE(("arg_end(%d) returns %p\n", maxcount, result));
return result;
}
void arg_print_errors_ds(arg_dstr_t ds, struct arg_end* end, const char* progname) {
int i;
ARG_TRACE(("arg_errors()\n"));
for (i = 0; i < end->count; i++) {
struct arg_hdr* errorparent = (struct arg_hdr*)(end->parent[i]);
if (errorparent->errorfn)
errorparent->errorfn(end->parent[i], ds, end->error[i], end->argval[i], progname);
}
}
void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname) {
arg_dstr_t ds = arg_dstr_create();
arg_print_errors_ds(ds, end, progname);
fputs(arg_dstr_cstr(ds), fp);
arg_dstr_destroy(ds);
}

View file

@ -1,213 +0,0 @@
/*
* SPDX-FileCopyrightText: 1998-2001,2003-2011,2013 Stewart Heitmann
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_file: Implements the file command-line option
*
* This file is part of the argtable3 library.
*
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
* <sheitmann@users.sourceforge.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#define FILESEPARATOR1 '\\'
#define FILESEPARATOR2 '/'
#else
#define FILESEPARATOR1 '/'
#define FILESEPARATOR2 '/'
#endif
static void arg_file_resetfn(struct arg_file* parent) {
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
parent->count = 0;
}
/* Returns ptr to the base filename within *filename */
static const char* arg_basename(const char* filename) {
const char *result = NULL, *result1, *result2;
/* Find the last occurrence of eother file separator character. */
/* Two alternative file separator chars are supported as legal */
/* file separators but not both together in the same filename. */
result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL);
result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL);
if (result2)
result = result2 + 1; /* using FILESEPARATOR2 (the alternative file separator) */
if (result1)
result = result1 + 1; /* using FILESEPARATOR1 (the preferred file separator) */
if (!result)
result = filename; /* neither file separator was found so basename is the whole filename */
/* special cases of "." and ".." are not considered basenames */
if (result && (strcmp(".", result) == 0 || strcmp("..", result) == 0))
result = filename + strlen(filename);
return result;
}
/* Returns ptr to the file extension within *basename */
static const char* arg_extension(const char* basename) {
/* find the last occurrence of '.' in basename */
const char* result = (basename ? strrchr(basename, '.') : NULL);
/* if no '.' was found then return pointer to end of basename */
if (basename && !result)
result = basename + strlen(basename);
/* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */
if (basename && result == basename)
result = basename + strlen(basename);
/* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */
if (basename && result && strlen(result) == 1)
result = basename + strlen(basename);
return result;
}
static int arg_file_scanfn(struct arg_file* parent, const char* argval) {
int errorcode = 0;
if (parent->count == parent->hdr.maxcount) {
/* maximum number of arguments exceeded */
errorcode = ARG_ERR_MAXCOUNT;
} else if (!argval) {
/* a valid argument with no argument value was given. */
/* This happens when an optional argument value was invoked. */
/* leave parent arguiment value unaltered but still count the argument. */
parent->count++;
} else {
parent->filename[parent->count] = argval;
parent->basename[parent->count] = arg_basename(argval);
parent->extension[parent->count] =
arg_extension(parent->basename[parent->count]); /* only seek extensions within the basename (not the file path)*/
parent->count++;
}
ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
return errorcode;
}
static int arg_file_checkfn(struct arg_file* parent) {
int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
return errorcode;
}
static void arg_file_errorfn(struct arg_file* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
const char* shortopts = parent->hdr.shortopts;
const char* longopts = parent->hdr.longopts;
const char* datatype = parent->hdr.datatype;
/* make argval NULL safe */
argval = argval ? argval : "";
arg_dstr_catf(ds, "%s: ", progname);
switch (errorcode) {
case ARG_ERR_MINCOUNT:
arg_dstr_cat(ds, "missing option ");
arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
break;
case ARG_ERR_MAXCOUNT:
arg_dstr_cat(ds, "excess option ");
arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
break;
default:
arg_dstr_catf(ds, "unknown error at \"%s\"\n", argval);
}
}
struct arg_file* arg_file0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
return arg_filen(shortopts, longopts, datatype, 0, 1, glossary);
}
struct arg_file* arg_file1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
return arg_filen(shortopts, longopts, datatype, 1, 1, glossary);
}
struct arg_file* arg_filen(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {
size_t nbytes;
struct arg_file* result;
int i;
/* foolproof things by ensuring maxcount is not less than mincount */
maxcount = (maxcount < mincount) ? mincount : maxcount;
nbytes = sizeof(struct arg_file) /* storage for struct arg_file */
+ sizeof(char*) * (size_t)maxcount /* storage for filename[maxcount] array */
+ sizeof(char*) * (size_t)maxcount /* storage for basename[maxcount] array */
+ sizeof(char*) * (size_t)maxcount; /* storage for extension[maxcount] array */
result = (struct arg_file*)xmalloc(nbytes);
/* init the arg_hdr struct */
result->hdr.flag = ARG_HASVALUE;
result->hdr.shortopts = shortopts;
result->hdr.longopts = longopts;
result->hdr.glossary = glossary;
result->hdr.datatype = datatype ? datatype : "<file>";
result->hdr.mincount = mincount;
result->hdr.maxcount = maxcount;
result->hdr.parent = result;
result->hdr.resetfn = (arg_resetfn*)arg_file_resetfn;
result->hdr.scanfn = (arg_scanfn*)arg_file_scanfn;
result->hdr.checkfn = (arg_checkfn*)arg_file_checkfn;
result->hdr.errorfn = (arg_errorfn*)arg_file_errorfn;
/* store the filename,basename,extension arrays immediately after the arg_file struct */
result->filename = (const char**)(result + 1);
result->basename = result->filename + maxcount;
result->extension = result->basename + maxcount;
result->count = 0;
/* foolproof the string pointers by initialising them with empty strings */
for (i = 0; i < maxcount; i++) {
result->filename[i] = "";
result->basename[i] = "";
result->extension[i] = "";
}
ARG_TRACE(("arg_filen() returns %p\n", result));
return result;
}

View file

@ -1,428 +0,0 @@
/*
* SPDX-FileCopyrightText: 2013-2019 Tom G. Huang
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_hashtable: Implements the hash table utilities
*
* This file is part of the argtable3 library.
*
* Copyright (C) 2013-2019 Tom G. Huang
* <tomghuang@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* This hash table module is adapted from the C hash table implementation by
* Christopher Clark. Here is the copyright notice from the library:
*
* Copyright (c) 2002, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Credit for primes table: Aaron Krowne
* http://br.endernet.org/~akrowne/
* http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
*/
static const unsigned int primes[] = {53, 97, 193, 389, 769, 1543, 3079, 6151, 12289,
24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741};
const unsigned int prime_table_length = sizeof(primes) / sizeof(primes[0]);
const float max_load_factor = (float)0.65;
static unsigned int enhanced_hash(arg_hashtable_t* h, const void* k) {
/*
* Aim to protect against poor hash functions by adding logic here.
* The logic is taken from Java 1.4 hash table source.
*/
unsigned int i = h->hashfn(k);
i += ~(i << 9);
i ^= ((i >> 14) | (i << 18)); /* >>> */
i += (i << 4);
i ^= ((i >> 10) | (i << 22)); /* >>> */
return i;
}
static unsigned int index_for(unsigned int tablelength, unsigned int hashvalue) {
return (hashvalue % tablelength);
}
arg_hashtable_t* arg_hashtable_create(unsigned int minsize, unsigned int (*hashfn)(const void*), int (*eqfn)(const void*, const void*)) {
arg_hashtable_t* h;
unsigned int pindex;
unsigned int size = primes[0];
/* Check requested hash table isn't too large */
if (minsize > (1u << 30))
return NULL;
/*
* Enforce size as prime. The reason is to avoid clustering of values
* into a small number of buckets (yes, distribution). A more even
* distributed hash table will perform more consistently.
*/
for (pindex = 0; pindex < prime_table_length; pindex++) {
if (primes[pindex] > minsize) {
size = primes[pindex];
break;
}
}
h = (arg_hashtable_t*)xmalloc(sizeof(arg_hashtable_t));
h->table = (struct arg_hashtable_entry**)xmalloc(sizeof(struct arg_hashtable_entry*) * size);
memset(h->table, 0, size * sizeof(struct arg_hashtable_entry*));
h->tablelength = size;
h->primeindex = pindex;
h->entrycount = 0;
h->hashfn = hashfn;
h->eqfn = eqfn;
h->loadlimit = (unsigned int)ceil(size * (double)max_load_factor);
return h;
}
static int arg_hashtable_expand(arg_hashtable_t* h) {
/* Double the size of the table to accommodate more entries */
struct arg_hashtable_entry** newtable;
struct arg_hashtable_entry* e;
unsigned int newsize;
unsigned int i;
unsigned int index;
/* Check we're not hitting max capacity */
if (h->primeindex == (prime_table_length - 1))
return 0;
newsize = primes[++(h->primeindex)];
newtable = (struct arg_hashtable_entry**)xmalloc(sizeof(struct arg_hashtable_entry*) * newsize);
memset(newtable, 0, newsize * sizeof(struct arg_hashtable_entry*));
/*
* This algorithm is not 'stable': it reverses the list
* when it transfers entries between the tables
*/
for (i = 0; i < h->tablelength; i++) {
while (NULL != (e = h->table[i])) {
h->table[i] = e->next;
index = index_for(newsize, e->h);
e->next = newtable[index];
newtable[index] = e;
}
}
xfree(h->table);
h->table = newtable;
h->tablelength = newsize;
h->loadlimit = (unsigned int)ceil(newsize * (double)max_load_factor);
return -1;
}
unsigned int arg_hashtable_count(arg_hashtable_t* h) {
return h->entrycount;
}
void arg_hashtable_insert(arg_hashtable_t* h, void* k, void* v) {
/* This method allows duplicate keys - but they shouldn't be used */
unsigned int index;
struct arg_hashtable_entry* e;
if ((h->entrycount + 1) > h->loadlimit) {
/*
* Ignore the return value. If expand fails, we should
* still try cramming just this value into the existing table
* -- we may not have memory for a larger table, but one more
* element may be ok. Next time we insert, we'll try expanding again.
*/
arg_hashtable_expand(h);
}
e = (struct arg_hashtable_entry*)xmalloc(sizeof(struct arg_hashtable_entry));
e->h = enhanced_hash(h, k);
index = index_for(h->tablelength, e->h);
e->k = k;
e->v = v;
e->next = h->table[index];
h->table[index] = e;
h->entrycount++;
}
void* arg_hashtable_search(arg_hashtable_t* h, const void* k) {
struct arg_hashtable_entry* e;
unsigned int hashvalue;
unsigned int index;
hashvalue = enhanced_hash(h, k);
index = index_for(h->tablelength, hashvalue);
e = h->table[index];
while (e != NULL) {
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
return e->v;
e = e->next;
}
return NULL;
}
void arg_hashtable_remove(arg_hashtable_t* h, const void* k) {
/*
* TODO: consider compacting the table when the load factor drops enough,
* or provide a 'compact' method.
*/
struct arg_hashtable_entry* e;
struct arg_hashtable_entry** pE;
unsigned int hashvalue;
unsigned int index;
hashvalue = enhanced_hash(h, k);
index = index_for(h->tablelength, hashvalue);
pE = &(h->table[index]);
e = *pE;
while (NULL != e) {
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {
*pE = e->next;
h->entrycount--;
xfree(e->k);
xfree(e->v);
xfree(e);
return;
}
pE = &(e->next);
e = e->next;
}
}
void arg_hashtable_destroy(arg_hashtable_t* h, int free_values) {
unsigned int i;
struct arg_hashtable_entry *e, *f;
struct arg_hashtable_entry** table = h->table;
if (free_values) {
for (i = 0; i < h->tablelength; i++) {
e = table[i];
while (NULL != e) {
f = e;
e = e->next;
xfree(f->k);
xfree(f->v);
xfree(f);
}
}
} else {
for (i = 0; i < h->tablelength; i++) {
e = table[i];
while (NULL != e) {
f = e;
e = e->next;
xfree(f->k);
xfree(f);
}
}
}
xfree(h->table);
xfree(h);
}
arg_hashtable_itr_t* arg_hashtable_itr_create(arg_hashtable_t* h) {
unsigned int i;
unsigned int tablelength;
arg_hashtable_itr_t* itr = (arg_hashtable_itr_t*)xmalloc(sizeof(arg_hashtable_itr_t));
itr->h = h;
itr->e = NULL;
itr->parent = NULL;
tablelength = h->tablelength;
itr->index = tablelength;
if (0 == h->entrycount)
return itr;
for (i = 0; i < tablelength; i++) {
if (h->table[i] != NULL) {
itr->e = h->table[i];
itr->index = i;
break;
}
}
return itr;
}
void arg_hashtable_itr_destroy(arg_hashtable_itr_t* itr) {
xfree(itr);
}
void* arg_hashtable_itr_key(arg_hashtable_itr_t* i) {
return i->e->k;
}
void* arg_hashtable_itr_value(arg_hashtable_itr_t* i) {
return i->e->v;
}
int arg_hashtable_itr_advance(arg_hashtable_itr_t* itr) {
unsigned int j;
unsigned int tablelength;
struct arg_hashtable_entry** table;
struct arg_hashtable_entry* next;
if (itr->e == NULL)
return 0; /* stupidity check */
next = itr->e->next;
if (NULL != next) {
itr->parent = itr->e;
itr->e = next;
return -1;
}
tablelength = itr->h->tablelength;
itr->parent = NULL;
if (tablelength <= (j = ++(itr->index))) {
itr->e = NULL;
return 0;
}
table = itr->h->table;
while (NULL == (next = table[j])) {
if (++j >= tablelength) {
itr->index = tablelength;
itr->e = NULL;
return 0;
}
}
itr->index = j;
itr->e = next;
return -1;
}
int arg_hashtable_itr_remove(arg_hashtable_itr_t* itr) {
struct arg_hashtable_entry* remember_e;
struct arg_hashtable_entry* remember_parent;
int ret;
/* Do the removal */
if ((itr->parent) == NULL) {
/* element is head of a chain */
itr->h->table[itr->index] = itr->e->next;
} else {
/* element is mid-chain */
itr->parent->next = itr->e->next;
}
/* itr->e is now outside the hashtable */
remember_e = itr->e;
itr->h->entrycount--;
xfree(remember_e->k);
xfree(remember_e->v);
/* Advance the iterator, correcting the parent */
remember_parent = itr->parent;
ret = arg_hashtable_itr_advance(itr);
if (itr->parent == remember_e) {
itr->parent = remember_parent;
}
xfree(remember_e);
return ret;
}
int arg_hashtable_itr_search(arg_hashtable_itr_t* itr, arg_hashtable_t* h, void* k) {
struct arg_hashtable_entry* e;
struct arg_hashtable_entry* parent;
unsigned int hashvalue;
unsigned int index;
hashvalue = enhanced_hash(h, k);
index = index_for(h->tablelength, hashvalue);
e = h->table[index];
parent = NULL;
while (e != NULL) {
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {
itr->index = index;
itr->e = e;
itr->parent = parent;
itr->h = h;
return -1;
}
parent = e;
e = e->next;
}
return 0;
}
int arg_hashtable_change(arg_hashtable_t* h, void* k, void* v) {
struct arg_hashtable_entry* e;
unsigned int hashvalue;
unsigned int index;
hashvalue = enhanced_hash(h, k);
index = index_for(h->tablelength, hashvalue);
e = h->table[index];
while (e != NULL) {
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {
xfree(e->v);
e->v = v;
return -1;
}
e = e->next;
}
return 0;
}

View file

@ -1,294 +0,0 @@
/*
* SPDX-FileCopyrightText: 1998-2001,2003-2011,2013 Stewart Heitmann
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_int: Implements the int command-line option
*
* This file is part of the argtable3 library.
*
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
* <sheitmann@users.sourceforge.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <ctype.h>
#include <limits.h>
#include <stdlib.h>
static void arg_int_resetfn(struct arg_int* parent) {
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
parent->count = 0;
}
/* strtol0x() is like strtol() except that the numeric string is */
/* expected to be prefixed by "0X" where X is a user supplied char. */
/* The string may optionally be prefixed by white space and + or - */
/* as in +0X123 or -0X123. */
/* Once the prefix has been scanned, the remainder of the numeric */
/* string is converted using strtol() with the given base. */
/* eg: to parse hex str="-0X12324", specify X='X' and base=16. */
/* eg: to parse oct str="+0o12324", specify X='O' and base=8. */
/* eg: to parse bin str="-0B01010", specify X='B' and base=2. */
/* Failure of conversion is indicated by result where *endptr==str. */
static long int strtol0X(const char* str, const char** endptr, char X, int base) {
long int val; /* stores result */
int s = 1; /* sign is +1 or -1 */
const char* ptr = str; /* ptr to current position in str */
/* skip leading whitespace */
while (isspace((int)(*ptr)))
ptr++;
/* printf("1) %s\n",ptr); */
/* scan optional sign character */
switch (*ptr) {
case '+':
ptr++;
s = 1;
break;
case '-':
ptr++;
s = -1;
break;
default:
s = 1;
break;
}
/* printf("2) %s\n",ptr); */
/* '0X' prefix */
if ((*ptr++) != '0') {
/* printf("failed to detect '0'\n"); */
*endptr = str;
return 0;
}
/* printf("3) %s\n",ptr); */
if (toupper(*ptr++) != toupper(X)) {
/* printf("failed to detect '%c'\n",X); */
*endptr = str;
return 0;
}
/* printf("4) %s\n",ptr); */
/* attempt conversion on remainder of string using strtol() */
val = strtol(ptr, (char**)endptr, base);
if (*endptr == ptr) {
/* conversion failed */
*endptr = str;
return 0;
}
/* success */
return s * val;
}
/* Returns 1 if str matches suffix (case insensitive). */
/* Str may contain trailing whitespace, but nothing else. */
static int detectsuffix(const char* str, const char* suffix) {
/* scan pairwise through strings until mismatch detected */
while (toupper(*str) == toupper(*suffix)) {
/* printf("'%c' '%c'\n", *str, *suffix); */
/* return 1 (success) if match persists until the string terminator */
if (*str == '\0')
return 1;
/* next chars */
str++;
suffix++;
}
/* printf("'%c' '%c' mismatch\n", *str, *suffix); */
/* return 0 (fail) if the matching did not consume the entire suffix */
if (*suffix != 0)
return 0; /* failed to consume entire suffix */
/* skip any remaining whitespace in str */
while (isspace((int)(*str)))
str++;
/* return 1 (success) if we have reached end of str else return 0 (fail) */
return (*str == '\0') ? 1 : 0;
}
static int arg_int_scanfn(struct arg_int* parent, const char* argval) {
int errorcode = 0;
if (parent->count == parent->hdr.maxcount) {
/* maximum number of arguments exceeded */
errorcode = ARG_ERR_MAXCOUNT;
} else if (!argval) {
/* a valid argument with no argument value was given. */
/* This happens when an optional argument value was invoked. */
/* leave parent arguiment value unaltered but still count the argument. */
parent->count++;
} else {
long int val;
const char* end;
/* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
val = strtol0X(argval, &end, 'X', 16);
if (end == argval) {
/* hex failed, attempt octal conversion (eg +0o123) */
val = strtol0X(argval, &end, 'O', 8);
if (end == argval) {
/* octal failed, attempt binary conversion (eg +0B101) */
val = strtol0X(argval, &end, 'B', 2);
if (end == argval) {
/* binary failed, attempt decimal conversion with no prefix (eg 1234) */
val = strtol(argval, (char**)&end, 10);
if (end == argval) {
/* all supported number formats failed */
return ARG_ERR_BADINT;
}
}
}
}
/* Safety check for integer overflow. WARNING: this check */
/* achieves nothing on machines where size(int)==size(long). */
if (val > INT_MAX || val < INT_MIN)
errorcode = ARG_ERR_OVERFLOW;
/* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
/* We need to be mindful of integer overflows when using such big numbers. */
if (detectsuffix(end, "KB")) /* kilobytes */
{
if (val > (INT_MAX / 1024) || val < (INT_MIN / 1024))
errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */
else
val *= 1024; /* 1KB = 1024 */
} else if (detectsuffix(end, "MB")) /* megabytes */
{
if (val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576))
errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */
else
val *= 1048576; /* 1MB = 1024*1024 */
} else if (detectsuffix(end, "GB")) /* gigabytes */
{
if (val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824))
errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */
else
val *= 1073741824; /* 1GB = 1024*1024*1024 */
} else if (!detectsuffix(end, ""))
errorcode = ARG_ERR_BADINT; /* invalid suffix detected */
/* if success then store result in parent->ival[] array */
if (errorcode == 0)
parent->ival[parent->count++] = (int)val;
}
/* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
return errorcode;
}
static int arg_int_checkfn(struct arg_int* parent) {
int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
/*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
return errorcode;
}
static void arg_int_errorfn(struct arg_int* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
const char* shortopts = parent->hdr.shortopts;
const char* longopts = parent->hdr.longopts;
const char* datatype = parent->hdr.datatype;
/* make argval NULL safe */
argval = argval ? argval : "";
arg_dstr_catf(ds, "%s: ", progname);
switch (errorcode) {
case ARG_ERR_MINCOUNT:
arg_dstr_cat(ds, "missing option ");
arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
break;
case ARG_ERR_MAXCOUNT:
arg_dstr_cat(ds, "excess option ");
arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
break;
case ARG_ERR_BADINT:
arg_dstr_catf(ds, "invalid argument \"%s\" to option ", argval);
arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
break;
case ARG_ERR_OVERFLOW:
arg_dstr_cat(ds, "integer overflow at option ");
arg_print_option_ds(ds, shortopts, longopts, datatype, " ");
arg_dstr_catf(ds, "(%s is too large)\n", argval);
break;
}
}
struct arg_int* arg_int0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
return arg_intn(shortopts, longopts, datatype, 0, 1, glossary);
}
struct arg_int* arg_int1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
return arg_intn(shortopts, longopts, datatype, 1, 1, glossary);
}
struct arg_int* arg_intn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {
size_t nbytes;
struct arg_int* result;
/* foolproof things by ensuring maxcount is not less than mincount */
maxcount = (maxcount < mincount) ? mincount : maxcount;
nbytes = sizeof(struct arg_int) /* storage for struct arg_int */
+ (size_t)maxcount * sizeof(int); /* storage for ival[maxcount] array */
result = (struct arg_int*)xmalloc(nbytes);
/* init the arg_hdr struct */
result->hdr.flag = ARG_HASVALUE;
result->hdr.shortopts = shortopts;
result->hdr.longopts = longopts;
result->hdr.datatype = datatype ? datatype : "<int>";
result->hdr.glossary = glossary;
result->hdr.mincount = mincount;
result->hdr.maxcount = maxcount;
result->hdr.parent = result;
result->hdr.resetfn = (arg_resetfn*)arg_int_resetfn;
result->hdr.scanfn = (arg_scanfn*)arg_int_scanfn;
result->hdr.checkfn = (arg_checkfn*)arg_int_checkfn;
result->hdr.errorfn = (arg_errorfn*)arg_int_errorfn;
/* store the ival[maxcount] array immediately after the arg_int struct */
result->ival = (int*)(result + 1);
result->count = 0;
ARG_TRACE(("arg_intn() returns %p\n", result));
return result;
}

View file

@ -1,124 +0,0 @@
/*
* SPDX-FileCopyrightText: 1998-2001,2003-2011,2013 Stewart Heitmann
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_lit: Implements the literature command-line option
*
* This file is part of the argtable3 library.
*
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
* <sheitmann@users.sourceforge.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <stdlib.h>
static void arg_lit_resetfn(struct arg_lit* parent) {
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
parent->count = 0;
}
static int arg_lit_scanfn(struct arg_lit* parent, const char* argval) {
int errorcode = 0;
if (parent->count < parent->hdr.maxcount)
parent->count++;
else
errorcode = ARG_ERR_MAXCOUNT;
ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval, errorcode));
return errorcode;
}
static int arg_lit_checkfn(struct arg_lit* parent) {
int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
return errorcode;
}
static void arg_lit_errorfn(struct arg_lit* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
const char* shortopts = parent->hdr.shortopts;
const char* longopts = parent->hdr.longopts;
const char* datatype = parent->hdr.datatype;
switch (errorcode) {
case ARG_ERR_MINCOUNT:
arg_dstr_catf(ds, "%s: missing option ", progname);
arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
arg_dstr_cat(ds, "\n");
break;
case ARG_ERR_MAXCOUNT:
arg_dstr_catf(ds, "%s: extraneous option ", progname);
arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
break;
}
ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, ds, errorcode, argval, progname));
}
struct arg_lit* arg_lit0(const char* shortopts, const char* longopts, const char* glossary) {
return arg_litn(shortopts, longopts, 0, 1, glossary);
}
struct arg_lit* arg_lit1(const char* shortopts, const char* longopts, const char* glossary) {
return arg_litn(shortopts, longopts, 1, 1, glossary);
}
struct arg_lit* arg_litn(const char* shortopts, const char* longopts, int mincount, int maxcount, const char* glossary) {
struct arg_lit* result;
/* foolproof things by ensuring maxcount is not less than mincount */
maxcount = (maxcount < mincount) ? mincount : maxcount;
result = (struct arg_lit*)xmalloc(sizeof(struct arg_lit));
/* init the arg_hdr struct */
result->hdr.flag = 0;
result->hdr.shortopts = shortopts;
result->hdr.longopts = longopts;
result->hdr.datatype = NULL;
result->hdr.glossary = glossary;
result->hdr.mincount = mincount;
result->hdr.maxcount = maxcount;
result->hdr.parent = result;
result->hdr.resetfn = (arg_resetfn*)arg_lit_resetfn;
result->hdr.scanfn = (arg_scanfn*)arg_lit_scanfn;
result->hdr.checkfn = (arg_checkfn*)arg_lit_checkfn;
result->hdr.errorfn = (arg_errorfn*)arg_lit_errorfn;
/* init local variables */
result->count = 0;
ARG_TRACE(("arg_litn() returns %p\n", result));
return result;
}

View file

@ -1,64 +0,0 @@
/*
* SPDX-FileCopyrightText: 1998-2001,2003-2011,2013 Stewart Heitmann
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_rem: Implements the rem command-line option
*
* This file is part of the argtable3 library.
*
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
* <sheitmann@users.sourceforge.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <stdlib.h>
struct arg_rem* arg_rem(const char* datatype, const char* glossary) {
struct arg_rem* result = (struct arg_rem*)xmalloc(sizeof(struct arg_rem));
result->hdr.flag = 0;
result->hdr.shortopts = NULL;
result->hdr.longopts = NULL;
result->hdr.datatype = datatype;
result->hdr.glossary = glossary;
result->hdr.mincount = 1;
result->hdr.maxcount = 1;
result->hdr.parent = result;
result->hdr.resetfn = NULL;
result->hdr.scanfn = NULL;
result->hdr.checkfn = NULL;
result->hdr.errorfn = NULL;
ARG_TRACE(("arg_rem() returns %p\n", result));
return result;
}

File diff suppressed because it is too large Load diff

View file

@ -1,151 +0,0 @@
/*
* SPDX-FileCopyrightText: 1998-2001,2003-2011,2013 Stewart Heitmann
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_str: Implements the str command-line option
*
* This file is part of the argtable3 library.
*
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
* <sheitmann@users.sourceforge.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <stdlib.h>
static void arg_str_resetfn(struct arg_str* parent) {
int i;
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
for (i = 0; i < parent->count; i++) {
parent->sval[i] = "";
}
parent->count = 0;
}
static int arg_str_scanfn(struct arg_str* parent, const char* argval) {
int errorcode = 0;
if (parent->count == parent->hdr.maxcount) {
/* maximum number of arguments exceeded */
errorcode = ARG_ERR_MAXCOUNT;
} else if (!argval) {
/* a valid argument with no argument value was given. */
/* This happens when an optional argument value was invoked. */
/* leave parent argument value unaltered but still count the argument. */
parent->count++;
} else {
parent->sval[parent->count++] = argval;
}
ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
return errorcode;
}
static int arg_str_checkfn(struct arg_str* parent) {
int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
return errorcode;
}
static void arg_str_errorfn(struct arg_str* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
const char* shortopts = parent->hdr.shortopts;
const char* longopts = parent->hdr.longopts;
const char* datatype = parent->hdr.datatype;
/* make argval NULL safe */
argval = argval ? argval : "";
arg_dstr_catf(ds, "%s: ", progname);
switch (errorcode) {
case ARG_ERR_MINCOUNT:
arg_dstr_cat(ds, "missing option ");
arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
break;
case ARG_ERR_MAXCOUNT:
arg_dstr_cat(ds, "excess option ");
arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
break;
}
}
struct arg_str* arg_str0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
return arg_strn(shortopts, longopts, datatype, 0, 1, glossary);
}
struct arg_str* arg_str1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
return arg_strn(shortopts, longopts, datatype, 1, 1, glossary);
}
struct arg_str* arg_strn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {
size_t nbytes;
struct arg_str* result;
int i;
/* should not allow this stupid error */
/* we should return an error code warning this logic error */
/* foolproof things by ensuring maxcount is not less than mincount */
maxcount = (maxcount < mincount) ? mincount : maxcount;
nbytes = sizeof(struct arg_str) /* storage for struct arg_str */
+ (size_t)maxcount * sizeof(char*); /* storage for sval[maxcount] array */
result = (struct arg_str*)xmalloc(nbytes);
/* init the arg_hdr struct */
result->hdr.flag = ARG_HASVALUE;
result->hdr.shortopts = shortopts;
result->hdr.longopts = longopts;
result->hdr.datatype = datatype ? datatype : "<string>";
result->hdr.glossary = glossary;
result->hdr.mincount = mincount;
result->hdr.maxcount = maxcount;
result->hdr.parent = result;
result->hdr.resetfn = (arg_resetfn*)arg_str_resetfn;
result->hdr.scanfn = (arg_scanfn*)arg_str_scanfn;
result->hdr.checkfn = (arg_checkfn*)arg_str_checkfn;
result->hdr.errorfn = (arg_errorfn*)arg_str_errorfn;
/* store the sval[maxcount] array immediately after the arg_str struct */
result->sval = (const char**)(result + 1);
result->count = 0;
/* foolproof the string pointers by initializing them to reference empty strings */
for (i = 0; i < maxcount; i++)
result->sval[i] = "";
ARG_TRACE(("arg_strn() returns %p\n", result));
return result;
}

View file

@ -1,183 +0,0 @@
/*
* SPDX-FileCopyrightText: 2013-2019 Tom G. Huang
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* arg_utils: Implements memory, panic, and other utility functions
*
* This file is part of the argtable3 library.
*
* Copyright (C) 2013-2019 Tom G. Huang
* <tomghuang@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void panic(const char* fmt, ...);
static arg_panicfn* s_panic = panic;
void dbg_printf(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
static void panic(const char* fmt, ...) {
va_list args;
char* s;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
s = getenv("EF_DUMPCORE");
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
if (s != NULL && *s != '\0') {
abort();
} else {
exit(EXIT_FAILURE);
}
}
void arg_set_panic(arg_panicfn* proc) {
s_panic = proc;
}
void* xmalloc(size_t size) {
void* ret = malloc(size);
if (!ret) {
s_panic("Out of memory!\n");
}
return ret;
}
void* xcalloc(size_t count, size_t size) {
size_t allocated_count = count && size ? count : 1;
size_t allocated_size = count && size ? size : 1;
void* ret = calloc(allocated_count, allocated_size);
if (!ret) {
s_panic("Out of memory!\n");
}
return ret;
}
void* xrealloc(void* ptr, size_t size) {
size_t allocated_size = size ? size : 1;
void* ret = realloc(ptr, allocated_size);
if (!ret) {
s_panic("Out of memory!\n");
}
return ret;
}
void xfree(void* ptr) {
free(ptr);
}
static void merge(void* data, int esize, int i, int j, int k, arg_comparefn* comparefn) {
char* a = (char*)data;
char* m;
int ipos, jpos, mpos;
/* Initialize the counters used in merging. */
ipos = i;
jpos = j + 1;
mpos = 0;
/* Allocate storage for the merged elements. */
m = (char*)xmalloc((size_t)(esize * ((k - i) + 1)));
/* Continue while either division has elements to merge. */
while (ipos <= j || jpos <= k) {
if (ipos > j) {
/* The left division has no more elements to merge. */
while (jpos <= k) {
memcpy(&m[mpos * esize], &a[jpos * esize], (size_t)esize);
jpos++;
mpos++;
}
continue;
} else if (jpos > k) {
/* The right division has no more elements to merge. */
while (ipos <= j) {
memcpy(&m[mpos * esize], &a[ipos * esize], (size_t)esize);
ipos++;
mpos++;
}
continue;
}
/* Append the next ordered element to the merged elements. */
if (comparefn(&a[ipos * esize], &a[jpos * esize]) < 0) {
memcpy(&m[mpos * esize], &a[ipos * esize], (size_t)esize);
ipos++;
mpos++;
} else {
memcpy(&m[mpos * esize], &a[jpos * esize], (size_t)esize);
jpos++;
mpos++;
}
}
/* Prepare to pass back the merged data. */
memcpy(&a[i * esize], m, (size_t)(esize * ((k - i) + 1)));
xfree(m);
}
void arg_mgsort(void* data, int size, int esize, int i, int k, arg_comparefn* comparefn) {
int j;
/* Stop the recursion when no more divisions can be made. */
if (i < k) {
/* Determine where to divide the elements. */
j = (int)(((i + k - 1)) / 2);
/* Recursively sort the two divisions. */
arg_mgsort(data, size, esize, i, j, comparefn);
arg_mgsort(data, size, esize, j + 1, k, comparefn);
merge(data, esize, i, j, k, comparefn);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,4 @@
/*
* SPDX-FileCopyrightText: 1998-2001,2003-2011,2013 Stewart Heitmann
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/******************************************************************************* /*******************************************************************************
* argtable3: Declares the main interfaces of the library
*
* This file is part of the argtable3 library. * This file is part of the argtable3 library.
* *
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
@ -38,240 +31,273 @@
#ifndef ARGTABLE3 #ifndef ARGTABLE3
#define ARGTABLE3 #define ARGTABLE3
#include <stdio.h> /* FILE */ #include <stdio.h> /* FILE */
#include <time.h> /* struct tm */ #include <time.h> /* struct tm */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#define ARG_REX_ICASE 1 #define ARG_REX_ICASE 1
#define ARG_DSTR_SIZE 200
#define ARG_CMD_NAME_LEN 100
#define ARG_CMD_DESCRIPTION_LEN 256
#ifndef ARG_REPLACE_GETOPT
#define ARG_REPLACE_GETOPT 0 /* ESP-IDF-specific: use newlib-provided getopt instead of the embedded one */
#endif /* ARG_REPLACE_GETOPT */
/* bit masks for arg_hdr.flag */ /* bit masks for arg_hdr.flag */
enum { ARG_TERMINATOR = 0x1, ARG_HASVALUE = 0x2, ARG_HASOPTVALUE = 0x4 }; enum
{
ARG_TERMINATOR=0x1,
ARG_HASVALUE=0x2,
ARG_HASOPTVALUE=0x4
};
#if defined(_WIN32) typedef void (arg_resetfn)(void *parent);
#if defined(argtable3_EXPORTS) typedef int (arg_scanfn)(void *parent, const char *argval);
#define ARG_EXTERN __declspec(dllexport) typedef int (arg_checkfn)(void *parent);
#elif defined(argtable3_IMPORTS) typedef void (arg_errorfn)(void *parent, FILE *fp, int error, const char *argval, const char *progname);
#define ARG_EXTERN __declspec(dllimport)
#else
#define ARG_EXTERN
#endif
#else
#define ARG_EXTERN
#endif
typedef struct _internal_arg_dstr* arg_dstr_t;
typedef void* arg_cmd_itr_t;
typedef void(arg_resetfn)(void* parent);
typedef int(arg_scanfn)(void* parent, const char* argval);
typedef int(arg_checkfn)(void* parent);
typedef void(arg_errorfn)(void* parent, arg_dstr_t ds, int error, const char* argval, const char* progname);
typedef void(arg_dstr_freefn)(char* buf);
typedef int(arg_cmdfn)(int argc, char* argv[], arg_dstr_t res);
typedef int(arg_comparefn)(const void* k1, const void* k2);
/* /*
* The arg_hdr struct defines properties that are common to all arg_xxx structs. * The arg_hdr struct defines properties that are common to all arg_xxx structs.
* The argtable library requires each arg_xxx struct to have an arg_hdr * The argtable library requires each arg_xxx struct to have an arg_hdr
* struct as its first data member. * struct as its first data member.
* The argtable library functions then use this data to identify the * The argtable library functions then use this data to identify the
* properties of the command line option, such as its option tags, * properties of the command line option, such as its option tags,
* datatype string, and glossary strings, and so on. * datatype string, and glossary strings, and so on.
* Moreover, the arg_hdr struct contains pointers to custom functions that * Moreover, the arg_hdr struct contains pointers to custom functions that
* are provided by each arg_xxx struct which perform the tasks of parsing * are provided by each arg_xxx struct which perform the tasks of parsing
* that particular arg_xxx arguments, performing post-parse checks, and * that particular arg_xxx arguments, performing post-parse checks, and
* reporting errors. * reporting errors.
* These functions are private to the individual arg_xxx source code * These functions are private to the individual arg_xxx source code
* and are the pointer to them are initiliased by that arg_xxx struct's * and are the pointer to them are initiliased by that arg_xxx struct's
* constructor function. The user could alter them after construction * constructor function. The user could alter them after construction
* if desired, but the original intention is for them to be set by the * if desired, but the original intention is for them to be set by the
* constructor and left unaltered. * constructor and left unaltered.
*/ */
typedef struct arg_hdr { struct arg_hdr
char flag; /* Modifier flags: ARG_TERMINATOR, ARG_HASVALUE. */ {
const char* shortopts; /* String defining the short options */ char flag; /* Modifier flags: ARG_TERMINATOR, ARG_HASVALUE. */
const char* longopts; /* String defiing the long options */ const char *shortopts; /* String defining the short options */
const char* datatype; /* Description of the argument data type */ const char *longopts; /* String defiing the long options */
const char* glossary; /* Description of the option as shown by arg_print_glossary function */ const char *datatype; /* Description of the argument data type */
int mincount; /* Minimum number of occurences of this option accepted */ const char *glossary; /* Description of the option as shown by arg_print_glossary function */
int maxcount; /* Maximum number of occurences if this option accepted */ int mincount; /* Minimum number of occurences of this option accepted */
void* parent; /* Pointer to parent arg_xxx struct */ int maxcount; /* Maximum number of occurences if this option accepted */
arg_resetfn* resetfn; /* Pointer to parent arg_xxx reset function */ void *parent; /* Pointer to parent arg_xxx struct */
arg_scanfn* scanfn; /* Pointer to parent arg_xxx scan function */ arg_resetfn *resetfn; /* Pointer to parent arg_xxx reset function */
arg_checkfn* checkfn; /* Pointer to parent arg_xxx check function */ arg_scanfn *scanfn; /* Pointer to parent arg_xxx scan function */
arg_errorfn* errorfn; /* Pointer to parent arg_xxx error function */ arg_checkfn *checkfn; /* Pointer to parent arg_xxx check function */
void* priv; /* Pointer to private header data for use by arg_xxx functions */ arg_errorfn *errorfn; /* Pointer to parent arg_xxx error function */
} arg_hdr_t; void *priv; /* Pointer to private header data for use by arg_xxx functions */
};
typedef struct arg_rem { struct arg_rem
struct arg_hdr hdr; /* The mandatory argtable header struct */ {
} arg_rem_t; struct arg_hdr hdr; /* The mandatory argtable header struct */
};
typedef struct arg_lit { struct arg_lit
struct arg_hdr hdr; /* The mandatory argtable header struct */ {
int count; /* Number of matching command line args */ struct arg_hdr hdr; /* The mandatory argtable header struct */
} arg_lit_t; int count; /* Number of matching command line args */
};
typedef struct arg_int { struct arg_int
struct arg_hdr hdr; /* The mandatory argtable header struct */ {
int count; /* Number of matching command line args */ struct arg_hdr hdr; /* The mandatory argtable header struct */
int* ival; /* Array of parsed argument values */ int count; /* Number of matching command line args */
} arg_int_t; int *ival; /* Array of parsed argument values */
};
typedef struct arg_dbl { struct arg_dbl
struct arg_hdr hdr; /* The mandatory argtable header struct */ {
int count; /* Number of matching command line args */ struct arg_hdr hdr; /* The mandatory argtable header struct */
double* dval; /* Array of parsed argument values */ int count; /* Number of matching command line args */
} arg_dbl_t; double *dval; /* Array of parsed argument values */
};
typedef struct arg_str { struct arg_str
struct arg_hdr hdr; /* The mandatory argtable header struct */ {
int count; /* Number of matching command line args */ struct arg_hdr hdr; /* The mandatory argtable header struct */
const char** sval; /* Array of parsed argument values */ int count; /* Number of matching command line args */
} arg_str_t; const char **sval; /* Array of parsed argument values */
};
typedef struct arg_rex { struct arg_rex
struct arg_hdr hdr; /* The mandatory argtable header struct */ {
int count; /* Number of matching command line args */ struct arg_hdr hdr; /* The mandatory argtable header struct */
const char** sval; /* Array of parsed argument values */ int count; /* Number of matching command line args */
} arg_rex_t; const char **sval; /* Array of parsed argument values */
};
typedef struct arg_file { struct arg_file
struct arg_hdr hdr; /* The mandatory argtable header struct */ {
int count; /* Number of matching command line args*/ struct arg_hdr hdr; /* The mandatory argtable header struct */
const char** filename; /* Array of parsed filenames (eg: /home/foo.bar) */ int count; /* Number of matching command line args*/
const char** basename; /* Array of parsed basenames (eg: foo.bar) */ const char **filename; /* Array of parsed filenames (eg: /home/foo.bar) */
const char** extension; /* Array of parsed extensions (eg: .bar) */ const char **basename; /* Array of parsed basenames (eg: foo.bar) */
} arg_file_t; const char **extension; /* Array of parsed extensions (eg: .bar) */
};
typedef struct arg_date { struct arg_date
struct arg_hdr hdr; /* The mandatory argtable header struct */ {
const char* format; /* strptime format string used to parse the date */ struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */ const char *format; /* strptime format string used to parse the date */
struct tm* tmval; /* Array of parsed time values */ int count; /* Number of matching command line args */
} arg_date_t; struct tm *tmval; /* Array of parsed time values */
};
enum { ARG_ELIMIT = 1, ARG_EMALLOC, ARG_ENOMATCH, ARG_ELONGOPT, ARG_EMISSARG }; enum {ARG_ELIMIT=1, ARG_EMALLOC, ARG_ENOMATCH, ARG_ELONGOPT, ARG_EMISSARG};
typedef struct arg_end { struct arg_end
struct arg_hdr hdr; /* The mandatory argtable header struct */ {
int count; /* Number of errors encountered */ struct arg_hdr hdr; /* The mandatory argtable header struct */
int* error; /* Array of error codes */ int count; /* Number of errors encountered */
void** parent; /* Array of pointers to offending arg_xxx struct */ int *error; /* Array of error codes */
const char** argval; /* Array of pointers to offending argv[] string */ void **parent; /* Array of pointers to offending arg_xxx struct */
} arg_end_t; const char **argval; /* Array of pointers to offending argv[] string */
};
typedef struct arg_cmd_info {
char name[ARG_CMD_NAME_LEN];
char description[ARG_CMD_DESCRIPTION_LEN];
arg_cmdfn* proc;
} arg_cmd_info_t;
/**** arg_xxx constructor functions *********************************/ /**** arg_xxx constructor functions *********************************/
ARG_EXTERN struct arg_rem* arg_rem(const char* datatype, const char* glossary); struct arg_rem* arg_rem(const char* datatype, const char* glossary);
ARG_EXTERN struct arg_lit* arg_lit0(const char* shortopts, const char* longopts, const char* glossary); struct arg_lit* arg_lit0(const char* shortopts,
ARG_EXTERN struct arg_lit* arg_lit1(const char* shortopts, const char* longopts, const char* glossary); const char* longopts,
ARG_EXTERN struct arg_lit* arg_litn(const char* shortopts, const char* longopts, int mincount, int maxcount, const char* glossary); const char* glossary);
struct arg_lit* arg_lit1(const char* shortopts,
const char* longopts,
const char *glossary);
struct arg_lit* arg_litn(const char* shortopts,
const char* longopts,
int mincount,
int maxcount,
const char *glossary);
ARG_EXTERN struct arg_int* arg_int0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); struct arg_key* arg_key0(const char* keyword,
ARG_EXTERN struct arg_int* arg_int1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); int flags,
ARG_EXTERN struct arg_int* arg_intn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary); const char* glossary);
struct arg_key* arg_key1(const char* keyword,
int flags,
const char* glossary);
struct arg_key* arg_keyn(const char* keyword,
int flags,
int mincount,
int maxcount,
const char* glossary);
ARG_EXTERN struct arg_dbl* arg_dbl0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); struct arg_int* arg_int0(const char* shortopts,
ARG_EXTERN struct arg_dbl* arg_dbl1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); const char* longopts,
ARG_EXTERN struct arg_dbl* arg_dbln(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary); const char* datatype,
const char* glossary);
struct arg_int* arg_int1(const char* shortopts,
const char* longopts,
const char* datatype,
const char *glossary);
struct arg_int* arg_intn(const char* shortopts,
const char* longopts,
const char *datatype,
int mincount,
int maxcount,
const char *glossary);
ARG_EXTERN struct arg_str* arg_str0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); struct arg_dbl* arg_dbl0(const char* shortopts,
ARG_EXTERN struct arg_str* arg_str1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); const char* longopts,
ARG_EXTERN struct arg_str* arg_strn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary); const char* datatype,
const char* glossary);
struct arg_dbl* arg_dbl1(const char* shortopts,
const char* longopts,
const char* datatype,
const char *glossary);
struct arg_dbl* arg_dbln(const char* shortopts,
const char* longopts,
const char *datatype,
int mincount,
int maxcount,
const char *glossary);
ARG_EXTERN struct arg_rex* arg_rex0(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary); struct arg_str* arg_str0(const char* shortopts,
ARG_EXTERN struct arg_rex* arg_rex1(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary); const char* longopts,
ARG_EXTERN struct arg_rex* arg_rexn(const char* shortopts, const char* datatype,
const char* longopts, const char* glossary);
const char* pattern, struct arg_str* arg_str1(const char* shortopts,
const char* datatype, const char* longopts,
int mincount, const char* datatype,
int maxcount, const char *glossary);
int flags, struct arg_str* arg_strn(const char* shortopts,
const char* glossary); const char* longopts,
const char* datatype,
int mincount,
int maxcount,
const char *glossary);
ARG_EXTERN struct arg_file* arg_file0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); struct arg_rex* arg_rex0(const char* shortopts,
ARG_EXTERN struct arg_file* arg_file1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); const char* longopts,
ARG_EXTERN struct arg_file* arg_filen(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary); const char* pattern,
const char* datatype,
int flags,
const char* glossary);
struct arg_rex* arg_rex1(const char* shortopts,
const char* longopts,
const char* pattern,
const char* datatype,
int flags,
const char *glossary);
struct arg_rex* arg_rexn(const char* shortopts,
const char* longopts,
const char* pattern,
const char* datatype,
int mincount,
int maxcount,
int flags,
const char *glossary);
ARG_EXTERN struct arg_date* arg_date0(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary); struct arg_file* arg_file0(const char* shortopts,
ARG_EXTERN struct arg_date* arg_date1(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary); const char* longopts,
ARG_EXTERN struct arg_date* arg_daten(const char* shortopts, const char* longopts, const char* format, const char* datatype, int mincount, int maxcount, const char* glossary); const char* datatype,
const char* glossary);
struct arg_file* arg_file1(const char* shortopts,
const char* longopts,
const char* datatype,
const char *glossary);
struct arg_file* arg_filen(const char* shortopts,
const char* longopts,
const char* datatype,
int mincount,
int maxcount,
const char *glossary);
ARG_EXTERN struct arg_end* arg_end(int maxcount); struct arg_date* arg_date0(const char* shortopts,
const char* longopts,
const char* format,
const char* datatype,
const char* glossary);
struct arg_date* arg_date1(const char* shortopts,
const char* longopts,
const char* format,
const char* datatype,
const char *glossary);
struct arg_date* arg_daten(const char* shortopts,
const char* longopts,
const char* format,
const char* datatype,
int mincount,
int maxcount,
const char *glossary);
struct arg_end* arg_end(int maxerrors);
#define ARG_DSTR_STATIC ((arg_dstr_freefn*)0)
#define ARG_DSTR_VOLATILE ((arg_dstr_freefn*)1)
#define ARG_DSTR_DYNAMIC ((arg_dstr_freefn*)3)
/**** other functions *******************************************/ /**** other functions *******************************************/
ARG_EXTERN int arg_nullcheck(void** argtable); int arg_nullcheck(void **argtable);
ARG_EXTERN int arg_parse(int argc, char** argv, void** argtable); int arg_parse(int argc, char **argv, void **argtable);
ARG_EXTERN void arg_print_option(FILE* fp, const char* shortopts, const char* longopts, const char* datatype, const char* suffix); void arg_print_option(FILE *fp, const char *shortopts, const char *longopts, const char *datatype, const char *suffix);
ARG_EXTERN void arg_print_syntax(FILE* fp, void** argtable, const char* suffix); void arg_print_syntax(FILE *fp, void **argtable, const char *suffix);
ARG_EXTERN void arg_print_syntaxv(FILE* fp, void** argtable, const char* suffix); void arg_print_syntaxv(FILE *fp, void **argtable, const char *suffix);
ARG_EXTERN void arg_print_glossary(FILE* fp, void** argtable, const char* format); void arg_print_glossary(FILE *fp, void **argtable, const char *format);
ARG_EXTERN void arg_print_glossary_gnu(FILE* fp, void** argtable); void arg_print_glossary_gnu(FILE *fp, void **argtable);
ARG_EXTERN void arg_print_formatted(FILE *fp, const unsigned lmargin, const unsigned rmargin, const char *text); void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname);
ARG_EXTERN void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname); void arg_freetable(void **argtable, size_t n);
ARG_EXTERN void arg_print_option_ds(arg_dstr_t ds, const char* shortopts, const char* longopts, const char* datatype, const char* suffix);
ARG_EXTERN void arg_print_syntax_ds(arg_dstr_t ds, void** argtable, const char* suffix);
ARG_EXTERN void arg_print_syntaxv_ds(arg_dstr_t ds, void** argtable, const char* suffix);
ARG_EXTERN void arg_print_glossary_ds(arg_dstr_t ds, void** argtable, const char* format);
ARG_EXTERN void arg_print_glossary_gnu_ds(arg_dstr_t ds, void** argtable);
ARG_EXTERN void arg_print_errors_ds(arg_dstr_t ds, struct arg_end* end, const char* progname);
ARG_EXTERN void arg_freetable(void** argtable, size_t n);
ARG_EXTERN arg_dstr_t arg_dstr_create(void);
ARG_EXTERN void arg_dstr_destroy(arg_dstr_t ds);
ARG_EXTERN void arg_dstr_reset(arg_dstr_t ds);
ARG_EXTERN void arg_dstr_free(arg_dstr_t ds);
ARG_EXTERN void arg_dstr_set(arg_dstr_t ds, char* str, arg_dstr_freefn* free_proc);
ARG_EXTERN void arg_dstr_cat(arg_dstr_t ds, const char* str);
ARG_EXTERN void arg_dstr_catc(arg_dstr_t ds, char c);
ARG_EXTERN void arg_dstr_catf(arg_dstr_t ds, const char* fmt, ...);
ARG_EXTERN char* arg_dstr_cstr(arg_dstr_t ds);
ARG_EXTERN void arg_cmd_init(void);
ARG_EXTERN void arg_cmd_uninit(void);
ARG_EXTERN void arg_cmd_register(const char* name, arg_cmdfn* proc, const char* description);
ARG_EXTERN void arg_cmd_unregister(const char* name);
ARG_EXTERN int arg_cmd_dispatch(const char* name, int argc, char* argv[], arg_dstr_t res);
ARG_EXTERN unsigned int arg_cmd_count(void);
ARG_EXTERN arg_cmd_info_t* arg_cmd_info(const char* name);
ARG_EXTERN arg_cmd_itr_t arg_cmd_itr_create(void);
ARG_EXTERN void arg_cmd_itr_destroy(arg_cmd_itr_t itr);
ARG_EXTERN int arg_cmd_itr_advance(arg_cmd_itr_t itr);
ARG_EXTERN char* arg_cmd_itr_key(arg_cmd_itr_t itr);
ARG_EXTERN arg_cmd_info_t* arg_cmd_itr_value(arg_cmd_itr_t itr);
ARG_EXTERN int arg_cmd_itr_search(arg_cmd_itr_t itr, void* k);
ARG_EXTERN void arg_mgsort(void* data, int size, int esize, int i, int k, arg_comparefn* comparefn);
ARG_EXTERN void arg_make_get_help_msg(arg_dstr_t res);
ARG_EXTERN void arg_make_help_msg(arg_dstr_t ds, char* cmd_name, void** argtable);
ARG_EXTERN void arg_make_syntax_err_msg(arg_dstr_t ds, void** argtable, struct arg_end* end);
ARG_EXTERN int arg_make_syntax_err_help_msg(arg_dstr_t ds, char* name, int help, int nerrors, void** argtable, struct arg_end* end, int* exitcode);
ARG_EXTERN void arg_set_module_name(const char* name);
ARG_EXTERN void arg_set_module_version(int major, int minor, int patch, const char* tag);
/**** deprecated functions, for back-compatibility only ********/ /**** deprecated functions, for back-compatibility only ********/
ARG_EXTERN void arg_free(void** argtable); void arg_free(void **argtable);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -1,245 +0,0 @@
/*
* SPDX-FileCopyrightText: 2013-2019 Tom G. Huang
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* argtable3_private: Declares private types, constants, and interfaces
*
* This file is part of the argtable3 library.
*
* Copyright (C) 2013-2019 Tom G. Huang
* <tomghuang@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#ifndef ARG_UTILS_H
#define ARG_UTILS_H
#include <stdlib.h>
#define ARG_ENABLE_TRACE 0
#define ARG_ENABLE_LOG 0
#ifdef __cplusplus
extern "C" {
#endif
enum { ARG_ERR_MINCOUNT = 1, ARG_ERR_MAXCOUNT, ARG_ERR_BADINT, ARG_ERR_OVERFLOW, ARG_ERR_BADDOUBLE, ARG_ERR_BADDATE, ARG_ERR_REGNOMATCH };
typedef void(arg_panicfn)(const char* fmt, ...);
#if defined(_MSC_VER)
#define ARG_TRACE(x) \
__pragma(warning(push)) __pragma(warning(disable : 4127)) do { \
if (ARG_ENABLE_TRACE) \
dbg_printf x; \
} \
while (0) \
__pragma(warning(pop))
#define ARG_LOG(x) \
__pragma(warning(push)) __pragma(warning(disable : 4127)) do { \
if (ARG_ENABLE_LOG) \
dbg_printf x; \
} \
while (0) \
__pragma(warning(pop))
#else
#define ARG_TRACE(x) \
do { \
if (ARG_ENABLE_TRACE) \
dbg_printf x; \
} while (0)
#define ARG_LOG(x) \
do { \
if (ARG_ENABLE_LOG) \
dbg_printf x; \
} while (0)
#endif
/*
* Rename a few generic names to unique names.
* They can be a problem for the platforms like NuttX, where
* the namespace is flat for everything including apps and libraries.
*/
#define xmalloc argtable3_xmalloc
#define xcalloc argtable3_xcalloc
#define xrealloc argtable3_xrealloc
#define xfree argtable3_xfree
extern void dbg_printf(const char* fmt, ...);
extern void arg_set_panic(arg_panicfn* proc);
extern void* xmalloc(size_t size);
extern void* xcalloc(size_t count, size_t size);
extern void* xrealloc(void* ptr, size_t size);
extern void xfree(void* ptr);
struct arg_hashtable_entry {
void *k, *v;
unsigned int h;
struct arg_hashtable_entry* next;
};
typedef struct arg_hashtable {
unsigned int tablelength;
struct arg_hashtable_entry** table;
unsigned int entrycount;
unsigned int loadlimit;
unsigned int primeindex;
unsigned int (*hashfn)(const void* k);
int (*eqfn)(const void* k1, const void* k2);
} arg_hashtable_t;
/**
* @brief Create a hash table.
*
* @param minsize minimum initial size of hash table
* @param hashfn function for hashing keys
* @param eqfn function for determining key equality
* @return newly created hash table or NULL on failure
*/
arg_hashtable_t* arg_hashtable_create(unsigned int minsize, unsigned int (*hashfn)(const void*), int (*eqfn)(const void*, const void*));
/**
* @brief This function will cause the table to expand if the insertion would take
* the ratio of entries to table size over the maximum load factor.
*
* This function does not check for repeated insertions with a duplicate key.
* The value returned when using a duplicate key is undefined -- when
* the hash table changes size, the order of retrieval of duplicate key
* entries is reversed.
* If in doubt, remove before insert.
*
* @param h the hash table to insert into
* @param k the key - hash table claims ownership and will free on removal
* @param v the value - does not claim ownership
* @return non-zero for successful insertion
*/
void arg_hashtable_insert(arg_hashtable_t* h, void* k, void* v);
#define ARG_DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
int fnname(arg_hashtable_t* h, keytype* k, valuetype* v) { return arg_hashtable_insert(h, k, v); }
/**
* @brief Search the specified key in the hash table.
*
* @param h the hash table to search
* @param k the key to search for - does not claim ownership
* @return the value associated with the key, or NULL if none found
*/
void* arg_hashtable_search(arg_hashtable_t* h, const void* k);
#define ARG_DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
valuetype* fnname(arg_hashtable_t* h, keytype* k) { return (valuetype*)(arg_hashtable_search(h, k)); }
/**
* @brief Remove the specified key from the hash table.
*
* @param h the hash table to remove the item from
* @param k the key to search for - does not claim ownership
*/
void arg_hashtable_remove(arg_hashtable_t* h, const void* k);
#define ARG_DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
void fnname(arg_hashtable_t* h, keytype* k) { arg_hashtable_remove(h, k); }
/**
* @brief Return the number of keys in the hash table.
*
* @param h the hash table
* @return the number of items stored in the hash table
*/
unsigned int arg_hashtable_count(arg_hashtable_t* h);
/**
* @brief Change the value associated with the key.
*
* function to change the value associated with a key, where there already
* exists a value bound to the key in the hash table.
* Source due to Holger Schemel.
*
* @name hashtable_change
* @param h the hash table
* @param key
* @param value
*/
int arg_hashtable_change(arg_hashtable_t* h, void* k, void* v);
/**
* @brief Free the hash table and the memory allocated for each key-value pair.
*
* @param h the hash table
* @param free_values whether to call 'free' on the remaining values
*/
void arg_hashtable_destroy(arg_hashtable_t* h, int free_values);
typedef struct arg_hashtable_itr {
arg_hashtable_t* h;
struct arg_hashtable_entry* e;
struct arg_hashtable_entry* parent;
unsigned int index;
} arg_hashtable_itr_t;
arg_hashtable_itr_t* arg_hashtable_itr_create(arg_hashtable_t* h);
void arg_hashtable_itr_destroy(arg_hashtable_itr_t* itr);
/**
* @brief Return the value of the (key,value) pair at the current position.
*/
extern void* arg_hashtable_itr_key(arg_hashtable_itr_t* i);
/**
* @brief Return the value of the (key,value) pair at the current position.
*/
extern void* arg_hashtable_itr_value(arg_hashtable_itr_t* i);
/**
* @brief Advance the iterator to the next element. Returns zero if advanced to end of table.
*/
int arg_hashtable_itr_advance(arg_hashtable_itr_t* itr);
/**
* @brief Remove current element and advance the iterator to the next element.
*/
int arg_hashtable_itr_remove(arg_hashtable_itr_t* itr);
/**
* @brief Search and overwrite the supplied iterator, to point to the entry matching the supplied key.
*
* @return Zero if not found.
*/
int arg_hashtable_itr_search(arg_hashtable_itr_t* itr, arg_hashtable_t* h, void* k);
#define ARG_DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
int fnname(arg_hashtable_itr_t* i, arg_hashtable_t* h, keytype* k) { return (arg_hashtable_iterator_search(i, h, k)); }
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,8 +1,16 @@
/* // Copyright 2016-2017 Espressif Systems (Shanghai) PTE LTD
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD //
* // Licensed under the Apache License, Version 2.0 (the "License");
* SPDX-License-Identifier: Apache-2.0 // you may not use this file except in compliance with the License.
*/ // You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -10,10 +18,9 @@
#include <sys/param.h> #include <sys/param.h>
#include "esp_log.h" #include "esp_log.h"
#include "esp_console.h" #include "esp_console.h"
#include "esp_system.h"
#include "linenoise/linenoise.h" #include "linenoise/linenoise.h"
#include "argtable3/argtable3.h" #include "argtable3/argtable3.h"
#include "sys/queue.h" #include "rom/queue.h"
#define ANSI_COLOR_DEFAULT 39 /** Default foreground color */ #define ANSI_COLOR_DEFAULT 39 /** Default foreground color */
@ -21,18 +28,18 @@ typedef struct cmd_item_ {
/** /**
* Command name (statically allocated by application) * Command name (statically allocated by application)
*/ */
const char *command; const char* command;
/** /**
* Help text (statically allocated by application), may be NULL. * Help text (statically allocated by application), may be NULL.
*/ */
const char *help; const char* help;
/** /**
* Hint text, usually lists possible arguments, dynamically allocated. * Hint text, usually lists possible arguments, dynamically allocated.
* May be NULL. * May be NULL.
*/ */
char *hint; char* hint;
esp_console_cmd_func_t func; //!< pointer to the command handler esp_console_cmd_func_t func; //!< pointer to the command handler
void *argtable; //!< optional pointer to arg table void* argtable; //!< optional pointer to arg table
SLIST_ENTRY(cmd_item_) next; //!< next command in the list SLIST_ENTRY(cmd_item_) next; //!< next command in the list
} cmd_item_t; } cmd_item_t;
@ -43,15 +50,12 @@ static SLIST_HEAD(cmd_list_, cmd_item_) s_cmd_list;
static esp_console_config_t s_config; static esp_console_config_t s_config;
/** temporary buffer used for command line parsing */ /** temporary buffer used for command line parsing */
static char *s_tmp_line_buf; static char* s_tmp_line_buf;
static const cmd_item_t *find_command_by_name(const char *name); static const cmd_item_t* find_command_by_name(const char* name);
esp_err_t esp_console_init(const esp_console_config_t *config) esp_err_t esp_console_init(const esp_console_config_t* config)
{ {
if (!config) {
return ESP_ERR_INVALID_ARG;
}
if (s_tmp_line_buf) { if (s_tmp_line_buf) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
@ -66,16 +70,14 @@ esp_err_t esp_console_init(const esp_console_config_t *config)
return ESP_OK; return ESP_OK;
} }
esp_err_t esp_console_deinit(void) esp_err_t esp_console_deinit()
{ {
if (!s_tmp_line_buf) { if (!s_tmp_line_buf) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
free(s_tmp_line_buf); free(s_tmp_line_buf);
s_tmp_line_buf = NULL;
cmd_item_t *it, *tmp; cmd_item_t *it, *tmp;
SLIST_FOREACH_SAFE(it, &s_cmd_list, next, tmp) { SLIST_FOREACH_SAFE(it, &s_cmd_list, next, tmp) {
SLIST_REMOVE(&s_cmd_list, it, cmd_item_, next);
free(it->hint); free(it->hint);
free(it); free(it);
} }
@ -84,51 +86,39 @@ esp_err_t esp_console_deinit(void)
esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd) esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd)
{ {
cmd_item_t *item = NULL; cmd_item_t *item = (cmd_item_t *) calloc(1, sizeof(*item));
if (!cmd || cmd->command == NULL) { if (item == NULL) {
return ESP_ERR_NO_MEM;
}
if (cmd->command == NULL) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
if (strchr(cmd->command, ' ') != NULL) { if (strchr(cmd->command, ' ') != NULL) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
item = (cmd_item_t *)find_command_by_name(cmd->command);
if (!item) {
// not registered before
item = calloc(1, sizeof(*item));
if (item == NULL) {
return ESP_ERR_NO_MEM;
}
} else {
// remove from list and free the old hint, because we will alloc new hint for the command
SLIST_REMOVE(&s_cmd_list, item, cmd_item_, next);
free(item->hint);
}
item->command = cmd->command; item->command = cmd->command;
item->help = cmd->help; item->help = cmd->help;
if (cmd->hint) { if (cmd->hint) {
/* Prepend a space before the hint. It separates command name and /* Prepend a space before the hint. It separates command name and
* the hint. arg_print_syntax below adds this space as well. * the hint. arg_print_syntax below adds this space as well.
*/ */
int unused __attribute__((unused)); asprintf(&item->hint, " %s", cmd->hint);
unused = asprintf(&item->hint, " %s", cmd->hint);
} else if (cmd->argtable) { } else if (cmd->argtable) {
/* Generate hint based on cmd->argtable */ /* Generate hint based on cmd->argtable */
char *buf = NULL; char* buf;
size_t buf_size = 0; size_t buf_size;
FILE *f = open_memstream(&buf, &buf_size); FILE* f = open_memstream(&buf, &buf_size);
if (f != NULL) { arg_print_syntax(f, cmd->argtable, NULL);
arg_print_syntax(f, cmd->argtable, NULL); fclose(f);
fclose(f);
}
item->hint = buf; item->hint = buf;
} }
item->argtable = cmd->argtable; item->argtable = cmd->argtable;
item->func = cmd->func; item->func = cmd->func;
cmd_item_t *last = SLIST_FIRST(&s_cmd_list); cmd_item_t* last = SLIST_FIRST(&s_cmd_list);
if (last == NULL) { if (last == NULL) {
SLIST_INSERT_HEAD(&s_cmd_list, item, next); SLIST_INSERT_HEAD(&s_cmd_list, item, next);
} else { } else {
cmd_item_t *it; cmd_item_t* it;
while ((it = SLIST_NEXT(last, next)) != NULL) { while ((it = SLIST_NEXT(last, next)) != NULL) {
last = it; last = it;
} }
@ -143,7 +133,7 @@ void esp_console_get_completion(const char *buf, linenoiseCompletions *lc)
if (len == 0) { if (len == 0) {
return; return;
} }
cmd_item_t *it; cmd_item_t* it;
SLIST_FOREACH(it, &s_cmd_list, next) { SLIST_FOREACH(it, &s_cmd_list, next) {
/* Check if command starts with buf */ /* Check if command starts with buf */
if (strncmp(buf, it->command, len) == 0) { if (strncmp(buf, it->command, len) == 0) {
@ -152,10 +142,10 @@ void esp_console_get_completion(const char *buf, linenoiseCompletions *lc)
} }
} }
const char *esp_console_get_hint(const char *buf, int *color, int *bold) const char* esp_console_get_hint(const char *buf, int *color, int *bold)
{ {
size_t len = strlen(buf); int len = strlen(buf);
cmd_item_t *it; cmd_item_t* it;
SLIST_FOREACH(it, &s_cmd_list, next) { SLIST_FOREACH(it, &s_cmd_list, next) {
if (strlen(it->command) == len && if (strlen(it->command) == len &&
strncmp(buf, it->command, len) == 0) { strncmp(buf, it->command, len) == 0) {
@ -167,14 +157,12 @@ const char *esp_console_get_hint(const char *buf, int *color, int *bold)
return NULL; return NULL;
} }
static const cmd_item_t *find_command_by_name(const char *name) static const cmd_item_t* find_command_by_name(const char* name)
{ {
const cmd_item_t *cmd = NULL; const cmd_item_t* cmd = NULL;
cmd_item_t *it; cmd_item_t* it;
size_t len = strlen(name);
SLIST_FOREACH(it, &s_cmd_list, next) { SLIST_FOREACH(it, &s_cmd_list, next) {
if (strlen(it->command) == len && if (strcmp(name, it->command) == 0) {
strcmp(name, it->command) == 0) {
cmd = it; cmd = it;
break; break;
} }
@ -182,26 +170,22 @@ static const cmd_item_t *find_command_by_name(const char *name)
return cmd; return cmd;
} }
esp_err_t esp_console_run(const char *cmdline, int *cmd_ret) esp_err_t esp_console_run(const char* cmdline, int* cmd_ret)
{ {
if (s_tmp_line_buf == NULL) { if (s_tmp_line_buf == NULL) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
char **argv = (char **) calloc(s_config.max_cmdline_args, sizeof(char *)); char** argv = (char**) calloc(s_config.max_cmdline_args, sizeof(char*));
if (argv == NULL) { if (argv == NULL) {
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
strlcpy(s_tmp_line_buf, cmdline, s_config.max_cmdline_length); strlcpy(s_tmp_line_buf, cmdline, s_config.max_cmdline_length);
size_t argc = esp_console_split_argv(s_tmp_line_buf, argv, size_t argc = esp_console_split_argv(s_tmp_line_buf, argv,
s_config.max_cmdline_args); s_config.max_cmdline_args);
if (argc == 0) {
free(argv); const cmd_item_t* cmd = find_command_by_name(argv[0]);
return ESP_ERR_INVALID_ARG;
}
const cmd_item_t *cmd = find_command_by_name(argv[0]);
if (cmd == NULL) { if (cmd == NULL) {
free(argv);
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
*cmd_ret = (*cmd->func)(argc, argv); *cmd_ret = (*cmd->func)(argc, argv);
@ -209,9 +193,9 @@ esp_err_t esp_console_run(const char *cmdline, int *cmd_ret)
return ESP_OK; return ESP_OK;
} }
static int help_command(int argc, char **argv) static int help_command(int argc, char** argv)
{ {
cmd_item_t *it; cmd_item_t* it;
/* Print summary of each command */ /* Print summary of each command */
SLIST_FOREACH(it, &s_cmd_list, next) { SLIST_FOREACH(it, &s_cmd_list, next) {
@ -221,7 +205,7 @@ static int help_command(int argc, char **argv)
/* First line: command name and hint /* First line: command name and hint
* Pad all the hints to the same column * Pad all the hints to the same column
*/ */
const char *hint = (it->hint) ? it->hint : ""; const char* hint = (it->hint) ? it->hint : "";
printf("%-s %s\n", it->command, hint); printf("%-s %s\n", it->command, hint);
/* Second line: print help. /* Second line: print help.
* Argtable has a nice helper function for this which does line * Argtable has a nice helper function for this which does line
@ -231,19 +215,20 @@ static int help_command(int argc, char **argv)
arg_print_formatted(stdout, 2, 78, it->help); arg_print_formatted(stdout, 2, 78, it->help);
/* Finally, print the list of arguments */ /* Finally, print the list of arguments */
if (it->argtable) { if (it->argtable) {
arg_print_glossary(stdout, (void **) it->argtable, " %12s %s\n"); arg_print_glossary(stdout, (void**) it->argtable, " %12s %s\n");
} }
printf("\n"); printf("\n");
} }
return 0; return 0;
} }
esp_err_t esp_console_register_help_command(void)
esp_err_t esp_console_register_help_command()
{ {
esp_console_cmd_t command = { esp_console_cmd_t command = {
.command = "help", .command = "help",
.help = "Print the list of registered commands", .help = "Print the list of registered commands",
.func = &help_command .func = &help_command
}; };
return esp_console_cmd_register(&command); return esp_console_cmd_register(&command);
} }

View file

@ -0,0 +1,2 @@
COMPONENT_ADD_INCLUDEDIRS := .
COMPONENT_SRCDIRS := linenoise argtable3 .

View file

@ -1,16 +1,19 @@
/* // Copyright 2016-2017 Espressif Systems (Shanghai) PTE LTD
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD //
* // Licensed under the Apache License, Version 2.0 (the "License");
* SPDX-License-Identifier: Apache-2.0 // you may not use this file except in compliance with the License.
*/ // You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h> #include <stddef.h>
#include "sdkconfig.h"
#include "esp_err.h" #include "esp_err.h"
// Forward declaration. Definition in linenoise/linenoise.h. // Forward declaration. Definition in linenoise/linenoise.h.
@ -22,128 +25,30 @@ typedef struct linenoiseCompletions linenoiseCompletions;
typedef struct { typedef struct {
size_t max_cmdline_length; //!< length of command line buffer, in bytes size_t max_cmdline_length; //!< length of command line buffer, in bytes
size_t max_cmdline_args; //!< maximum number of command line arguments to parse size_t max_cmdline_args; //!< maximum number of command line arguments to parse
int hint_color; //!< ASCII color code of hint text int hint_color; //!< ASCII color code of hint text
int hint_bold; //!< Set to 1 to print hint text in bold int hint_bold; //!< Set to 1 to print hint text in bold
} esp_console_config_t; } esp_console_config_t;
/**
* @brief Default console configuration value
*
*/
#define ESP_CONSOLE_CONFIG_DEFAULT() \
{ \
.max_cmdline_length = 256, \
.max_cmdline_args = 32, \
.hint_color = 39, \
.hint_bold = 0 \
}
/**
* @brief Parameters for console REPL (Read Eval Print Loop)
*
*/
typedef struct {
uint32_t max_history_len; //!< maximum length for the history
const char *history_save_path; //!< file path used to save history commands, set to NULL won't save to file system
uint32_t task_stack_size; //!< repl task stack size
uint32_t task_priority; //!< repl task priority
const char *prompt; //!< prompt (NULL represents default: "esp> ")
size_t max_cmdline_length; //!< maximum length of a command line. If 0, default value will be used
} esp_console_repl_config_t;
/**
* @brief Default console repl configuration value
*
*/
#define ESP_CONSOLE_REPL_CONFIG_DEFAULT() \
{ \
.max_history_len = 32, \
.history_save_path = NULL, \
.task_stack_size = 4096, \
.task_priority = 2, \
.prompt = NULL, \
.max_cmdline_length = 0, \
}
#if CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
/**
* @brief Parameters for console device: UART
*
*/
typedef struct {
int channel; //!< UART channel number (count from zero)
int baud_rate; //!< Comunication baud rate
int tx_gpio_num; //!< GPIO number for TX path, -1 means using default one
int rx_gpio_num; //!< GPIO number for RX path, -1 means using default one
} esp_console_dev_uart_config_t;
#if CONFIG_ESP_CONSOLE_UART_CUSTOM
#define ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT() \
{ \
.channel = CONFIG_ESP_CONSOLE_UART_NUM, \
.baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE, \
.tx_gpio_num = CONFIG_ESP_CONSOLE_UART_TX_GPIO, \
.rx_gpio_num = CONFIG_ESP_CONSOLE_UART_RX_GPIO, \
}
#else
#define ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT() \
{ \
.channel = CONFIG_ESP_CONSOLE_UART_NUM, \
.baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE, \
.tx_gpio_num = -1, \
.rx_gpio_num = -1, \
}
#endif // CONFIG_ESP_CONSOLE_UART_CUSTOM
#endif // CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
#if CONFIG_ESP_CONSOLE_USB_CDC || (defined __DOXYGEN__ && SOC_USB_OTG_SUPPORTED)
/**
* @brief Parameters for console device: USB CDC
*
* @note It's an empty structure for now, reserved for future
*
*/
typedef struct {
} esp_console_dev_usb_cdc_config_t;
#define ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT() {}
#endif // CONFIG_ESP_CONSOLE_USB_CDC || (defined __DOXYGEN__ && SOC_USB_OTG_SUPPORTED)
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG || (defined __DOXYGEN__ && SOC_USB_SERIAL_JTAG_SUPPORTED)
/**
* @brief Parameters for console device: USB-SERIAL-JTAG
*
* @note It's an empty structure for now, reserved for future
*
*/
typedef struct {
} esp_console_dev_usb_serial_jtag_config_t;
#define ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT() {}
#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG || (defined __DOXYGEN__ && SOC_USB_SERIAL_JTAG_SUPPORTED)
/** /**
* @brief initialize console module * @brief initialize console module
* @param config console configuration * Call this once before using other console module features
* @note Call this once before using other console module features
* @return * @return
* - ESP_OK on success * - ESP_OK on success
* - ESP_ERR_NO_MEM if out of memory * - ESP_ERR_NO_MEM if out of memory
* - ESP_ERR_INVALID_STATE if already initialized * - ESP_ERR_INVALID_STATE if already initialized
* - ESP_ERR_INVALID_ARG if the configuration is invalid
*/ */
esp_err_t esp_console_init(const esp_console_config_t *config); esp_err_t esp_console_init(const esp_console_config_t* config);
/** /**
* @brief de-initialize console module * @brief de-initialize console module
* @note Call this once when done using console module functions * Call this once when done using console module functions
* @return * @return
* - ESP_OK on success * - ESP_OK on success
* - ESP_ERR_INVALID_STATE if not initialized yet * - ESP_ERR_INVALID_STATE if not initialized yet
*/ */
esp_err_t esp_console_deinit(void); esp_err_t esp_console_deinit();
/** /**
* @brief Console command main function * @brief Console command main function
@ -151,7 +56,7 @@ esp_err_t esp_console_deinit(void);
* @param argv array with argc entries, each pointing to a zero-terminated string argument * @param argv array with argc entries, each pointing to a zero-terminated string argument
* @return console command return code, 0 indicates "success" * @return console command return code, 0 indicates "success"
*/ */
typedef int (*esp_console_cmd_func_t)(int argc, char **argv); typedef int (*esp_console_cmd_func_t)(int argc, char** argv);
/** /**
* @brief Console command description * @brief Console command description
@ -161,19 +66,19 @@ typedef struct {
* Command name. Must not be NULL, must not contain spaces. * Command name. Must not be NULL, must not contain spaces.
* The pointer must be valid until the call to esp_console_deinit. * The pointer must be valid until the call to esp_console_deinit.
*/ */
const char *command; const char* command; //!< command name
/** /**
* Help text for the command, shown by help command. * Help text for the command, shown by help command.
* If set, the pointer must be valid until the call to esp_console_deinit. * If set, the pointer must be valid until the call to esp_console_deinit.
* If not set, the command will not be listed in 'help' output. * If not set, the command will not be listed in 'help' output.
*/ */
const char *help; const char* help;
/** /**
* Hint text, usually lists possible arguments. * Hint text, usually lists possible arguments.
* If set to NULL, and 'argtable' field is non-NULL, hint will be generated * If set to NULL, and 'argtable' field is non-NULL, hint will be generated
* automatically * automatically
*/ */
const char *hint; const char* hint;
/** /**
* Pointer to a function which implements the command. * Pointer to a function which implements the command.
*/ */
@ -184,7 +89,7 @@ typedef struct {
* Array/structure which this field points to must end with an arg_end. * Array/structure which this field points to must end with an arg_end.
* Only used for the duration of esp_console_cmd_register call. * Only used for the duration of esp_console_cmd_register call.
*/ */
void *argtable; void* argtable;
} esp_console_cmd_t; } esp_console_cmd_t;
/** /**
@ -193,7 +98,6 @@ typedef struct {
* @return * @return
* - ESP_OK on success * - ESP_OK on success
* - ESP_ERR_NO_MEM if out of memory * - ESP_ERR_NO_MEM if out of memory
* - ESP_ERR_INVALID_ARG if command description includes invalid arguments
*/ */
esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd); esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd);
@ -203,16 +107,14 @@ esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd);
* @param[out] cmd_ret return code from the command (set if command was run) * @param[out] cmd_ret return code from the command (set if command was run)
* @return * @return
* - ESP_OK, if command was run * - ESP_OK, if command was run
* - ESP_ERR_INVALID_ARG, if the command line is empty, or only contained
* whitespace
* - ESP_ERR_NOT_FOUND, if command with given name wasn't registered * - ESP_ERR_NOT_FOUND, if command with given name wasn't registered
* - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called * - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called
*/ */
esp_err_t esp_console_run(const char *cmdline, int *cmd_ret); esp_err_t esp_console_run(const char* cmdline, int* cmd_ret);
/** /**
* @brief Split command line into arguments in place * @brief Split command line into arguments in place
* @verbatim *
* - This function finds whitespace-separated arguments in the given input line. * - This function finds whitespace-separated arguments in the given input line.
* *
* 'abc def 1 20 .3' -> [ 'abc', 'def', '1', '20', '.3' ] * 'abc def 1 20 .3' -> [ 'abc', 'def', '1', '20', '.3' ]
@ -225,9 +127,9 @@ esp_err_t esp_console_run(const char *cmdline, int *cmd_ret);
* - Escape sequences may be used to produce backslash, double quote, and space: * - Escape sequences may be used to produce backslash, double quote, and space:
* *
* 'a\ b\\c\"' -> [ 'a b\c"' ] * 'a\ b\\c\"' -> [ 'a b\c"' ]
* @endverbatim *
* @note Pointers to at most argv_size - 1 arguments are returned in argv array. * Pointers to at most argv_size - 1 arguments are returned in argv array.
* The pointer after the last one (i.e. argv[argc]) is set to NULL. * The pointer after the last one (i.e. argv[argc]) is set to NULL.
* *
* @param line pointer to buffer to parse; it is modified in place * @param line pointer to buffer to parse; it is modified in place
* @param argv array where the pointers to arguments are written * @param argv array where the pointers to arguments are written
@ -270,122 +172,10 @@ const char *esp_console_get_hint(const char *buf, int *color, int *bold);
/** /**
* @brief Register a 'help' command * @brief Register a 'help' command
*
* Default 'help' command prints the list of registered commands along with * Default 'help' command prints the list of registered commands along with
* hints and help strings. * hints and help strings.
*
* @return * @return
* - ESP_OK on success * - ESP_OK on success
* - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called * - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called
*/ */
esp_err_t esp_console_register_help_command(void); esp_err_t esp_console_register_help_command();
/******************************************************************************
* Console REPL
******************************************************************************/
/**
* @brief Type defined for console REPL
*
*/
typedef struct esp_console_repl_s esp_console_repl_t;
/**
* @brief Console REPL base structure
*
*/
struct esp_console_repl_s {
/**
* @brief Delete console REPL environment
* @param[in] repl REPL handle returned from esp_console_new_repl_xxx
* @return
* - ESP_OK on success
* - ESP_FAIL on errors
*/
esp_err_t (*del)(esp_console_repl_t *repl);
};
#if CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
/**
* @brief Establish a console REPL environment over UART driver
*
* @param[in] dev_config UART device configuration
* @param[in] repl_config REPL configuration
* @param[out] ret_repl return REPL handle after initialization succeed, return NULL otherwise
*
* @note This is an all-in-one function to establish the environment needed for REPL, includes:
* - Install the UART driver on the console UART (8n1, 115200, REF_TICK clock source)
* - Configures the stdin/stdout to go through the UART driver
* - Initializes linenoise
* - Spawn new thread to run REPL in the background
*
* @attention This function is meant to be used in the examples to make the code more compact.
* Applications which use console functionality should be based on
* the underlying linenoise and esp_console functions.
*
* @return
* - ESP_OK on success
* - ESP_FAIL Parameter error
*/
esp_err_t esp_console_new_repl_uart(const esp_console_dev_uart_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl);
#endif // CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
#if CONFIG_ESP_CONSOLE_USB_CDC || (defined __DOXYGEN__ && SOC_USB_OTG_SUPPORTED)
/**
* @brief Establish a console REPL environment over USB CDC
*
* @param[in] dev_config USB CDC configuration
* @param[in] repl_config REPL configuration
* @param[out] ret_repl return REPL handle after initialization succeed, return NULL otherwise
*
* @note This is a all-in-one function to establish the environment needed for REPL, includes:
* - Initializes linenoise
* - Spawn new thread to run REPL in the background
*
* @attention This function is meant to be used in the examples to make the code more compact.
* Applications which use console functionality should be based on
* the underlying linenoise and esp_console functions.
*
* @return
* - ESP_OK on success
* - ESP_FAIL Parameter error
*/
esp_err_t esp_console_new_repl_usb_cdc(const esp_console_dev_usb_cdc_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl);
#endif // CONFIG_ESP_CONSOLE_USB_CDC || (defined __DOXYGEN__ && SOC_USB_OTG_SUPPORTED)
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG || (defined __DOXYGEN__ && SOC_USB_SERIAL_JTAG_SUPPORTED)
/**
* @brief Establish a console REPL (Read-eval-print loop) environment over USB-SERIAL-JTAG
*
* @param[in] dev_config USB-SERIAL-JTAG configuration
* @param[in] repl_config REPL configuration
* @param[out] ret_repl return REPL handle after initialization succeed, return NULL otherwise
*
* @note This is an all-in-one function to establish the environment needed for REPL, includes:
* - Initializes linenoise
* - Spawn new thread to run REPL in the background
*
* @attention This function is meant to be used in the examples to make the code more compact.
* Applications which use console functionality should be based on
* the underlying linenoise and esp_console functions.
*
* @return
* - ESP_OK on success
* - ESP_FAIL Parameter error
*/
esp_err_t esp_console_new_repl_usb_serial_jtag(const esp_console_dev_usb_serial_jtag_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl);
#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG || (defined __DOXYGEN__ && SOC_USB_SERIAL_JTAG_SUPPORTED)
/**
* @brief Start REPL environment
* @param[in] repl REPL handle returned from esp_console_new_repl_xxx
* @note Once the REPL gets started, it won't be stopped until the user calls repl->del(repl) to destroy the REPL environment.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE, if repl has started already
*/
esp_err_t esp_console_start_repl(esp_console_repl_t *repl);
#ifdef __cplusplus
}
#endif

View file

@ -1,552 +0,0 @@
/*
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/cdefs.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_vfs_dev.h"
#include "esp_vfs_cdcacm.h"
#include "esp_vfs_usb_serial_jtag.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/usb_serial_jtag.h"
#include "linenoise/linenoise.h"
static const char *TAG = "console.repl";
#define CONSOLE_PROMPT_MAX_LEN (32)
#define CONSOLE_PATH_MAX_LEN (ESP_VFS_PATH_MAX)
typedef enum {
CONSOLE_REPL_STATE_DEINIT,
CONSOLE_REPL_STATE_INIT,
CONSOLE_REPL_STATE_START,
} repl_state_t;
typedef struct {
esp_console_repl_t repl_core; // base class
char prompt[CONSOLE_PROMPT_MAX_LEN]; // Prompt to be printed before each line
repl_state_t state;
const char *history_save_path;
TaskHandle_t task_hdl; // REPL task handle
size_t max_cmdline_length; // Maximum length of a command line. If 0, default value will be used.
} esp_console_repl_com_t;
typedef struct {
esp_console_repl_com_t repl_com; // base class
int uart_channel; // uart channel number
} esp_console_repl_universal_t;
static void esp_console_repl_task(void *args);
#if CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
static esp_err_t esp_console_repl_uart_delete(esp_console_repl_t *repl);
#endif // CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
#if CONFIG_ESP_CONSOLE_USB_CDC
static esp_err_t esp_console_repl_usb_cdc_delete(esp_console_repl_t *repl);
#endif // CONFIG_ESP_CONSOLE_USB_CDC
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
static esp_err_t esp_console_repl_usb_serial_jtag_delete(esp_console_repl_t *repl);
#endif //CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
static esp_err_t esp_console_common_init(size_t max_cmdline_length, esp_console_repl_com_t *repl_com);
static esp_err_t esp_console_setup_prompt(const char *prompt, esp_console_repl_com_t *repl_com);
static esp_err_t esp_console_setup_history(const char *history_path, uint32_t max_history_len, esp_console_repl_com_t *repl_com);
#if CONFIG_ESP_CONSOLE_USB_CDC
esp_err_t esp_console_new_repl_usb_cdc(const esp_console_dev_usb_cdc_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl)
{
esp_err_t ret = ESP_OK;
esp_console_repl_universal_t *cdc_repl = NULL;
if (!repl_config | !dev_config | !ret_repl) {
ret = ESP_ERR_INVALID_ARG;
goto _exit;
}
// allocate memory for console REPL context
cdc_repl = calloc(1, sizeof(esp_console_repl_universal_t));
if (!cdc_repl) {
ret = ESP_ERR_NO_MEM;
goto _exit;
}
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_cdcacm_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_cdcacm_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Enable non-blocking mode on stdin and stdout */
fcntl(fileno(stdout), F_SETFL, 0);
fcntl(fileno(stdin), F_SETFL, 0);
// initialize console, common part
ret = esp_console_common_init(repl_config->max_cmdline_length, &cdc_repl->repl_com);
if (ret != ESP_OK) {
goto _exit;
}
// setup history
ret = esp_console_setup_history(repl_config->history_save_path, repl_config->max_history_len, &cdc_repl->repl_com);
if (ret != ESP_OK) {
goto _exit;
}
// setup prompt
esp_console_setup_prompt(repl_config->prompt, &cdc_repl->repl_com);
/* Fill the structure here as it will be used directly by the created task. */
cdc_repl->uart_channel = CONFIG_ESP_CONSOLE_UART_NUM;
cdc_repl->repl_com.state = CONSOLE_REPL_STATE_INIT;
cdc_repl->repl_com.repl_core.del = esp_console_repl_usb_cdc_delete;
/* spawn a single thread to run REPL */
if (xTaskCreate(esp_console_repl_task, "console_repl", repl_config->task_stack_size,
cdc_repl, repl_config->task_priority, &cdc_repl->repl_com.task_hdl) != pdTRUE) {
ret = ESP_FAIL;
goto _exit;
}
*ret_repl = &cdc_repl->repl_com.repl_core;
return ESP_OK;
_exit:
if (cdc_repl) {
esp_console_deinit();
free(cdc_repl);
}
if (ret_repl) {
*ret_repl = NULL;
}
return ret;
}
#endif // CONFIG_ESP_CONSOLE_USB_CDC
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
esp_err_t esp_console_new_repl_usb_serial_jtag(const esp_console_dev_usb_serial_jtag_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl)
{
esp_console_repl_universal_t *usb_serial_jtag_repl = NULL;
if (!repl_config | !dev_config | !ret_repl) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = ESP_OK;
// allocate memory for console REPL context
usb_serial_jtag_repl = calloc(1, sizeof(esp_console_repl_universal_t));
if (!usb_serial_jtag_repl) {
ret = ESP_ERR_NO_MEM;
goto _exit;
}
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_usb_serial_jtag_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Enable non-blocking mode on stdin and stdout */
fcntl(fileno(stdout), F_SETFL, 0);
fcntl(fileno(stdin), F_SETFL, 0);
usb_serial_jtag_driver_config_t usb_serial_jtag_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();
/* Install USB-SERIAL-JTAG driver for interrupt-driven reads and writes */
ret = usb_serial_jtag_driver_install(&usb_serial_jtag_config);
if (ret != ESP_OK) {
goto _exit;
}
// initialize console, common part
ret = esp_console_common_init(repl_config->max_cmdline_length, &usb_serial_jtag_repl->repl_com);
if (ret != ESP_OK) {
goto _exit;
}
/* Tell vfs to use usb-serial-jtag driver */
esp_vfs_usb_serial_jtag_use_driver();
// setup history
ret = esp_console_setup_history(repl_config->history_save_path, repl_config->max_history_len, &usb_serial_jtag_repl->repl_com);
if (ret != ESP_OK) {
goto _exit;
}
// setup prompt
esp_console_setup_prompt(repl_config->prompt, &usb_serial_jtag_repl->repl_com);
/* Fill the structure here as it will be used directly by the created task. */
usb_serial_jtag_repl->uart_channel = CONFIG_ESP_CONSOLE_UART_NUM;
usb_serial_jtag_repl->repl_com.state = CONSOLE_REPL_STATE_INIT;
usb_serial_jtag_repl->repl_com.repl_core.del = esp_console_repl_usb_serial_jtag_delete;
/* spawn a single thread to run REPL */
if (xTaskCreate(esp_console_repl_task, "console_repl", repl_config->task_stack_size,
usb_serial_jtag_repl, repl_config->task_priority, &usb_serial_jtag_repl->repl_com.task_hdl) != pdTRUE) {
ret = ESP_FAIL;
goto _exit;
}
*ret_repl = &usb_serial_jtag_repl->repl_com.repl_core;
return ESP_OK;
_exit:
if (usb_serial_jtag_repl) {
esp_console_deinit();
free(usb_serial_jtag_repl);
}
if (ret_repl) {
*ret_repl = NULL;
}
return ret;
}
#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
#if CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
esp_err_t esp_console_new_repl_uart(const esp_console_dev_uart_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl)
{
esp_err_t ret = ESP_OK;
esp_console_repl_universal_t *uart_repl = NULL;
if (!repl_config | !dev_config | !ret_repl) {
ret = ESP_ERR_INVALID_ARG;
goto _exit;
}
// allocate memory for console REPL context
uart_repl = calloc(1, sizeof(esp_console_repl_universal_t));
if (!uart_repl) {
ret = ESP_ERR_NO_MEM;
goto _exit;
}
/* Drain stdout before reconfiguring it */
fflush(stdout);
fsync(fileno(stdout));
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_port_set_rx_line_endings(dev_config->channel, ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_port_set_tx_line_endings(dev_config->channel, ESP_LINE_ENDINGS_CRLF);
/* Configure UART. Note that REF_TICK/XTAL is used so that the baud rate remains
* correct while APB frequency is changing in light sleep mode.
*/
#if SOC_UART_SUPPORT_REF_TICK
uart_sclk_t clk_source = UART_SCLK_REF_TICK;
// REF_TICK clock can't provide a high baudrate
if (dev_config->baud_rate > 1 * 1000 * 1000) {
clk_source = UART_SCLK_DEFAULT;
ESP_LOGW(TAG, "light sleep UART wakeup might not work at the configured baud rate");
}
#elif SOC_UART_SUPPORT_XTAL_CLK
uart_sclk_t clk_source = UART_SCLK_XTAL;
#else
#error "No UART clock source is aware of DFS"
#endif // SOC_UART_SUPPORT_xxx
const uart_config_t uart_config = {
.baud_rate = dev_config->baud_rate,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.source_clk = clk_source,
};
uart_param_config(dev_config->channel, &uart_config);
uart_set_pin(dev_config->channel, dev_config->tx_gpio_num, dev_config->rx_gpio_num, -1, -1);
/* Install UART driver for interrupt-driven reads and writes */
ret = uart_driver_install(dev_config->channel, 256, 0, 0, NULL, 0);
if (ret != ESP_OK) {
goto _exit;
}
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(dev_config->channel);
// initialize console, common part
ret = esp_console_common_init(repl_config->max_cmdline_length, &uart_repl->repl_com);
if (ret != ESP_OK) {
goto _exit;
}
// setup history
ret = esp_console_setup_history(repl_config->history_save_path, repl_config->max_history_len, &uart_repl->repl_com);
if (ret != ESP_OK) {
goto _exit;
}
// setup prompt
esp_console_setup_prompt(repl_config->prompt, &uart_repl->repl_com);
/* Fill the structure here as it will be used directly by the created task. */
uart_repl->uart_channel = dev_config->channel;
uart_repl->repl_com.state = CONSOLE_REPL_STATE_INIT;
uart_repl->repl_com.repl_core.del = esp_console_repl_uart_delete;
/* Spawn a single thread to run REPL, we need to pass `uart_repl` to it as
* it also requires the uart channel. */
if (xTaskCreate(esp_console_repl_task, "console_repl", repl_config->task_stack_size,
uart_repl, repl_config->task_priority, &uart_repl->repl_com.task_hdl) != pdTRUE) {
ret = ESP_FAIL;
goto _exit;
}
*ret_repl = &uart_repl->repl_com.repl_core;
return ESP_OK;
_exit:
if (uart_repl) {
esp_console_deinit();
uart_driver_delete(dev_config->channel);
free(uart_repl);
}
if (ret_repl) {
*ret_repl = NULL;
}
return ret;
}
#endif // CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
esp_err_t esp_console_start_repl(esp_console_repl_t *repl)
{
esp_err_t ret = ESP_OK;
esp_console_repl_com_t *repl_com = __containerof(repl, esp_console_repl_com_t, repl_core);
// check if already initialized
if (repl_com->state != CONSOLE_REPL_STATE_INIT) {
ret = ESP_ERR_INVALID_STATE;
goto _exit;
}
repl_com->state = CONSOLE_REPL_STATE_START;
xTaskNotifyGive(repl_com->task_hdl);
return ESP_OK;
_exit:
return ret;
}
static esp_err_t esp_console_setup_prompt(const char *prompt, esp_console_repl_com_t *repl_com)
{
/* set command line prompt */
const char *prompt_temp = "esp>";
if (prompt) {
prompt_temp = prompt;
}
snprintf(repl_com->prompt, CONSOLE_PROMPT_MAX_LEN - 1, LOG_COLOR_I "%s " LOG_RESET_COLOR, prompt_temp);
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) {
/* zero indicates success */
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the s_prompt.
*/
snprintf(repl_com->prompt, CONSOLE_PROMPT_MAX_LEN - 1, "%s ", prompt_temp);
#endif //CONFIG_LOG_COLORS
}
return ESP_OK;
}
static esp_err_t esp_console_setup_history(const char *history_path, uint32_t max_history_len, esp_console_repl_com_t *repl_com)
{
esp_err_t ret = ESP_OK;
repl_com->history_save_path = history_path;
if (history_path) {
/* Load command history from filesystem */
linenoiseHistoryLoad(history_path);
}
/* Set command history size */
if (linenoiseHistorySetMaxLen(max_history_len) != 1) {
ESP_LOGE(TAG, "set max history length to %"PRIu32" failed", max_history_len);
ret = ESP_FAIL;
goto _exit;
}
return ESP_OK;
_exit:
return ret;
}
static esp_err_t esp_console_common_init(size_t max_cmdline_length, esp_console_repl_com_t *repl_com)
{
esp_err_t ret = ESP_OK;
/* Initialize the console */
esp_console_config_t console_config = ESP_CONSOLE_CONFIG_DEFAULT();
repl_com->max_cmdline_length = console_config.max_cmdline_length;
/* Replace the default command line length if passed as a parameter */
if (max_cmdline_length != 0) {
console_config.max_cmdline_length = max_cmdline_length;
repl_com->max_cmdline_length = max_cmdline_length;
}
#if CONFIG_LOG_COLORS
console_config.hint_color = atoi(LOG_COLOR_CYAN);
#else
console_config.hint_color = -1;
#endif
ret = esp_console_init(&console_config);
if (ret != ESP_OK) {
goto _exit;
}
ret = esp_console_register_help_command();
if (ret != ESP_OK) {
goto _exit;
}
/* Configure linenoise line completion library */
/* Enable multiline editing. If not set, long commands will scroll within single line */
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint);
return ESP_OK;
_exit:
return ret;
}
#if CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
static esp_err_t esp_console_repl_uart_delete(esp_console_repl_t *repl)
{
esp_err_t ret = ESP_OK;
esp_console_repl_com_t *repl_com = __containerof(repl, esp_console_repl_com_t, repl_core);
esp_console_repl_universal_t *uart_repl = __containerof(repl_com, esp_console_repl_universal_t, repl_com);
// check if already de-initialized
if (repl_com->state == CONSOLE_REPL_STATE_DEINIT) {
ESP_LOGE(TAG, "already de-initialized");
ret = ESP_ERR_INVALID_STATE;
goto _exit;
}
repl_com->state = CONSOLE_REPL_STATE_DEINIT;
esp_console_deinit();
esp_vfs_dev_uart_use_nonblocking(uart_repl->uart_channel);
uart_driver_delete(uart_repl->uart_channel);
free(uart_repl);
_exit:
return ret;
}
#endif // CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
#if CONFIG_ESP_CONSOLE_USB_CDC
static esp_err_t esp_console_repl_usb_cdc_delete(esp_console_repl_t *repl)
{
esp_err_t ret = ESP_OK;
esp_console_repl_com_t *repl_com = __containerof(repl, esp_console_repl_com_t, repl_core);
esp_console_repl_universal_t *cdc_repl = __containerof(repl_com, esp_console_repl_universal_t, repl_com);
// check if already de-initialized
if (repl_com->state == CONSOLE_REPL_STATE_DEINIT) {
ESP_LOGE(TAG, "already de-initialized");
ret = ESP_ERR_INVALID_STATE;
goto _exit;
}
repl_com->state = CONSOLE_REPL_STATE_DEINIT;
esp_console_deinit();
free(cdc_repl);
_exit:
return ret;
}
#endif // CONFIG_ESP_CONSOLE_USB_CDC
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
static esp_err_t esp_console_repl_usb_serial_jtag_delete(esp_console_repl_t *repl)
{
esp_err_t ret = ESP_OK;
esp_console_repl_com_t *repl_com = __containerof(repl, esp_console_repl_com_t, repl_core);
esp_console_repl_universal_t *usb_serial_jtag_repl = __containerof(repl_com, esp_console_repl_universal_t, repl_com);
// check if already de-initialized
if (repl_com->state == CONSOLE_REPL_STATE_DEINIT) {
ESP_LOGE(TAG, "already de-initialized");
ret = ESP_ERR_INVALID_STATE;
goto _exit;
}
repl_com->state = CONSOLE_REPL_STATE_DEINIT;
esp_console_deinit();
esp_vfs_usb_serial_jtag_use_nonblocking();
usb_serial_jtag_driver_uninstall();
free(usb_serial_jtag_repl);
_exit:
return ret;
}
#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
static void esp_console_repl_task(void *args)
{
esp_console_repl_universal_t *repl_conf = (esp_console_repl_universal_t *) args;
esp_console_repl_com_t *repl_com = &repl_conf->repl_com;
const int uart_channel = repl_conf->uart_channel;
/* Waiting for task notify. This happens when `esp_console_start_repl()`
* function is called. */
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
/* Change standard input and output of the task if the requested UART is
* NOT the default one. This block will replace stdin, stdout and stderr.
*/
if (uart_channel != CONFIG_ESP_CONSOLE_UART_NUM) {
char path[CONSOLE_PATH_MAX_LEN] = { 0 };
snprintf(path, CONSOLE_PATH_MAX_LEN, "/dev/uart/%d", uart_channel);
stdin = fopen(path, "r");
stdout = fopen(path, "w");
stderr = stdout;
}
/* Disable buffering on stdin of the current task.
* If the console is ran on a different UART than the default one,
* buffering shall only be disabled for the current one. */
setvbuf(stdin, NULL, _IONBF, 0);
/* This message shall be printed here and not earlier as the stdout
* has just been set above. */
printf("\r\n"
"Type 'help' to get the list of commands.\r\n"
"Use UP/DOWN arrows to navigate through command history.\r\n"
"Press TAB when typing command name to auto-complete.\r\n");
if (linenoiseIsDumbMode()) {
printf("\r\n"
"Your terminal application does not support escape sequences.\n\n"
"Line editing and history features are disabled.\n\n"
"On Windows, try using Putty instead.\r\n");
}
linenoiseSetMaxLineLen(repl_com->max_cmdline_length);
while (repl_com->state == CONSOLE_REPL_STATE_START) {
char *line = linenoise(repl_com->prompt);
if (line == NULL) {
ESP_LOGD(TAG, "empty line");
/* Ignore empty lines */
continue;
}
/* Add the command to the history */
linenoiseHistoryAdd(line);
/* Save command history to filesystem */
if (repl_com->history_save_path) {
linenoiseHistorySave(repl_com->history_save_path);
}
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
printf("Unrecognized command\n");
} else if (err == ESP_ERR_INVALID_ARG) {
// command was empty
} else if (err == ESP_OK && ret != ESP_OK) {
printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret));
} else if (err != ESP_OK) {
printf("Internal error: %s\n", esp_err_to_name(err));
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
ESP_LOGD(TAG, "The End");
vTaskDelete(NULL);
}

View file

@ -106,35 +106,26 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdio_ext.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include "linenoise.h" #include "linenoise.h"
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
#define LINENOISE_DEFAULT_MAX_LINE 4096 #define LINENOISE_MAX_LINE 4096
#define LINENOISE_MINIMAL_MAX_LINE 64
#define LINENOISE_COMMAND_MAX_LEN 32
#define LINENOISE_PASTE_KEY_DELAY 30 /* Delay, in milliseconds, between two characters being pasted from clipboard */
static linenoiseCompletionCallback *completionCallback = NULL; static linenoiseCompletionCallback *completionCallback = NULL;
static linenoiseHintsCallback *hintsCallback = NULL; static linenoiseHintsCallback *hintsCallback = NULL;
static linenoiseFreeHintsCallback *freeHintsCallback = NULL; static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
static size_t max_cmdline_length = LINENOISE_DEFAULT_MAX_LINE;
static int mlmode = 0; /* Multi line mode. Default is single line. */ static int mlmode = 0; /* Multi line mode. Default is single line. */
static int dumbmode = 0; /* Dumb mode where line editing is disabled. Off by default */
static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
static int history_len = 0; static int history_len = 0;
static char **history = NULL; static char **history = NULL;
static bool allow_empty = true;
/* The linenoiseState structure represents the state during line editing. /* The linenoiseState structure represents the state during line editing.
* We pass this state to functions implementing specific editing * We pass this state to functions implementing specific editing
@ -203,130 +194,50 @@ void linenoiseSetMultiLine(int ml) {
mlmode = ml; mlmode = ml;
} }
/* Set if terminal does not recognize escape sequences */
void linenoiseSetDumbMode(int set) {
dumbmode = set;
}
/* Returns whether the current mode is dumbmode or not. */
bool linenoiseIsDumbMode(void) {
return dumbmode;
}
static void flushWrite(void) {
if (__fbufsize(stdout) > 0) {
fflush(stdout);
}
fsync(fileno(stdout));
}
/* Use the ESC [6n escape sequence to query the horizontal cursor position /* Use the ESC [6n escape sequence to query the horizontal cursor position
* and return it. On error -1 is returned, on success the position of the * and return it. On error -1 is returned, on success the position of the
* cursor. */ * cursor. */
static int getCursorPosition(void) { static int getCursorPosition() {
char buf[LINENOISE_COMMAND_MAX_LEN] = { 0 }; char buf[32];
int cols = 0; int cols, rows;
int rows = 0; unsigned int i = 0;
int i = 0;
const int out_fd = fileno(stdout);
const int in_fd = fileno(stdin);
/* The following ANSI escape sequence is used to get from the TTY the
* cursor position. */
const char get_cursor_cmd[] = "\x1b[6n";
/* Send the command to the TTY on the other end of the UART. /* Report cursor location */
* Let's use unistd's write function. Thus, data sent through it are raw fprintf(stdout, "\x1b[6n");
* reducing the overhead compared to using fputs, fprintf, etc... */ /* Read the response: ESC [ rows ; cols R */
write(out_fd, get_cursor_cmd, sizeof(get_cursor_cmd));
/* For USB CDC, it is required to flush the output. */
flushWrite();
/* The other end will send its response which format is ESC [ rows ; cols R
* We don't know exactly how many bytes we have to read, thus, perform a
* read for each byte.
* Stop right before the last character of the buffer, to be able to NULL
* terminate it. */
while (i < sizeof(buf)-1) { while (i < sizeof(buf)-1) {
/* Keep using unistd's functions. Here, using `read` instead of `fgets` if (fread(buf+i, 1, 1, stdin) != 1) break;
* or `fgets` guarantees us that we we can read a byte regardless on if (buf[i] == 'R') break;
* whether the sender sent end of line character(s) (CR, CRLF, LF). */ i++;
if (read(in_fd, buf + i, 1) != 1 || buf[i] == 'R') {
/* If we couldn't read a byte from STDIN or if 'R' was received,
* the transmission is finished. */
break;
}
/* For some reasons, it is possible that we receive new line character
* after querying the cursor position on some UART. Let's ignore them,
* this will not affect the rest of the program. */
if (buf[i] != '\n') {
i++;
}
} }
/* NULL-terminate the buffer, this is required by `sscanf`. */
buf[i] = '\0'; buf[i] = '\0';
/* Parse it. */
/* Parse the received data to get the position of the cursor. */ if (buf[0] != ESC || buf[1] != '[') return -1;
if (buf[0] != ESC || buf[1] != '[' || sscanf(buf+2,"%d;%d",&rows,&cols) != 2) { if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
return -1;
}
return cols; return cols;
} }
/* Try to get the number of columns in the current terminal, or assume 80 /* Try to get the number of columns in the current terminal, or assume 80
* if it fails. */ * if it fails. */
static int getColumns(void) { static int getColumns() {
int start = 0; int start, cols;
int cols = 0;
int written = 0;
char seq[LINENOISE_COMMAND_MAX_LEN] = { 0 };
const int fd = fileno(stdout);
/* The following ANSI escape sequence is used to tell the TTY to move
* the cursor to the most-right position. */
const char move_cursor_right[] = "\x1b[999C";
const size_t cmd_len = sizeof(move_cursor_right);
/* This one is used to set the cursor position. */
const char set_cursor_pos[] = "\x1b[%dD";
/* Get the initial position so we can restore it later. */ /* Get the initial position so we can restore it later. */
start = getCursorPosition(); start = getCursorPosition();
if (start == -1) { if (start == -1) goto failed;
goto failed;
}
/* Send the command to go to right margin. Use `write` function instead of /* Go to right margin and get position. */
* `fwrite` for the same reasons explained in `getCursorPosition()` */ if (fwrite("\x1b[999C", 1, 6, stdout) != 6) goto failed;
if (write(fd, move_cursor_right, cmd_len) != cmd_len) {
goto failed;
}
flushWrite();
/* After sending this command, we can get the new position of the cursor,
* we'd get the size, in columns, of the opened TTY. */
cols = getCursorPosition(); cols = getCursorPosition();
if (cols == -1) { if (cols == -1) goto failed;
goto failed;
}
/* Restore the position of the cursor back. */ /* Restore position. */
if (cols > start) { if (cols > start) {
/* Generate the move cursor command. */ char seq[32];
written = snprintf(seq, LINENOISE_COMMAND_MAX_LEN, set_cursor_pos, cols-start); snprintf(seq,32,"\x1b[%dD",cols-start);
if (fwrite(seq, 1, strlen(seq), stdout) == -1) {
/* If `written` is equal or bigger than LINENOISE_COMMAND_MAX_LEN, it
* means that the output has been truncated because the size provided
* is too small. */
assert (written < LINENOISE_COMMAND_MAX_LEN);
/* Send the command with `write`, which is not buffered. */
if (write(fd, seq, written) == -1) {
/* Can't recover... */ /* Can't recover... */
} }
flushWrite();
} }
return cols; return cols;
@ -337,14 +248,12 @@ failed:
/* Clear the screen. Used to handle ctrl+l */ /* Clear the screen. Used to handle ctrl+l */
void linenoiseClearScreen(void) { void linenoiseClearScreen(void) {
fprintf(stdout,"\x1b[H\x1b[2J"); fprintf(stdout,"\x1b[H\x1b[2J");
flushWrite();
} }
/* Beep, used for completion when there is nothing to complete or when all /* Beep, used for completion when there is nothing to complete or when all
* the choices were already shown. */ * the choices were already shown. */
static void linenoiseBeep(void) { static void linenoiseBeep(void) {
fprintf(stdout, "\x7"); fprintf(stdout, "\x7");
flushWrite();
} }
/* ============================== Completion ================================ */ /* ============================== Completion ================================ */
@ -368,7 +277,6 @@ static int completeLine(struct linenoiseState *ls) {
linenoiseCompletions lc = { 0, NULL }; linenoiseCompletions lc = { 0, NULL };
int nread, nwritten; int nread, nwritten;
char c = 0; char c = 0;
int in_fd = fileno(stdin);
completionCallback(ls->buf,&lc); completionCallback(ls->buf,&lc);
if (lc.len == 0) { if (lc.len == 0) {
@ -391,7 +299,7 @@ static int completeLine(struct linenoiseState *ls) {
refreshLine(ls); refreshLine(ls);
} }
nread = read(in_fd, &c, 1); nread = fread(&c, 1, 1, stdin);
if (nread <= 0) { if (nread <= 0) {
freeCompletions(&lc); freeCompletions(&lc);
return -1; return -1;
@ -501,10 +409,9 @@ void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
int hintmaxlen = l->cols-(plen+l->len); int hintmaxlen = l->cols-(plen+l->len);
if (hintlen > hintmaxlen) hintlen = hintmaxlen; if (hintlen > hintmaxlen) hintlen = hintmaxlen;
if (bold == 1 && color == -1) color = 37; if (bold == 1 && color == -1) color = 37;
if (color != -1 || bold != 0) { if (color != -1 || bold != 0)
snprintf(seq,64,"\033[%d;%d;49m",bold,color); snprintf(seq,64,"\033[%d;%d;49m",bold,color);
abAppend(ab,seq,strlen(seq)); abAppend(ab,seq,strlen(seq));
}
abAppend(ab,hint,hintlen); abAppend(ab,hint,hintlen);
if (color != -1 || bold != 0) if (color != -1 || bold != 0)
abAppend(ab,"\033[0m",4); abAppend(ab,"\033[0m",4);
@ -521,7 +428,6 @@ void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
static void refreshSingleLine(struct linenoiseState *l) { static void refreshSingleLine(struct linenoiseState *l) {
char seq[64]; char seq[64];
size_t plen = l->plen; size_t plen = l->plen;
int fd = fileno(stdout);
char *buf = l->buf; char *buf = l->buf;
size_t len = l->len; size_t len = l->len;
size_t pos = l->pos; size_t pos = l->pos;
@ -551,8 +457,7 @@ static void refreshSingleLine(struct linenoiseState *l) {
/* Move cursor to original position. */ /* Move cursor to original position. */
snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen)); snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
abAppend(&ab,seq,strlen(seq)); abAppend(&ab,seq,strlen(seq));
if (write(fd, ab.b, ab.len) == -1) {} /* Can't recover from write error. */ if (fwrite(ab.b, ab.len, 1, stdout) == -1) {} /* Can't recover from write error. */
flushWrite();
abFree(&ab); abFree(&ab);
} }
@ -569,7 +474,6 @@ static void refreshMultiLine(struct linenoiseState *l) {
int col; /* colum position, zero-based. */ int col; /* colum position, zero-based. */
int old_rows = l->maxrows; int old_rows = l->maxrows;
int j; int j;
int fd = fileno(stdout);
struct abuf ab; struct abuf ab;
/* Update maxrows if needed. */ /* Update maxrows if needed. */
@ -640,8 +544,7 @@ static void refreshMultiLine(struct linenoiseState *l) {
lndebug("\n"); lndebug("\n");
l->oldpos = l->pos; l->oldpos = l->pos;
if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ if (fwrite(ab.b,ab.len,1,stdout) == -1) {} /* Can't recover from write error. */
flushWrite();
abFree(&ab); abFree(&ab);
} }
@ -658,7 +561,6 @@ static void refreshLine(struct linenoiseState *l) {
* *
* On error writing to the terminal -1 is returned, otherwise 0. */ * On error writing to the terminal -1 is returned, otherwise 0. */
int linenoiseEditInsert(struct linenoiseState *l, char c) { int linenoiseEditInsert(struct linenoiseState *l, char c) {
int fd = fileno(stdout);
if (l->len < l->buflen) { if (l->len < l->buflen) {
if (l->len == l->pos) { if (l->len == l->pos) {
l->buf[l->pos] = c; l->buf[l->pos] = c;
@ -668,10 +570,7 @@ int linenoiseEditInsert(struct linenoiseState *l, char c) {
if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) { if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
/* Avoid a full update of the line in the /* Avoid a full update of the line in the
* trivial case. */ * trivial case. */
if (write(fd, &c,1) == -1) { if (fwrite(&c,1,1,stdout) == -1) return -1;
return -1;
}
flushWrite();
} else { } else {
refreshLine(l); refreshLine(l);
} }
@ -687,21 +586,6 @@ int linenoiseEditInsert(struct linenoiseState *l, char c) {
return 0; return 0;
} }
int linenoiseInsertPastedChar(struct linenoiseState *l, char c) {
int fd = fileno(stdout);
if (l->len < l->buflen && l->len == l->pos) {
l->buf[l->pos] = c;
l->pos++;
l->len++;
l->buf[l->len] = '\0';
if (write(fd, &c,1) == -1) {
return -1;
}
flushWrite();
}
return 0;
}
/* Move cursor on the left. */ /* Move cursor on the left. */
void linenoiseEditMoveLeft(struct linenoiseState *l) { void linenoiseEditMoveLeft(struct linenoiseState *l) {
if (l->pos > 0) { if (l->pos > 0) {
@ -798,12 +682,6 @@ void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
refreshLine(l); refreshLine(l);
} }
uint32_t getMillis(void) {
struct timeval tv = { 0 };
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
/* This function is the core of the line editing capability of linenoise. /* This function is the core of the line editing capability of linenoise.
* It expects 'fd' to be already in "raw mode" so that every key pressed * It expects 'fd' to be already in "raw mode" so that every key pressed
* will be returned ASAP to read(). * will be returned ASAP to read().
@ -814,10 +692,7 @@ uint32_t getMillis(void) {
* The function returns the length of the current buffer. */ * The function returns the length of the current buffer. */
static int linenoiseEdit(char *buf, size_t buflen, const char *prompt) static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
{ {
uint32_t t1 = 0;
struct linenoiseState l; struct linenoiseState l;
int out_fd = fileno(stdout);
int in_fd = fileno(stdin);
/* Populate the linenoise state that we pass to functions implementing /* Populate the linenoise state that we pass to functions implementing
* specific editing functionalities. */ * specific editing functionalities. */
@ -840,10 +715,7 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
linenoiseHistoryAdd(""); linenoiseHistoryAdd("");
int pos1 = getCursorPosition(); int pos1 = getCursorPosition();
if (write(out_fd, prompt,l.plen) == -1) { if (fwrite(prompt,l.plen,1,stdout) == -1) return -1;
return -1;
}
flushWrite();
int pos2 = getCursorPosition(); int pos2 = getCursorPosition();
if (pos1 >= 0 && pos2 >= 0) { if (pos1 >= 0 && pos2 >= 0) {
l.plen = pos2 - pos1; l.plen = pos2 - pos1;
@ -853,29 +725,9 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
int nread; int nread;
char seq[3]; char seq[3];
/** nread = fread(&c, 1, 1, stdin);
* To determine whether the user is pasting data or typing itself, we
* need to calculate how many milliseconds elapsed between two key
* presses. Indeed, if there is less than LINENOISE_PASTE_KEY_DELAY
* (typically 30-40ms), then a paste is being performed, else, the
* user is typing.
* NOTE: pressing a key down without releasing it will also spend
* about 40ms (or even more)
*/
t1 = getMillis();
nread = read(in_fd, &c, 1);
if (nread <= 0) return l.len; if (nread <= 0) return l.len;
if ( (getMillis() - t1) < LINENOISE_PASTE_KEY_DELAY && c != ENTER) {
/* Pasting data, insert characters without formatting.
* This can only be performed when the cursor is at the end of the
* line. */
if (linenoiseInsertPastedChar(&l,c)) {
return -1;
}
continue;
}
/* Only autocomplete when the callback is set. It returns < 0 when /* Only autocomplete when the callback is set. It returns < 0 when
* there was an error reading from fd. Otherwise it will return the * there was an error reading from fd. Otherwise it will return the
* character that should be handled next. */ * character that should be handled next. */
@ -942,17 +794,13 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
break; break;
case ESC: /* escape sequence */ case ESC: /* escape sequence */
/* Read the next two bytes representing the escape sequence. */ /* Read the next two bytes representing the escape sequence. */
if (read(in_fd, seq, 2) < 2) { if (fread(seq, 1, 2, stdin) < 2) break;
break;
}
/* ESC [ sequences. */ /* ESC [ sequences. */
if (seq[0] == '[') { if (seq[0] == '[') {
if (seq[1] >= '0' && seq[1] <= '9') { if (seq[1] >= '0' && seq[1] <= '9') {
/* Extended escape, read additional byte. */ /* Extended escape, read additional byte. */
if (read(in_fd, seq+2, 1) == -1) { if (fread(seq+2, 1, 1, stdin) == -1) break;
break;
}
if (seq[2] == '~') { if (seq[2] == '~') {
switch(seq[1]) { switch(seq[1]) {
case '3': /* Delete key. */ case '3': /* Delete key. */
@ -1023,57 +871,10 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
linenoiseEditDeletePrevWord(&l); linenoiseEditDeletePrevWord(&l);
break; break;
} }
flushWrite();
} }
return l.len; return l.len;
} }
void linenoiseAllowEmpty(bool val) {
allow_empty = val;
}
int linenoiseProbe(void) {
/* Switch to non-blocking mode */
int stdin_fileno = fileno(stdin);
int flags = fcntl(stdin_fileno, F_GETFL);
flags |= O_NONBLOCK;
int res = fcntl(stdin_fileno, F_SETFL, flags);
if (res != 0) {
return -1;
}
/* Device status request */
fprintf(stdout, "\x1b[5n");
flushWrite();
/* Try to read response */
int timeout_ms = 500;
const int retry_ms = 10;
size_t read_bytes = 0;
while (timeout_ms > 0 && read_bytes < 4) { // response is ESC[0n or ESC[3n
usleep(retry_ms * 1000);
timeout_ms -= retry_ms;
char c;
int cb = read(stdin_fileno, &c, 1);
if (cb < 0) {
continue;
}
if (read_bytes == 0 && c != '\x1b') {
/* invalid response */
break;
}
read_bytes += cb;
}
/* Restore old mode */
flags &= ~O_NONBLOCK;
res = fcntl(stdin_fileno, F_SETFL, flags);
if (res != 0) {
return -1;
}
if (read_bytes < 4) {
return -2;
}
return 0;
}
static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) { static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
int count; int count;
@ -1084,71 +885,18 @@ static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
} }
count = linenoiseEdit(buf, buflen, prompt); count = linenoiseEdit(buf, buflen, prompt);
fputc('\n', stdout); printf("\n");
flushWrite();
return count; return count;
} }
static int linenoiseDumb(char* buf, size_t buflen, const char* prompt) {
/* dumb terminal, fall back to fgets */
fputs(prompt, stdout);
size_t count = 0;
while (count < buflen) {
int c = fgetc(stdin);
if (c == '\n') {
break;
} else if (c >= 0x1c && c <= 0x1f){
continue; /* consume arrow keys */
} else if (c == BACKSPACE || c == 0x8) {
if (count > 0) {
buf[count - 1] = 0;
count --;
}
fputs("\x08 ", stdout); /* Windows CMD: erase symbol under cursor */
} else {
buf[count] = c;
++count;
}
fputc(c, stdout); /* echo */
}
fputc('\n', stdout);
flushWrite();
return count;
}
static void sanitize(char* src) {
char* dst = src;
for (int c = *src; c != 0; src++, c = *src) {
if (isprint(c)) {
*dst = c;
++dst;
}
}
*dst = 0;
}
/* The high level function that is the main API of the linenoise library. */ /* The high level function that is the main API of the linenoise library. */
char *linenoise(const char *prompt) { char *linenoise(const char *prompt) {
char *buf = calloc(1, max_cmdline_length); char buf[LINENOISE_MAX_LINE];
int count = 0; int count;
if (buf == NULL) {
return NULL; count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
} if (count == -1) return NULL;
if (!dumbmode) { return strdup(buf);
count = linenoiseRaw(buf, max_cmdline_length, prompt);
} else {
count = linenoiseDumb(buf, max_cmdline_length, prompt);
}
if (count > 0) {
sanitize(buf);
count = strlen(buf);
} else if (count == 0 && allow_empty) {
/* will return an empty (0-length) string */
} else {
free(buf);
return NULL;
}
return buf;
} }
/* This is just a wrapper the user may want to call in order to make sure /* This is just a wrapper the user may want to call in order to make sure
@ -1161,7 +909,7 @@ void linenoiseFree(void *ptr) {
/* ================================ History ================================= */ /* ================================ History ================================= */
void linenoiseHistoryFree(void) { void linenoiseHistoryFree() {
if (history) { if (history) {
for (int j = 0; j < history_len; j++) { for (int j = 0; j < history_len; j++) {
free(history[j]); free(history[j]);
@ -1259,18 +1007,12 @@ int linenoiseHistorySave(const char *filename) {
* If the file exists and the operation succeeded 0 is returned, otherwise * If the file exists and the operation succeeded 0 is returned, otherwise
* on error -1 is returned. */ * on error -1 is returned. */
int linenoiseHistoryLoad(const char *filename) { int linenoiseHistoryLoad(const char *filename) {
FILE *fp = fopen(filename, "r"); FILE *fp = fopen(filename,"r");
if (fp == NULL) { char buf[LINENOISE_MAX_LINE];
return -1;
}
char *buf = calloc(1, max_cmdline_length); if (fp == NULL) return -1;
if (buf == NULL) {
fclose(fp);
return -1;
}
while (fgets(buf, max_cmdline_length, fp) != NULL) { while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
char *p; char *p;
p = strchr(buf,'\r'); p = strchr(buf,'\r');
@ -1278,20 +1020,6 @@ int linenoiseHistoryLoad(const char *filename) {
if (p) *p = '\0'; if (p) *p = '\0';
linenoiseHistoryAdd(buf); linenoiseHistoryAdd(buf);
} }
free(buf);
fclose(fp); fclose(fp);
return 0;
}
/* Set line maximum length. If len parameter is smaller than
* LINENOISE_MINIMAL_MAX_LINE, -1 is returned
* otherwise 0 is returned. */
int linenoiseSetMaxLineLen(size_t len) {
if (len < LINENOISE_MINIMAL_MAX_LINE) {
return -1;
}
max_cmdline_length = len;
return 0; return 0;
} }

View file

@ -43,9 +43,6 @@
extern "C" { extern "C" {
#endif #endif
#include <stdbool.h>
#include <stddef.h>
typedef struct linenoiseCompletions { typedef struct linenoiseCompletions {
size_t len; size_t len;
char **cvec; char **cvec;
@ -59,21 +56,16 @@ void linenoiseSetHintsCallback(linenoiseHintsCallback *);
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *); void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
void linenoiseAddCompletion(linenoiseCompletions *, const char *); void linenoiseAddCompletion(linenoiseCompletions *, const char *);
int linenoiseProbe(void);
char *linenoise(const char *prompt); char *linenoise(const char *prompt);
void linenoiseFree(void *ptr); void linenoiseFree(void *ptr);
int linenoiseHistoryAdd(const char *line); int linenoiseHistoryAdd(const char *line);
int linenoiseHistorySetMaxLen(int len); int linenoiseHistorySetMaxLen(int len);
int linenoiseHistorySave(const char *filename); int linenoiseHistorySave(const char *filename);
int linenoiseHistoryLoad(const char *filename); int linenoiseHistoryLoad(const char *filename);
void linenoiseHistoryFree(void); void linenoiseHistoryFree();
void linenoiseClearScreen(void); void linenoiseClearScreen(void);
void linenoiseSetMultiLine(int ml); void linenoiseSetMultiLine(int ml);
void linenoiseSetDumbMode(int set);
bool linenoiseIsDumbMode(void);
void linenoisePrintKeyCodes(void); void linenoisePrintKeyCodes(void);
void linenoiseAllowEmpty(bool);
int linenoiseSetMaxLineLen(size_t len);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -1,8 +1,16 @@
/* // Copyright 2016-2017 Espressif Systems (Shanghai) PTE LTD
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD //
* // Licensed under the Apache License, Version 2.0 (the "License");
* SPDX-License-Identifier: Apache-2.0 // you may not use this file except in compliance with the License.
*/ // You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
@ -23,20 +31,13 @@ typedef enum {
SS_QUOTED_ARG_ESCAPED = SS_QUOTED_ARG | SS_FLAG_ESCAPE, SS_QUOTED_ARG_ESCAPED = SS_QUOTED_ARG | SS_FLAG_ESCAPE,
} split_state_t; } split_state_t;
/* helper macro, called when done with an argument */
#define END_ARG() do { \
char_out = 0; \
argv[argc++] = next_arg_start; \
state = SS_SPACE; \
} while(0)
size_t esp_console_split_argv(char *line, char **argv, size_t argv_size) size_t esp_console_split_argv(char *line, char **argv, size_t argv_size)
{ {
const int QUOTE = '"'; const int QUOTE = '"';
const int ESCAPE = '\\'; const int ESCAPE = '\\';
const int SPACE = ' '; const int SPACE = ' ';
split_state_t state = SS_SPACE; split_state_t state = SS_SPACE;
size_t argc = 0; int argc = 0;
char *next_arg_start = line; char *next_arg_start = line;
char *out_ptr = line; char *out_ptr = line;
for (char *in_ptr = line; argc < argv_size - 1; ++in_ptr) { for (char *in_ptr = line; argc < argv_size - 1; ++in_ptr) {
@ -46,6 +47,13 @@ size_t esp_console_split_argv(char *line, char **argv, size_t argv_size)
} }
int char_out = -1; int char_out = -1;
/* helper function, called when done with an argument */
void end_arg() {
char_out = 0;
argv[argc++] = next_arg_start;
state = SS_SPACE;
}
switch (state) { switch (state) {
case SS_SPACE: case SS_SPACE:
if (char_in == SPACE) { if (char_in == SPACE) {
@ -65,7 +73,7 @@ size_t esp_console_split_argv(char *line, char **argv, size_t argv_size)
case SS_QUOTED_ARG: case SS_QUOTED_ARG:
if (char_in == QUOTE) { if (char_in == QUOTE) {
END_ARG(); end_arg();
} else if (char_in == ESCAPE) { } else if (char_in == ESCAPE) {
state = SS_QUOTED_ARG_ESCAPED; state = SS_QUOTED_ARG_ESCAPED;
} else { } else {
@ -85,7 +93,7 @@ size_t esp_console_split_argv(char *line, char **argv, size_t argv_size)
case SS_ARG: case SS_ARG:
if (char_in == SPACE) { if (char_in == SPACE) {
END_ARG(); end_arg();
} else if (char_in == ESCAPE) { } else if (char_in == ESCAPE) {
state = SS_ARG_ESCAPED; state = SS_ARG_ESCAPED;
} else { } else {

View file

@ -1,12 +0,0 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
list(PREPEND SDKCONFIG_DEFAULTS "$ENV{IDF_PATH}/tools/test_apps/configs/sdkconfig.debug_helpers" "sdkconfig.defaults")
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
set(COMPONENTS main)
project(test_console)

View file

@ -1,2 +0,0 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |

View file

@ -1,4 +0,0 @@
idf_component_register(SRCS "test_app_main.c" "test_console.c"
INCLUDE_DIRS "."
PRIV_REQUIRES unity console
WHOLE_ARCHIVE)

View file

@ -1,45 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "esp_heap_caps.h"
// Some resources are lazy allocated (newlib locks) in the console code, the threshold is left for that case
#define TEST_MEMORY_LEAK_THRESHOLD (-100)
static size_t before_free_8bit;
static size_t before_free_32bit;
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
printf("Running console component tests\n");
unity_run_menu();
}

View file

@ -1,63 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "unity.h"
#include "esp_console.h"
#include "argtable3/argtable3.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static int do_hello_cmd(int argc, char **argv)
{
printf("Hello World\n");
return 0;
}
TEST_CASE("esp console init/deinit test", "[console]")
{
esp_console_config_t console_config = ESP_CONSOLE_CONFIG_DEFAULT();
TEST_ESP_OK(esp_console_init(&console_config));
const esp_console_cmd_t cmd = {
.command = "hello",
.help = "Print Hello World",
.hint = NULL,
.func = do_hello_cmd,
};
TEST_ESP_OK(esp_console_cmd_register(&cmd));
// re-register the same command, just for test
TEST_ESP_OK(esp_console_cmd_register(&cmd));
TEST_ESP_OK(esp_console_deinit());
}
static esp_console_repl_t *s_repl = NULL;
/* handle 'quit' command */
static int do_cmd_quit(int argc, char **argv)
{
printf("ByeBye\r\n");
s_repl->del(s_repl);
return 0;
}
// Enter "quit" to exit REPL environment
TEST_CASE("esp console repl test", "[console][ignore]")
{
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
TEST_ESP_OK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl));
esp_console_cmd_t cmd = {
.command = "quit",
.help = "Quit REPL environment",
.func = &do_cmd_quit
};
TEST_ESP_OK(esp_console_cmd_register(&cmd));
TEST_ESP_OK(esp_console_start_repl(s_repl));
vTaskDelay(pdMS_TO_TICKS(2000));
}

View file

@ -1,11 +0,0 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.generic
@pytest.mark.supported_targets
def test_console(dut: Dut) -> None:
dut.run_all_single_board_cases()

View file

@ -1,3 +0,0 @@
# This "default" configuration is appended to all other configurations
# The contents of "sdkconfig.debug_helpers" is also appended to all other configurations (see CMakeLists.txt)
CONFIG_ESP_TASK_WDT_INIT=n

View file

@ -25,23 +25,6 @@ void console_task(void* arg) {
"Use UP/DOWN arrows to navigate through command history.\n" "Use UP/DOWN arrows to navigate through command history.\n"
"Press TAB when typing command name to auto-complete.\n" "Press TAB when typing command name to auto-complete.\n"
"Ctrl+C will terminate the console environment.\n"); "Ctrl+C will terminate the console environment.\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) { /* zero indicates success */
printf("\n"
"Your terminal application does not support escape sequences.\n"
"Line editing and history features are disabled.\n"
"On Windows, try using Putty instead.\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the prompt.
*/
prompt = PROMPT_STR;
#endif // CONFIG_LOG_COLORS
}
/* Main loop */ /* Main loop */
while (true) { while (true) {

View file

@ -58,12 +58,6 @@ static void initialize_console(void) {
/* Set command history size */ /* Set command history size */
linenoiseHistorySetMaxLen(100); linenoiseHistorySetMaxLen(100);
/* Set command maximum length */
linenoiseSetMaxLineLen(console_config.max_cmdline_length);
/* Allow empty lines */
linenoiseAllowEmpty(true);
/* Load command history from filesystem */ /* Load command history from filesystem */
linenoiseHistoryLoad(HISTORY_PATH); linenoiseHistoryLoad(HISTORY_PATH);
} }