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