]> cvs.zerfleddert.de Git - micropolis/blob - src/tclx/src/tclxhndl.c
Add legacy mode inspired by the work of virtuallyfun/tenox7
[micropolis] / src / tclx / src / tclxhndl.c
1 /*
2 *
3 * tclXhandles.c --
4 *
5 * Tcl handles. Provides a mechanism for managing expandable tables that are
6 * addressed by textual handles.
7 *-----------------------------------------------------------------------------
8 * Copyright 1992 Karl Lehenbauer and Mark Diekhans.
9 *
10 * Permission to use, copy, modify, and distribute this software and its
11 * documentation for any purpose and without fee is hereby granted, provided
12 * that the above copyright notice appear in all copies. Karl Lehenbauer and
13 * Mark Diekhans make no representations about the suitability of this
14 * software for any purpose. It is provided "as is" without express or
15 * implied warranty.
16 *-----------------------------------------------------------------------------
17 * $Id: tclXhandles.c,v 2.0 1992/10/16 04:50:49 markd Rel $
18 *-----------------------------------------------------------------------------
19 */
20
21 #include "tclxint.h"
22
23 /*
24 * This is the table header. It is separately allocated from the table body,
25 * since it must keep track of a table body that might move. Each entry in the
26 * table is preceded with a header which has the free list link, which is a
27 * entry index of the next free entry. Special values keep track of allocated
28 * entries.
29 */
30
31 #define NULL_IDX -1
32 #define ALLOCATED_IDX -2
33
34 typedef unsigned char ubyte_t;
35 typedef ubyte_t *ubyte_pt;
36
37 typedef struct {
38 int useCount; /* Keeps track of the number sharing */
39 int entrySize; /* Entry size in bytes, including overhead */
40 int tableSize; /* Current number of entries in the table */
41 int freeHeadIdx; /* Index of first free entry in the table */
42 ubyte_pt bodyP; /* Pointer to table body */
43 int baseLength; /* Length of handleBase. */
44 char handleBase [1]; /* Base handle name. MUST BE LAST FIELD! */
45 } tblHeader_t;
46 typedef tblHeader_t *tblHeader_pt;
47
48 typedef struct {
49 int freeLink;
50 } entryHeader_t;
51 typedef entryHeader_t *entryHeader_pt;
52
53 /*
54 * This macro is used to return a pointer to an entry, given its index.
55 */
56 #define TBL_INDEX(hdrP, idx) \
57 ((entryHeader_pt) (hdrP->bodyP + (hdrP->entrySize * idx)))
58
59 /*
60 * This macros to convert between pointers to the user and header area of
61 * an table entry.
62 */
63 #define USER_AREA(entryPtr) \
64 (void_pt) (((ubyte_pt) entryPtr) + sizeof (entryHeader_t));
65 #define HEADER_AREA(entryPtr) \
66 (entryHeader_pt) (((ubyte_pt) entryPtr) - sizeof (entryHeader_t));
67
68 /*
69 * Prototypes of internal functions.
70 */
71 static void
72 LinkInNewEntries _ANSI_ARGS_((tblHeader_pt tblHdrPtr,
73 int newIdx,
74 int numEntries));
75
76 static void
77 ExpandTable _ANSI_ARGS_((tblHeader_pt tblHdrPtr,
78 int neededIdx));
79
80 static entryHeader_pt
81 AllocEntry _ANSI_ARGS_((tblHeader_pt tblHdrPtr,
82 int *entryIdxPtr));
83
84 static int
85 HandleDecode _ANSI_ARGS_((Tcl_Interp *interp,
86 tblHeader_pt tblHdrPtr,
87 CONST char *handle));
88 \f
89 /*=============================================================================
90 * LinkInNewEntries --
91 * Build free links through the newly allocated part of a table.
92 *
93 * Parameters:
94 * o tblHdrPtr (I) - A pointer to the table header.
95 * o newIdx (I) - Index of the first new entry.
96 * o numEntries (I) - The number of new entries.
97 *-----------------------------------------------------------------------------
98 */
99 static void
100 LinkInNewEntries (tblHeader_pt tblHdrPtr, int newIdx, int numEntries)
101 {
102 int entIdx, lastIdx;
103 entryHeader_pt entryPtr;
104
105 lastIdx = newIdx + numEntries - 1;
106
107 for (entIdx = newIdx; entIdx < lastIdx; entIdx++) {
108 entryPtr = TBL_INDEX (tblHdrPtr, entIdx);
109 entryPtr->freeLink = entIdx + 1;
110 }
111 entryPtr = TBL_INDEX (tblHdrPtr, lastIdx);
112 entryPtr->freeLink = tblHdrPtr->freeHeadIdx;
113 tblHdrPtr->freeHeadIdx = newIdx;
114
115 } /* LinkInNewEntries */
116 \f
117 /*=============================================================================
118 * ExpandTable --
119 * Expand a handle table, doubling its size.
120 * Parameters:
121 * o tblHdrPtr (I) - A pointer to the table header.
122 * o neededIdx (I) - If positive, then the table will be expanded so that
123 * this entry is available. If -1, then just expand by the number of
124 * entries specified on table creation. MUST be smaller than this size.
125 *-----------------------------------------------------------------------------
126 */
127 static void
128 ExpandTable (tblHeader_pt tblHdrPtr, int neededIdx)
129 {
130 ubyte_pt oldBodyP = tblHdrPtr->bodyP;
131 int numNewEntries;
132 int newSize;
133
134 if (neededIdx < 0)
135 numNewEntries = tblHdrPtr->tableSize;
136 else
137 numNewEntries = (neededIdx - tblHdrPtr->tableSize) + 1;
138 newSize = (tblHdrPtr->tableSize + numNewEntries) * tblHdrPtr->entrySize;
139
140 tblHdrPtr->bodyP = (ubyte_pt) ckalloc (newSize);
141 memcpy (tblHdrPtr->bodyP, oldBodyP, newSize);
142 LinkInNewEntries (tblHdrPtr, tblHdrPtr->tableSize, numNewEntries);
143 tblHdrPtr->tableSize += numNewEntries;
144 ckfree (oldBodyP);
145
146 } /* ExpandTable */
147 \f
148 /*=============================================================================
149 * AllocEntry --
150 * Allocate a table entry, expanding if necessary.
151 *
152 * Parameters:
153 * o tblHdrPtr (I) - A pointer to the table header.
154 * o entryIdxPtr (O) - The index of the table entry is returned here.
155 * Returns:
156 * The a pointer to the entry.
157 *-----------------------------------------------------------------------------
158 */
159 static entryHeader_pt
160 AllocEntry (tblHeader_pt tblHdrPtr, int *entryIdxPtr)
161 {
162 int entryIdx;
163 entryHeader_pt entryPtr;
164
165 if (tblHdrPtr->freeHeadIdx == NULL_IDX)
166 ExpandTable (tblHdrPtr, -1);
167
168 entryIdx = tblHdrPtr->freeHeadIdx;
169 entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
170 tblHdrPtr->freeHeadIdx = entryPtr->freeLink;
171 entryPtr->freeLink = ALLOCATED_IDX;
172
173 *entryIdxPtr = entryIdx;
174 return entryPtr;
175
176 } /* AllocEntry */
177 \f
178 /*=============================================================================
179 * HandleDecode --
180 * Decode handle into an entry number.
181 *
182 * Parameters:
183 * o interp (I) - A error message may be returned in result.
184 * o tblHdrPtr (I) - A pointer to the table header.
185 * o handle (I) - Handle to decode.
186 * Returns:
187 * The entry index decoded from the handle, or a negative number if an error
188 * occured.
189 *-----------------------------------------------------------------------------
190 */
191 static int
192 HandleDecode (Tcl_Interp *interp, tblHeader_pt tblHdrPtr, CONST char *handle)
193 {
194 unsigned entryIdx;
195
196 if ((strncmp (tblHdrPtr->handleBase, (char *) handle,
197 tblHdrPtr->baseLength) != 0) ||
198 !Tcl_StrToUnsigned (&handle [tblHdrPtr->baseLength], 10,
199 &entryIdx)) {
200 Tcl_AppendResult (interp, "invalid ", tblHdrPtr->handleBase,
201 " handle: ", handle, (char *) NULL);
202 return -1;
203 }
204 return entryIdx;
205
206 } /* HandleDecode */
207 \f
208 /*=============================================================================
209 * Tcl_HandleTblInit --
210 * Create and initialize a Tcl dynamic handle table. The use count on the
211 * table is set to one.
212 * Parameters:
213 * o handleBase(I) - The base name of the handle, the handle will be returned
214 * in the form "baseNN", where NN is the table entry number.
215 * o entrySize (I) - The size of an entry, in bytes.
216 * o initEntries (I) - Initial size of the table, in entries.
217 * Returns:
218 * A pointer to the table header.
219 *-----------------------------------------------------------------------------
220 */
221 void_pt
222 Tcl_HandleTblInit (CONST char *handleBase, int entrySize, int initEntries)
223 {
224 tblHeader_pt tblHdrPtr;
225 int baseLength = strlen ((char *) handleBase);
226
227 tblHdrPtr = (tblHeader_pt) ckalloc (sizeof (tblHeader_t) + baseLength + 1);
228
229 tblHdrPtr->useCount = 1;
230 tblHdrPtr->baseLength = baseLength;
231 strcpy (tblHdrPtr->handleBase, (char *) handleBase);
232
233 /*
234 * Calculate entry size, including header, rounded up to sizeof (int).
235 */
236 tblHdrPtr->entrySize = entrySize + sizeof (entryHeader_t);
237 tblHdrPtr->entrySize = ((tblHdrPtr->entrySize + sizeof (int) - 1) /
238 sizeof (int)) * sizeof (int);
239 tblHdrPtr->freeHeadIdx = NULL_IDX;
240 tblHdrPtr->tableSize = initEntries;
241 tblHdrPtr->bodyP = (ubyte_pt) ckalloc (initEntries * tblHdrPtr->entrySize);
242 LinkInNewEntries (tblHdrPtr, 0, initEntries);
243
244 return (void_pt) tblHdrPtr;
245
246 } /* Tcl_HandleTblInit */
247 \f
248 /*=============================================================================
249 * Tcl_HandleTblUseCount --
250 * Alter the handle table use count by the specified amount, which can be
251 * positive or negative. Amount may be zero to retrieve the use count.
252 * Parameters:
253 * o headerPtr (I) - Pointer to the table header.
254 * o amount (I) - The amount to alter the use count by.
255 * Returns:
256 * The resulting use count.
257 *-----------------------------------------------------------------------------
258 */
259 int
260 Tcl_HandleTblUseCount (void_pt headerPtr, int amount)
261 {
262 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
263
264 tblHdrPtr->useCount += amount;
265 return tblHdrPtr->useCount;
266 }
267 \f
268 /*=============================================================================
269 * Tcl_HandleTblRelease --
270 * Decrement the use count on a Tcl dynamic handle table. If the count
271 * goes to zero or negative, then release the table. It is designed to be
272 * called when a command is released.
273 * Parameters:
274 * o headerPtr (I) - Pointer to the table header.
275 *-----------------------------------------------------------------------------
276 */
277 void
278 Tcl_HandleTblRelease (void_pt headerPtr)
279 {
280 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
281
282 tblHdrPtr->useCount--;
283 if (tblHdrPtr->useCount <= 0) {
284 ckfree (tblHdrPtr->bodyP);
285 ckfree ((char *) tblHdrPtr);
286 }
287 }
288 \f
289 /*=============================================================================
290 * Tcl_HandleAlloc --
291 * Allocate an entry and associate a handle with it.
292 *
293 * Parameters:
294 * o headerPtr (I) - A pointer to the table header.
295 * o handlePtr (O) - Buffer to return handle in. It must be big enough to
296 * hold the name.
297 * Returns:
298 * A pointer to the allocated entry (user part).
299 *-----------------------------------------------------------------------------
300 */
301 void_pt
302 Tcl_HandleAlloc (void_pt headerPtr, char *handlePtr)
303 {
304 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
305 entryHeader_pt entryPtr;
306 int entryIdx;
307
308 entryPtr = AllocEntry ((tblHeader_pt) headerPtr, &entryIdx);
309 sprintf (handlePtr, "%s%d", tblHdrPtr->handleBase, entryIdx);
310
311 return USER_AREA (entryPtr);
312
313 } /* Tcl_HandleAlloc */
314 \f
315 /*=============================================================================
316 * Tcl_HandleXlate --
317 * Translate a handle to a entry pointer.
318 *
319 * Parameters:
320 * o interp (I) - A error message may be returned in result.
321 * o headerPtr (I) - A pointer to the table header.
322 * o handle (I) - The handle assigned to the entry.
323 * Returns:
324 * A pointer to the entry, or NULL if an error occured.
325 *-----------------------------------------------------------------------------
326 */
327 void_pt
328 Tcl_HandleXlate (Tcl_Interp *interp, void_pt headerPtr, CONST char *handle)
329 {
330 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
331 entryHeader_pt entryPtr;
332 int entryIdx;
333
334 if ((entryIdx = HandleDecode (interp, tblHdrPtr, handle)) < 0)
335 return NULL;
336 entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
337
338 if ((entryIdx >= tblHdrPtr->tableSize) ||
339 (entryPtr->freeLink != ALLOCATED_IDX)) {
340 Tcl_AppendResult (interp, tblHdrPtr->handleBase, " is not open",
341 (char *) NULL);
342 return NULL;
343 }
344
345 return USER_AREA (entryPtr);
346
347 } /* Tcl_HandleXlate */
348 \f
349 /*=============================================================================
350 * Tcl_HandleWalk --
351 * Walk through and find every allocated entry in a table. Entries may
352 * be deallocated during a walk, but should not be allocated.
353 *
354 * Parameters:
355 * o headerPtr (I) - A pointer to the table header.
356 * o walkKeyPtr (I/O) - Pointer to a variable to use to keep track of the
357 * place in the table. The variable should be initialized to -1 before
358 * the first call.
359 * Returns:
360 * A pointer to the next allocated entry, or NULL if there are not more.
361 *-----------------------------------------------------------------------------
362 */
363 void_pt
364 Tcl_HandleWalk (void_pt headerPtr, int *walkKeyPtr)
365 {
366 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
367 int entryIdx;
368 entryHeader_pt entryPtr;
369
370 if (*walkKeyPtr == -1)
371 entryIdx = 0;
372 else
373 entryIdx = *walkKeyPtr + 1;
374
375 while (entryIdx < tblHdrPtr->tableSize) {
376 entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
377 if (entryPtr->freeLink == ALLOCATED_IDX) {
378 *walkKeyPtr = entryIdx;
379 return USER_AREA (entryPtr);
380 }
381 entryIdx++;
382 }
383 return NULL;
384
385 } /* Tcl_HandleWalk */
386 \f
387 /*=============================================================================
388 * Tcl_WalkKeyToHandle --
389 * Convert a walk key, as returned from a call to Tcl_HandleWalk into a
390 * handle. The Tcl_HandleWalk must have succeeded.
391 * Parameters:
392 * o headerPtr (I) - A pointer to the table header.
393 * o walkKey (I) - The walk key.
394 * o handlePtr (O) - Buffer to return handle in. It must be big enough to
395 * hold the name.
396 *-----------------------------------------------------------------------------
397 */
398 void
399 Tcl_WalkKeyToHandle (void_pt headerPtr, int walkKey, char *handlePtr)
400 {
401 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
402
403 sprintf (handlePtr, "%s%d", tblHdrPtr->handleBase, walkKey);
404
405 } /* Tcl_WalkKeyToHandle */
406 \f
407 /*=============================================================================
408 * Tcl_HandleFree --
409 * Frees a handle table entry.
410 *
411 * Parameters:
412 * o headerPtr (I) - A pointer to the table header.
413 * o entryPtr (I) - Entry to free.
414 *-----------------------------------------------------------------------------
415 */
416 void
417 Tcl_HandleFree (void_pt headerPtr, void_pt entryPtr)
418 {
419 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
420 entryHeader_pt freeentryPtr;
421
422 freeentryPtr = HEADER_AREA (entryPtr);
423 freeentryPtr->freeLink = tblHdrPtr->freeHeadIdx;
424 tblHdrPtr->freeHeadIdx = (((ubyte_pt) entryPtr) - tblHdrPtr->bodyP) /
425 tblHdrPtr->entrySize;
426
427 } /* Tcl_HandleFree */
428
Impressum, Datenschutz