source: cmd.c @ 95b52d1

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