Mercurial > pidgin.yaz
diff libpurple/plugins/tcl/tcl_ref.c @ 15374:5fe8042783c1
Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sat, 20 Jan 2007 02:32:10 +0000 |
parents | |
children | 32c366eeeb99 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/plugins/tcl/tcl_ref.c Sat Jan 20 02:32:10 2007 +0000 @@ -0,0 +1,152 @@ +/** + * @file tcl_ref.c Gaim Tcl typed references API + * + * gaim + * + * Copyright (C) 2006 Ethan Blanton <eblanton@cs.purdue.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <tcl.h> +#include <glib.h> + +#include "tcl_gaim.h" +#include "stringref.h" + +/* Instead of all that internal representation mumbo jumbo, use these + * macros to access the internal representation of a GaimTclRef */ +#define OBJ_REF_TYPE(obj) (obj->internalRep.twoPtrValue.ptr1) +#define OBJ_REF_VALUE(obj) (obj->internalRep.twoPtrValue.ptr2) + +static Tcl_FreeInternalRepProc gaim_tcl_ref_free; +static Tcl_DupInternalRepProc gaim_tcl_ref_dup; +static Tcl_UpdateStringProc gaim_tcl_ref_update; +static Tcl_SetFromAnyProc gaim_tcl_ref_set; + +static Tcl_ObjType gaim_tcl_ref = { + "GaimTclRef", + gaim_tcl_ref_free, + gaim_tcl_ref_dup, + gaim_tcl_ref_update, + gaim_tcl_ref_set +}; + +void gaim_tcl_ref_init() +{ + Tcl_RegisterObjType(&gaim_tcl_ref); +} + +void *gaim_tcl_ref_get(Tcl_Interp *interp, Tcl_Obj *obj, GaimStringref *type) +{ + if (obj->typePtr != &gaim_tcl_ref) { + if (Tcl_ConvertToType(interp, obj, &gaim_tcl_ref) != TCL_OK) + return NULL; + } + if (strcmp(gaim_stringref_value(OBJ_REF_TYPE(obj)), + gaim_stringref_value(type))) { + if (interp) { + Tcl_Obj *error = Tcl_NewStringObj("Bad Gaim reference type: expected ", -1); + Tcl_AppendToObj(error, gaim_stringref_value(type), -1); + Tcl_AppendToObj(error, " but got ", -1); + Tcl_AppendToObj(error, gaim_stringref_value(OBJ_REF_TYPE(obj)), -1); + Tcl_SetObjResult(interp, error); + } + return NULL; + } + return OBJ_REF_VALUE(obj); +} + +Tcl_Obj *gaim_tcl_ref_new(GaimStringref *type, void *value) +{ + Tcl_Obj *obj = Tcl_NewObj(); + obj->typePtr = &gaim_tcl_ref; + OBJ_REF_TYPE(obj) = gaim_stringref_ref(type); + OBJ_REF_VALUE(obj) = value; + Tcl_InvalidateStringRep(obj); + return obj; +} + +static void gaim_tcl_ref_free(Tcl_Obj *obj) +{ + gaim_stringref_unref(OBJ_REF_TYPE(obj)); +} + +static void gaim_tcl_ref_dup(Tcl_Obj *obj1, Tcl_Obj *obj2) +{ + OBJ_REF_TYPE(obj2) = gaim_stringref_ref(OBJ_REF_TYPE(obj1)); + OBJ_REF_VALUE(obj2) = OBJ_REF_VALUE(obj1); +} + +static void gaim_tcl_ref_update(Tcl_Obj *obj) +{ + /* This is ugly on memory, but we pretty much have to either + * do this or guesstimate lengths or introduce a varargs + * function in here ... ugh. */ + char *bytes = g_strdup_printf("gaim-%s:%p", + gaim_stringref_value(OBJ_REF_TYPE(obj)), + OBJ_REF_VALUE(obj)); + + obj->length = strlen(bytes); + obj->bytes = ckalloc(obj->length + 1); + strcpy(obj->bytes, bytes); + g_free(bytes); +} + +/* This isn't as memory-efficient as setting could be, because we + * essentially have to synthesize the Stringref here, where we would + * really rather dup it. Oh, well. */ +static int gaim_tcl_ref_set(Tcl_Interp *interp, Tcl_Obj *obj) +{ + char *bytes = Tcl_GetStringFromObj(obj, NULL); + char *ptr; + GaimStringref *type; + void *value; + + if (strlen(bytes) < 7 + || strncmp(bytes, "gaim-", 5) + || (ptr = strchr(bytes, ':')) == NULL + || (ptr - bytes) == 5) + goto badobject; + + /* Bad Ethan */ + *ptr = '\0'; + type = gaim_stringref_new(bytes + 5); + *ptr = ':'; + ptr++; + + if (sscanf(ptr, "%p", &value) == 0) { + gaim_stringref_unref(type); + goto badobject; + } + + /* At this point we know we have a good object; free the old and + * install our internal representation. */ + if (obj->typePtr != NULL && obj->typePtr->freeIntRepProc != NULL) + obj->typePtr->freeIntRepProc(obj); + + obj->typePtr = &gaim_tcl_ref; + OBJ_REF_TYPE(obj) = type; + OBJ_REF_VALUE(obj) = value; + + return TCL_OK; + +badobject: + if (interp) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("invalid GaimTclRef representation", -1)); + } + return TCL_ERROR; +}