/[dtapublic]/projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tcllink.c
ViewVC logotype

Diff of /projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tcllink.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 66 by dashley, Sun Oct 30 21:57:38 2016 UTC revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
1  /* $Header$ */  /* $Header$ */
2  /*  /*
3   * tclLink.c --   * tclLink.c --
4   *   *
5   *      This file implements linked variables (a C variable that is   *      This file implements linked variables (a C variable that is
6   *      tied to a Tcl variable).  The idea of linked variables was   *      tied to a Tcl variable).  The idea of linked variables was
7   *      first suggested by Andreas Stolcke and this implementation is   *      first suggested by Andreas Stolcke and this implementation is
8   *      based heavily on a prototype implementation provided by   *      based heavily on a prototype implementation provided by
9   *      him.   *      him.
10   *   *
11   * Copyright (c) 1993 The Regents of the University of California.   * Copyright (c) 1993 The Regents of the University of California.
12   * Copyright (c) 1994-1997 Sun Microsystems, Inc.   * Copyright (c) 1994-1997 Sun Microsystems, Inc.
13   *   *
14   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
15   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16   *   *
17   * RCS: @(#) $Id: tcllink.c,v 1.1.1.1 2001/06/13 04:42:27 dtashley Exp $   * RCS: @(#) $Id: tcllink.c,v 1.1.1.1 2001/06/13 04:42:27 dtashley Exp $
18   */   */
19    
20  #include "tclInt.h"  #include "tclInt.h"
21    
22  /*  /*
23   * For each linked variable there is a data structure of the following   * For each linked variable there is a data structure of the following
24   * type, which describes the link and is the clientData for the trace   * type, which describes the link and is the clientData for the trace
25   * set on the Tcl variable.   * set on the Tcl variable.
26   */   */
27    
28  typedef struct Link {  typedef struct Link {
29      Tcl_Interp *interp;         /* Interpreter containing Tcl variable. */      Tcl_Interp *interp;         /* Interpreter containing Tcl variable. */
30      char *varName;              /* Name of variable (must be global).  This      char *varName;              /* Name of variable (must be global).  This
31                                   * is needed during trace callbacks, since                                   * is needed during trace callbacks, since
32                                   * the actual variable may be aliased at                                   * the actual variable may be aliased at
33                                   * that time via upvar. */                                   * that time via upvar. */
34      char *addr;                 /* Location of C variable. */      char *addr;                 /* Location of C variable. */
35      int type;                   /* Type of link (TCL_LINK_INT, etc.). */      int type;                   /* Type of link (TCL_LINK_INT, etc.). */
36      union {      union {
37          int i;          int i;
38          double d;          double d;
39      } lastValue;                /* Last known value of C variable;  used to      } lastValue;                /* Last known value of C variable;  used to
40                                   * avoid string conversions. */                                   * avoid string conversions. */
41      int flags;                  /* Miscellaneous one-bit values;  see below      int flags;                  /* Miscellaneous one-bit values;  see below
42                                   * for definitions. */                                   * for definitions. */
43  } Link;  } Link;
44    
45  /*  /*
46   * Definitions for flag bits:   * Definitions for flag bits:
47   * LINK_READ_ONLY -             1 means errors should be generated if Tcl   * LINK_READ_ONLY -             1 means errors should be generated if Tcl
48   *                              script attempts to write variable.   *                              script attempts to write variable.
49   * LINK_BEING_UPDATED -         1 means that a call to Tcl_UpdateLinkedVar   * LINK_BEING_UPDATED -         1 means that a call to Tcl_UpdateLinkedVar
50   *                              is in progress for this variable, so   *                              is in progress for this variable, so
51   *                              trace callbacks on the variable should   *                              trace callbacks on the variable should
52   *                              be ignored.   *                              be ignored.
53   */   */
54    
55  #define LINK_READ_ONLY          1  #define LINK_READ_ONLY          1
56  #define LINK_BEING_UPDATED      2  #define LINK_BEING_UPDATED      2
57    
58  /*  /*
59   * Forward references to procedures defined later in this file:   * Forward references to procedures defined later in this file:
60   */   */
61    
62  static char *           LinkTraceProc _ANSI_ARGS_((ClientData clientData,  static char *           LinkTraceProc _ANSI_ARGS_((ClientData clientData,
63                              Tcl_Interp *interp, char *name1, char *name2,                              Tcl_Interp *interp, char *name1, char *name2,
64                              int flags));                              int flags));
65  static char *           StringValue _ANSI_ARGS_((Link *linkPtr,  static char *           StringValue _ANSI_ARGS_((Link *linkPtr,
66                              char *buffer));                              char *buffer));
67    
68  /*  /*
69   *----------------------------------------------------------------------   *----------------------------------------------------------------------
70   *   *
71   * Tcl_LinkVar --   * Tcl_LinkVar --
72   *   *
73   *      Link a C variable to a Tcl variable so that changes to either   *      Link a C variable to a Tcl variable so that changes to either
74   *      one causes the other to change.   *      one causes the other to change.
75   *   *
76   * Results:   * Results:
77   *      The return value is TCL_OK if everything went well or TCL_ERROR   *      The return value is TCL_OK if everything went well or TCL_ERROR
78   *      if an error occurred (the interp's result is also set after   *      if an error occurred (the interp's result is also set after
79   *      errors).   *      errors).
80   *   *
81   * Side effects:   * Side effects:
82   *      The value at *addr is linked to the Tcl variable "varName",   *      The value at *addr is linked to the Tcl variable "varName",
83   *      using "type" to convert between string values for Tcl and   *      using "type" to convert between string values for Tcl and
84   *      binary values for *addr.   *      binary values for *addr.
85   *   *
86   *----------------------------------------------------------------------   *----------------------------------------------------------------------
87   */   */
88    
89  int  int
90  Tcl_LinkVar(interp, varName, addr, type)  Tcl_LinkVar(interp, varName, addr, type)
91      Tcl_Interp *interp;         /* Interpreter in which varName exists. */      Tcl_Interp *interp;         /* Interpreter in which varName exists. */
92      char *varName;              /* Name of a global variable in interp. */      char *varName;              /* Name of a global variable in interp. */
93      char *addr;                 /* Address of a C variable to be linked      char *addr;                 /* Address of a C variable to be linked
94                                   * to varName. */                                   * to varName. */
95      int type;                   /* Type of C variable: TCL_LINK_INT, etc.      int type;                   /* Type of C variable: TCL_LINK_INT, etc.
96                                   * Also may have TCL_LINK_READ_ONLY                                   * Also may have TCL_LINK_READ_ONLY
97                                   * OR'ed in. */                                   * OR'ed in. */
98  {  {
99      Link *linkPtr;      Link *linkPtr;
100      char buffer[TCL_DOUBLE_SPACE];      char buffer[TCL_DOUBLE_SPACE];
101      int code;      int code;
102    
103      linkPtr = (Link *) ckalloc(sizeof(Link));      linkPtr = (Link *) ckalloc(sizeof(Link));
104      linkPtr->interp = interp;      linkPtr->interp = interp;
105      linkPtr->varName = (char *) ckalloc((unsigned) (strlen(varName) + 1));      linkPtr->varName = (char *) ckalloc((unsigned) (strlen(varName) + 1));
106      strcpy(linkPtr->varName, varName);      strcpy(linkPtr->varName, varName);
107      linkPtr->addr = addr;      linkPtr->addr = addr;
108      linkPtr->type = type & ~TCL_LINK_READ_ONLY;      linkPtr->type = type & ~TCL_LINK_READ_ONLY;
109      if (type & TCL_LINK_READ_ONLY) {      if (type & TCL_LINK_READ_ONLY) {
110          linkPtr->flags = LINK_READ_ONLY;          linkPtr->flags = LINK_READ_ONLY;
111      } else {      } else {
112          linkPtr->flags = 0;          linkPtr->flags = 0;
113      }      }
114      if (Tcl_SetVar(interp, varName, StringValue(linkPtr, buffer),      if (Tcl_SetVar(interp, varName, StringValue(linkPtr, buffer),
115              TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {              TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
116          ckfree(linkPtr->varName);          ckfree(linkPtr->varName);
117          ckfree((char *) linkPtr);          ckfree((char *) linkPtr);
118          return TCL_ERROR;          return TCL_ERROR;
119      }      }
120      code = Tcl_TraceVar(interp, varName, TCL_GLOBAL_ONLY|TCL_TRACE_READS      code = Tcl_TraceVar(interp, varName, TCL_GLOBAL_ONLY|TCL_TRACE_READS
121              |TCL_TRACE_WRITES|TCL_TRACE_UNSETS, LinkTraceProc,              |TCL_TRACE_WRITES|TCL_TRACE_UNSETS, LinkTraceProc,
122              (ClientData) linkPtr);              (ClientData) linkPtr);
123      if (code != TCL_OK) {      if (code != TCL_OK) {
124          ckfree(linkPtr->varName);          ckfree(linkPtr->varName);
125          ckfree((char *) linkPtr);          ckfree((char *) linkPtr);
126      }      }
127      return code;      return code;
128  }  }
129    
130  /*  /*
131   *----------------------------------------------------------------------   *----------------------------------------------------------------------
132   *   *
133   * Tcl_UnlinkVar --   * Tcl_UnlinkVar --
134   *   *
135   *      Destroy the link between a Tcl variable and a C variable.   *      Destroy the link between a Tcl variable and a C variable.
136   *   *
137   * Results:   * Results:
138   *      None.   *      None.
139   *   *
140   * Side effects:   * Side effects:
141   *      If "varName" was previously linked to a C variable, the link   *      If "varName" was previously linked to a C variable, the link
142   *      is broken to make the variable independent.  If there was no   *      is broken to make the variable independent.  If there was no
143   *      previous link for "varName" then nothing happens.   *      previous link for "varName" then nothing happens.
144   *   *
145   *----------------------------------------------------------------------   *----------------------------------------------------------------------
146   */   */
147    
148  void  void
149  Tcl_UnlinkVar(interp, varName)  Tcl_UnlinkVar(interp, varName)
150      Tcl_Interp *interp;         /* Interpreter containing variable to unlink. */      Tcl_Interp *interp;         /* Interpreter containing variable to unlink. */
151      char *varName;              /* Global variable in interp to unlink. */      char *varName;              /* Global variable in interp to unlink. */
152  {  {
153      Link *linkPtr;      Link *linkPtr;
154    
155      linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY,      linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY,
156              LinkTraceProc, (ClientData) NULL);              LinkTraceProc, (ClientData) NULL);
157      if (linkPtr == NULL) {      if (linkPtr == NULL) {
158          return;          return;
159      }      }
160      Tcl_UntraceVar(interp, varName,      Tcl_UntraceVar(interp, varName,
161              TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,              TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
162              LinkTraceProc, (ClientData) linkPtr);              LinkTraceProc, (ClientData) linkPtr);
163      ckfree(linkPtr->varName);      ckfree(linkPtr->varName);
164      ckfree((char *) linkPtr);      ckfree((char *) linkPtr);
165  }  }
166    
167  /*  /*
168   *----------------------------------------------------------------------   *----------------------------------------------------------------------
169   *   *
170   * Tcl_UpdateLinkedVar --   * Tcl_UpdateLinkedVar --
171   *   *
172   *      This procedure is invoked after a linked variable has been   *      This procedure is invoked after a linked variable has been
173   *      changed by C code.  It updates the Tcl variable so that   *      changed by C code.  It updates the Tcl variable so that
174   *      traces on the variable will trigger.   *      traces on the variable will trigger.
175   *   *
176   * Results:   * Results:
177   *      None.   *      None.
178   *   *
179   * Side effects:   * Side effects:
180   *      The Tcl variable "varName" is updated from its C value,   *      The Tcl variable "varName" is updated from its C value,
181   *      causing traces on the variable to trigger.   *      causing traces on the variable to trigger.
182   *   *
183   *----------------------------------------------------------------------   *----------------------------------------------------------------------
184   */   */
185    
186  void  void
187  Tcl_UpdateLinkedVar(interp, varName)  Tcl_UpdateLinkedVar(interp, varName)
188      Tcl_Interp *interp;         /* Interpreter containing variable. */      Tcl_Interp *interp;         /* Interpreter containing variable. */
189      char *varName;              /* Name of global variable that is linked. */      char *varName;              /* Name of global variable that is linked. */
190  {  {
191      Link *linkPtr;      Link *linkPtr;
192      char buffer[TCL_DOUBLE_SPACE];      char buffer[TCL_DOUBLE_SPACE];
193      int savedFlag;      int savedFlag;
194    
195      linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY,      linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY,
196              LinkTraceProc, (ClientData) NULL);              LinkTraceProc, (ClientData) NULL);
197      if (linkPtr == NULL) {      if (linkPtr == NULL) {
198          return;          return;
199      }      }
200      savedFlag = linkPtr->flags & LINK_BEING_UPDATED;      savedFlag = linkPtr->flags & LINK_BEING_UPDATED;
201      linkPtr->flags |= LINK_BEING_UPDATED;      linkPtr->flags |= LINK_BEING_UPDATED;
202      Tcl_SetVar(interp, linkPtr->varName, StringValue(linkPtr, buffer),      Tcl_SetVar(interp, linkPtr->varName, StringValue(linkPtr, buffer),
203              TCL_GLOBAL_ONLY);              TCL_GLOBAL_ONLY);
204      linkPtr->flags = (linkPtr->flags & ~LINK_BEING_UPDATED) | savedFlag;      linkPtr->flags = (linkPtr->flags & ~LINK_BEING_UPDATED) | savedFlag;
205  }  }
206    
207  /*  /*
208   *----------------------------------------------------------------------   *----------------------------------------------------------------------
209   *   *
210   * LinkTraceProc --   * LinkTraceProc --
211   *   *
212   *      This procedure is invoked when a linked Tcl variable is read,   *      This procedure is invoked when a linked Tcl variable is read,
213   *      written, or unset from Tcl.  It's responsible for keeping the   *      written, or unset from Tcl.  It's responsible for keeping the
214   *      C variable in sync with the Tcl variable.   *      C variable in sync with the Tcl variable.
215   *   *
216   * Results:   * Results:
217   *      If all goes well, NULL is returned; otherwise an error message   *      If all goes well, NULL is returned; otherwise an error message
218   *      is returned.   *      is returned.
219   *   *
220   * Side effects:   * Side effects:
221   *      The C variable may be updated to make it consistent with the   *      The C variable may be updated to make it consistent with the
222   *      Tcl variable, or the Tcl variable may be overwritten to reject   *      Tcl variable, or the Tcl variable may be overwritten to reject
223   *      a modification.   *      a modification.
224   *   *
225   *----------------------------------------------------------------------   *----------------------------------------------------------------------
226   */   */
227    
228  static char *  static char *
229  LinkTraceProc(clientData, interp, name1, name2, flags)  LinkTraceProc(clientData, interp, name1, name2, flags)
230      ClientData clientData;      /* Contains information about the link. */      ClientData clientData;      /* Contains information about the link. */
231      Tcl_Interp *interp;         /* Interpreter containing Tcl variable. */      Tcl_Interp *interp;         /* Interpreter containing Tcl variable. */
232      char *name1;                /* First part of variable name. */      char *name1;                /* First part of variable name. */
233      char *name2;                /* Second part of variable name. */      char *name2;                /* Second part of variable name. */
234      int flags;                  /* Miscellaneous additional information. */      int flags;                  /* Miscellaneous additional information. */
235  {  {
236      Link *linkPtr = (Link *) clientData;      Link *linkPtr = (Link *) clientData;
237      int changed;      int changed;
238      char buffer[TCL_DOUBLE_SPACE];      char buffer[TCL_DOUBLE_SPACE];
239      char *value, **pp, *result;      char *value, **pp, *result;
240      Tcl_Obj *objPtr;      Tcl_Obj *objPtr;
241    
242      /*      /*
243       * If the variable is being unset, then just re-create it (with a       * If the variable is being unset, then just re-create it (with a
244       * trace) unless the whole interpreter is going away.       * trace) unless the whole interpreter is going away.
245       */       */
246    
247      if (flags & TCL_TRACE_UNSETS) {      if (flags & TCL_TRACE_UNSETS) {
248          if (flags & TCL_INTERP_DESTROYED) {          if (flags & TCL_INTERP_DESTROYED) {
249              ckfree(linkPtr->varName);              ckfree(linkPtr->varName);
250              ckfree((char *) linkPtr);              ckfree((char *) linkPtr);
251          } else if (flags & TCL_TRACE_DESTROYED) {          } else if (flags & TCL_TRACE_DESTROYED) {
252              Tcl_SetVar(interp, linkPtr->varName, StringValue(linkPtr, buffer),              Tcl_SetVar(interp, linkPtr->varName, StringValue(linkPtr, buffer),
253                      TCL_GLOBAL_ONLY);                      TCL_GLOBAL_ONLY);
254              Tcl_TraceVar(interp, linkPtr->varName, TCL_GLOBAL_ONLY              Tcl_TraceVar(interp, linkPtr->varName, TCL_GLOBAL_ONLY
255                      |TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,                      |TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
256                      LinkTraceProc, (ClientData) linkPtr);                      LinkTraceProc, (ClientData) linkPtr);
257          }          }
258          return NULL;          return NULL;
259      }      }
260    
261      /*      /*
262       * If we were invoked because of a call to Tcl_UpdateLinkedVar, then       * If we were invoked because of a call to Tcl_UpdateLinkedVar, then
263       * don't do anything at all.  In particular, we don't want to get       * don't do anything at all.  In particular, we don't want to get
264       * upset that the variable is being modified, even if it is       * upset that the variable is being modified, even if it is
265       * supposed to be read-only.       * supposed to be read-only.
266       */       */
267    
268      if (linkPtr->flags & LINK_BEING_UPDATED) {      if (linkPtr->flags & LINK_BEING_UPDATED) {
269          return NULL;          return NULL;
270      }      }
271    
272      /*      /*
273       * For read accesses, update the Tcl variable if the C variable       * For read accesses, update the Tcl variable if the C variable
274       * has changed since the last time we updated the Tcl variable.       * has changed since the last time we updated the Tcl variable.
275       */       */
276    
277      if (flags & TCL_TRACE_READS) {      if (flags & TCL_TRACE_READS) {
278          switch (linkPtr->type) {          switch (linkPtr->type) {
279              case TCL_LINK_INT:              case TCL_LINK_INT:
280              case TCL_LINK_BOOLEAN:              case TCL_LINK_BOOLEAN:
281                  changed = *(int *)(linkPtr->addr) != linkPtr->lastValue.i;                  changed = *(int *)(linkPtr->addr) != linkPtr->lastValue.i;
282                  break;                  break;
283              case TCL_LINK_DOUBLE:              case TCL_LINK_DOUBLE:
284                  changed = *(double *)(linkPtr->addr) != linkPtr->lastValue.d;                  changed = *(double *)(linkPtr->addr) != linkPtr->lastValue.d;
285                  break;                  break;
286              case TCL_LINK_STRING:              case TCL_LINK_STRING:
287                  changed = 1;                  changed = 1;
288                  break;                  break;
289              default:              default:
290                  return "internal error: bad linked variable type";                  return "internal error: bad linked variable type";
291          }          }
292          if (changed) {          if (changed) {
293              Tcl_SetVar(interp, linkPtr->varName, StringValue(linkPtr, buffer),              Tcl_SetVar(interp, linkPtr->varName, StringValue(linkPtr, buffer),
294                      TCL_GLOBAL_ONLY);                      TCL_GLOBAL_ONLY);
295          }          }
296          return NULL;          return NULL;
297      }      }
298    
299      /*      /*
300       * For writes, first make sure that the variable is writable.  Then       * For writes, first make sure that the variable is writable.  Then
301       * convert the Tcl value to C if possible.  If the variable isn't       * convert the Tcl value to C if possible.  If the variable isn't
302       * writable or can't be converted, then restore the varaible's old       * writable or can't be converted, then restore the varaible's old
303       * value and return an error.  Another tricky thing: we have to save       * value and return an error.  Another tricky thing: we have to save
304       * and restore the interpreter's result, since the variable access       * and restore the interpreter's result, since the variable access
305       * could occur when the result has been partially set.       * could occur when the result has been partially set.
306       */       */
307    
308      if (linkPtr->flags & LINK_READ_ONLY) {      if (linkPtr->flags & LINK_READ_ONLY) {
309          Tcl_SetVar(interp, linkPtr->varName, StringValue(linkPtr, buffer),          Tcl_SetVar(interp, linkPtr->varName, StringValue(linkPtr, buffer),
310                  TCL_GLOBAL_ONLY);                  TCL_GLOBAL_ONLY);
311          return "linked variable is read-only";          return "linked variable is read-only";
312      }      }
313      value = Tcl_GetVar(interp, linkPtr->varName, TCL_GLOBAL_ONLY);      value = Tcl_GetVar(interp, linkPtr->varName, TCL_GLOBAL_ONLY);
314      if (value == NULL) {      if (value == NULL) {
315          /*          /*
316           * This shouldn't ever happen.           * This shouldn't ever happen.
317           */           */
318          return "internal error: linked variable couldn't be read";          return "internal error: linked variable couldn't be read";
319      }      }
320    
321      objPtr = Tcl_GetObjResult(interp);      objPtr = Tcl_GetObjResult(interp);
322      Tcl_IncrRefCount(objPtr);      Tcl_IncrRefCount(objPtr);
323      Tcl_ResetResult(interp);      Tcl_ResetResult(interp);
324      result = NULL;      result = NULL;
325    
326      switch (linkPtr->type) {      switch (linkPtr->type) {
327          case TCL_LINK_INT:          case TCL_LINK_INT:
328              if (Tcl_GetInt(interp, value, &linkPtr->lastValue.i) != TCL_OK) {              if (Tcl_GetInt(interp, value, &linkPtr->lastValue.i) != TCL_OK) {
329                  Tcl_SetObjResult(interp, objPtr);                  Tcl_SetObjResult(interp, objPtr);
330                  Tcl_SetVar(interp, linkPtr->varName,                  Tcl_SetVar(interp, linkPtr->varName,
331                          StringValue(linkPtr, buffer), TCL_GLOBAL_ONLY);                          StringValue(linkPtr, buffer), TCL_GLOBAL_ONLY);
332                  result = "variable must have integer value";                  result = "variable must have integer value";
333                  goto end;                  goto end;
334              }              }
335              *(int *)(linkPtr->addr) = linkPtr->lastValue.i;              *(int *)(linkPtr->addr) = linkPtr->lastValue.i;
336              break;              break;
337          case TCL_LINK_DOUBLE:          case TCL_LINK_DOUBLE:
338              if (Tcl_GetDouble(interp, value, &linkPtr->lastValue.d)              if (Tcl_GetDouble(interp, value, &linkPtr->lastValue.d)
339                      != TCL_OK) {                      != TCL_OK) {
340                  Tcl_SetObjResult(interp, objPtr);                  Tcl_SetObjResult(interp, objPtr);
341                  Tcl_SetVar(interp, linkPtr->varName,                  Tcl_SetVar(interp, linkPtr->varName,
342                          StringValue(linkPtr, buffer), TCL_GLOBAL_ONLY);                          StringValue(linkPtr, buffer), TCL_GLOBAL_ONLY);
343                  result = "variable must have real value";                  result = "variable must have real value";
344                  goto end;                  goto end;
345              }              }
346              *(double *)(linkPtr->addr) = linkPtr->lastValue.d;              *(double *)(linkPtr->addr) = linkPtr->lastValue.d;
347              break;              break;
348          case TCL_LINK_BOOLEAN:          case TCL_LINK_BOOLEAN:
349              if (Tcl_GetBoolean(interp, value, &linkPtr->lastValue.i)              if (Tcl_GetBoolean(interp, value, &linkPtr->lastValue.i)
350                      != TCL_OK) {                      != TCL_OK) {
351                  Tcl_SetObjResult(interp, objPtr);                  Tcl_SetObjResult(interp, objPtr);
352                  Tcl_SetVar(interp, linkPtr->varName,                  Tcl_SetVar(interp, linkPtr->varName,
353                          StringValue(linkPtr, buffer), TCL_GLOBAL_ONLY);                          StringValue(linkPtr, buffer), TCL_GLOBAL_ONLY);
354                  result = "variable must have boolean value";                  result = "variable must have boolean value";
355                  goto end;                  goto end;
356              }              }
357              *(int *)(linkPtr->addr) = linkPtr->lastValue.i;              *(int *)(linkPtr->addr) = linkPtr->lastValue.i;
358              break;              break;
359          case TCL_LINK_STRING:          case TCL_LINK_STRING:
360              pp = (char **)(linkPtr->addr);              pp = (char **)(linkPtr->addr);
361              if (*pp != NULL) {              if (*pp != NULL) {
362                  ckfree(*pp);                  ckfree(*pp);
363              }              }
364              *pp = (char *) ckalloc((unsigned) (strlen(value) + 1));              *pp = (char *) ckalloc((unsigned) (strlen(value) + 1));
365              strcpy(*pp, value);              strcpy(*pp, value);
366              break;              break;
367          default:          default:
368              return "internal error: bad linked variable type";              return "internal error: bad linked variable type";
369      }      }
370      end:      end:
371      Tcl_DecrRefCount(objPtr);      Tcl_DecrRefCount(objPtr);
372      return result;      return result;
373  }  }
374    
375  /*  /*
376   *----------------------------------------------------------------------   *----------------------------------------------------------------------
377   *   *
378   * StringValue --   * StringValue --
379   *   *
380   *      Converts the value of a C variable to a string for use in a   *      Converts the value of a C variable to a string for use in a
381   *      Tcl variable to which it is linked.   *      Tcl variable to which it is linked.
382   *   *
383   * Results:   * Results:
384   *      The return value is a pointer to a string that represents   *      The return value is a pointer to a string that represents
385   *      the value of the C variable given by linkPtr.   *      the value of the C variable given by linkPtr.
386   *   *
387   * Side effects:   * Side effects:
388   *      None.   *      None.
389   *   *
390   *----------------------------------------------------------------------   *----------------------------------------------------------------------
391   */   */
392    
393  static char *  static char *
394  StringValue(linkPtr, buffer)  StringValue(linkPtr, buffer)
395      Link *linkPtr;              /* Structure describing linked variable. */      Link *linkPtr;              /* Structure describing linked variable. */
396      char *buffer;               /* Small buffer to use for converting      char *buffer;               /* Small buffer to use for converting
397                                   * values.  Must have TCL_DOUBLE_SPACE                                   * values.  Must have TCL_DOUBLE_SPACE
398                                   * bytes or more. */                                   * bytes or more. */
399  {  {
400      char *p;      char *p;
401    
402      switch (linkPtr->type) {      switch (linkPtr->type) {
403          case TCL_LINK_INT:          case TCL_LINK_INT:
404              linkPtr->lastValue.i = *(int *)(linkPtr->addr);              linkPtr->lastValue.i = *(int *)(linkPtr->addr);
405              TclFormatInt(buffer, linkPtr->lastValue.i);              TclFormatInt(buffer, linkPtr->lastValue.i);
406              return buffer;              return buffer;
407          case TCL_LINK_DOUBLE:          case TCL_LINK_DOUBLE:
408              linkPtr->lastValue.d = *(double *)(linkPtr->addr);              linkPtr->lastValue.d = *(double *)(linkPtr->addr);
409              Tcl_PrintDouble((Tcl_Interp *) NULL, linkPtr->lastValue.d, buffer);              Tcl_PrintDouble((Tcl_Interp *) NULL, linkPtr->lastValue.d, buffer);
410              return buffer;              return buffer;
411          case TCL_LINK_BOOLEAN:          case TCL_LINK_BOOLEAN:
412              linkPtr->lastValue.i = *(int *)(linkPtr->addr);              linkPtr->lastValue.i = *(int *)(linkPtr->addr);
413              if (linkPtr->lastValue.i != 0) {              if (linkPtr->lastValue.i != 0) {
414                  return "1";                  return "1";
415              }              }
416              return "0";              return "0";
417          case TCL_LINK_STRING:          case TCL_LINK_STRING:
418              p = *(char **)(linkPtr->addr);              p = *(char **)(linkPtr->addr);
419              if (p == NULL) {              if (p == NULL) {
420                  return "NULL";                  return "NULL";
421              }              }
422              return p;              return p;
423      }      }
424    
425      /*      /*
426       * This code only gets executed if the link type is unknown       * This code only gets executed if the link type is unknown
427       * (shouldn't ever happen).       * (shouldn't ever happen).
428       */       */
429    
430      return "??";      return "??";
431  }  }
432    
433  /* End of tcllink.c */  /* End of tcllink.c */

Legend:
Removed from v.66  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25