added qse_mbsistype(), qse_wcsistype()

added qse_cli_t and related functions as an alternative interface to parse command-line arguments
This commit is contained in:
hyung-hwan 2018-01-12 08:21:57 +00:00
parent 7b1db985c5
commit 5e3507e836
7 changed files with 425 additions and 39 deletions

View File

@ -317,7 +317,6 @@ static void print_warning (const qse_char_t* fmt, ...)
va_end (va);
}
struct opttab_t
{
const qse_char_t* name;

View File

@ -64,25 +64,79 @@ struct qse_opt_t
qse_char_t* cur;
};
/* --------------------------------------------------------------------- */
#define QSE_CLI_OPTNAME (1 << 0)
#define QSE_CLI_OPTVAL (1 << 1)
#define QSE_CLI_ERROR_INVALID_OPTNAME 1
#define QSE_CLI_ERROR_MISSING_OPTNAME 2
#define QSE_CLI_ERROR_REDUNDANT_OPTVAL 3
#define QSE_CLI_ERROR_MISSING_OPTVAL 4
#define QSE_CLI_ERROR_MEMORY 5
typedef struct qse_cli_opt_t qse_cli_opt_t;
typedef struct qse_cli_t qse_cli_t;
struct qse_cli_opt_t
{
/* input */
const qse_char_t* name;
int requires;
/* output - you don't have to initialize this field */
qse_char_t* value;
};
typedef int (*qse_cli_errcb_t) (
qse_cli_t* cli,
int code,
const qse_char_t* qname,
const qse_char_t* qval
);
struct qse_cli_data_t
{
/* input */
qse_cli_errcb_t errcb;
const qse_char_t** optsta;
const qse_char_t* optasn;
qse_cli_opt_t* opts;
};
typedef struct qse_cli_data_t qse_cli_data_t;
struct qse_cli_t
{
qse_mmgr_t* mmgr;
qse_cli_data_t data;
/* output - you don't have to initialize these fields */
qse_char_t* verb;
int nparams;
qse_char_t** params;
};
#if defined(__cplusplus)
extern "C" {
#endif
/**
* The qse_getopt() function processes the @a argc command-line arguments
* pointed to by @a argv as configured in @a opt. It can process two
* The qse_getopt() function processes the \a argc command-line arguments
* pointed to by \a argv as configured in \a opt. It can process two
* different option styles: a single character starting with '-', and a
* long name starting with '--'.
*
* A character in @a opt.str is treated as a single character option. Should
* A character in \a opt.str is treated as a single character option. Should
* it require a parameter, specify ':' after it.
*
* Two special returning option characters indicate special error conditions.
* - @b ? indicates a bad option stored in the @a opt->opt field.
* - @b : indicates a bad parameter for an option stored in the
* @a opt->opt field.
* - \b ? indicates a bad option stored in the \a opt->opt field.
* - \b : indicates a bad parameter for an option stored in the
* \a opt->opt field.
*
* @return an option character on success, QSE_CHAR_EOF on no more options.
* \return an option character on success, QSE_CHAR_EOF on no more options.
*/
QSE_EXPORT qse_cint_t qse_getopt (
int argc, /* argument count */
@ -90,6 +144,42 @@ QSE_EXPORT qse_cint_t qse_getopt (
qse_opt_t* opt /* option configuration */
);
/* --------------------------------------------------------------------- */
QSE_EXPORT int qse_parsecli (
qse_cli_t* cli,
qse_mmgr_t* mmgr,
int argc,
qse_char_t* const argv[],
qse_cli_data_t* data
);
QSE_EXPORT void qse_clearcli (
qse_cli_t* cli
);
QSE_EXPORT qse_char_t* qse_getcliverb (
qse_cli_t* cli
);
QSE_EXPORT qse_char_t* qse_getclioptval (
qse_cli_t* cli,
const qse_char_t* opt
);
QSE_EXPORT qse_char_t* qse_getcliparams (
qse_cli_t* cli,
int index
);
#if defined(QSE_HAVE_INLINE)
static QSE_INLINE int qse_getncliparams (qse_cli_t* cli) { return cli->nparams; }
#else
# define qse_getncliparams(cli) ((cli)->nparams)
#endif
#if defined(__cplusplus)
}
#endif

View File

@ -29,6 +29,7 @@
#include <qse/types.h>
#include <qse/macros.h>
#include <qse/cmn/chr.h>
#include <stdarg.h>
/** \file
@ -3003,6 +3004,22 @@ QSE_EXPORT int qse_wcsxnfnmat (
# define qse_strxnfnmat(str,slen,ptn,plen,flags) qse_wcsxnfnmat(str,slen,ptn,plen,flags)
#endif
QSE_EXPORT int qse_mbsistype (
const qse_mchar_t* str,
qse_mctype_t type
);
QSE_EXPORT int qse_wcsistype (
const qse_wchar_t* str,
qse_wctype_t type
);
#if defined(QSE_CHAR_IS_MCHAR)
# define qse_stristype(str,type) qse_mbsistype(str,type)
#else
# define qse_stristype(str,type) qse_wcsistype(str,type)
#endif
/* ------------------------------------------------------------------------- */
/**
* The qse_mbs_open() function creates a dynamically resizable multibyte string.
@ -3219,6 +3236,9 @@ QSE_EXPORT qse_size_t qse_mbs_vfmt (
va_list ap
);
/* ------------------------------------------------------------------------- */
/**
* The qse_wcs_open() function creates a dynamically resizable wide-character
* string.

View File

@ -57,6 +57,7 @@ libqsecmn_la_SOURCES = \
mem.c \
oht.c \
opt.c \
opt-cli.c \
path-base.c \
path-canon.c \
path-core.c \
@ -95,6 +96,7 @@ libqsecmn_la_SOURCES = \
str-subst.c \
str-tok.c \
str-trm.c \
str-type.c \
str-word.c \
time.c \
tmr.c \

View File

@ -145,33 +145,33 @@ libqsecmn_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
am__libqsecmn_la_SOURCES_DIST = alg-base64.c alg-rand.c alg-search.c \
alg-sort.c arr.c assert.c chr.c dll.c env.c gdl.c htb.c htl.c \
fma.c fmt-intmax.c fmt-out.c hton.c hwad.c ipad.c main.c mb8.c \
mbwc.c mbwc-str.c mem.c oht.c opt.c path-base.c path-canon.c \
path-core.c path-merge.c pma.c rbt.c rex.c sll.c slmb.c \
str-beg.c str-cat.c str-chr.c str-cnv.c str-cmp.c str-cpy.c \
str-del.c str-dup.c str-dyn.c str-end.c str-excl.c str-fcpy.c \
str-fmt.c str-fnmat.c str-incl.c str-join.c str-len.c \
str-pac.c str-pbrk.c str-put.c str-rev.c str-rot.c str-set.c \
str-spl.c str-spn.c str-str.c str-subst.c str-tok.c str-trm.c \
str-word.c time.c tmr.c tre.c tre-ast.c tre-compile.c \
tre-match-bt.c tre-match-pa.c tre-parse.c tre-stack.c uri.c \
utf8.c xma.c uni.c cp949.c cp950.c
mbwc.c mbwc-str.c mem.c oht.c opt.c opt-cli.c path-base.c \
path-canon.c path-core.c path-merge.c pma.c rbt.c rex.c sll.c \
slmb.c str-beg.c str-cat.c str-chr.c str-cnv.c str-cmp.c \
str-cpy.c str-del.c str-dup.c str-dyn.c str-end.c str-excl.c \
str-fcpy.c str-fmt.c str-fnmat.c str-incl.c str-join.c \
str-len.c str-pac.c str-pbrk.c str-put.c str-rev.c str-rot.c \
str-set.c str-spl.c str-spn.c str-str.c str-subst.c str-tok.c \
str-trm.c str-type.c str-word.c time.c tmr.c tre.c tre-ast.c \
tre-compile.c tre-match-bt.c tre-match-pa.c tre-parse.c \
tre-stack.c uri.c utf8.c xma.c uni.c cp949.c cp950.c
@ENABLE_BUNDLED_UNICODE_TRUE@am__objects_1 = uni.lo
@ENABLE_XCMGRS_TRUE@am__objects_2 = cp949.lo cp950.lo
am_libqsecmn_la_OBJECTS = alg-base64.lo alg-rand.lo alg-search.lo \
alg-sort.lo arr.lo assert.lo chr.lo dll.lo env.lo gdl.lo \
htb.lo htl.lo fma.lo fmt-intmax.lo fmt-out.lo hton.lo hwad.lo \
ipad.lo main.lo mb8.lo mbwc.lo mbwc-str.lo mem.lo oht.lo \
opt.lo path-base.lo path-canon.lo path-core.lo path-merge.lo \
pma.lo rbt.lo rex.lo sll.lo slmb.lo str-beg.lo str-cat.lo \
str-chr.lo str-cnv.lo str-cmp.lo str-cpy.lo str-del.lo \
str-dup.lo str-dyn.lo str-end.lo str-excl.lo str-fcpy.lo \
str-fmt.lo str-fnmat.lo str-incl.lo str-join.lo str-len.lo \
str-pac.lo str-pbrk.lo str-put.lo str-rev.lo str-rot.lo \
str-set.lo str-spl.lo str-spn.lo str-str.lo str-subst.lo \
str-tok.lo str-trm.lo str-word.lo time.lo tmr.lo tre.lo \
tre-ast.lo tre-compile.lo tre-match-bt.lo tre-match-pa.lo \
tre-parse.lo tre-stack.lo uri.lo utf8.lo xma.lo \
$(am__objects_1) $(am__objects_2)
opt.lo opt-cli.lo path-base.lo path-canon.lo path-core.lo \
path-merge.lo pma.lo rbt.lo rex.lo sll.lo slmb.lo str-beg.lo \
str-cat.lo str-chr.lo str-cnv.lo str-cmp.lo str-cpy.lo \
str-del.lo str-dup.lo str-dyn.lo str-end.lo str-excl.lo \
str-fcpy.lo str-fmt.lo str-fnmat.lo str-incl.lo str-join.lo \
str-len.lo str-pac.lo str-pbrk.lo str-put.lo str-rev.lo \
str-rot.lo str-set.lo str-spl.lo str-spn.lo str-str.lo \
str-subst.lo str-tok.lo str-trm.lo str-type.lo str-word.lo \
time.lo tmr.lo tre.lo tre-ast.lo tre-compile.lo \
tre-match-bt.lo tre-match-pa.lo tre-parse.lo tre-stack.lo \
uri.lo utf8.lo xma.lo $(am__objects_1) $(am__objects_2)
libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@ -487,16 +487,16 @@ noinst_HEADERS = \
libqsecmn_la_SOURCES = alg-base64.c alg-rand.c alg-search.c alg-sort.c \
arr.c assert.c chr.c dll.c env.c gdl.c htb.c htl.c fma.c \
fmt-intmax.c fmt-out.c hton.c hwad.c ipad.c main.c mb8.c \
mbwc.c mbwc-str.c mem.c oht.c opt.c path-base.c path-canon.c \
path-core.c path-merge.c pma.c rbt.c rex.c sll.c slmb.c \
str-beg.c str-cat.c str-chr.c str-cnv.c str-cmp.c str-cpy.c \
str-del.c str-dup.c str-dyn.c str-end.c str-excl.c str-fcpy.c \
str-fmt.c str-fnmat.c str-incl.c str-join.c str-len.c \
str-pac.c str-pbrk.c str-put.c str-rev.c str-rot.c str-set.c \
str-spl.c str-spn.c str-str.c str-subst.c str-tok.c str-trm.c \
str-word.c time.c tmr.c tre.c tre-ast.c tre-compile.c \
tre-match-bt.c tre-match-pa.c tre-parse.c tre-stack.c uri.c \
utf8.c xma.c $(am__append_1) $(am__append_2)
mbwc.c mbwc-str.c mem.c oht.c opt.c opt-cli.c path-base.c \
path-canon.c path-core.c path-merge.c pma.c rbt.c rex.c sll.c \
slmb.c str-beg.c str-cat.c str-chr.c str-cnv.c str-cmp.c \
str-cpy.c str-del.c str-dup.c str-dyn.c str-end.c str-excl.c \
str-fcpy.c str-fmt.c str-fnmat.c str-incl.c str-join.c \
str-len.c str-pac.c str-pbrk.c str-put.c str-rev.c str-rot.c \
str-set.c str-spl.c str-spn.c str-str.c str-subst.c str-tok.c \
str-trm.c str-type.c str-word.c time.c tmr.c tre.c tre-ast.c \
tre-compile.c tre-match-bt.c tre-match-pa.c tre-parse.c \
tre-stack.c uri.c utf8.c xma.c $(am__append_1) $(am__append_2)
libqsecmn_la_LDFLAGS = -version-info 1:0:0 -no-undefined
libqsecmn_la_LIBADD = $(SOCKET_LIBS) $(QUADMATH_LIBS)
@ENABLE_CXX_TRUE@libqsecmnxx_la_SOURCES = \
@ -617,6 +617,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbwc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oht.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt-cli.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path-base.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path-canon.Plo@am__quote@
@ -656,6 +657,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-subst.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-tok.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-trm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-type.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-word.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tmr.Plo@am__quote@

224
qse/lib/cmn/opt-cli.c Normal file
View File

@ -0,0 +1,224 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
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 AUTHOR "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 AUTHOR 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 <qse/cmn/opt.h>
#include <qse/cmn/str.h>
#include <qse/cmn/mem.h>
/*
* PARAM_BUNCH should be always 2^n if you don't want to the % operator
*/
#define PARAM_BUNCH 8
static const qse_char_t* __optsta[] =
{
QSE_T("--"),
QSE_NULL
};
static const qse_char_t* __optasn = QSE_T("=");
static qse_char_t __emptyval[] = { QSE_T('\0') };
static qse_char_t* __begins_with (const qse_char_t* str, const qse_char_t* prefixes[])
{
const qse_char_t** pp = prefixes;
while (*pp)
{
if (qse_strbeg(str, *pp)) return (qse_char_t*)*pp;
pp++;
}
return QSE_NULL;
}
int qse_parsecli (qse_cli_t* cli, qse_mmgr_t* mmgr, int argc, qse_char_t* const argv[], qse_cli_data_t* data)
{
int index = 1;
qse_cli_opt_t* opt;
const qse_char_t** optsta;
const qse_char_t* optasn;
cli->mmgr = mmgr;
cli->data = *data;
cli->verb = argv[0];
cli->nparams = 0;
cli->params = QSE_NULL;
optsta = cli->data.optsta;
optasn = cli->data.optasn;
if (!optsta) optsta = __optsta;
if (!optasn) optasn = __optasn;
/* initialize value for each opt */
for (opt = cli->data.opts; opt->name; opt++)
{
opt->value = QSE_NULL;
}
while (index < argc)
{
const qse_char_t* ip;
qse_char_t* ap = argv[index++];
qse_char_t* value;
ip = __begins_with(ap, optsta);
if (ip)
{
/* opt */
qse_cstr_t name;
ap = qse_strtok (ap + qse_strlen(ip), optasn, &name);
if (name.len <= 0) continue;
for (opt = cli->data.opts; opt->name; opt++)
{
if (qse_strxcmp(name.ptr, name.len, opt->name) == 0) break;
}
value = QSE_NULL;
if (ap == QSE_NULL)
{
if (index < argc && !__begins_with(argv[index], optsta))
{
value = argv[index++];
}
}
else
{
/* beware that this changes the original text */
name.ptr[name.len] = QSE_T('\0');
value = ap;
}
if (opt->name == QSE_NULL)
{
if (cli->data.errcb(cli, QSE_CLI_ERROR_INVALID_OPTNAME, name.ptr, value) <= -1)
{
qse_clearcli (cli);
return -1;
}
}
else
{
if (value && !(opt->requires & QSE_CLI_OPTVAL))
{
if (cli->data.errcb(cli, QSE_CLI_ERROR_REDUNDANT_OPTVAL, name.ptr, value) <= -1)
{
qse_clearcli (cli);
return -1;
}
}
else if (!value && (opt->requires & QSE_CLI_OPTVAL))
{
if (cli->data.errcb(cli, QSE_CLI_ERROR_MISSING_OPTVAL, name.ptr, value) <= -1)
{
qse_clearcli (cli);
return -1;
}
}
else if (!value)
{
opt->value = __emptyval;
}
else
{
opt->value = value;
}
}
}
else
{
if ((cli->nparams & (PARAM_BUNCH - 1)) == 0)
{
qse_char_t** t;
t = (qse_char_t**)QSE_MMGR_REALLOC(cli->mmgr, cli->params, (cli->nparams + PARAM_BUNCH) * QSE_SIZEOF(qse_char_t*));
if (!t)
{
if (cli->data.errcb(cli, QSE_CLI_ERROR_MEMORY, ap, QSE_NULL) <= -1)
{
qse_clearcli (cli);
return -1;
}
else continue;
}
cli->params = t;
}
cli->params[cli->nparams++] = ap;
}
}
for (opt = cli->data.opts; opt->name != QSE_NULL; opt++)
{
if ((opt->requires & QSE_CLI_OPTNAME) && opt->value == QSE_NULL)
{
if (cli->data.errcb(cli, QSE_CLI_ERROR_MISSING_OPTNAME, opt->name, QSE_NULL) <= -1)
{
qse_clearcli (cli);
return -1;
}
}
}
return 0;
}
void qse_clearcli (qse_cli_t* cli)
{
if (cli->params)
{
QSE_ASSERT (cli->nparams > 0);
QSE_MMGR_FREE (cli->mmgr, cli->params);
cli->nparams = 0;
cli->params = QSE_NULL;
}
}
qse_char_t* qse_getcliverb (qse_cli_t* cli)
{
return cli->verb;
}
qse_char_t* qse_getclioptval (qse_cli_t* cli, const qse_char_t* opt)
{
qse_cli_opt_t* q = cli->data.opts;
while (q->name)
{
if (q->value && qse_strcmp(opt, q->name) == 0) return q->value;
q++;
}
return QSE_NULL;
}
qse_char_t* qse_getcliparam (qse_cli_t* cli, int index)
{
QSE_ASSERT (index >= 0 && index < cli->nparams);
return cli->params[index];
}

49
qse/lib/cmn/str-type.c Normal file
View File

@ -0,0 +1,49 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
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 AUTHOR "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 AUTHOR 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 <qse/cmn/str.h>
#include <qse/cmn/chr.h>
#include "mem-prv.h"
int qse_mbsistype (const qse_mchar_t* str, qse_mctype_t type)
{
while (*str)
{
if (!qse_ismctype(*str, type)) return 0;
str++;
}
return 1;
}
int qse_wcsistype (const qse_wchar_t* str, qse_wctype_t type)
{
while (*str)
{
if (!qse_iswctype(*str, type)) return 0;
str++;
}
return 1;
}