Libecoli  0.11.3
Extensible COmmand LIne library
node_bool_tuple.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
3  */
4 
5 #include <assert.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #include <ecoli.h>
11 
12 EC_LOG_TYPE_REGISTER(node_bool_tuple);
13 
14 enum bool_tuple_state {
15  BT_EMPTY,
16  BT_OPEN,
17  BT_BOOL,
18  BT_COMMA,
19  BT_END,
20  BT_FAIL,
21 };
22 
23 /* Check if input matches a bool tuple like this: "(true,false,true)". On success, *state is set to
24  * BT_END. If parsing is incomplete or fails, set the *state to something else, and return the
25  * pointer to the incomplete or failing token.
26  */
27 static const char *parse_bool_tuple(const char *input, enum bool_tuple_state *state)
28 {
29  *state = BT_EMPTY;
30  if (*input == '\0')
31  return input;
32 
33  if (*input != '(') {
34  *state = BT_FAIL;
35  return input;
36  }
37  input++;
38  *state = BT_OPEN;
39 
40  if (*input == ')') {
41  *state = BT_END;
42  input++;
43  if (*input != '\0') {
44  *state = BT_FAIL;
45  return input;
46  }
47 
48  return input;
49  }
50 
51  while (1) {
52  if (ec_str_startswith(input, "true")) {
53  input += 4;
54  } else if (ec_str_startswith(input, "false")) {
55  input += 5;
56  } else {
57  if (!ec_str_startswith("true", input) && !ec_str_startswith("false", input))
58  *state = BT_FAIL;
59  return input;
60  }
61 
62  *state = BT_BOOL;
63  if (*input == '\0')
64  return input;
65 
66  if (*input == ')') {
67  *state = BT_END;
68  input++;
69  if (*input != '\0') {
70  *state = BT_FAIL;
71  return input;
72  }
73  return input;
74  }
75 
76  if (*input != ',') {
77  *state = BT_FAIL;
78  return input;
79  }
80 
81  input++;
82  *state = BT_COMMA;
83  }
84 }
85 
86 static int ec_node_bool_tuple_parse(
87  const struct ec_node *node,
88  struct ec_pnode *pstate,
89  const struct ec_strvec *strvec
90 )
91 {
92  enum bool_tuple_state state;
93  const char *input;
94 
95  (void)node;
96  (void)pstate;
97 
98  if (ec_strvec_len(strvec) == 0)
99  return EC_PARSE_NOMATCH;
100 
101  input = ec_strvec_val(strvec, 0);
102  parse_bool_tuple(input, &state);
103 
104  if (state != BT_END)
105  return EC_PARSE_NOMATCH;
106 
107  return 1;
108 }
109 
110 static int ec_node_bool_tuple_complete(
111  const struct ec_node *node,
112  struct ec_comp *comp,
113  const struct ec_strvec *strvec
114 )
115 {
116  struct ec_comp_item *item = NULL;
117  const char *false_str = "false";
118  const char *true_str = "true";
119  enum bool_tuple_state state;
120  char *comp_str = NULL;
121  char *disp_str = NULL;
122  const char *incomplete;
123  const char *input;
124  int ret;
125 
126  if (ec_strvec_len(strvec) != 1)
127  return 0;
128 
129  input = ec_strvec_val(strvec, 0);
130  incomplete = parse_bool_tuple(input, &state);
131 
132  switch (state) {
133  case BT_EMPTY:
134  if (asprintf(&comp_str, "%s(", input) < 0)
135  goto fail;
136  if (asprintf(&disp_str, "(") < 0)
137  goto fail;
138  item = ec_comp_add_item(comp, node, EC_COMP_PARTIAL, input, comp_str);
139  if (item == NULL)
140  goto fail;
141  if (ec_comp_item_set_display(item, disp_str) < 0)
142  goto fail;
143  break;
144  case BT_OPEN:
145  if (incomplete[0] == '\0') {
146  if (asprintf(&comp_str, "%s)", input) < 0)
147  goto fail;
148  if (asprintf(&disp_str, ")") < 0)
149  goto fail;
150  item = ec_comp_add_item(comp, node, EC_COMP_FULL, input, comp_str);
151  if (item == NULL)
152  goto fail;
153  if (ec_comp_item_set_display(item, disp_str) < 0)
154  goto fail;
155  free(comp_str);
156  comp_str = NULL;
157  free(disp_str);
158  disp_str = NULL;
159  }
160  /* fallthrough */
161  case BT_COMMA:
162  if (incomplete[0] == 't' || incomplete[0] == '\0') {
163  if (asprintf(&comp_str, "%s%s", input, &true_str[strlen(incomplete)]) < 0)
164  goto fail;
165  if (asprintf(&disp_str, "true") < 0)
166  goto fail;
167  item = ec_comp_add_item(comp, node, EC_COMP_PARTIAL, input, comp_str);
168  if (item == NULL)
169  goto fail;
170  if (ec_comp_item_set_display(item, disp_str) < 0)
171  goto fail;
172  free(comp_str);
173  comp_str = NULL;
174  free(disp_str);
175  disp_str = NULL;
176  }
177  if (incomplete[0] == 'f' || incomplete[0] == '\0') {
178  if (asprintf(&comp_str, "%s%s", input, &false_str[strlen(incomplete)]) < 0)
179  goto fail;
180  if (asprintf(&disp_str, "false") < 0)
181  goto fail;
182  item = ec_comp_add_item(comp, node, EC_COMP_PARTIAL, input, comp_str);
183  if (item == NULL)
184  goto fail;
185  if (ec_comp_item_set_display(item, disp_str) < 0)
186  goto fail;
187  free(comp_str);
188  comp_str = NULL;
189  free(disp_str);
190  disp_str = NULL;
191  }
192  break;
193  case BT_BOOL:
194  if (asprintf(&comp_str, "%s,", input) < 0)
195  goto fail;
196  if (asprintf(&disp_str, ",") < 0)
197  goto fail;
198  item = ec_comp_add_item(comp, node, EC_COMP_PARTIAL, input, comp_str);
199  if (item == NULL)
200  goto fail;
201  if (ec_comp_item_set_display(item, disp_str) < 0)
202  goto fail;
203  if (asprintf(&comp_str, "%s)", input) < 0)
204  goto fail;
205  if (asprintf(&disp_str, ")") < 0)
206  goto fail;
207  item = ec_comp_add_item(comp, node, EC_COMP_PARTIAL, input, comp_str);
208  if (item == NULL)
209  goto fail;
210  if (ec_comp_item_set_display(item, disp_str) < 0)
211  goto fail;
212  break;
213  case BT_END:
214  item = ec_comp_add_item(comp, node, EC_COMP_FULL, input, input);
215  if (item == NULL)
216  goto fail;
217  break;
218  default:
219  break;
220  }
221 
222  ret = 0;
223 out:
224  free(comp_str);
225  free(disp_str);
226 
227  return ret;
228 
229 fail:
230  ret = -1;
231  goto out;
232 }
233 
234 static struct ec_node_type ec_node_bool_tuple_type = {
235  .name = "bool_tuple",
236  .parse = ec_node_bool_tuple_parse,
237  .complete = ec_node_bool_tuple_complete,
238 };
239 
240 EC_NODE_TYPE_REGISTER(ec_node_bool_tuple_type);
struct ec_comp * ec_comp(void)
struct ec_comp_item * ec_comp_add_item(struct ec_comp *comp, const struct ec_node *node, enum ec_comp_type type, const char *current, const char *full)
int ec_comp_item_set_display(struct ec_comp_item *item, const char *display)
@ EC_COMP_FULL
Definition: complete.h:49
@ EC_COMP_PARTIAL
Definition: complete.h:50
#define EC_LOG_TYPE_REGISTER(name)
Definition: log.h:69
#define EC_NODE_TYPE_REGISTER(t)
Definition: node.h:88
struct ec_node * ec_node(const char *typename, const char *id)
#define EC_PARSE_NOMATCH
Definition: parse.h:145
struct ec_pnode * ec_pnode(const struct ec_node *node)
int ec_str_startswith(const char *s, const char *beginning)
struct ec_strvec * ec_strvec(void)
size_t ec_strvec_len(const struct ec_strvec *strvec)
const char * ec_strvec_val(const struct ec_strvec *strvec, size_t idx)