chiark / gitweb /
Merge branch 'nmus'
[chiark-tcl.git] / base / scriptinv.c
1 /*
2  * base code for various Tcl extensions
3  * Copyright 2006 Ian Jackson
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301, USA.
19  */
20
21 #include "chiark-tcl-base.h"
22
23 void cht_scriptinv_init(ScriptToInvoke *si) {
24   si->ipq= 0;
25   si->script= 0;
26   si->xargs= 0;
27 }
28
29 void cht_scriptinv_cancel(ScriptToInvoke *si) {
30   if (si->script) { Tcl_DecrRefCount(si->script); si->script= 0; }
31   if (si->xargs) { Tcl_DecrRefCount(si->xargs); si->xargs= 0; }
32   si->ipq= 0;
33 }
34
35 int cht_scriptinv_set(ScriptToInvoke *si, Tcl_Interp *ip,
36                   Tcl_Obj *newscript, Tcl_Obj *xargs) {
37   int rc, xlength;
38   
39   cht_scriptinv_cancel(si);
40   if (!newscript) return 0;
41
42   rc= Tcl_ListObjLength(ip, newscript, &si->llen);  if (rc) return rc;
43   Tcl_IncrRefCount(newscript);
44
45   if (xargs) {
46     rc= Tcl_ListObjLength(ip, xargs, &xlength);  if (rc) return rc;
47     Tcl_IncrRefCount(xargs);
48     assert(si->llen < INT_MAX/2 && xlength < INT_MAX/2);
49     si->llen += xlength;
50   }
51
52   si->script= newscript;
53   si->xargs= xargs;
54   si->ipq= ip;
55   return 0;
56 }  
57   
58 int cht_scriptinv_invoke_fg(ScriptToInvoke *si, int argc,
59                             Tcl_Obj *const *argv) {
60   Tcl_Obj *invoke=0;
61   int i, rc;
62
63   if (!si->ipq) return TCL_OK;
64
65   for (i=0; i<argc; i++) Tcl_IncrRefCount(argv[i]);
66
67   invoke= Tcl_DuplicateObj(si->script);
68   Tcl_IncrRefCount(invoke);
69
70   if (si->xargs) {
71     rc= Tcl_ListObjAppendList(si->ipq, invoke, si->xargs);
72     if (rc) goto x_rc;
73   }
74
75   rc= Tcl_ListObjReplace(si->ipq, invoke,si->llen,0, argc,argv);
76   if (rc) goto x_rc;
77
78   rc= Tcl_EvalObjEx(si->ipq, invoke, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
79   if (rc) goto x_rc;
80
81   rc= 0;
82   
83 x_rc:
84   for (i=0; i<argc; i++) Tcl_DecrRefCount(argv[i]);
85   if (invoke) Tcl_DecrRefCount(invoke);
86   return rc;
87 }
88
89 void cht_scriptinv_invoke(ScriptToInvoke *si, int argc, Tcl_Obj *const *argv) {
90   int rc;
91   rc= cht_scriptinv_invoke_fg(si, argc, argv);
92   if (rc) Tcl_BackgroundError(si->ipq);
93 }