1 /*
2  * tkTableUtil.c --
3  *
4  *	This module contains utility functions for table widgets.
5  *
6  * Copyright (c) 2000-2002 Jeffrey Hobbs
7  *
8  * See the file "license.terms" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  * RCS: @(#) $Id: tkTableUtil.c,v 1.2 2004/02/08 03:09:48 cerney Exp $
12  */
13 
14 #include "tkTable.h"
15 
16 static char *	Cmd_GetName _ANSI_ARGS_((const Cmd_Struct *cmds, int val));
17 static int	Cmd_GetValue _ANSI_ARGS_((const Cmd_Struct *cmds,
18 			Arg arg));
19 static void	Cmd_GetError _ANSI_ARGS_((Tcl_Interp *interp,
20 			const Cmd_Struct *cmds, Arg arg));
21 
22 /*
23  *--------------------------------------------------------------
24  *
25  * Table_ClearHashTable --
26  *	This procedure is invoked to clear a STRING_KEY hash table,
27  *	freeing the string entries and then deleting the hash table.
28  *	The hash table cannot be used after calling this, except to
29  *	be freed or reinitialized.
30  *
31  * Results:
32  *	Cached info will be lost.
33  *
34  * Side effects:
35  *	Can cause redraw.
36  *	See the user documentation.
37  *
38  *--------------------------------------------------------------
39  */
40 void
Table_ClearHashTable(Tcl_HashTable * hashTblPtr)41 Table_ClearHashTable(Tcl_HashTable *hashTblPtr)
42 {
43     Tcl_HashEntry *entryPtr;
44     Tcl_HashSearch search;
45     char *value;
46 
47     for (entryPtr = Tcl_FirstHashEntry(hashTblPtr, &search);
48 	 entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
49 	value = (char *) Tcl_GetHashValue(entryPtr);
50 	if (value != NULL) ckfree(value);
51     }
52 
53     Tcl_DeleteHashTable(hashTblPtr);
54 }
55 
56 /*
57  *----------------------------------------------------------------------
58  *
59  * TableOptionBdSet --
60  *
61  *	This routine configures the borderwidth value for a tag.
62  *
63  * Results:
64  *	A standard Tcl result.
65  *
66  * Side effects:
67  *	It may adjust the tag struct values of bd[0..4] and borders.
68  *
69  *----------------------------------------------------------------------
70  */
71 
72 int
TableOptionBdSet(clientData,interp,tkwin,value,widgRec,offset)73 TableOptionBdSet(clientData, interp, tkwin, value, widgRec, offset)
74     ClientData clientData;		/* Type of struct being set. */
75     Tcl_Interp *interp;			/* Used for reporting errors. */
76     Tk_Window tkwin;			/* Window containing table widget. */
77     Arg  value;				/* Value of option. */
78     char *widgRec;			/* Pointer to record for item. */
79     int offset;				/* Offset into item. */
80 {
81     char **borderStr;
82     int *bordersPtr, *bdPtr;
83     int type	= (int) clientData;
84     int result	= TCL_OK;
85     int argc;
86     Arg *args;
87 
88 
89     if ((type == BD_TABLE) && (STREQ(LangString(value),"") )) {
90 	/*
91 	 * NULL strings aren't allowed for the table global -bd
92 	 */
93 	Tcl_AppendResult(interp, "borderwidth value may not be empty",
94 		(char *) NULL);
95 	return TCL_ERROR;
96     }
97 
98     if ((type == BD_TABLE) || (type == BD_TABLE_TAG)) {
99 	TableTag *tagPtr = (TableTag *) (widgRec + offset);
100 	borderStr	= &(tagPtr->borderStr);
101 	bordersPtr	= &(tagPtr->borders);
102 	bdPtr		= tagPtr->bd;
103     } else if (type == BD_TABLE_WIN) {
104 	TableEmbWindow *tagPtr = (TableEmbWindow *) widgRec;
105 	borderStr	= &(tagPtr->borderStr);
106 	bordersPtr	= &(tagPtr->borders);
107 	bdPtr		= tagPtr->bd;
108     } else {
109 	panic("invalid type given to TableOptionBdSet\n");
110 	return TCL_ERROR; /* lint */
111     }
112 
113     result = Tcl_ListObjGetElements(interp, value, &argc, &args);
114     if (result == TCL_OK) {
115 	int i, bd[4];
116 
117 	if (((type == BD_TABLE) && (argc == 0)) || (argc == 3) || (argc > 4)) {
118 	    Tcl_AppendResult(interp,
119 		    "1, 2 or 4 values must be specified for borderwidth",
120 		    (char *) NULL);
121 	    result = TCL_ERROR;
122 	} else {
123 	    /*
124 	     * We use the shadow bd array first, in case we have an error
125 	     * parsing arguments half way through.
126 	     */
127 	    for (i = 0; i < argc; i++) {
128 		if (Tk_GetPixels(interp, tkwin, LangString(args[i]), &(bd[i])) != TCL_OK) {
129 		    result = TCL_ERROR;
130 		    break;
131 		}
132 	    }
133 	    /*
134 	     * If everything is OK, store the parsed and given values for
135 	     * easy retrieval.
136 	     */
137 	    if (result == TCL_OK) {
138 		for (i = 0; i < argc; i++) {
139 		    bdPtr[i] = MAX(0, bd[i]);
140 		}
141 		if (*borderStr) {
142 		    ckfree(*borderStr);
143 		}
144 		if (value) {
145 		    *borderStr	= (char *) ckalloc( strlen( LangString(value) ) + 1);
146 		    strcpy(*borderStr, LangString(value));
147 		} else {
148 		    *borderStr	= NULL;
149 		}
150 		*bordersPtr	= argc;
151 	    }
152 	}
153 	/*ckfree ((char *) argv);*/
154     }
155 
156     return result;
157 }
158 
159 /*
160  *----------------------------------------------------------------------
161  *
162  * TableOptionBdGet --
163  *
164  * Results:
165  *	Value of the -bd option.
166  *
167  * Side effects:
168  *	None.
169  *
170  *----------------------------------------------------------------------
171  */
172 
173 Arg
TableOptionBdGet(clientData,tkwin,widgRec,offset,freeProcPtr)174 TableOptionBdGet(clientData, tkwin, widgRec, offset, freeProcPtr)
175     ClientData clientData;		/* Type of struct being set. */
176     Tk_Window tkwin;			/* Window containing canvas widget. */
177     char *widgRec;			/* Pointer to record for item. */
178     int offset;				/* Offset into item. */
179     Tcl_FreeProc **freeProcPtr;		/* Pointer to variable to fill in with
180 					 * information about how to reclaim
181 					 * storage for return string. */
182 {
183     register int type	= (int) clientData;
184 
185     if (type == BD_TABLE) {
186 	return LangStringArg( ((TableTag *) (widgRec + offset))->borderStr);
187     } else if (type == BD_TABLE_TAG) {
188 	return LangStringArg( ((TableTag *) widgRec)->borderStr);
189     } else if (type == BD_TABLE_WIN) {
190 	return LangStringArg( ((TableEmbWindow *) widgRec)->borderStr);
191     } else {
192 	panic("invalid type given to TableOptionBdSet\n");
193 	return NULL; /* lint */
194     }
195 }
196 
197 /*
198  *----------------------------------------------------------------------
199  *
200  * TableTagConfigureBd --
201  *	This routine configures the border values based on a tag.
202  *	The previous value of the bd string (oldValue) is assumed to
203  *	be a valid value for this tag.
204  *
205  * Results:
206  *	A standard Tcl result.
207  *
208  * Side effects:
209  *	It may adjust the value used by -bd.
210  *
211  *----------------------------------------------------------------------
212  */
213 
214 int
TableTagConfigureBd(Table * tablePtr,TableTag * tagPtr,Arg oldValue,int nullOK)215 TableTagConfigureBd(Table *tablePtr, TableTag *tagPtr,
216 	Arg oldValue, int nullOK)
217 {
218     int i, argc, result = TCL_OK;
219     Arg *args;
220 
221     /*
222      * First check to see if the value really changed.
223      */
224     if (strcmp(tagPtr->borderStr ? tagPtr->borderStr : "",
225 	    LangString(oldValue) ? LangString(oldValue) : "") == 0) {
226 	return TCL_OK;
227     }
228 
229     tagPtr->borders = 0;
230     if (!nullOK && ((tagPtr->borderStr == NULL)
231 	    || (*(tagPtr->borderStr) == '\0'))) {
232 	/*
233 	 * NULL strings aren't allowed for this tag
234 	 */
235 	result = TCL_ERROR;
236     } else if (tagPtr->borderStr) {
237         result = Tcl_ListObjGetElements(tablePtr->interp, LangStringArg(tagPtr->borderStr), &argc, &args);
238 	if (result == TCL_OK) {
239 	    if ((!nullOK && (argc == 0)) || (argc == 3) || (argc > 4)) {
240 		Tcl_SetResult(tablePtr->interp,
241 			"1, 2 or 4 values must be specified to -borderwidth",
242 			TCL_STATIC);
243 		result = TCL_ERROR;
244 	    } else {
245 		for (i = 0; i < argc; i++) {
246 		    if (Tk_GetPixels(tablePtr->interp, tablePtr->tkwin,
247 			    LangString(args[i]), &(tagPtr->bd[i])) != TCL_OK) {
248 			result = TCL_ERROR;
249 			break;
250 		    }
251 		    tagPtr->bd[i] = MAX(0, tagPtr->bd[i]);
252 		}
253 		tagPtr->borders = argc;
254 	    }
255 	    /* ckfree ((char *) argv); */
256 	}
257     }
258 
259     if (result != TCL_OK) {
260 	if (tagPtr->borderStr) {
261 	    ckfree ((char *) tagPtr->borderStr);
262 	}
263 	if (oldValue != NULL) {
264 	    size_t length = strlen(LangString(oldValue)) + 1;
265 	    /*
266 	     * We are making the assumption that oldValue is correct.
267 	     * We have to reparse in case the bad new value had a couple
268 	     * of correct args before failing on a bad pixel value.
269 	     */
270     	    Tcl_ListObjGetElements(tablePtr->interp, oldValue, &argc, &args);
271 	    for (i = 0; i < argc; i++) {
272 		Tk_GetPixels(tablePtr->interp, tablePtr->tkwin,
273 			LangString(args[i]), &(tagPtr->bd[i]));
274 	    }
275 	    /* ckfree ((char *) argv); */
276 	    tagPtr->borders	= argc;
277 	    tagPtr->borderStr	= (char *) ckalloc(length);
278 	    memcpy(tagPtr->borderStr, LangString(oldValue), length);
279 	} else {
280 	    tagPtr->borders	= 0;
281 	    tagPtr->borderStr	= (char *) NULL;
282 	}
283     }
284 
285     return result;
286 }
287 
288 /*
289  *----------------------------------------------------------------------
290  *
291  * Cmd_OptionSet --
292  *
293  *
294  * Results:
295  *	A standard Tcl result.
296  *
297  * Side effects:
298  *	None.
299  *
300  *----------------------------------------------------------------------
301  */
302 
303 int
Cmd_OptionSet(ClientData clientData,Tcl_Interp * interp,Tk_Window unused,Arg value,char * widgRec,int offset)304 Cmd_OptionSet(ClientData clientData, Tcl_Interp *interp,
305 	Tk_Window unused, Arg value, char *widgRec, int offset)
306 {
307   Cmd_Struct *p = (Cmd_Struct *)clientData;
308   int mode = Cmd_GetValue(p,value);
309   if (!mode) {
310     Cmd_GetError(interp,p,value);
311     return TCL_ERROR;
312   }
313   *((int*)(widgRec+offset)) = mode;
314   return TCL_OK;
315 }
316 
317 /*
318  *----------------------------------------------------------------------
319  *
320  * Cmd_OptionGet --
321  *
322  *
323  * Results:
324  *	Value of the option.
325  *
326  * Side effects:
327  *	None.
328  *
329  *----------------------------------------------------------------------
330  */
331 
332 Arg
Cmd_OptionGet(ClientData clientData,Tk_Window unused,char * widgRec,int offset,Tcl_FreeProc ** freeProcPtr)333 Cmd_OptionGet(ClientData clientData, Tk_Window unused,
334 	      char *widgRec, int offset, Tcl_FreeProc **freeProcPtr)
335 {
336   Cmd_Struct *p = (Cmd_Struct *)clientData;
337   int mode = *((int*)(widgRec+offset));
338   return LangStringArg(Cmd_GetName(p,mode));
339 }
340 
341 /*
342  * simple Cmd_Struct lookup functions
343  */
344 
345 char *
Cmd_GetName(const Cmd_Struct * cmds,int val)346 Cmd_GetName(const Cmd_Struct *cmds, int val)
347 {
348   for(;cmds->name && cmds->name[0];cmds++) {
349     if (cmds->value==val) return cmds->name;
350   }
351   return NULL;
352 }
353 
354 int
Cmd_GetValue(const Cmd_Struct * cmds,Arg arg)355 Cmd_GetValue(const Cmd_Struct *cmds, Arg arg)
356 {
357   unsigned int len = strlen(LangString(arg));
358   for(;cmds->name && cmds->name[0];cmds++) {
359     if (!strncmp(cmds->name, LangString(arg), len)) return cmds->value;
360   }
361   return 0;
362 }
363 
364 void
Cmd_GetError(Tcl_Interp * interp,const Cmd_Struct * cmds,Arg arg)365 Cmd_GetError(Tcl_Interp *interp, const Cmd_Struct *cmds, Arg arg)
366 {
367   int i;
368   char *argstring = LangString(arg);
369   Tcl_AppendResult(interp, "bad option \"", argstring, "\" must be ", (char *) 0);
370   for(i=0;cmds->name && cmds->name[0];cmds++,i++) {
371     Tcl_AppendResult(interp, (i?", ":""), cmds->name, (char *) 0);
372   }
373 }
374