⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tkunixsend.c

📁 linux系统下的音频通信
💻 C
📖 第 1 页 / 共 4 页
字号:
/*  * tkUnixSend.c -- * *	This file provides procedures that implement the "send" *	command, allowing commands to be passed from interpreter *	to interpreter. * * Copyright (c) 1989-1994 The Regents of the University of California. * Copyright (c) 1994-1996 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: @(#) tkUnixSend.c 1.74 97/11/04 17:12:18 */#include "tkPort.h"#include "tkInt.h"#include "tkUnixInt.h"/*  * The following structure is used to keep track of the interpreters * registered by this process. */typedef struct RegisteredInterp {    char *name;			/* Interpreter's name (malloc-ed). */    Tcl_Interp *interp;		/* Interpreter associated with name.  NULL				 * means that the application was unregistered				 * or deleted while a send was in progress				 * to it. */    TkDisplay *dispPtr;		/* Display for the application.  Needed				 * because we may need to unregister the				 * interpreter after its main window has				 * been deleted. */    struct RegisteredInterp *nextPtr;				/* Next in list of names associated				 * with interps in this process.				 * NULL means end of list. */} RegisteredInterp;static RegisteredInterp *registry = NULL;				/* List of all interpreters				 * registered by this process. *//* * A registry of all interpreters for a display is kept in a * property "InterpRegistry" on the root window of the display. * It is organized as a series of zero or more concatenated strings * (in no particular order), each of the form * 	window space name '\0' * where "window" is the hex id of the comm. window to use to talk * to an interpreter named "name". * * When the registry is being manipulated by an application (e.g. to * add or remove an entry), it is loaded into memory using a structure * of the following type: */typedef struct NameRegistry {    TkDisplay *dispPtr;		/* Display from which the registry was				 * read. */    int locked;			/* Non-zero means that the display was				 * locked when the property was read in. */    int modified;		/* Non-zero means that the property has				 * been modified, so it needs to be written				 * out when the NameRegistry is closed. */    unsigned long propLength;	/* Length of the property, in bytes. */    char *property;		/* The contents of the property, or NULL				 * if none.  See format description above;				 * this is *not* terminated by the first				 * null character.  Dynamically allocated. */    int allocedByX;		/* Non-zero means must free property with				 * XFree;  zero means use ckfree. */} NameRegistry;/* * When a result is being awaited from a sent command, one of * the following structures is present on a list of all outstanding * sent commands.  The information in the structure is used to * process the result when it arrives.  You're probably wondering * how there could ever be multiple outstanding sent commands. * This could happen if interpreters invoke each other recursively. * It's unlikely, but possible. */typedef struct PendingCommand {    int serial;			/* Serial number expected in				 * result. */    TkDisplay *dispPtr;		/* Display being used for communication. */    char *target;		/* Name of interpreter command is				 * being sent to. */    Window commWindow;		/* Target's communication window. */    Tcl_Interp *interp;		/* Interpreter from which the send				 * was invoked. */    int code;			/* Tcl return code for command				 * will be stored here. */    char *result;		/* String result for command (malloc'ed),				 * or NULL. */    char *errorInfo;		/* Information for "errorInfo" variable,				 * or NULL (malloc'ed). */    char *errorCode;		/* Information for "errorCode" variable,				 * or NULL (malloc'ed). */    int gotResponse;		/* 1 means a response has been received,				 * 0 means the command is still outstanding. */    struct PendingCommand *nextPtr;				/* Next in list of all outstanding				 * commands.  NULL means end of				 * list. */} PendingCommand;static PendingCommand *pendingCommands = NULL;				/* List of all commands currently				 * being waited for. *//* * The information below is used for communication between processes * during "send" commands.  Each process keeps a private window, never * even mapped, with one property, "Comm".  When a command is sent to * an interpreter, the command is appended to the comm property of the * communication window associated with the interp's process.  Similarly, * when a result is returned from a sent command, it is also appended * to the comm property. * * Each command and each result takes the form of ASCII text.  For a * command, the text consists of a zero character followed by several * null-terminated ASCII strings.  The first string consists of the * single letter "c".  Subsequent strings have the form "option value" * where the following options are supported: * * -r commWindow serial * *	This option means that a response should be sent to the window *	whose X identifier is "commWindow" (in hex), and the response should *	be identified with the serial number given by "serial" (in decimal). *	If this option isn't specified then the send is asynchronous and *	no response is sent. * * -n name *	"Name" gives the name of the application for which the command is *	intended.  This option must be present. * * -s script * *	"Script" is the script to be executed.  This option must be present. * * The options may appear in any order.  The -n and -s options must be * present, but -r may be omitted for asynchronous RPCs.  For compatibility * with future releases that may add new features, there may be additional * options present;  as long as they start with a "-" character, they will * be ignored. * * A result also consists of a zero character followed by several null- * terminated ASCII strings.  The first string consists of the single * letter "r".  Subsequent strings have the form "option value" where * the following options are supported: * * -s serial * *	Identifies the command for which this is the result.  It is the *	same as the "serial" field from the -s option in the command.  This *	option must be present. * * -c code * *	"Code" is the completion code for the script, in decimal.  If the *	code is omitted it defaults to TCL_OK. * * -r result * *	"Result" is the result string for the script, which may be either *	a result or an error message.  If this field is omitted then it *	defaults to an empty string. * * -i errorInfo * *	"ErrorInfo" gives a string with which to initialize the errorInfo *	variable.  This option may be omitted;  it is ignored unless the *	completion code is TCL_ERROR. * * -e errorCode * *	"ErrorCode" gives a string with with to initialize the errorCode *	variable.  This option may be omitted;  it is ignored  unless the *	completion code is TCL_ERROR. * * Options may appear in any order, and only the -s option must be * present.  As with commands, there may be additional options besides * these;  unknown options are ignored. *//* * The following variable is the serial number that was used in the * last "send" command.  It is exported only for testing purposes. */int tkSendSerial = 0;/* * Maximum size property that can be read at one time by * this module: */#define MAX_PROP_WORDS 100000/* * The following variable can be set while debugging to do things like * skip locking the server. */static int sendDebug = 0;/* * Forward declarations for procedures defined later in this file: */static int		AppendErrorProc _ANSI_ARGS_((ClientData clientData,				XErrorEvent *errorPtr));static void		AppendPropCarefully _ANSI_ARGS_((Display *display,			    Window window, Atom property, char *value,			    int length, PendingCommand *pendingPtr));static void		DeleteProc _ANSI_ARGS_((ClientData clientData));static void		RegAddName _ANSI_ARGS_((NameRegistry *regPtr,			    char *name, Window commWindow));static void		RegClose _ANSI_ARGS_((NameRegistry *regPtr));static void		RegDeleteName _ANSI_ARGS_((NameRegistry *regPtr,			    char *name));static Window		RegFindName _ANSI_ARGS_((NameRegistry *regPtr,			    char *name));static NameRegistry *	RegOpen _ANSI_ARGS_((Tcl_Interp *interp,			    TkDisplay *dispPtr, int lock));static void		SendEventProc _ANSI_ARGS_((ClientData clientData,			    XEvent *eventPtr));static int		SendInit _ANSI_ARGS_((Tcl_Interp *interp,			    TkDisplay *dispPtr));static Tk_RestrictAction SendRestrictProc _ANSI_ARGS_((ClientData clientData,			    XEvent *eventPtr));static int		ServerSecure _ANSI_ARGS_((TkDisplay *dispPtr));static void		UpdateCommWindow _ANSI_ARGS_((TkDisplay *dispPtr));static int		ValidateName _ANSI_ARGS_((TkDisplay *dispPtr,			    char *name, Window commWindow, int oldOK));/* *---------------------------------------------------------------------- * * RegOpen -- * *	This procedure loads the name registry for a display into *	memory so that it can be manipulated. * * Results: *	The return value is a pointer to the loaded registry. * * Side effects: *	If "lock" is set then the server will be locked.  It is the *	caller's responsibility to call RegClose when finished with *	the registry, so that we can write back the registry if *	neeeded, unlock the server if needed, and free memory. * *---------------------------------------------------------------------- */static NameRegistry *RegOpen(interp, dispPtr, lock)    Tcl_Interp *interp;		/* Interpreter to use for error reporting				 * (errors cause a panic so in fact no				 * error is ever returned, but the interpreter				 * is needed anyway). */    TkDisplay *dispPtr;		/* Display whose name registry is to be				 * opened. */    int lock;			/* Non-zero means lock the window server				 * when opening the registry, so no-one				 * else can use the registry until we				 * close it. */{    NameRegistry *regPtr;    int result, actualFormat;    unsigned long bytesAfter;    Atom actualType;    if (dispPtr->commTkwin == NULL) {	SendInit(interp, dispPtr);    }    regPtr = (NameRegistry *) ckalloc(sizeof(NameRegistry));    regPtr->dispPtr = dispPtr;    regPtr->locked = 0;    regPtr->modified = 0;    regPtr->allocedByX = 1;    if (lock && !sendDebug) {	XGrabServer(dispPtr->display);	regPtr->locked = 1;    }    /*     * Read the registry property.     */    result = XGetWindowProperty(dispPtr->display,	    RootWindow(dispPtr->display, 0),	    dispPtr->registryProperty, 0, MAX_PROP_WORDS,	    False, XA_STRING, &actualType, &actualFormat,	    &regPtr->propLength, &bytesAfter,	    (unsigned char **) &regPtr->property);    if (actualType == None) {	regPtr->propLength = 0;	regPtr->property = NULL;    } else if ((result != Success) || (actualFormat != 8)	    || (actualType != XA_STRING)) {	/*	 * The property is improperly formed;  delete it.	 */	if (regPtr->property != NULL) {	    XFree(regPtr->property);	    regPtr->propLength = 0;	    regPtr->property = NULL;	}	XDeleteProperty(dispPtr->display,		RootWindow(dispPtr->display, 0),		dispPtr->registryProperty);    }    /*     * Xlib placed an extra null byte after the end of the property, just     * to make sure that it is always NULL-terminated.  Be sure to include     * this byte in our count if it's needed to ensure null termination     * (note: as of 8/95 I'm no longer sure why this code is needed;  seems     * like it shouldn't be).     */    if ((regPtr->propLength > 0)	    && (regPtr->property[regPtr->propLength-1] != 0)) {	regPtr->propLength++;    }    return regPtr;}/* *---------------------------------------------------------------------- * * RegFindName -- * *	Given an open name registry, this procedure finds an entry *	with a given name, if there is one, and returns information *	about that entry. * * Results: *	The return value is the X identifier for the comm window for *	the application named "name", or None if there is no such *	entry in the registry. * * Side effects: *	None. * *---------------------------------------------------------------------- */static WindowRegFindName(regPtr, name)    NameRegistry *regPtr;	/* Pointer to a registry opened with a				 * previous call to RegOpen. */    char *name;			/* Name of an application. */{    char *p, *entry;    unsigned int id;    for (p = regPtr->property; (p-regPtr->property) < (int) regPtr->propLength; ) {	entry = p;	while ((*p != 0) && (!isspace(UCHAR(*p)))) {	    p++;	}	if ((*p != 0) && (strcmp(name, p+1) == 0)) {	    if (sscanf(entry, "%x", &id) == 1) {		/*		 * Must cast from an unsigned int to a Window in case we		 * are on a 64-bit architecture.		 */		return (Window) id;	    }	}	while (*p != 0) {	    p++;	}	p++;    }    return None;}/* *---------------------------------------------------------------------- * * RegDeleteName -- * *	This procedure deletes the entry for a given name from *	an open registry. * * Results: *	None. * * Side effects: *	If there used to be an entry named "name" in the registry, *	then it is deleted and the registry is marked as modified *	so it will be written back when closed. * *---------------------------------------------------------------------- */static voidRegDeleteName(regPtr, name)    NameRegistry *regPtr;	/* Pointer to a registry opened with a				 * previous call to RegOpen. */    char *name;			/* Name of an application. */{    char *p, *entry, *entryName;    int count;    for (p = regPtr->property; (p-regPtr->property) < (int) regPtr->propLength; ) {	entry = p;	while ((*p != 0) && (!isspace(UCHAR(*p)))) {	    p++;	}	if (*p != 0) {	    p++;	}	entryName = p;	while (*p != 0) {	    p++;	}	p++;	if ((strcmp(name, entryName) == 0)) {	    /*	     * Found the matching entry.  Copy everything after it	     * down on top of it.	     */	    count = regPtr->propLength - (p - regPtr->property);	    if (count > 0)  {		char *src, *dst;		for (src = p, dst = entry; count > 0; src++, dst++, count--) {		    *dst = *src;		}	    }	    regPtr->propLength -=  p - entry;	    regPtr->modified = 1;	    return;	}    }}/* *---------------------------------------------------------------------- * * RegAddName -- * *	Add a new entry to an open registry. * * Results: *	None.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -