260 lines
6.3 KiB
C
260 lines
6.3 KiB
C
|
/*
|
|||
|
* tclFHandle.c --
|
|||
|
*
|
|||
|
* This file contains functions for manipulating Tcl file handles.
|
|||
|
*
|
|||
|
* Copyright (c) 1995 Sun Microsystems, Inc.
|
|||
|
*
|
|||
|
* See the file "license.terms" for information on usage and redistribution
|
|||
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|||
|
*
|
|||
|
* SCCS: @(#) tclFHandle.c 1.9 96/07/01 15:41:26
|
|||
|
*/
|
|||
|
|
|||
|
#include "tcl.h"
|
|||
|
#include "tclInt.h"
|
|||
|
#include "tclPort.h"
|
|||
|
|
|||
|
/*
|
|||
|
* The FileHashKey structure is used to associate the OS file handle and type
|
|||
|
* with the corresponding notifier data in a FileHandle.
|
|||
|
*/
|
|||
|
|
|||
|
typedef struct FileHashKey {
|
|||
|
int type; /* File handle type. */
|
|||
|
ClientData osHandle; /* Platform specific OS file handle. */
|
|||
|
} FileHashKey;
|
|||
|
|
|||
|
typedef struct FileHandle {
|
|||
|
FileHashKey key; /* Hash key for a given file. */
|
|||
|
ClientData data; /* Platform specific notifier data. */
|
|||
|
Tcl_FileFreeProc *proc; /* Callback to invoke when file is freed. */
|
|||
|
} FileHandle;
|
|||
|
|
|||
|
/*
|
|||
|
* Static variables used in this file:
|
|||
|
*/
|
|||
|
|
|||
|
static Tcl_HashTable fileTable; /* Hash table containing file handles. */
|
|||
|
static int initialized = 0; /* 1 if this module has been initialized. */
|
|||
|
|
|||
|
/*
|
|||
|
* Static procedures used in this file:
|
|||
|
*/
|
|||
|
|
|||
|
static void FileExitProc _ANSI_ARGS_((ClientData clientData));
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* Tcl_GetFile --
|
|||
|
*
|
|||
|
* This function retrieves the file handle associated with a
|
|||
|
* platform specific file handle of the given type. It creates
|
|||
|
* a new file handle if needed.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* Returns the file handle associated with the file descriptor.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* Initializes the file handle table if necessary.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
Tcl_File
|
|||
|
Tcl_GetFile(osHandle, type)
|
|||
|
ClientData osHandle; /* Platform specific file handle. */
|
|||
|
int type; /* Type of file handle. */
|
|||
|
{
|
|||
|
FileHashKey key;
|
|||
|
Tcl_HashEntry *entryPtr;
|
|||
|
int new;
|
|||
|
|
|||
|
if (!initialized) {
|
|||
|
Tcl_InitHashTable(&fileTable, sizeof(FileHashKey)/sizeof(int));
|
|||
|
Tcl_CreateExitHandler(FileExitProc, 0);
|
|||
|
initialized = 1;
|
|||
|
}
|
|||
|
key.osHandle = osHandle;
|
|||
|
key.type = type;
|
|||
|
entryPtr = Tcl_CreateHashEntry(&fileTable, (char *) &key, &new);
|
|||
|
if (new) {
|
|||
|
FileHandle *newHandlePtr;
|
|||
|
newHandlePtr = (FileHandle *) ckalloc(sizeof(FileHandle));
|
|||
|
newHandlePtr->key = key;
|
|||
|
newHandlePtr->data = NULL;
|
|||
|
newHandlePtr->proc = NULL;
|
|||
|
Tcl_SetHashValue(entryPtr, newHandlePtr);
|
|||
|
}
|
|||
|
|
|||
|
return (Tcl_File) Tcl_GetHashValue(entryPtr);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* Tcl_FreeFile --
|
|||
|
*
|
|||
|
* Deallocates an entry in the file handle table.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
void
|
|||
|
Tcl_FreeFile(handle)
|
|||
|
Tcl_File handle;
|
|||
|
{
|
|||
|
Tcl_HashEntry *entryPtr;
|
|||
|
FileHandle *handlePtr = (FileHandle *) handle;
|
|||
|
|
|||
|
/*
|
|||
|
* Invoke free procedure, then delete the handle.
|
|||
|
*/
|
|||
|
|
|||
|
if (handlePtr->proc) {
|
|||
|
(*handlePtr->proc)(handlePtr->data);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Tcl_File structures may be freed as a result of running the
|
|||
|
* channel table exit handler. The file table is freed by the file
|
|||
|
* table exit handler, which may run before the channel table exit
|
|||
|
* handler. The file table exit handler sets the "initialized"
|
|||
|
* variable back to zero, so that the Tcl_FreeFile (when invoked
|
|||
|
* from the channel table exit handler) can notice that the file
|
|||
|
* table has already been destroyed. Otherwise, accessing a
|
|||
|
* deleted hash table would cause a panic.
|
|||
|
*/
|
|||
|
|
|||
|
if (initialized) {
|
|||
|
entryPtr = Tcl_FindHashEntry(&fileTable, (char *) &handlePtr->key);
|
|||
|
if (entryPtr) {
|
|||
|
Tcl_DeleteHashEntry(entryPtr);
|
|||
|
}
|
|||
|
}
|
|||
|
ckfree((char *) handlePtr);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* Tcl_GetFileInfo --
|
|||
|
*
|
|||
|
* This function retrieves the platform specific file data and
|
|||
|
* type from the file handle.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* If typePtr is not NULL, sets *typePtr to the type of the file.
|
|||
|
* Returns the platform specific file data.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
ClientData
|
|||
|
Tcl_GetFileInfo(handle, typePtr)
|
|||
|
Tcl_File handle;
|
|||
|
int *typePtr;
|
|||
|
{
|
|||
|
FileHandle *handlePtr = (FileHandle *) handle;
|
|||
|
|
|||
|
if (typePtr) {
|
|||
|
*typePtr = handlePtr->key.type;
|
|||
|
}
|
|||
|
return handlePtr->key.osHandle;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* Tcl_SetNotifierData --
|
|||
|
*
|
|||
|
* This function is used by the notifier to associate platform
|
|||
|
* specific notifier information and a deletion procedure with
|
|||
|
* a file handle.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* Updates the data and delProc slots in the file handle.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
void
|
|||
|
Tcl_SetNotifierData(handle, proc, data)
|
|||
|
Tcl_File handle;
|
|||
|
Tcl_FileFreeProc *proc;
|
|||
|
ClientData data;
|
|||
|
{
|
|||
|
FileHandle *handlePtr = (FileHandle *) handle;
|
|||
|
handlePtr->proc = proc;
|
|||
|
handlePtr->data = data;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* Tcl_GetNotifierData --
|
|||
|
*
|
|||
|
* This function is used by the notifier to retrieve the platform
|
|||
|
* specific notifier information associated with a file handle.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* Returns the data stored in a file handle by a previous call to
|
|||
|
* Tcl_SetNotifierData, and places a pointer to the free proc
|
|||
|
* in the location referred to by procPtr.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
ClientData
|
|||
|
Tcl_GetNotifierData(handle, procPtr)
|
|||
|
Tcl_File handle;
|
|||
|
Tcl_FileFreeProc **procPtr;
|
|||
|
{
|
|||
|
FileHandle *handlePtr = (FileHandle *) handle;
|
|||
|
if (procPtr != NULL) {
|
|||
|
*procPtr = handlePtr->proc;
|
|||
|
}
|
|||
|
return handlePtr->data;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* FileExitProc --
|
|||
|
*
|
|||
|
* This function an exit handler that frees any memory allocated
|
|||
|
* for the file handle table.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* Cleans up the file handle table.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
FileExitProc(clientData)
|
|||
|
ClientData clientData; /* Not used. */
|
|||
|
{
|
|||
|
Tcl_DeleteHashTable(&fileTable);
|
|||
|
initialized = 0;
|
|||
|
}
|