1 /* File: cmdinfo.c */
2
3 /* Purpose: command stuff */
4
5 /*
6 * Copyright (c) 1997-2001 Tim Baker
7 *
8 * This software may be copied and distributed for educational, research, and
9 * not for profit purposes provided that this copyright and statement are
10 * included in all such copies.
11 */
12
13 #include "tnb.h"
14
CommandInfo_ObjCmd(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])15 int CommandInfo_ObjCmd(ClientData clientData, Tcl_Interp *interp, int objc,
16 Tcl_Obj *CONST objv[])
17 {
18 CommandInfo *infoCmd = (CommandInfo *) clientData;
19 int objC = objc - infoCmd->depth;
20 Tcl_Obj *CONST *objV = objv + infoCmd->depth;
21 int subCmdIndex;
22
23 if (infoCmd->subCmd.count)
24 {
25 if (objC < 2)
26 {
27 Tcl_WrongNumArgs(interp, infoCmd->depth + 1, objv, "option ?arg ...?");
28 return TCL_ERROR;
29 }
30 if (Tcl_GetIndexFromObj(interp, objV[1], infoCmd->subCmd.name,
31 "option", 0, &subCmdIndex) != TCL_OK)
32 {
33 return TCL_ERROR;
34 }
35 infoCmd = infoCmd->subCmd.info[subCmdIndex];
36 return CommandInfo_ObjCmd((ClientData) infoCmd, interp, objc, objv);
37 }
38
39 if ((infoCmd->minArgs && (objC < infoCmd->minArgs)) ||
40 (infoCmd->maxArgs && (objC > infoCmd->maxArgs)))
41 {
42 Tcl_WrongNumArgs(interp, infoCmd->depth + 1, objv,
43 infoCmd->errorMsg);
44 return TCL_ERROR;
45 }
46
47 return (*infoCmd->proc)(clientData, interp, objc, objv);
48 }
49
CommandInfo_Add(CommandInfo * infoCmd,CommandInfo * infoSubCmd)50 void CommandInfo_Add(CommandInfo *infoCmd, CommandInfo *infoSubCmd)
51 {
52 int i;
53 int alloc = infoCmd->subCmd.alloc;
54 int count = infoCmd->subCmd.count;
55
56 if ((count + 1) >= alloc)
57 {
58 CommandInfo **info;
59 cptr *name;
60
61 C_MAKE(info, alloc + 5, CommandInfo*);
62 C_MAKE(name, alloc + 5 + 1, cptr);
63
64 if (infoCmd->subCmd.count)
65 {
66 for (i = 0; i < count; i++)
67 {
68 name[i] = infoCmd->subCmd.name[i];
69 info[i] = infoCmd->subCmd.info[i];
70 }
71 FREE(infoCmd->subCmd.name);
72 FREE(infoCmd->subCmd.info);
73 }
74 infoCmd->subCmd.name = name;
75 infoCmd->subCmd.info = info;
76 infoCmd->subCmd.alloc += 5;
77 }
78
79 infoCmd->subCmd.name[count] = infoSubCmd->name;
80 infoCmd->subCmd.name[count + 1] = NULL;
81 infoCmd->subCmd.info[count] = infoSubCmd;
82 ++infoCmd->subCmd.count;
83 }
84
CommandInfo_New(CommandInit * init)85 CommandInfo *CommandInfo_New(CommandInit *init)
86 {
87 CommandInfo *infoCmd;
88
89 MAKE(infoCmd, CommandInfo);
90
91 infoCmd->name = init->name;
92 infoCmd->minArgs = init->minArgs;
93 infoCmd->maxArgs = init->maxArgs;
94 infoCmd->errorMsg = init->errorMsg;
95 infoCmd->proc = init->proc;
96 infoCmd->clientData = init->clientData;
97 infoCmd->depth = init->depth;
98 infoCmd->subCmd.name = NULL;
99 infoCmd->subCmd.info = NULL;
100 infoCmd->subCmd.count = 0;
101 infoCmd->subCmd.alloc = 0;
102
103 return infoCmd;
104 }
105
106 /*
107 * Get the CommandInfo for a command or subcommand.
108 */
CommandInfo_GetInfoAux(Tcl_Interp * interp,cptr names[],CommandInfo * infoCmd)109 static CommandInfo *CommandInfo_GetInfoAux(Tcl_Interp *interp, cptr names[],
110 CommandInfo *infoCmd)
111 {
112 int subCmdIndex;
113
114 #if 0
115 if (strcmp(infoCmd->name, names[0]))
116 {
117 /* REPORT */
118 return NULL;
119 }
120 #endif
121
122 /* This is the command we're looking for */
123 if (names[1] == NULL)
124 {
125 return infoCmd;
126 }
127
128 /* Check subcommands */
129 if (infoCmd->subCmd.count)
130 {
131 Tcl_Obj *nameObjPtr = Tcl_NewStringObj(names[1], -1);
132
133 if (Tcl_GetIndexFromObj(interp, nameObjPtr, infoCmd->subCmd.name,
134 "option", 0, &subCmdIndex) != TCL_OK)
135 {
136 Tcl_DecrRefCount(nameObjPtr);
137 return NULL;
138 }
139 Tcl_DecrRefCount(nameObjPtr);
140 infoCmd = infoCmd->subCmd.info[subCmdIndex];
141 return CommandInfo_GetInfoAux(interp, names + 1, infoCmd);
142 }
143
144 /* REPORT */
145 return NULL;
146 }
147
CommandInfo_GetInfo(Tcl_Interp * interp,cptr names[])148 CommandInfo *CommandInfo_GetInfo(Tcl_Interp *interp, cptr names[])
149 {
150 Tcl_CmdInfo cmdInfo;
151
152 if (Tcl_GetCommandInfo(interp, names[0], &cmdInfo) == 0)
153 {
154 return NULL;
155 }
156 return CommandInfo_GetInfoAux(interp, names,
157 (CommandInfo *) cmdInfo.objClientData);
158 }
159
CommandInfo_InitAux(Tcl_Interp * interp,CommandInit * init,int index,CommandInfo * parent)160 int CommandInfo_InitAux(Tcl_Interp *interp, CommandInit *init, int index,
161 CommandInfo *parent)
162 {
163 int i;
164 CommandInfo *infoCmd = NULL;
165
166 /* Done */
167 if (init[index].name == NULL) return -1;
168
169 if (parent == NULL)
170 {
171 cptr names[2];
172 names[0] = init[index].name;
173 names[1] = NULL;
174 infoCmd = CommandInfo_GetInfo(interp, names);
175 }
176
177 if (infoCmd == NULL)
178 {
179 /* Create a new command */
180 infoCmd = CommandInfo_New(&init[index]);
181
182 if (parent == NULL)
183 {
184 Tcl_CreateObjCommand(interp, infoCmd->name,
185 CommandInfo_ObjCmd, (ClientData) infoCmd, NULL);
186 }
187 else
188 {
189 CommandInfo_Add(parent, infoCmd);
190 }
191 }
192
193 i = index++;
194 while (init[index].depth > init[i].depth)
195 {
196 index = CommandInfo_InitAux(interp, init, index, infoCmd);
197 if (index == -1) break; /* ? */
198 }
199
200 return index;
201 }
202
CommandInfo_Init(Tcl_Interp * interp,CommandInit * init,CommandInfo * parent)203 int CommandInfo_Init(Tcl_Interp *interp, CommandInit *init, CommandInfo *parent)
204 {
205 int i;
206
207 for (i = 0; (i >= 0) && init[i].name; )
208 {
209 i = CommandInfo_InitAux(interp, init, i, parent);
210 }
211
212 return TCL_OK;
213 }
214
215