4 #include "jim-subcmd.h"
5 #include "jimautoconf.h"
8 * Implements the common 'commands' subcommand
10 static int subcmd_null(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
12 /* Nothing to do, since the result has already been created */
17 * Do-nothing command to support -commands and -usage
19 static const jim_subcmd_type dummy_subcmd
= {
21 .function
= subcmd_null
,
22 .flags
= JIM_MODFLAG_HIDDEN
,
25 static void add_commands(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, const char *sep
)
29 for (; ct
->cmd
; ct
++) {
30 if (!(ct
->flags
& JIM_MODFLAG_HIDDEN
)) {
31 Jim_AppendStrings(interp
, Jim_GetResult(interp
), s
, ct
->cmd
, NULL
);
37 static void bad_subcmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, const char *type
,
38 Jim_Obj
*cmd
, Jim_Obj
*subcmd
)
40 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
41 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), ", ", type
,
42 " command \"", Jim_String(subcmd
), "\": should be ", NULL
);
43 add_commands(interp
, command_table
, ", ");
46 static void show_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, int argc
,
49 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
50 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Usage: \"", Jim_String(argv
[0]),
51 " command ... \", where command is one of: ", NULL
);
52 add_commands(interp
, command_table
, ", ");
55 static void add_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, Jim_Obj
*cmd
)
58 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), " ", NULL
);
60 Jim_AppendStrings(interp
, Jim_GetResult(interp
), ct
->cmd
, NULL
);
61 if (ct
->args
&& *ct
->args
) {
62 Jim_AppendStrings(interp
, Jim_GetResult(interp
), " ", ct
->args
, NULL
);
66 static void show_full_usage(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, int argc
,
69 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
70 for (; ct
->cmd
; ct
++) {
71 if (!(ct
->flags
& JIM_MODFLAG_HIDDEN
)) {
73 add_cmd_usage(interp
, ct
, argv
[0]);
74 if (ct
->description
) {
75 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\n\n ", ct
->description
, NULL
);
77 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\n\n", NULL
);
82 static void set_wrong_args(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, Jim_Obj
*subcmd
)
84 Jim_SetResultString(interp
, "wrong # args: must be \"", -1);
85 add_cmd_usage(interp
, command_table
, subcmd
);
86 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
89 const jim_subcmd_type
*Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
,
90 int argc
, Jim_Obj
*const *argv
)
92 const jim_subcmd_type
*ct
;
93 const jim_subcmd_type
*partial
= 0;
100 cmdname
= Jim_String(argv
[0]);
103 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
104 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "wrong # args: should be \"", cmdname
,
105 " command ...\"\n", NULL
);
106 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Use \"", cmdname
, " -help\" or \"",
107 cmdname
, " -help command\" for help", NULL
);
113 if (argc
== 2 && Jim_CompareStringImmediate(interp
, cmd
, "-usage")) {
114 /* Show full usage */
115 show_full_usage(interp
, command_table
, argc
, argv
);
116 return &dummy_subcmd
;
119 /* Check for the help command */
120 if (Jim_CompareStringImmediate(interp
, cmd
, "-help")) {
122 /* Usage for the command, not the subcommand */
123 show_cmd_usage(interp
, command_table
, argc
, argv
);
124 return &dummy_subcmd
;
128 /* Skip the 'help' command */
132 /* Check for special builtin '-commands' command first */
133 if (Jim_CompareStringImmediate(interp
, cmd
, "-commands")) {
134 /* Build the result here */
135 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
136 add_commands(interp
, command_table
, " ");
137 return &dummy_subcmd
;
140 cmdstr
= Jim_GetString(cmd
, &cmdlen
);
142 for (ct
= command_table
; ct
->cmd
; ct
++) {
143 if (Jim_CompareStringImmediate(interp
, cmd
, ct
->cmd
)) {
144 /* Found an exact match */
147 if (strncmp(cmdstr
, ct
->cmd
, cmdlen
) == 0) {
151 /* Just show the top level help here */
152 show_cmd_usage(interp
, command_table
, argc
, argv
);
153 return &dummy_subcmd
;
155 bad_subcmd(interp
, command_table
, "ambiguous", argv
[0], argv
[1 + help
]);
163 /* If we had an unambiguous partial match */
164 if (partial
&& !ct
->cmd
) {
169 /* No matching command */
171 /* Just show the top level help here */
172 show_cmd_usage(interp
, command_table
, argc
, argv
);
173 return &dummy_subcmd
;
175 bad_subcmd(interp
, command_table
, "unknown", argv
[0], argv
[1 + help
]);
180 Jim_SetResultString(interp
, "Usage: ", -1);
182 add_cmd_usage(interp
, ct
, argv
[0]);
183 if (ct
->description
) {
184 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\n\n", ct
->description
, NULL
);
186 return &dummy_subcmd
;
189 /* Check the number of args */
190 if (argc
- 2 < ct
->minargs
|| (ct
->maxargs
>= 0 && argc
- 2 > ct
->maxargs
)) {
191 Jim_SetResultString(interp
, "wrong # args: must be \"", -1);
193 add_cmd_usage(interp
, ct
, argv
[0]);
194 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
203 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, int argc
, Jim_Obj
*const *argv
)
208 if (ct
->flags
& JIM_MODFLAG_FULLARGV
) {
209 ret
= ct
->function(interp
, argc
, argv
);
212 ret
= ct
->function(interp
, argc
- 2, argv
+ 2);
215 set_wrong_args(interp
, ct
, argv
[0]);
222 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
224 const jim_subcmd_type
*ct
=
225 Jim_ParseSubCmd(interp
, (const jim_subcmd_type
*)Jim_CmdPrivData(interp
), argc
, argv
);
227 return Jim_CallSubCmd(interp
, ct
, argc
, argv
);
230 /* The following two functions are for normal commands */
232 Jim_CheckCmdUsage(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, int argc
,
233 Jim_Obj
*const *argv
)
235 /* -usage or -help */
237 if (Jim_CompareStringImmediate(interp
, argv
[1], "-usage")
238 || Jim_CompareStringImmediate(interp
, argv
[1], "-help")) {
239 Jim_SetResultString(interp
, "Usage: ", -1);
240 add_cmd_usage(interp
, command_table
, NULL
);
241 if (command_table
->description
) {
242 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\n\n", command_table
->description
,
248 if (argc
>= 2 && command_table
->function
) {
249 /* This is actually a sub command table */
253 const char *subcmd
= NULL
;
255 if (Jim_CompareStringImmediate(interp
, argv
[1], "-subcommands")) {
256 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
257 add_commands(interp
, (jim_subcmd_type
*) command_table
->function
, " ");
261 if (Jim_CompareStringImmediate(interp
, argv
[1], "-subhelp")
262 || Jim_CompareStringImmediate(interp
, argv
[1], "-help")) {
265 else if (Jim_CompareStringImmediate(interp
, argv
[1], "-subusage")) {
270 nargv
[nargc
++] = Jim_NewStringObj(interp
, "$handle", -1);
271 nargv
[nargc
++] = Jim_NewStringObj(interp
, subcmd
, -1);
273 nargv
[nargc
++] = argv
[2];
275 Jim_ParseSubCmd(interp
, (jim_subcmd_type
*) command_table
->function
, nargc
, nargv
);
276 Jim_FreeNewObj(interp
, nargv
[0]);
277 Jim_FreeNewObj(interp
, nargv
[1]);
282 /* Check the number of args */
283 if (argc
- 1 < command_table
->minargs
|| (command_table
->maxargs
>= 0
284 && argc
- 1 > command_table
->maxargs
)) {
285 set_wrong_args(interp
, command_table
, NULL
);
286 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\nUse \"", Jim_String(argv
[0]),
287 " -help\" for help", NULL
);
291 /* Not usage, but passed arg checking */