Loading...
Searching...
No Matches
main.c
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2025, Olivier MATZ <zer0@droids-corp.org>
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ecoli.h>
#define ID_NAME "id_name"
#define ID_JOHN "id_john"
#define ID_COUNT "id_count"
/* stop program when true */
static bool done;
static int hello_cb(const struct ec_pnode *parse)
{
const char *count;
const char *name;
name = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_NAME)), 0);
count = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_COUNT)), 0);
printf("you say hello to %s", name);
if (count)
printf(" %s times", count);
printf("\n");
return 0;
}
static int bye_cb(const struct ec_pnode *parse)
{
const char *name;
name = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_NAME)), 0);
printf("you say bye to %s\n", name);
return 0;
}
static int exit_cb(const struct ec_pnode *parse)
{
(void)parse;
printf("Exit !\n");
done = true;
return 0;
}
static int check_exit(void *opaque)
{
(void)opaque;
return done;
}
static struct ec_node *create_commands(void)
{
struct ec_node *cmdlist = NULL, *cmd = NULL;
struct ec_node *names = NULL;
int ret;
/* the top node containing the list of commands */
cmdlist = ec_node("or", EC_NO_ID);
if (cmdlist == NULL)
goto fail;
/* a common subtree containing a list of names */
names = EC_NODE_OR(
ID_NAME,
ec_node_str(ID_JOHN, "john"),
ec_node_str(EC_NO_ID, "johnny"),
ec_node_str(EC_NO_ID, "mike")
);
if (names == NULL)
goto fail;
/* the hello command */
cmd = EC_NODE_SEQ(
EC_NO_ID,
ec_node_str(EC_NO_ID, "hello"),
ec_node_clone(names),
ec_node_option(EC_NO_ID, ec_node_int(ID_COUNT, 0, 10, 10))
);
if (cmd == NULL)
goto fail;
if (ec_interact_set_callback(cmd, hello_cb) < 0)
goto fail;
if (ec_interact_set_help(cmd, "say hello to someone several times") < 0)
goto fail;
if (ec_interact_set_help(ec_node_find(cmd, ID_JOHN), "specific help for john") < 0)
goto fail;
if (ec_interact_set_help(ec_node_find(cmd, ID_NAME), "the name of the person") < 0)
goto fail;
if (ec_interact_set_help(ec_node_find(cmd, ID_COUNT), "an integer (0-10)") < 0)
goto fail;
ret = ec_node_or_add(cmdlist, cmd);
cmd = NULL; /* already freed, even on error */
if (ret < 0)
goto fail;
/* the bye command */
cmd = EC_NODE_SEQ(EC_NO_ID, ec_node_str(EC_NO_ID, "bye"), ec_node_clone(names));
if (ec_interact_set_callback(cmd, bye_cb) < 0)
goto fail;
if (ec_interact_set_help(cmd, "say bye") < 0)
goto fail;
ret = ec_node_or_add(cmdlist, cmd);
cmd = NULL; /* already freed, even on error */
if (ret < 0)
goto fail;
/* the exit command */
cmd = ec_node_str(EC_NO_ID, "exit");
if (ec_interact_set_callback(cmd, exit_cb) < 0)
goto fail;
if (ec_interact_set_help(cmd, "exit program") < 0)
goto fail;
ret = ec_node_or_add(cmdlist, cmd);
cmd = NULL; /* already freed, even on error */
if (ret < 0)
goto fail;
/* the lexer, added above the command list */
cmdlist = ec_node_sh_lex(EC_NO_ID, cmdlist);
if (cmdlist == NULL)
goto fail;
ec_node_free(names);
return cmdlist;
fail:
fprintf(stderr, "cannot initialize nodes\n");
ec_node_free(names);
ec_node_free(cmdlist);
ec_node_free(cmd);
return NULL;
}
int main(void)
{
struct ec_editline *editline = NULL;
struct ec_node *node = NULL;
if (ec_init() < 0) {
fprintf(stderr, "cannot init ecoli: %s\n", strerror(errno));
return 1;
}
node = create_commands();
if (node == NULL) {
fprintf(stderr, "failed to create commands: %s\n", strerror(errno));
goto fail;
}
editline = ec_editline("simple-editline", stdin, stdout, stderr, 0);
if (editline == NULL) {
fprintf(stderr, "Failed to initialize editline\n");
goto fail;
}
if (ec_editline_set_prompt(editline, "simple> ") < 0) {
fprintf(stderr, "Failed to set prompt\n");
goto fail;
}
ec_editline_set_node(editline, node);
if (ec_editline_interact(editline, check_exit, NULL) < 0)
goto fail;
ec_editline_free(editline);
ec_node_free(node);
return 0;
fail:
ec_editline_free(editline);
ec_node_free(node);
return 1;
}
ec_editline_set_prompt
int ec_editline_set_prompt(struct ec_editline *editline, const char *prompt)
Set editline prompt.
ec_editline
struct ec_editline * ec_editline(const char *prog, FILE *f_in, FILE *f_out, FILE *f_err, enum ec_editline_init_flags flags)
Create an editline instance with default behavior.
ec_editline_free
void ec_editline_free(struct ec_editline *editline)
Free an editline structure allocated with ec_editline().
ec_editline_interact
int ec_editline_interact(struct ec_editline *editline, ec_editline_check_exit_cb_t check_exit_cb, void *opaque)
Interact with the user until exit.
ec_editline_set_node
int ec_editline_set_node(struct ec_editline *editline, const struct ec_node *node)
Attach an ecoli node to the editline structure.
ec_init
int ec_init(void)
Initialize ecoli library.
ec_interact_set_help
int ec_interact_set_help(struct ec_node *node, const char *help)
Set help on a grammar node.
ec_interact_set_callback
int ec_interact_set_callback(struct ec_node *node, ec_interact_command_cb_t cb)
Set callback function on a grammar node.
ec_node_int
struct ec_node * ec_node_int(const char *id, int64_t min, int64_t max, unsigned int base)
Create a signed integer node.
ec_node_option
struct ec_node * ec_node_option(const char *id, struct ec_node *node)
Create an option node that makes its child optional.
ec_node_or_add
int ec_node_or_add(struct ec_node *node, struct ec_node *child)
Add a child to an "or" node.
EC_NODE_OR
#define EC_NODE_OR(args...)
Create a new "or" node from an arbitrary list of child nodes.
Definition node_or.h:23
EC_NODE_SEQ
#define EC_NODE_SEQ(args...)
Create a sequence node from a list of child nodes.
Definition node_seq.h:29
ec_node_sh_lex
struct ec_node * ec_node_sh_lex(const char *id, struct ec_node *child)
Create a shell lexer node.
ec_node_str
struct ec_node * ec_node_str(const char *id, const char *str)
Create a string node that matches a specific string.
ec_node_clone
struct ec_node * ec_node_clone(struct ec_node *node)
Clone a grammar node.
ec_node
struct ec_node * ec_node(const char *typename, const char *id)
Create a new node from its type name.
ec_node_find
struct ec_node * ec_node_find(struct ec_node *node, const char *id)
Find a node from its identifier string.
EC_NO_ID
#define EC_NO_ID
Node has no identifier.
Definition node.h:64
ec_node_free
void ec_node_free(struct ec_node *node)
Decrement node reference counter and free the node if it is the last reference.
ec_pnode_get_strvec
const struct ec_strvec * ec_pnode_get_strvec(const struct ec_pnode *pnode)
Get the string vector associated with a parsing node.
ec_pnode_find
const struct ec_pnode * ec_pnode_find(const struct ec_pnode *root, const char *id)
Find a node from its identifier.
ec_pnode
struct ec_pnode * ec_pnode(const struct ec_node *node)
Create an empty parsing tree.
ec_strvec_val
const char * ec_strvec_val(const struct ec_strvec *strvec, size_t idx)
Get a string element from a vector.