source: cmd.c @ 257b9c4

release-1.8release-1.9
Last change on this file since 257b9c4 was f25df21, checked in by David Benjamin <davidben@mit.edu>, 11 years ago
Don't call owl_list_create in owl_dict_get_keys Until we get rid of this owl_list thing altogether, there should be a convention as to who initializes the thing. Otherwise, we leak memory from people initializing it too many times. Whoever reviews this probably wants to look over this very carefully in case I missed one of the owl_list_creates. Also kill the various wrappers over owl_list_cleanup as they are not the inverse of any operation.
  • Property mode set to 100644
File size: 8.5 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include "owl.h"
6
7extern const owl_cmd commands_to_init[];
8
9/**************************************************************************/
10/***************************** COMMAND DICT *******************************/
11/**************************************************************************/
12
13int owl_cmddict_setup(owl_cmddict *cd) {
14  if (0 != owl_cmddict_init(cd)) return(-1);
15  if (0 != owl_cmddict_add_from_list(cd, commands_to_init)) return(-1);
16  return(0);
17}
18
19int owl_cmddict_init(owl_cmddict *cd) {
20  if (owl_dict_create(cd)) return(-1);
21  return(0);
22}
23
24/* for bulk initialization at startup */
25int owl_cmddict_add_from_list(owl_cmddict *cd, const owl_cmd *cmds) {
26  const owl_cmd *cur;
27  int ret = 0;
28  for (cur = cmds; cur->name != NULL; cur++) {
29    ret = owl_cmddict_add_cmd(cd, cur);
30    if (ret < 0) break;
31  }
32  return ret;
33}
34
35void owl_cmddict_get_names(const owl_cmddict *d, owl_list *l) {
36  owl_dict_get_keys(d, l);
37}
38
39const owl_cmd *owl_cmddict_find(const owl_cmddict *d, const char *name) {
40  return owl_dict_find_element(d, name);
41}
42
43/* creates a new command alias */
44int owl_cmddict_add_alias(owl_cmddict *cd, const char *alias_from, const char *alias_to) {
45  owl_cmd *cmd;
46  cmd = g_new(owl_cmd, 1);
47  owl_cmd_create_alias(cmd, alias_from, alias_to);
48  owl_perlconfig_new_command(cmd->name);
49  owl_dict_insert_element(cd, cmd->name, cmd, (void (*)(void *))owl_cmd_delete);
50  return(0);
51}
52
53int owl_cmddict_add_cmd(owl_cmddict *cd, const owl_cmd * cmd) {
54  owl_cmd * newcmd = g_new(owl_cmd, 1);
55  if(owl_cmd_create_from_template(newcmd, cmd) < 0) {
56    g_free(newcmd);
57    return -1;
58  }
59  owl_perlconfig_new_command(cmd->name);
60  return owl_dict_insert_element(cd, newcmd->name, newcmd, (void (*)(void *))owl_cmd_delete);
61}
62
63char *_owl_cmddict_execute(const owl_cmddict *cd, const owl_context *ctx, const char *const *argv, int argc, const char *buff) {
64  char *retval = NULL;
65  const owl_cmd *cmd;
66
67  if (!strcmp(argv[0], "")) {
68  } else if (NULL != (cmd = owl_dict_find_element(cd, argv[0]))) {
69    retval = owl_cmd_execute(cmd, cd, ctx, argc, argv, buff);
70    /* redraw the sepbar; TODO: don't violate layering */
71    owl_global_sepbar_dirty(&g);
72  } else {
73    owl_function_makemsg("Unknown command '%s'.", buff);
74  }
75  return retval;
76}
77
78char *owl_cmddict_execute(const owl_cmddict *cd, const owl_context *ctx, const char *cmdbuff) {
79  char **argv;
80  int argc;
81  char *retval = NULL;
82
83  argv = owl_parseline(cmdbuff, &argc);
84  if (argv == NULL) {
85    owl_function_makemsg("Unbalanced quotes");
86    return NULL;
87  } 
88 
89  if (argc < 1) {
90    g_strfreev(argv);
91    return NULL;
92  }
93
94  retval = _owl_cmddict_execute(cd, ctx, strs(argv), argc, cmdbuff);
95
96  g_strfreev(argv);
97  return retval;
98}
99
100char *owl_cmddict_execute_argv(const owl_cmddict *cd, const owl_context *ctx, const char *const *argv, int argc) {
101  GString *buf = g_string_new("");
102  int i;
103  char *retval;
104
105  /* We weren't given a command line, so fabricate a valid one. */
106  for(i = 0; i < argc; i++) {
107    if (i != 0)
108      g_string_append_c(buf, ' ');
109    owl_string_append_quoted_arg(buf, argv[i]);
110  }
111
112  retval = _owl_cmddict_execute(cd, ctx, argv, argc, buf->str);
113
114  g_string_free(buf, true);
115  return retval;
116}
117
118/*********************************************************************/
119/***************************** COMMAND *******************************/
120/*********************************************************************/
121
122/* sets up a new command based on a template, copying strings */
123int owl_cmd_create_from_template(owl_cmd *cmd, const owl_cmd *templ) {
124  *cmd = *templ;
125  if (!templ->name) return(-1);
126  cmd->name = g_strdup(templ->name);
127  if (templ->summary)     cmd->summary     = g_strdup(templ->summary);
128  if (templ->usage)       cmd->usage       = g_strdup(templ->usage);
129  if (templ->description) cmd->description = g_strdup(templ->description);
130  if (templ->cmd_aliased_to) cmd->cmd_aliased_to = g_strdup(templ->cmd_aliased_to);
131  return(0);
132}
133
134int owl_cmd_create_alias(owl_cmd *cmd, const char *name, const char *aliased_to) {
135  memset(cmd, 0, sizeof(owl_cmd));
136  cmd->name = g_strdup(name);
137  cmd->cmd_aliased_to = g_strdup(aliased_to);
138  cmd->summary = g_strdup_printf("%s%s", OWL_CMD_ALIAS_SUMMARY_PREFIX, aliased_to);
139  return(0);
140}
141
142void owl_cmd_cleanup(owl_cmd *cmd)
143{
144  if (cmd->name) g_free(cmd->name);
145  if (cmd->summary) g_free(cmd->summary);
146  if (cmd->usage) g_free(cmd->usage);
147  if (cmd->description) g_free(cmd->description);
148  if (cmd->cmd_aliased_to) g_free(cmd->cmd_aliased_to);
149  if (cmd->cmd_perl) owl_perlconfig_cmd_cleanup(cmd);
150}
151
152void owl_cmd_delete(owl_cmd *cmd)
153{
154  owl_cmd_cleanup(cmd);
155  g_free(cmd);
156}
157
158int owl_cmd_is_context_valid(const owl_cmd *cmd, const owl_context *ctx) { 
159  if (owl_context_matches(ctx, cmd->validctx)) return 1;
160  else return 0;
161}
162
163char *owl_cmd_execute(const owl_cmd *cmd, const owl_cmddict *cd, const owl_context *ctx, int argc, const char *const *argv, const char *cmdbuff) {
164  static int alias_recurse_depth = 0;
165  int ival=0;
166  const char *cmdbuffargs;
167  char *newcmd, *rv=NULL;
168
169  if (argc < 1) return(NULL);
170
171  /* Recurse if this is an alias */
172  if (cmd->cmd_aliased_to) {
173    if (alias_recurse_depth++ > 50) {
174      owl_function_makemsg("Alias loop detected for '%s'.", cmdbuff);
175    } else {
176      cmdbuffargs = skiptokens(cmdbuff, 1);
177      newcmd = g_strdup_printf("%s %s", cmd->cmd_aliased_to, cmdbuffargs);
178      rv = owl_function_command(newcmd);
179      g_free(newcmd);
180    } 
181    alias_recurse_depth--;
182    return rv;
183  }
184
185  /* Do validation and conversions */
186  if (cmd->cmd_ctxargs_fn || cmd->cmd_ctxv_fn || cmd->cmd_ctxi_fn) {
187    if (!owl_cmd_is_context_valid(cmd, ctx)) {
188      owl_function_makemsg("Invalid context for command '%s'.", cmdbuff);
189      return NULL;
190    }
191  }
192
193  if ((argc != 1) && (cmd->cmd_v_fn || cmd->cmd_ctxv_fn)) {
194    owl_function_makemsg("Wrong number of arguments for %s command.", argv[0]);
195    return NULL;
196  }
197
198  if (cmd->cmd_i_fn || cmd->cmd_ctxi_fn) {
199      char *ep;
200      if (argc != 2) {
201        owl_function_makemsg("Wrong number of arguments for %s command.", argv[0]);
202        return NULL;
203      }
204      ival = strtol(argv[1], &ep, 10);
205      if (*ep || ep==argv[1]) {
206        owl_function_makemsg("Invalid argument '%s' for %s command.", argv[1], argv[0]);
207        return(NULL);
208      }
209  }
210
211  if (cmd->cmd_args_fn) {
212    return cmd->cmd_args_fn(argc, argv, cmdbuff);
213  } else if (cmd->cmd_v_fn) {   
214    cmd->cmd_v_fn();
215  } else if (cmd->cmd_i_fn) {
216    cmd->cmd_i_fn(ival);
217  } else if (cmd->cmd_ctxargs_fn) {
218    return cmd->cmd_ctxargs_fn(owl_context_get_data(ctx), argc, argv, cmdbuff);
219  } else if (cmd->cmd_ctxv_fn) {   
220    cmd->cmd_ctxv_fn(owl_context_get_data(ctx));
221  } else if (cmd->cmd_ctxi_fn) {
222    cmd->cmd_ctxi_fn(owl_context_get_data(ctx), ival);
223  } else if (cmd->cmd_perl) {
224    return owl_perlconfig_perlcmd(cmd, argc, argv);
225  }
226
227  return NULL;
228}
229
230/* returns a reference */
231const char *owl_cmd_get_summary(const owl_cmd *cmd) {
232  return cmd->summary;
233}
234
235/* returns a summary line describing this keymap.  the caller must free. */
236char *owl_cmd_describe(const owl_cmd *cmd) {
237  if (!cmd || !cmd->name || !cmd->summary) return NULL;
238  return g_strdup_printf("%-25s - %s", cmd->name, cmd->summary);
239}
240
241
242
243void owl_cmd_get_help(const owl_cmddict *d, const char *name, owl_fmtext *fm) {
244  const char *s;
245  char *indent;
246  owl_cmd *cmd;
247
248  if (!name || (cmd = owl_dict_find_element(d, name)) == NULL) {
249    owl_fmtext_append_bold(fm, "OWL HELP\n\n");
250    owl_fmtext_append_normal(fm, "No such command...\n");
251    return;
252  }
253
254  owl_fmtext_append_bold(fm, "OWL HELP\n\n");
255  owl_fmtext_append_bold(fm, "NAME\n\n");
256  owl_fmtext_append_normal(fm, OWL_TABSTR);
257  owl_fmtext_append_normal(fm, cmd->name);
258
259  if (cmd->summary && *cmd->summary) {
260    owl_fmtext_append_normal(fm, " - ");
261    owl_fmtext_append_normal(fm, cmd->summary);
262  }
263  owl_fmtext_append_normal(fm, "\n");
264
265  if (cmd->usage && *cmd->usage) {
266    s = cmd->usage;
267    indent = owl_text_indent(s, OWL_TAB);
268    owl_fmtext_append_bold(fm, "\nSYNOPSIS\n");
269    owl_fmtext_append_normal(fm, indent);
270    owl_fmtext_append_normal(fm, "\n");
271    g_free(indent);
272  } else {
273    owl_fmtext_append_bold(fm, "\nSYNOPSIS\n");
274    owl_fmtext_append_normal(fm, OWL_TABSTR);
275    owl_fmtext_append_normal(fm, cmd->name);
276    owl_fmtext_append_normal(fm, "\n");
277  }
278
279  if (cmd->description && *cmd->description) {
280    s = cmd->description;
281    indent = owl_text_indent(s, OWL_TAB);
282    owl_fmtext_append_bold(fm, "\nDESCRIPTION\n");
283    owl_fmtext_append_normal(fm, indent);
284    owl_fmtext_append_normal(fm, "\n");
285    g_free(indent);
286  }
287
288  owl_fmtext_append_normal(fm, "\n\n"); 
289}
Note: See TracBrowser for help on using the repository browser.