]> git.zerfleddert.de Git - micropolis/blob - src/tclx/src/tclxhndl.c
Import Micropolis from http://www.donhopkins.com/home/micropolis/
[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 (tblHdrPtr, newIdx, numEntries)
101 tblHeader_pt tblHdrPtr;
102 int newIdx;
103 int numEntries;
104 {
105 int entIdx, lastIdx;
106 entryHeader_pt entryPtr;
107
108 lastIdx = newIdx + numEntries - 1;
109
110 for (entIdx = newIdx; entIdx < lastIdx; entIdx++) {
111 entryPtr = TBL_INDEX (tblHdrPtr, entIdx);
112 entryPtr->freeLink = entIdx + 1;
113 }
114 entryPtr = TBL_INDEX (tblHdrPtr, lastIdx);
115 entryPtr->freeLink = tblHdrPtr->freeHeadIdx;
116 tblHdrPtr->freeHeadIdx = newIdx;
117
118 } /* LinkInNewEntries */
119 \f
120 /*=============================================================================
121 * ExpandTable --
122 * Expand a handle table, doubling its size.
123 * Parameters:
124 * o tblHdrPtr (I) - A pointer to the table header.
125 * o neededIdx (I) - If positive, then the table will be expanded so that
126 * this entry is available. If -1, then just expand by the number of
127 * entries specified on table creation. MUST be smaller than this size.
128 *-----------------------------------------------------------------------------
129 */
130 static void
131 ExpandTable (tblHdrPtr, neededIdx)
132 tblHeader_pt tblHdrPtr;
133 int neededIdx;
134 {
135 ubyte_pt oldBodyP = tblHdrPtr->bodyP;
136 int numNewEntries;
137 int newSize;
138
139 if (neededIdx < 0)
140 numNewEntries = tblHdrPtr->tableSize;
141 else
142 numNewEntries = (neededIdx - tblHdrPtr->tableSize) + 1;
143 newSize = (tblHdrPtr->tableSize + numNewEntries) * tblHdrPtr->entrySize;
144
145 tblHdrPtr->bodyP = (ubyte_pt) ckalloc (newSize);
146 memcpy (tblHdrPtr->bodyP, oldBodyP, newSize);
147 LinkInNewEntries (tblHdrPtr, tblHdrPtr->tableSize, numNewEntries);
148 tblHdrPtr->tableSize += numNewEntries;
149 ckfree (oldBodyP);
150
151 } /* ExpandTable */
152 \f
153 /*=============================================================================
154 * AllocEntry --
155 * Allocate a table entry, expanding if necessary.
156 *
157 * Parameters:
158 * o tblHdrPtr (I) - A pointer to the table header.
159 * o entryIdxPtr (O) - The index of the table entry is returned here.
160 * Returns:
161 * The a pointer to the entry.
162 *-----------------------------------------------------------------------------
163 */
164 static entryHeader_pt
165 AllocEntry (tblHdrPtr, entryIdxPtr)
166 tblHeader_pt tblHdrPtr;
167 int *entryIdxPtr;
168 {
169 int entryIdx;
170 entryHeader_pt entryPtr;
171
172 if (tblHdrPtr->freeHeadIdx == NULL_IDX)
173 ExpandTable (tblHdrPtr, -1);
174
175 entryIdx = tblHdrPtr->freeHeadIdx;
176 entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
177 tblHdrPtr->freeHeadIdx = entryPtr->freeLink;
178 entryPtr->freeLink = ALLOCATED_IDX;
179
180 *entryIdxPtr = entryIdx;
181 return entryPtr;
182
183 } /* AllocEntry */
184 \f
185 /*=============================================================================
186 * HandleDecode --
187 * Decode handle into an entry number.
188 *
189 * Parameters:
190 * o interp (I) - A error message may be returned in result.
191 * o tblHdrPtr (I) - A pointer to the table header.
192 * o handle (I) - Handle to decode.
193 * Returns:
194 * The entry index decoded from the handle, or a negative number if an error
195 * occured.
196 *-----------------------------------------------------------------------------
197 */
198 static int
199 HandleDecode (interp, tblHdrPtr, handle)
200 Tcl_Interp *interp;
201 tblHeader_pt tblHdrPtr;
202 CONST char *handle;
203 {
204 unsigned entryIdx;
205
206 if ((strncmp (tblHdrPtr->handleBase, (char *) handle,
207 tblHdrPtr->baseLength) != 0) ||
208 !Tcl_StrToUnsigned (&handle [tblHdrPtr->baseLength], 10,
209 &entryIdx)) {
210 Tcl_AppendResult (interp, "invalid ", tblHdrPtr->handleBase,
211 " handle: ", handle, (char *) NULL);
212 return -1;
213 }
214 return entryIdx;
215
216 } /* HandleDecode */
217 \f
218 /*=============================================================================
219 * Tcl_HandleTblInit --
220 * Create and initialize a Tcl dynamic handle table. The use count on the
221 * table is set to one.
222 * Parameters:
223 * o handleBase(I) - The base name of the handle, the handle will be returned
224 * in the form "baseNN", where NN is the table entry number.
225 * o entrySize (I) - The size of an entry, in bytes.
226 * o initEntries (I) - Initial size of the table, in entries.
227 * Returns:
228 * A pointer to the table header.
229 *-----------------------------------------------------------------------------
230 */
231 void_pt
232 Tcl_HandleTblInit (handleBase, entrySize, initEntries)
233 CONST char *handleBase;
234 int entrySize;
235 int initEntries;
236 {
237 tblHeader_pt tblHdrPtr;
238 int baseLength = strlen ((char *) handleBase);
239
240 tblHdrPtr = (tblHeader_pt) ckalloc (sizeof (tblHeader_t) + baseLength + 1);
241
242 tblHdrPtr->useCount = 1;
243 tblHdrPtr->baseLength = baseLength;
244 strcpy (tblHdrPtr->handleBase, (char *) handleBase);
245
246 /*
247 * Calculate entry size, including header, rounded up to sizeof (int).
248 */
249 tblHdrPtr->entrySize = entrySize + sizeof (entryHeader_t);
250 tblHdrPtr->entrySize = ((tblHdrPtr->entrySize + sizeof (int) - 1) /
251 sizeof (int)) * sizeof (int);
252 tblHdrPtr->freeHeadIdx = NULL_IDX;
253 tblHdrPtr->tableSize = initEntries;
254 tblHdrPtr->bodyP = (ubyte_pt) ckalloc (initEntries * tblHdrPtr->entrySize);
255 LinkInNewEntries (tblHdrPtr, 0, initEntries);
256
257 return (void_pt) tblHdrPtr;
258
259 } /* Tcl_HandleTblInit */
260 \f
261 /*=============================================================================
262 * Tcl_HandleTblUseCount --
263 * Alter the handle table use count by the specified amount, which can be
264 * positive or negative. Amount may be zero to retrieve the use count.
265 * Parameters:
266 * o headerPtr (I) - Pointer to the table header.
267 * o amount (I) - The amount to alter the use count by.
268 * Returns:
269 * The resulting use count.
270 *-----------------------------------------------------------------------------
271 */
272 int
273 Tcl_HandleTblUseCount (headerPtr, amount)
274 void_pt headerPtr;
275 int amount;
276 {
277 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
278
279 tblHdrPtr->useCount += amount;
280 return tblHdrPtr->useCount;
281 }
282 \f
283 /*=============================================================================
284 * Tcl_HandleTblRelease --
285 * Decrement the use count on a Tcl dynamic handle table. If the count
286 * goes to zero or negative, then release the table. It is designed to be
287 * called when a command is released.
288 * Parameters:
289 * o headerPtr (I) - Pointer to the table header.
290 *-----------------------------------------------------------------------------
291 */
292 void
293 Tcl_HandleTblRelease (headerPtr)
294 void_pt headerPtr;
295 {
296 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
297
298 tblHdrPtr->useCount--;
299 if (tblHdrPtr->useCount <= 0) {
300 ckfree (tblHdrPtr->bodyP);
301 ckfree ((char *) tblHdrPtr);
302 }
303 }
304 \f
305 /*=============================================================================
306 * Tcl_HandleAlloc --
307 * Allocate an entry and associate a handle with it.
308 *
309 * Parameters:
310 * o headerPtr (I) - A pointer to the table header.
311 * o handlePtr (O) - Buffer to return handle in. It must be big enough to
312 * hold the name.
313 * Returns:
314 * A pointer to the allocated entry (user part).
315 *-----------------------------------------------------------------------------
316 */
317 void_pt
318 Tcl_HandleAlloc (headerPtr, handlePtr)
319 void_pt headerPtr;
320 char *handlePtr;
321 {
322 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
323 entryHeader_pt entryPtr;
324 int entryIdx;
325
326 entryPtr = AllocEntry ((tblHeader_pt) headerPtr, &entryIdx);
327 sprintf (handlePtr, "%s%d", tblHdrPtr->handleBase, entryIdx);
328
329 return USER_AREA (entryPtr);
330
331 } /* Tcl_HandleAlloc */
332 \f
333 /*=============================================================================
334 * Tcl_HandleXlate --
335 * Translate a handle to a entry pointer.
336 *
337 * Parameters:
338 * o interp (I) - A error message may be returned in result.
339 * o headerPtr (I) - A pointer to the table header.
340 * o handle (I) - The handle assigned to the entry.
341 * Returns:
342 * A pointer to the entry, or NULL if an error occured.
343 *-----------------------------------------------------------------------------
344 */
345 void_pt
346 Tcl_HandleXlate (interp, headerPtr, handle)
347 Tcl_Interp *interp;
348 void_pt headerPtr;
349 CONST char *handle;
350 {
351 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
352 entryHeader_pt entryPtr;
353 int entryIdx;
354
355 if ((entryIdx = HandleDecode (interp, tblHdrPtr, handle)) < 0)
356 return NULL;
357 entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
358
359 if ((entryIdx >= tblHdrPtr->tableSize) ||
360 (entryPtr->freeLink != ALLOCATED_IDX)) {
361 Tcl_AppendResult (interp, tblHdrPtr->handleBase, " is not open",
362 (char *) NULL);
363 return NULL;
364 }
365
366 return USER_AREA (entryPtr);
367
368 } /* Tcl_HandleXlate */
369 \f
370 /*=============================================================================
371 * Tcl_HandleWalk --
372 * Walk through and find every allocated entry in a table. Entries may
373 * be deallocated during a walk, but should not be allocated.
374 *
375 * Parameters:
376 * o headerPtr (I) - A pointer to the table header.
377 * o walkKeyPtr (I/O) - Pointer to a variable to use to keep track of the
378 * place in the table. The variable should be initialized to -1 before
379 * the first call.
380 * Returns:
381 * A pointer to the next allocated entry, or NULL if there are not more.
382 *-----------------------------------------------------------------------------
383 */
384 void_pt
385 Tcl_HandleWalk (headerPtr, walkKeyPtr)
386 void_pt headerPtr;
387 int *walkKeyPtr;
388 {
389 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
390 int entryIdx;
391 entryHeader_pt entryPtr;
392
393 if (*walkKeyPtr == -1)
394 entryIdx = 0;
395 else
396 entryIdx = *walkKeyPtr + 1;
397
398 while (entryIdx < tblHdrPtr->tableSize) {
399 entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
400 if (entryPtr->freeLink == ALLOCATED_IDX) {
401 *walkKeyPtr = entryIdx;
402 return USER_AREA (entryPtr);
403 }
404 entryIdx++;
405 }
406 return NULL;
407
408 } /* Tcl_HandleWalk */
409 \f
410 /*=============================================================================
411 * Tcl_WalkKeyToHandle --
412 * Convert a walk key, as returned from a call to Tcl_HandleWalk into a
413 * handle. The Tcl_HandleWalk must have succeeded.
414 * Parameters:
415 * o headerPtr (I) - A pointer to the table header.
416 * o walkKey (I) - The walk key.
417 * o handlePtr (O) - Buffer to return handle in. It must be big enough to
418 * hold the name.
419 *-----------------------------------------------------------------------------
420 */
421 void
422 Tcl_WalkKeyToHandle (headerPtr, walkKey, handlePtr)
423 void_pt headerPtr;
424 int walkKey;
425 char *handlePtr;
426 {
427 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
428
429 sprintf (handlePtr, "%s%d", tblHdrPtr->handleBase, walkKey);
430
431 } /* Tcl_WalkKeyToHandle */
432 \f
433 /*=============================================================================
434 * Tcl_HandleFree --
435 * Frees a handle table entry.
436 *
437 * Parameters:
438 * o headerPtr (I) - A pointer to the table header.
439 * o entryPtr (I) - Entry to free.
440 *-----------------------------------------------------------------------------
441 */
442 void
443 Tcl_HandleFree (headerPtr, entryPtr)
444 void_pt headerPtr;
445 void_pt entryPtr;
446 {
447 tblHeader_pt tblHdrPtr = (tblHeader_pt)headerPtr;
448 entryHeader_pt freeentryPtr;
449
450 freeentryPtr = HEADER_AREA (entryPtr);
451 freeentryPtr->freeLink = tblHdrPtr->freeHeadIdx;
452 tblHdrPtr->freeHeadIdx = (((ubyte_pt) entryPtr) - tblHdrPtr->bodyP) /
453 tblHdrPtr->entrySize;
454
455 } /* Tcl_HandleFree */
456
Impressum, Datenschutz