1 /*
2   * command.c
3   *
4   * This file provides the implementation of a command definition
5   */
6 #include "private.h"
7 #include "clish/types.h"
8 #include "lub/bintree.h"
9 #include "lub/string.h"
10 
11 #include <assert.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
15 
16 /*---------------------------------------------------------
17  * PRIVATE METHODS
18  *--------------------------------------------------------- */
19 static void
clish_command_init(clish_command_t * this,const char * name,const char * text)20 clish_command_init(clish_command_t *this, const char *name, const char *text)
21 {
22 	/* initialise the node part */
23 	this->name = lub_string_dup(name);
24 	this->text = lub_string_dup(text);
25 
26 	/* Be a good binary tree citizen */
27 	lub_bintree_node_init(&this->bt_node);
28 
29 	/* set up defaults */
30 	this->link = NULL;
31 	this->alias = NULL;
32 	this->alias_view = NULL;
33 	this->paramv = clish_paramv_new();
34 	this->viewid = NULL;
35 	this->viewname = NULL;
36 	this->action = clish_action_new();
37 	this->config = clish_config_new();
38 	this->detail = NULL;
39 	this->escape_chars = NULL;
40 	this->regex_chars = NULL;
41 	this->args = NULL;
42 	this->pview = NULL;
43 	this->lock = BOOL_TRUE;
44 	this->interrupt = BOOL_FALSE;
45 	this->dynamic = BOOL_FALSE;
46 	this->internal = BOOL_FALSE;
47 	this->access = NULL;
48 }
49 
50 /*--------------------------------------------------------- */
clish_command_fini(clish_command_t * this)51 static void clish_command_fini(clish_command_t * this)
52 {
53 	lub_string_free(this->name);
54 	lub_string_free(this->text);
55 
56 	/* Link need not full cleanup */
57 	if (this->link)
58 		return;
59 
60 	/* finalize each of the parameter instances */
61 	clish_paramv_delete(this->paramv);
62 
63 	clish_action_delete(this->action);
64 	clish_config_delete(this->config);
65 	lub_string_free(this->alias);
66 	lub_string_free(this->alias_view);
67 	lub_string_free(this->viewname);
68 	lub_string_free(this->viewid);
69 	lub_string_free(this->detail);
70 	lub_string_free(this->escape_chars);
71 	lub_string_free(this->regex_chars);
72 	lub_string_free(this->access);
73 	if (this->args)
74 		clish_param_delete(this->args);
75 }
76 
77 /*---------------------------------------------------------
78  * PUBLIC META FUNCTIONS
79  *--------------------------------------------------------- */
clish_command_bt_offset(void)80 size_t clish_command_bt_offset(void)
81 {
82 	return offsetof(clish_command_t, bt_node);
83 }
84 
85 /*--------------------------------------------------------- */
clish_command_bt_compare(const void * clientnode,const void * clientkey)86 int clish_command_bt_compare(const void *clientnode, const void *clientkey)
87 {
88 	const clish_command_t *this = clientnode;
89 	const char *key = clientkey;
90 
91 	return lub_string_nocasecmp(this->name, key);
92 }
93 
94 /*--------------------------------------------------------- */
clish_command_bt_getkey(const void * clientnode,lub_bintree_key_t * key)95 void clish_command_bt_getkey(const void *clientnode, lub_bintree_key_t * key)
96 {
97 	const clish_command_t *this = clientnode;
98 
99 	/* fill out the opaque key */
100 	strcpy((char *)key, this->name);
101 }
102 
103 /*--------------------------------------------------------- */
clish_command_new(const char * name,const char * help)104 clish_command_t *clish_command_new(const char *name, const char *help)
105 {
106 	clish_command_t *this = malloc(sizeof(clish_command_t));
107 
108 	if (this)
109 		clish_command_init(this, name, help);
110 
111 	return this;
112 }
113 
114 /*--------------------------------------------------------- */
clish_command_new_link(const char * name,const char * help,const clish_command_t * ref)115 clish_command_t *clish_command_new_link(const char *name,
116 	const char *help, const clish_command_t * ref)
117 {
118 	if (!ref)
119 		return NULL;
120 
121 	clish_command_t *this = malloc(sizeof(clish_command_t));
122 	assert(this);
123 
124 	/* Copy all fields to the new command-link */
125 	*this = *ref;
126 	/* Initialise the name (other than original name) */
127 	this->name = lub_string_dup(name);
128 	/* Initialise the help (other than original help) */
129 	this->text = lub_string_dup(help);
130 	/* Be a good binary tree citizen */
131 	lub_bintree_node_init(&this->bt_node);
132 	/* It a link to command so set the link flag */
133 	this->link = ref;
134 
135 	return this;
136 }
137 
138 /*--------------------------------------------------------- */
clish_command_alias_to_link(clish_command_t * this,clish_command_t * ref)139 clish_command_t * clish_command_alias_to_link(clish_command_t *this, clish_command_t *ref)
140 {
141 	clish_command_t tmp;
142 
143 	if (!this || !ref)
144 		return NULL;
145 	if (ref->alias) /* The reference is a link too */
146 		return NULL;
147 	memcpy(&tmp, this, sizeof(tmp));
148 	*this = *ref;
149 	memcpy(&this->bt_node, &tmp.bt_node, sizeof(tmp.bt_node));
150 	this->name = lub_string_dup(tmp.name); /* Save an original name */
151 	this->text = lub_string_dup(tmp.text); /* Save an original help */
152 	this->link = ref;
153 	this->pview = tmp.pview; /* Save an original parent view */
154 	clish_command_fini(&tmp);
155 
156 	return this;
157 }
158 
159 /*---------------------------------------------------------
160  * PUBLIC METHODS
161  *--------------------------------------------------------- */
clish_command_delete(clish_command_t * this)162 void clish_command_delete(clish_command_t * this)
163 {
164 	clish_command_fini(this);
165 	free(this);
166 }
167 
168 /*--------------------------------------------------------- */
clish_command_insert_param(clish_command_t * this,clish_param_t * param)169 void clish_command_insert_param(clish_command_t * this, clish_param_t * param)
170 {
171 	clish_paramv_insert(this->paramv, param);
172 }
173 
174 /*--------------------------------------------------------- */
clish_command_help(const clish_command_t * this)175 int clish_command_help(const clish_command_t *this)
176 {
177 	this = this; /* Happy compiler */
178 
179 	return 0;
180 }
181 
182 /*--------------------------------------------------------- */
clish_command_choose_longest(clish_command_t * cmd1,clish_command_t * cmd2)183 clish_command_t *clish_command_choose_longest(clish_command_t * cmd1,
184 	clish_command_t * cmd2)
185 {
186 	unsigned len1 = (cmd1 ? strlen(clish_command__get_name(cmd1)) : 0);
187 	unsigned len2 = (cmd2 ? strlen(clish_command__get_name(cmd2)) : 0);
188 
189 	if (len2 < len1) {
190 		return cmd1;
191 	} else if (len1 < len2) {
192 		return cmd2;
193 	} else {
194 		/* let local view override */
195 		return cmd1;
196 	}
197 }
198 
199 /*--------------------------------------------------------- */
clish_command_diff(const clish_command_t * cmd1,const clish_command_t * cmd2)200 int clish_command_diff(const clish_command_t * cmd1,
201 	const clish_command_t * cmd2)
202 {
203 	if (NULL == cmd1) {
204 		if (NULL != cmd2)
205 			return 1;
206 		else
207 			return 0;
208 	}
209 	if (NULL == cmd2)
210 		return -1;
211 
212 	return lub_string_nocasecmp(clish_command__get_name(cmd1),
213 		clish_command__get_name(cmd2));
214 }
215 
216 /*---------------------------------------------------------
217  * PUBLIC ATTRIBUTES
218  *--------------------------------------------------------- */
clish_command__get_name(const clish_command_t * this)219 const char *clish_command__get_name(const clish_command_t * this)
220 {
221 	if (!this)
222 		return NULL;
223 	return this->name;
224 }
225 
226 /*--------------------------------------------------------- */
clish_command__get_text(const clish_command_t * this)227 const char *clish_command__get_text(const clish_command_t * this)
228 {
229 	return this->text;
230 }
231 
232 /*--------------------------------------------------------- */
clish_command__get_detail(const clish_command_t * this)233 const char *clish_command__get_detail(const clish_command_t * this)
234 {
235 	return this->detail;
236 }
237 
238 /*--------------------------------------------------------- */
clish_command__set_detail(clish_command_t * this,const char * detail)239 void clish_command__set_detail(clish_command_t * this, const char *detail)
240 {
241 	assert(NULL == this->detail);
242 	this->detail = lub_string_dup(detail);
243 }
244 
245 /*--------------------------------------------------------- */
clish_command__get_action(const clish_command_t * this)246 clish_action_t *clish_command__get_action(const clish_command_t *this)
247 {
248 	return this->action;
249 }
250 
251 /*--------------------------------------------------------- */
clish_command__get_config(const clish_command_t * this)252 clish_config_t *clish_command__get_config(const clish_command_t *this)
253 {
254 	return this->config;
255 }
256 
257 /*--------------------------------------------------------- */
clish_command__set_viewname(clish_command_t * this,const char * viewname)258 void clish_command__set_viewname(clish_command_t * this, const char *viewname)
259 {
260 	assert(NULL == this->viewname);
261 	clish_command__force_viewname(this, viewname);
262 }
263 
264 /*--------------------------------------------------------- */
clish_command__force_viewname(clish_command_t * this,const char * viewname)265 void clish_command__force_viewname(clish_command_t * this, const char *viewname)
266 {
267 	if (this->viewname)
268 		lub_string_free(this->viewname);
269 	this->viewname = lub_string_dup(viewname);
270 }
271 
272 /*--------------------------------------------------------- */
clish_command__get_viewname(const clish_command_t * this)273 char *clish_command__get_viewname(const clish_command_t * this)
274 {
275 	return this->viewname;
276 }
277 
278 /*--------------------------------------------------------- */
clish_command__set_viewid(clish_command_t * this,const char * viewid)279 void clish_command__set_viewid(clish_command_t * this, const char *viewid)
280 {
281 	assert(NULL == this->viewid);
282 	clish_command__force_viewid(this, viewid);
283 }
284 
285 /*--------------------------------------------------------- */
clish_command__force_viewid(clish_command_t * this,const char * viewid)286 void clish_command__force_viewid(clish_command_t * this, const char *viewid)
287 {
288 	if (this->viewid)
289 		lub_string_free(this->viewid);
290 	this->viewid = lub_string_dup(viewid);
291 }
292 
293 /*--------------------------------------------------------- */
clish_command__get_viewid(const clish_command_t * this)294 char *clish_command__get_viewid(const clish_command_t * this)
295 {
296 	return this->viewid;
297 }
298 
299 /*--------------------------------------------------------- */
clish_command__get_param(const clish_command_t * this,unsigned index)300 const clish_param_t *clish_command__get_param(const clish_command_t * this,
301 	unsigned index)
302 {
303 	return clish_paramv__get_param(this->paramv, index);
304 }
305 
306 /*--------------------------------------------------------- */
clish_command__get_suffix(const clish_command_t * this)307 const char *clish_command__get_suffix(const clish_command_t * this)
308 {
309 	return lub_string_suffix(this->name);
310 }
311 
312 /*--------------------------------------------------------- */
313 void
clish_command__set_escape_chars(clish_command_t * this,const char * escape_chars)314 clish_command__set_escape_chars(clish_command_t * this,
315 	const char *escape_chars)
316 {
317 	assert(!this->escape_chars);
318 	this->escape_chars = lub_string_dup(escape_chars);
319 }
320 
321 /*--------------------------------------------------------- */
clish_command__get_escape_chars(const clish_command_t * this)322 const char *clish_command__get_escape_chars(const clish_command_t * this)
323 {
324 	return this->escape_chars;
325 }
326 
327 /*--------------------------------------------------------- */
clish_command__set_regex_chars(clish_command_t * this,const char * escape_chars)328 void clish_command__set_regex_chars(clish_command_t *this,
329 	const char *escape_chars)
330 {
331 	assert(!this->regex_chars);
332 	this->regex_chars = lub_string_dup(escape_chars);
333 }
334 
335 /*--------------------------------------------------------- */
clish_command__get_regex_chars(const clish_command_t * this)336 const char *clish_command__get_regex_chars(const clish_command_t *this)
337 {
338 	return this->regex_chars;
339 }
340 
341 /*--------------------------------------------------------- */
clish_command__set_args(clish_command_t * this,clish_param_t * args)342 void clish_command__set_args(clish_command_t * this, clish_param_t * args)
343 {
344 	assert(NULL == this->args);
345 	this->args = args;
346 }
347 
348 /*--------------------------------------------------------- */
clish_command__get_args(const clish_command_t * this)349 clish_param_t *clish_command__get_args(const clish_command_t * this)
350 {
351 	return this->args;
352 }
353 
354 /*--------------------------------------------------------- */
clish_command__get_param_count(const clish_command_t * this)355 unsigned int clish_command__get_param_count(const clish_command_t * this)
356 {
357 	return clish_paramv__get_count(this->paramv);
358 }
359 
360 /*--------------------------------------------------------- */
clish_command__get_paramv(const clish_command_t * this)361 clish_paramv_t *clish_command__get_paramv(const clish_command_t * this)
362 {
363 	return this->paramv;
364 }
365 
366 /*--------------------------------------------------------- */
clish_command__set_pview(clish_command_t * this,clish_view_t * view)367 void clish_command__set_pview(clish_command_t * this, clish_view_t * view)
368 {
369 	this->pview = view;
370 }
371 
372 /*--------------------------------------------------------- */
clish_command__get_pview(const clish_command_t * this)373 clish_view_t *clish_command__get_pview(const clish_command_t * this)
374 {
375 	return this->pview;
376 }
377 
378 /*--------------------------------------------------------- */
clish_command__get_depth(const clish_command_t * this)379 int clish_command__get_depth(const clish_command_t * this)
380 {
381 	if (!this->pview)
382 		return 0;
383 	return clish_view__get_depth(this->pview);
384 }
385 
386 /*--------------------------------------------------------- */
clish_command__get_restore(const clish_command_t * this)387 clish_view_restore_e clish_command__get_restore(const clish_command_t * this)
388 {
389 	if (!this->pview)
390 		return CLISH_RESTORE_NONE;
391 	return clish_view__get_restore(this->pview);
392 }
393 
394 /*--------------------------------------------------------- */
clish_command__get_orig(const clish_command_t * this)395 const clish_command_t * clish_command__get_orig(const clish_command_t * this)
396 {
397 	if (this->link)
398 		return clish_command__get_orig(this->link);
399 	return this;
400 }
401 
402 /*--------------------------------------------------------- */
clish_command__get_lock(const clish_command_t * this)403 bool_t clish_command__get_lock(const clish_command_t * this)
404 {
405 	return this->lock;
406 }
407 
408 /*--------------------------------------------------------- */
clish_command__set_lock(clish_command_t * this,bool_t lock)409 void clish_command__set_lock(clish_command_t * this, bool_t lock)
410 {
411 	this->lock = lock;
412 }
413 
414 /*--------------------------------------------------------- */
clish_command__set_alias(clish_command_t * this,const char * alias)415 void clish_command__set_alias(clish_command_t * this, const char * alias)
416 {
417 	if (this->alias)
418 		lub_string_free(this->alias);
419 	this->alias = lub_string_dup(alias);
420 }
421 
422 /*--------------------------------------------------------- */
clish_command__get_alias(const clish_command_t * this)423 const char * clish_command__get_alias(const clish_command_t * this)
424 {
425 	return this->alias;
426 }
427 
428 /*--------------------------------------------------------- */
clish_command__set_alias_view(clish_command_t * this,const char * alias_view)429 void clish_command__set_alias_view(clish_command_t *this,
430 	const char *alias_view)
431 {
432 	if (this->alias_view)
433 		lub_string_free(this->alias_view);
434 	this->alias_view = lub_string_dup(alias_view);
435 }
436 
437 /*--------------------------------------------------------- */
clish_command__get_alias_view(const clish_command_t * this)438 const char * clish_command__get_alias_view(const clish_command_t * this)
439 {
440 	return this->alias_view;
441 }
442 
443 /*--------------------------------------------------------- */
clish_command__set_dynamic(clish_command_t * this,bool_t dynamic)444 void clish_command__set_dynamic(clish_command_t * this, bool_t dynamic)
445 {
446 	this->dynamic = dynamic;
447 }
448 
449 /*--------------------------------------------------------- */
clish_command__get_dynamic(const clish_command_t * this)450 bool_t clish_command__get_dynamic(const clish_command_t * this)
451 {
452 	return this->dynamic;
453 }
454 
455 /*--------------------------------------------------------- */
clish_command__set_internal(clish_command_t * this,bool_t internal)456 void clish_command__set_internal(clish_command_t * this, bool_t internal)
457 {
458 	this->internal = internal;
459 }
460 
461 /*--------------------------------------------------------- */
clish_command__get_internal(const clish_command_t * this)462 bool_t clish_command__get_internal(const clish_command_t * this)
463 {
464 	return this->internal;
465 }
466 
467 /*--------------------------------------------------------- */
clish_command__get_cmd(const clish_command_t * this)468 const clish_command_t * clish_command__get_cmd(const clish_command_t * this)
469 {
470 	if (!this->dynamic)
471 		return this;
472 	if (this->link)
473 		return clish_command__get_cmd(this->link);
474 	return NULL;
475 }
476 
477 /*--------------------------------------------------------- */
clish_command__get_interrupt(const clish_command_t * this)478 bool_t clish_command__get_interrupt(const clish_command_t * this)
479 {
480 	return this->interrupt;
481 }
482 
483 /*--------------------------------------------------------- */
clish_command__set_interrupt(clish_command_t * this,bool_t interrupt)484 void clish_command__set_interrupt(clish_command_t * this, bool_t interrupt)
485 {
486 	this->interrupt = interrupt;
487 }
488 
489 /*--------------------------------------------------------- */
clish_command__set_access(clish_command_t * this,const char * access)490 void clish_command__set_access(clish_command_t *this, const char *access)
491 {
492 	if (this->access)
493 		lub_string_free(this->access);
494 	this->access = lub_string_dup(access);
495 }
496 
497 /*--------------------------------------------------------- */
clish_command__get_access(const clish_command_t * this)498 char *clish_command__get_access(const clish_command_t *this)
499 {
500 	return this->access;
501 }
502