Skip to content

Commit

Permalink
* New syntax @{} for expressing _sets_ of commands, as opposed to a…
Browse files Browse the repository at this point in the history
…lternative commands.

* Added parse tree dump functions, for pointer debugging (`pt_dump` and `co_dump`).
  • Loading branch information
olofhagsand committed Dec 9, 2019
1 parent 8ca9347 commit ed1997a
Show file tree
Hide file tree
Showing 17 changed files with 205 additions and 70 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Generated files
doc
build.c
cligen_parse.tab.c
cligen_parse.tab.h
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
## 4.3.0 (Expected: December 2019)
Bugfixes and internal struct reorganizing. Bumped version to match with clixon 4.3

* New syntax `@{}` for expressing _sets_ of commands, as opposed to alternative commands.
* Example: `@{a;b;c;}` where a, b, and c can occur at most once in any order, as opposed to either a, b, or c.
* This feature is EXPERIMENTAL since even if base cases work, there may be combinations with other usages that are not been fully understood.
* This was only possible previously by workarounds or by full command expansion consuming quadratric memory.
* This feature has been a root of many issues, including the following:
* [Syntax to enter commands regardless of order #32](https://github.com/olofhagsand/cligen/issues/32)
* [CLIgen code stuck in recursion at the time of parsing #23](https://github.com/olofhagsand/cligen/issues/23)
* [CLI syntax help #22](https://github.com/olofhagsand/cligen/issues/22)
* Added parse tree dump functions, for pointer debugging (`pt_dump` and `co_dump`).
* Fixed [Ability to use show attribute to display a multiword string #33](https://github.com/olofhagsand/cligen/issues/33)
* Fixed: [Is it possible to hide non-terminal commands? #31](https://github.com/olofhagsand/cligen/issues/31)
* Removed "auth" as a local variable in docs, since it is not implemented
Expand Down
1 change: 0 additions & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
INCLUDES = -I. -I@srcdir@ @INCLUDES@
SH_SUFFIX = @SH_SUFFIX@
pdflatex = pdflatex
HOST_VENDOR = @host_vendor@

INSTALL = @INSTALL@
Expand Down
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
CLIgen
======
# CLIgen

CLIgen is a Command-Line Interface generator.

Expand All @@ -12,8 +11,11 @@ write callback functions where you call the right library
routines. The callback functions add the semantics, that is, what the
commands in the CLI are supposed to do.

Presentations and tutorial is found on the [CLIgen project
page](http://www.cligen.se)
I try to keep thi [cligen tutorial](cligen_tutorial.pdf) up to date
and is probably the best way to understand CLIgen.

Some background material can be found on the [CLIgen project
page](http://www.cligen.se).

CLIgen is _not_ a system in itself, you need to build your own
'backend'. We have started another project: 'clixon' which is
Expand All @@ -30,23 +32,24 @@ The source code here is built and installed using:
sudo make install.
```



The source builds a single library. If you build applications, you should include cligen.h and link with the library.

There are several example applications:
* cligen_hello Simplest possible. Just builds a 'hello world' greeting by in-line C
* cligen_file Read a syntax specification from file. You must supply the file.
* cligen_tutorial Samples of techniques used in cligen_tutorial.pdf.
* cligen_tutorial Samples of techniques used in [cligen_tutorial.pdf](cligen_tutorial.pdf)

See also [Changelog](CHANGELOG.md).

For building the C reference documentation using doxygen, do: `make doc` and place your browser at `doc/index.html`.

CLIgen is dual license. Either Apache License, Version 2.0 or GNU
General Public License Version 2. You choose.

I can be found at olof@hagsand.se.

getline
## getline


CLIgen uses getline with the following copyright:

Expand Down
2 changes: 1 addition & 1 deletion cligen_custom.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ typedef void *cligen_handle; /* API */

/* New SETS functionality: @{ ... }. This is prototypish.
*/
#undef USE_SETS
#define USE_SETS
133 changes: 82 additions & 51 deletions cligen_expand.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,57 @@ pt_reference_trunc(parse_tree pt)
return retval;
}

#ifdef USE_SETS
/*!
* pt0 [ ... co ... ]
*/
static int
pt_expand_sets(parse_tree *pt0,
cg_obj *co,
parse_tree *ptcp)
{
int retval = -1;
parse_tree ptc2 = {0, };
int j;
cg_obj *coc;

/* If co is a SUB or GEN, and co is not already expanded, expand co with new
subs */
if (co_flags_get(co, CO_FLAGS_SETS_SUB|CO_FLAGS_SETS_GEN) &&
!co_flags_get(co, CO_FLAGS_SETS_EXP)){
if (ptcp->pt_len == 0){
if (pt_copy(*pt0, co, ptcp) < 0){ /* Make a copy of co children */
fprintf(stderr, "%s: Copying parse-tree\n", __FUNCTION__);
return -1;
}
}
if (pt_copy(*ptcp, co, &ptc2) < 0){ /* Make a copy of co children */
fprintf(stderr, "%s: Copying parse-tree\n", __FUNCTION__);
return -1;
}
for (j=0; j<ptc2.pt_len; j++){
if ((coc = ptc2.pt_vec[j]) != NULL){
if (co_eq(coc, co)==0)
continue;
if (co_flags_get(coc, CO_FLAGS_SETS_SUB) == 0 &&
co_flags_get(coc, CO_FLAGS_SETS_GEN) == 0)
continue;
co_flags_reset(coc, CO_FLAGS_SETS_SUB);
co_flags_set(coc, CO_FLAGS_SETS_GEN);
if (co_insert(&co->co_pt, coc) == NULL) /* XXX alphabetically */
return -1;
ptc2.pt_vec[j] = NULL;
}
}
cligen_parsetree_free(ptc2, 1);
co_flags_set(co, CO_FLAGS_SETS_EXP); /* This node is expanded */
}
retval = 0;
//done:
return retval;
}
#endif /* USE_SETS */

/*! Take a top-object parse-tree (pt0), and expand all tree references one level.
*
* One level only. Parse-tree is expanded itself (not copy).
Expand All @@ -291,28 +342,27 @@ pt_expand_treeref(cligen_handle h,
cg_obj *co0,
parse_tree *pt0)
{
int i;
int j;
cg_obj *co;
parse_tree *ptref = 0; /* tree referenced by pt0 orig */
parse_tree pt1ref = {0, }; /* tree referenced by pt0 resolved */
cg_obj *cot; /* treeref object */
char *treename;
cg_obj *co02;
int retval = -1;
int i;
int j;
cg_obj *co;
parse_tree *ptref = 0; /* tree referenced by pt0 orig */
parse_tree pt1ref = {0, }; /* tree referenced by pt0 resolved */
cg_obj *cot; /* treeref object */
char *treename;
cg_obj *co02;
#ifdef USE_SETS
parse_tree ptc = {0, };
parse_tree *ptcp = NULL;
parse_tree ptc2 = {0, };
cg_obj *coc;
parse_tree ptc = {0, };
parse_tree *ptcp = &ptc;
#endif

if (pt0->pt_vec == NULL)
return 0;
#ifdef USE_SETS
for (i=0; i<pt0->pt_len; i++){ /* */
if ((co = pt0->pt_vec[i]) == NULL)
continue;
if (co0){
if (co0){
for (i=0; i<pt0->pt_len; i++){ /* */
if ((co = pt0->pt_vec[i]) == NULL)
continue;
/* Mark all direct children of a SET as SUBS, Could be done at parsing? */
if (co_flags_get(co0, CO_FLAGS_SETS) && !co_flags_get(co, CO_FLAGS_SETS_SUB))
co_flags_set(co, CO_FLAGS_SETS_SUB);
Expand All @@ -325,38 +375,10 @@ pt_expand_treeref(cligen_handle h,
continue;
#ifdef USE_SETS
if (co0){
/* If co0 is a SUB or GEN, and co is not already expanded, expand co with new
subs */
if (co_flags_get(co, CO_FLAGS_SETS_SUB|CO_FLAGS_SETS_GEN) &&
!co_flags_get(co, CO_FLAGS_SETS_EXP)){
if (ptcp == NULL){
if (pt_copy(*pt0, co, &ptc) < 0){ /* Make a copy of co children */
fprintf(stderr, "%s: Copying parse-tree\n", __FUNCTION__);
return -1;
}
ptcp = &ptc;
}
if (pt_copy(*ptcp, co, &ptc2) < 0){ /* Make a copy of co children */
fprintf(stderr, "%s: Copying parse-tree\n", __FUNCTION__);
return -1;
}
for (j=0; j<ptc2.pt_len; j++){
if ((coc = ptc2.pt_vec[j]) != NULL){
if (co_eq(coc, co)==0)
continue;
if (co_flags_get(coc, CO_FLAGS_SETS_SUB|CO_FLAGS_SETS_GEN) == 0)
continue;
co_flags_set(coc, CO_FLAGS_SETS_GEN);
if (co_insert(&co->co_pt, coc) == NULL) /* XXX alphabetically */
return -1;
ptc2.pt_vec[j] = NULL;
}
}
cligen_parsetree_free(ptc2, 1);
co_flags_set(co, CO_FLAGS_SETS_EXP); /* This node is expanded */
}
if (pt_expand_sets(pt0, co, ptcp) < 0)
goto done;
}
#endif
#endif /* USE_SETS */
if (co->co_type == CO_REFERENCE && !co_flags_get(co, CO_FLAGS_REFDONE)){
/* Expansion is made in-line so we need to know if already
expanded */
Expand Down Expand Up @@ -402,10 +424,11 @@ pt_expand_treeref(cligen_handle h,
}
}
#ifdef USE_SETS
if (ptcp)
cligen_parsetree_free(*ptcp, 1);
cligen_parsetree_free(*ptcp, 1);
#endif
return 0;
retval = 0;
done:
return retval;
}

/*! Call expand callback and insert expanded commands in place of variable
Expand Down Expand Up @@ -604,7 +627,15 @@ pt_expand_treeref_cleanup(parse_tree *pt)
if ((co = pt->pt_vec[i]) != NULL){
if (co_flags_get(co, CO_FLAGS_REFDONE))
co_flags_reset(co, CO_FLAGS_REFDONE);
if (co_flags_get(co, CO_FLAGS_TREEREF)){
#ifdef USE_SETS
if (co_flags_get(co, CO_FLAGS_SETS_EXP))
co_flags_reset(co, CO_FLAGS_SETS_EXP);
#endif
if (co_flags_get(co, CO_FLAGS_TREEREF)
#ifdef USE_SETS
|| co_flags_get(co, CO_FLAGS_SETS_GEN)
#endif
){
pt->pt_vec[i] = NULL;
co_free(co, 1);
for (j=i; j<pt->pt_len-1; j++)
Expand Down
Empty file modified cligen_file.c
100755 → 100644
Empty file.
Empty file modified cligen_gen.c
100755 → 100644
Empty file.
Empty file modified cligen_match.c
100755 → 100644
Empty file.
1 change: 1 addition & 0 deletions cligen_parse.l
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ stripdup(char *s0)
<INITIAL>\(\" { BEGIN(HELP); return PDQ; /* parenth double-q*/ }
<INITIAL>\[ { return *yytext; }
<INITIAL>\] { return *yytext; }
<INITIAL>"@{" { return SETS; /* see USE_SETS */ }
<INITIAL>\{ { return *yytext; }
<INITIAL>\} { return *yytext; }
<INITIAL>\@ { return *yytext; }
Expand Down
2 changes: 1 addition & 1 deletion cligen_parse.y
Original file line number Diff line number Diff line change
Expand Up @@ -1129,7 +1129,7 @@ line1 : line2 { if (debug) printf("line1->line2\n"); }
;

preline : '{' { $$ = 0; }
/* | SETS { $$ = 1; } USE_SETS */
| SETS { $$ = 1; } /* USE_SETS */
;

line2 : ';' {
Expand Down
63 changes: 61 additions & 2 deletions cligen_print.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ pt2cbuf(cbuf *cb,

/*! Print CLIgen parse-tree to file, brief or detailed.
*
* @param[in] f File to print to
* @param[in] f Output file
* @param[in] pt Cligen parse-tree consisting of cg objects and variables
* @param[in] brief Print brief output, otherwise clispec parsable format
*
Expand Down Expand Up @@ -273,7 +273,7 @@ pt_print(FILE *f,

/*! Print CLIgen parse-tree object to file, brief or detailed.
*
* @param[in] f File to print to
* @param[in] f Output file
* @param[in] co Cligen object
* @param[in] brief Print brief output, otherwise clispec parsable format
*
Expand Down Expand Up @@ -301,6 +301,65 @@ co_print(FILE *f,
return retval;
}

static int
co_dump1(FILE *f,
cg_obj *co,
int margin)
{
int retval = -1;
parse_tree *pt;
int i;
cg_obj *coc;

fprintf(f, "%*s %s 0x%lx", margin, "", co->co_command, (intptr_t)co);
fprintf(f, " [0x%lx]", (intptr_t)co->co_prev);
if (co_flags_get(co, CO_FLAGS_SETS))
fprintf(f, " sets");
if (co_flags_get(co, CO_FLAGS_SETS_SUB))
fprintf(f, " sub");
if (co_flags_get(co, CO_FLAGS_SETS_GEN))
fprintf(f, " gen");
if (co_flags_get(co, CO_FLAGS_SETS_EXP))
fprintf(f, " exp");
fprintf(f, "\n");
pt = &co->co_pt;
margin +=3;
for (i=0; i<pt->pt_len; i++){
coc = pt->pt_vec[i];
if (coc == NULL || coc->co_type != CO_COMMAND)
continue;
if (co_dump1(f, coc, margin) < 0)
goto done;
}
retval = 0;
done:
return retval;
}

/*! Dump raw tree, object pointers, etc, of a cligen object
* @param[in] f Output file
* @param[in] co Cligen object
*/
int
co_dump(FILE *f,
cg_obj *co)
{
return co_dump1(f, co, 0);
}

int
pt_dump(FILE *f,
parse_tree *pt)
{
int i;

for (i=0; i<pt->pt_len; i++){
if (co_dump(f, pt->pt_vec[i]) < 0)
return -1;
}
return 0;
}

/*! Print list of CLIgen parse-trees
*
* @param[in] f File to print to
Expand Down
2 changes: 2 additions & 0 deletions cligen_print.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ int cov2cbuf(cbuf *cb, cg_obj *co, int brief);
int pt_print(FILE *f, parse_tree pt, int brief);
int co_print(FILE *f, cg_obj *co, int brief);
int cligen_print_trees(FILE *f, cligen_handle h, int brief);
int co_dump(FILE *f, cg_obj *co);
int pt_dump(FILE *f, parse_tree *pt);

/* obsolete */
#define cligen_print(f, pt, b) pt_print((f), (pt), (b))
Expand Down
Empty file modified cligen_read.h
100755 → 100644
Empty file.
Empty file modified cligen_tutorial.c
100755 → 100644
Empty file.
Binary file modified cligen_tutorial.pdf
Binary file not shown.
Loading

0 comments on commit ed1997a

Please sign in to comment.