X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-tcl.git;a=blobdiff_plain;f=base%2Fchiark-tcl.h;h=2f4ae7d5f3c5ea37f62e714d5e82494010523719;hp=4c022cb82c8c5922ecf2ac7046af64643a8e4216;hb=5f66b4d08a96e0effeed6b84c73bb0d82edceefa;hpb=40a4738e440a8412c61a12eca34ed6aa98d71a5a diff --git a/base/chiark-tcl.h b/base/chiark-tcl.h index 4c022cb..2f4ae7d 100644 --- a/base/chiark-tcl.h +++ b/base/chiark-tcl.h @@ -1,4 +1,19 @@ /* + * base code for various Tcl extensions + * Copyright 2006-2012 Ian Jackson + * + * 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 library; if not, see . */ #ifndef CHIARK_TCL_H @@ -9,12 +24,15 @@ #include #include #include +#include #include #include #include #include -#include +#ifndef _TCL /* if someone already included some tcl.h, use that */ +#include +#endif /*_TCL*/ #include @@ -35,20 +53,30 @@ int cht_pat_enum(Tcl_Interp*, Tcl_Obj*, const void**, /* from scriptinv.c */ -typedef struct { /* semi-opaque - read only, and then only where commented */ - Tcl_Interp *ip; /* valid, non-0 and useable if set */ - Tcl_Obj *obj; /* non-0 iff set (but only test for 0/non-0) */ - Tcl_Obj *xargs; - int llength; +typedef struct { /* opaque; comments are for scriptinv.c impl'n only */ + /* states: Cancelled Set */ + Tcl_Interp *ipq; /* 0 valid, non-0, useable */ + Tcl_Obj *script; /* 0 valid, non-0 */ + Tcl_Obj *xargs; /* 0 valid, may be 0 */ + int llen; /* undefined llength of script + xargs */ } ScriptToInvoke; -void cht_scriptinv_init(ScriptToInvoke *si); +void cht_scriptinv_init(ScriptToInvoke *si); /* undefined -> Cancelled */ int cht_scriptinv_set(ScriptToInvoke *si, Tcl_Interp *ip, - Tcl_Obj *newscript, Tcl_Obj *xargs); -void cht_scriptinv_cancel(ScriptToInvoke *si); /* then don't invoke */ - /* no separate free function - just cancel */ + Tcl_Obj *newscript, Tcl_Obj *xargs); + /* Cancelled/Set -> Set (newscript!=0, ok) / Cancelled (otherwise) */ +void cht_scriptinv_cancel(ScriptToInvoke *si); + /* Cancelled/Set -> Cancelled. No separate free function - just cancel. */ +#define cht_scriptinv_interp(si) ((si)->ipq) + /* int cht_scriptinv_interp(ScriptToInvoke *si); returns 0 if Cancelled */ + +int cht_scriptinv_invoke_fg(ScriptToInvoke *si, int argc, + Tcl_Obj *const *argv); + /* is a no-op if Cancelled rather than Set */ + /* if script fails, returns that error */ void cht_scriptinv_invoke(ScriptToInvoke *si, int argc, Tcl_Obj *const *argv); + /* if script fails, reports it with Tcl_BackgroundError */ /* from idtable.c */ @@ -70,25 +98,21 @@ void cht_tabledataid_disposing(Tcl_Interp *ip, void *val, const IdDataSpec *idds /* from hook.c */ -int cht_initextension(Tcl_Interp *ip, const TopLevel_Command *cmds, - int *donep /* or 0, meaning no types follow */, - ... /* types, terminated by 0 */); - int cht_staticerr(Tcl_Interp *ip, const char *m, const char *ec); int cht_posixerr(Tcl_Interp *ip, int errnoval, const char *m); int cht_newfdposixerr(Tcl_Interp *ip, int fd, const char *m); void cht_objfreeir(Tcl_Obj *o); int cht_get_urandom(Tcl_Interp *ip, Byte *buffer, int l); -void cht_obj_updatestr_array(Tcl_Obj *o, const Byte *array, int l); -void cht_obj_updatestr_array_prefix(Tcl_Obj *o, const Byte *byte, - int l, const char *prefix); - void cht_obj_updatestr_vstringls(Tcl_Obj *o, ...); - /* const char*, int, const char*, int, ..., (const char*)0 */ + /* const char*, size_t, const char*, size_t, ..., (const char*)0 */ void cht_obj_updatestr_string_len(Tcl_Obj *o, const char *str, int l); void cht_obj_updatestr_string(Tcl_Obj *o, const char *str); +void cht_prepare__basic(Tcl_Interp *ip); +void cht_setup__commands(Tcl_Interp *ip, const TopLevel_Command *cmds); + /* ... for use by CHT_INIT and CHTI_... macros only */ + /* from parse.c */ typedef struct { @@ -130,4 +154,76 @@ int cht_enum1_lookup_cached_func(Tcl_Interp *ip, Tcl_Obj *o, #define TFREE(f) (Tcl_Free((void*)(f))) #define TREALLOC(p,l) ((void*)Tcl_Realloc((void*)(p),(l))) +/* macros for Chiark_tcl_FOOBAR_Init et al */ + + /* + * use these macros like this: + * CHT_INIT(, + * , + * ) + * where + * + * is the short name eg `hbytes' + * and should correspond to EXTBASE from the Makefile. + * + * are the initialisations which cause new commands + * etc. to appear in the Tcl namespace. Eg, CHTI_COMMANDS, + * These initialisations are called only when a Tcl `load' + * command loads this extension. + * + * are the initialisations that we need but which + * do not interfere with the Tcl namespaces. For example, + * OBJECT types we used (CHTI_TYPE), and other chiark_tcl + * extensions (CHTI_OTHER). These initialisations are called + * both as a result of Tcl `load' (before the + * initialisations) and also when another extension declares a + * dependency on this one with CHTI_OTHER. + * + * Both and are whitespace-separated + * lists of calls to CHTI_... macros. If the list is to be empty, + * write `{ }' instead to prevent an empty macro argument. The + * preparations and results currently supported are: + * + * CHTI_COMMANDS(cht__entries) + * where the .tct file contains + * Table * TopLevel_Command + * + * CHTI_OTHER() + * which does the of that extension + * (if they have not already been done). + * + * CHTI_TYPE(cht__type) + * where extern Tcl_ObjType cht__type; + * Note that CHTI_TYPE should only be called by the + * extension which actually implements the type. Other + * extensions which need it should use CHTI_OTHER to bring + * in the implementing extension. + */ + +#define CHT_INIT(e, preparations, results) \ + extern void cht_prepare_##e(Tcl_Interp *ip); \ + void cht_prepare_##e(Tcl_Interp *ip) { \ + static int prepared; \ + if (prepared) return; \ + cht_prepare__basic(ip); \ + { preparations } \ + prepared= 1; \ + } \ + extern int Chiark_tcl_##e##_Init(Tcl_Interp *ip); /*called by load(3tcl)*/ \ + int Chiark_tcl_##e##_Init(Tcl_Interp *ip) { \ + static int initd; \ + if (initd) return TCL_OK; \ + cht_prepare_##e(ip); \ + { results } \ + initd= 1; \ + return TCL_OK; \ + } + +#define CHTI_OTHER(e) \ + { extern void cht_prepare_##e(Tcl_Interp *ip); cht_prepare_##e(ip); } + +#define CHTI_TYPE(ot) { Tcl_RegisterObjType(&(ot)); } + +#define CHTI_COMMANDS(cl) { cht_setup__commands(ip,cl); } + #endif /*CHIARK_TCL_H*/