Libecoli  0.11.3
Extensible COmmand LIne library
simple-editline/main.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2025, Olivier MATZ <zer0@droids-corp.org>
3  */
4 
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include <ecoli.h>
32 
33 #define ID_NAME "id_name"
34 #define ID_JOHN "id_john"
35 #define ID_COUNT "id_count"
36 
37 /* stop program when true */
38 static bool done;
39 
40 static int hello_cb(const struct ec_pnode *parse)
41 {
42  const char *count;
43  const char *name;
44 
45  name = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_NAME)), 0);
46  count = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_COUNT)), 0);
47 
48  printf("you say hello to %s", name);
49  if (count)
50  printf(" %s times", count);
51  printf("\n");
52 
53  return 0;
54 }
55 
56 static int bye_cb(const struct ec_pnode *parse)
57 {
58  const char *name;
59 
60  name = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_NAME)), 0);
61  printf("you say bye to %s\n", name);
62 
63  return 0;
64 }
65 
66 static int exit_cb(const struct ec_pnode *parse)
67 {
68  (void)parse;
69 
70  printf("Exit !\n");
71  done = true;
72 
73  return 0;
74 }
75 
76 static int check_exit(void *opaque)
77 {
78  (void)opaque;
79  return done;
80 }
81 
82 static struct ec_node *create_commands(void)
83 {
84  struct ec_node *cmdlist = NULL, *cmd = NULL;
85  struct ec_node *names = NULL;
86  int ret;
87 
88  /* the top node containing the list of commands */
89  cmdlist = ec_node("or", EC_NO_ID);
90  if (cmdlist == NULL)
91  goto fail;
92 
93  /* a common subtree containing a list of names */
94  names = EC_NODE_OR(
95  ID_NAME,
96  ec_node_str(ID_JOHN, "john"),
97  ec_node_str(EC_NO_ID, "johnny"),
98  ec_node_str(EC_NO_ID, "mike")
99  );
100  if (names == NULL)
101  goto fail;
102 
103  /* the hello command */
104  cmd = EC_NODE_SEQ(
105  EC_NO_ID,
106  ec_node_str(EC_NO_ID, "hello"),
107  ec_node_clone(names),
108  ec_node_option(EC_NO_ID, ec_node_int(ID_COUNT, 0, 10, 10))
109  );
110  if (cmd == NULL)
111  goto fail;
112  if (ec_interact_set_callback(cmd, hello_cb) < 0)
113  goto fail;
114  if (ec_interact_set_help(cmd, "say hello to someone several times") < 0)
115  goto fail;
116  if (ec_interact_set_help(ec_node_find(cmd, ID_JOHN), "specific help for john") < 0)
117  goto fail;
118  if (ec_interact_set_help(ec_node_find(cmd, ID_NAME), "the name of the person") < 0)
119  goto fail;
120  if (ec_interact_set_help(ec_node_find(cmd, ID_COUNT), "an integer (0-10)") < 0)
121  goto fail;
122  ret = ec_node_or_add(cmdlist, cmd);
123  cmd = NULL; /* already freed, even on error */
124  if (ret < 0)
125  goto fail;
126 
127  /* the bye command */
128  cmd = EC_NODE_SEQ(EC_NO_ID, ec_node_str(EC_NO_ID, "bye"), ec_node_clone(names));
129  if (ec_interact_set_callback(cmd, bye_cb) < 0)
130  goto fail;
131  if (ec_interact_set_help(cmd, "say bye") < 0)
132  goto fail;
133  ret = ec_node_or_add(cmdlist, cmd);
134  cmd = NULL; /* already freed, even on error */
135  if (ret < 0)
136  goto fail;
137 
138  /* the exit command */
139  cmd = ec_node_str(EC_NO_ID, "exit");
140  if (ec_interact_set_callback(cmd, exit_cb) < 0)
141  goto fail;
142  if (ec_interact_set_help(cmd, "exit program") < 0)
143  goto fail;
144  ret = ec_node_or_add(cmdlist, cmd);
145  cmd = NULL; /* already freed, even on error */
146  if (ret < 0)
147  goto fail;
148 
149  /* the lexer, added above the command list */
150  cmdlist = ec_node_sh_lex(EC_NO_ID, cmdlist);
151  if (cmdlist == NULL)
152  goto fail;
153 
154  ec_node_free(names);
155 
156  return cmdlist;
157 
158 fail:
159  fprintf(stderr, "cannot initialize nodes\n");
160  ec_node_free(names);
161  ec_node_free(cmdlist);
162  ec_node_free(cmd);
163  return NULL;
164 }
165 
166 int main(void)
167 {
168  struct ec_editline *editline = NULL;
169  struct ec_node *node = NULL;
170 
171  if (ec_init() < 0) {
172  fprintf(stderr, "cannot init ecoli: %s\n", strerror(errno));
173  return 1;
174  }
175 
176  node = create_commands();
177  if (node == NULL) {
178  fprintf(stderr, "failed to create commands: %s\n", strerror(errno));
179  goto fail;
180  }
181 
182  editline = ec_editline("simple-editline", stdin, stdout, stderr, 0);
183  if (editline == NULL) {
184  fprintf(stderr, "Failed to initialize editline\n");
185  goto fail;
186  }
187 
188  if (ec_editline_set_prompt(editline, "simple> ") < 0) {
189  fprintf(stderr, "Failed to set prompt\n");
190  goto fail;
191  }
192  ec_editline_set_node(editline, node);
193 
194  if (ec_editline_interact(editline, check_exit, NULL) < 0)
195  goto fail;
196 
197  ec_editline_free(editline);
198  ec_node_free(node);
199  return 0;
200 
201 fail:
202  ec_editline_free(editline);
203  ec_node_free(node);
204  return 1;
205 }
int ec_editline_set_prompt(struct ec_editline *editline, const char *prompt)
void ec_editline_free(struct ec_editline *editline)
struct ec_editline * ec_editline(const char *prog, FILE *f_in, FILE *f_out, FILE *f_err, enum ec_editline_init_flags flags)
int ec_editline_interact(struct ec_editline *editline, ec_editline_check_exit_cb_t check_exit_cb, void *opaque)
int ec_editline_set_node(struct ec_editline *editline, const struct ec_node *node)
int ec_init(void)
int ec_interact_set_help(struct ec_node *node, const char *help)
int ec_interact_set_callback(struct ec_node *node, ec_interact_command_cb_t cb)
struct ec_node * ec_node_int(const char *id, int64_t min, int64_t max, unsigned int base)
struct ec_node * ec_node_option(const char *id, struct ec_node *node)
int ec_node_or_add(struct ec_node *node, struct ec_node *child)
#define EC_NODE_OR(args...)
Definition: node_or.h:23
#define EC_NODE_SEQ(args...)
Definition: node_seq.h:29
struct ec_node * ec_node_sh_lex(const char *id, struct ec_node *child)
struct ec_node * ec_node_str(const char *id, const char *str)
#define EC_NO_ID
Definition: node.h:64
struct ec_node * ec_node_clone(struct ec_node *node)
struct ec_node * ec_node_find(struct ec_node *node, const char *id)
struct ec_node * ec_node(const char *typename, const char *id)
void ec_node_free(struct ec_node *node)
const struct ec_pnode * ec_pnode_find(const struct ec_pnode *root, const char *id)
struct ec_pnode * ec_pnode(const struct ec_node *node)
const struct ec_strvec * ec_pnode_get_strvec(const struct ec_pnode *pnode)
const char * ec_strvec_val(const struct ec_strvec *strvec, size_t idx)