2 * Makes it easy to support "ensembles". i.e. commands with subcommands
3 * like [string] and [array]
5 * (c) 2008 Steve Bennett <steveb@workware.net.au>
11 #include <jim-subcmd.h>
14 * Implements the common 'commands' subcommand
16 static int subcmd_null(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18 /* Nothing to do, since the result has already been created */
23 * Do-nothing command to support -commands and -usage
25 static const jim_subcmd_type dummy_subcmd
= {
26 "dummy", NULL
, subcmd_null
, 0, 0, JIM_MODFLAG_HIDDEN
29 static void add_commands(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, const char *sep
)
33 for (; ct
->cmd
; ct
++) {
34 if (!(ct
->flags
& JIM_MODFLAG_HIDDEN
)) {
35 Jim_AppendStrings(interp
, Jim_GetResult(interp
), s
, ct
->cmd
, NULL
);
41 static void bad_subcmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, const char *type
,
42 Jim_Obj
*cmd
, Jim_Obj
*subcmd
)
44 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
45 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), ", ", type
,
46 " command \"", Jim_String(subcmd
), "\": should be ", NULL
);
47 add_commands(interp
, command_table
, ", ");
50 static void show_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, int argc
,
53 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
54 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Usage: \"", Jim_String(argv
[0]),
55 " command ... \", where command is one of: ", NULL
);
56 add_commands(interp
, command_table
, ", ");
59 static void add_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, Jim_Obj
*cmd
)
62 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), " ", NULL
);
64 Jim_AppendStrings(interp
, Jim_GetResult(interp
), ct
->cmd
, NULL
);
65 if (ct
->args
&& *ct
->args
) {
66 Jim_AppendStrings(interp
, Jim_GetResult(interp
), " ", ct
->args
, NULL
);
70 static void set_wrong_args(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, Jim_Obj
*subcmd
)
72 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
73 add_cmd_usage(interp
, command_table
, subcmd
);
74 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
77 const jim_subcmd_type
*Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
,
78 int argc
, Jim_Obj
*const *argv
)
80 const jim_subcmd_type
*ct
;
81 const jim_subcmd_type
*partial
= 0;
88 cmdname
= Jim_String(argv
[0]);
91 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
92 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "wrong # args: should be \"", cmdname
,
93 " command ...\"\n", NULL
);
94 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Use \"", cmdname
, " -help ?command?\" for help", NULL
);
100 /* Check for the help command */
101 if (Jim_CompareStringImmediate(interp
, cmd
, "-help")) {
103 /* Usage for the command, not the subcommand */
104 show_cmd_usage(interp
, command_table
, argc
, argv
);
105 return &dummy_subcmd
;
109 /* Skip the 'help' command */
113 /* Check for special builtin '-commands' command first */
114 if (Jim_CompareStringImmediate(interp
, cmd
, "-commands")) {
115 /* Build the result here */
116 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
117 add_commands(interp
, command_table
, " ");
118 return &dummy_subcmd
;
121 cmdstr
= Jim_GetString(cmd
, &cmdlen
);
123 for (ct
= command_table
; ct
->cmd
; ct
++) {
124 if (Jim_CompareStringImmediate(interp
, cmd
, ct
->cmd
)) {
125 /* Found an exact match */
128 if (strncmp(cmdstr
, ct
->cmd
, cmdlen
) == 0) {
132 /* Just show the top level help here */
133 show_cmd_usage(interp
, command_table
, argc
, argv
);
134 return &dummy_subcmd
;
136 bad_subcmd(interp
, command_table
, "ambiguous", argv
[0], argv
[1 + help
]);
144 /* If we had an unambiguous partial match */
145 if (partial
&& !ct
->cmd
) {
150 /* No matching command */
152 /* Just show the top level help here */
153 show_cmd_usage(interp
, command_table
, argc
, argv
);
154 return &dummy_subcmd
;
156 bad_subcmd(interp
, command_table
, "unknown", argv
[0], argv
[1 + help
]);
161 Jim_SetResultString(interp
, "Usage: ", -1);
163 add_cmd_usage(interp
, ct
, argv
[0]);
164 return &dummy_subcmd
;
167 /* Check the number of args */
168 if (argc
- 2 < ct
->minargs
|| (ct
->maxargs
>= 0 && argc
- 2 > ct
->maxargs
)) {
169 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
171 add_cmd_usage(interp
, ct
, argv
[0]);
172 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
181 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, int argc
, Jim_Obj
*const *argv
)
186 if (ct
->flags
& JIM_MODFLAG_FULLARGV
) {
187 ret
= ct
->function(interp
, argc
, argv
);
190 ret
= ct
->function(interp
, argc
- 2, argv
+ 2);
193 set_wrong_args(interp
, ct
, argv
[0]);
200 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
202 const jim_subcmd_type
*ct
=
203 Jim_ParseSubCmd(interp
, (const jim_subcmd_type
*)Jim_CmdPrivData(interp
), argc
, argv
);
205 return Jim_CallSubCmd(interp
, ct
, argc
, argv
);