tcl++.h
Go to the documentation of this file.
1 /*
2  @copyright Russell Standish 2000-2013
3  @author Russell Standish
4  This file is part of EcoLab
5 
6  Open source licensed under the MIT license. See LICENSE for details.
7 */
8 
9 /* tcl++.h
10 
11 Contains 4 concepts - a NEWCMD macro for declaring Tcl procedures, a
12 tclvar class for accessing TCL variables as though they were C
13 variables, a tclcmd class that turns the TCL interpreter stream
14 into a simple I/O stream and tclindex, a simple iterator through a TCL array */
15 
20 #ifndef TCLPP_H
21 #define TCLPP_H
22 
23 #if MPI_SUPPORT
24 #undef HAVE_MPI_CPP
25 //#undef SEEK_SET
26 //#undef SEEK_CUR
27 //#undef SEEK_END
28 #include <mpi.h>
29 #endif
30 
31 #include "classdesc_access.h"
32 #include "pack_base.h"
33 
34 #include <stdio.h>
35 #include <assert.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <iostream>
40 #include <tcl.h>
41 
42 #include <string>
43 
44 /* for Tcl 8.4 compatibility */
45 #ifndef CONST84
46 #define CONST84
47 #endif
48 
49 #ifdef TK
50 #include <tk.h>
51 /* undefine all those spurious macros X11 defines - we don't need 'em! */
52 #undef Bool
53 #undef Status
54 #undef True
55 #undef False
56 #undef QueuedAlready
57 #undef QueuedAfterReading
58 #undef QueuedAfterFlush
59 #undef ConnectionNumber
60 #undef RootWindow
61 #undef DefaultScreen
62 #undef DefaultRootWindow
63 #undef DefaultVisual
64 #undef DefaultGC
65 #undef BlackPixel
66 #undef WhitePixel
67 #undef AllPlanes
68 #undef QLength
69 #undef DisplayWidth
70 #undef DisplayHeight
71 #undef DisplayWidthMM
72 #undef DisplayHeightMM
73 #undef DisplayPlanes
74 #undef DisplayCells
75 #undef ScreenCount
76 #undef ServerVendor
77 #undef ProtocolVersion
78 #undef ProtocolRevision
79 #undef VendorRelease
80 #undef DisplayString
81 #undef DefaultDepth
82 #undef DefaultColormap
83 #undef BitmapUnit
84 #undef BitmapBitOrder
85 #undef BitmapPad
86 #undef ImageByteOrder
87 #undef NextRequest
88 #undef LastKnownRequestProcessed
89 #undef ScreenOfDisplay
90 #undef DefaultScreenOfDisplay
91 #undef DisplayOfScreen
92 #undef RootWindowOfScreen
93 #undef BlackPixelOfScreen
94 #undef WhitePixelOfScreen
95 #undef DefaultColormapOfScreen
96 #undef DefaultDepthOfScreen
97 #undef DefaultGCOfScreen
98 #undef DefaultVisualOfScreen
99 #undef WidthOfScreen
100 #undef HeightOfScreen
101 #undef WidthMMOfScreen
102 #undef HeightMMOfScreen
103 #undef PlanesOfScreen
104 #undef CellsOfScreen
105 #undef MinCmapsOfScreen
106 #undef MaxCmapsOfScreen
107 #undef DoesSaveUnders
108 #undef DoesBackingStore
109 #undef EventMaskOfScreen
110 #undef XAllocID
111 #undef XNRequiredCharSet
112 #undef XNQueryOrientation
113 #undef XNBaseFontName
114 #undef XNOMAutomatic
115 #undef XNMissingCharSet
116 #undef XNDefaultString
117 #undef XNOrientation
118 #undef XNDirectionalDependentDrawing
119 #undef XNContextualDrawing
120 #undef XNFontInfo
121 #undef XIMPreeditArea
122 #undef XIMPreeditCallbacks
123 #undef XIMPreeditPosition
124 #undef XIMPreeditNothing
125 #undef XIMPreeditNone
126 #undef XIMStatusArea
127 #undef XIMStatusCallbacks
128 #undef XIMStatusNothing
129 #undef XIMStatusNone
130 #undef XNVaNestedList
131 #undef XNQueryInputStyle
132 #undef XNClientWindow
133 #undef XNInputStyle
134 #undef XNFocusWindow
135 #undef XNResourceName
136 #undef XNResourceClass
137 #undef XNGeometryCallback
138 #undef XNDestroyCallback
139 #undef XNFilterEvents
140 #undef XNPreeditStartCallback
141 #undef XNPreeditDoneCallback
142 #undef XNPreeditDrawCallback
143 #undef XNPreeditCaretCallback
144 #undef XNPreeditStateNotifyCallback
145 #undef XNPreeditAttributes
146 #undef XNStatusStartCallback
147 #undef XNStatusDoneCallback
148 #undef XNStatusDrawCallback
149 #undef XNStatusAttributes
150 #undef XNArea
151 #undef XNAreaNeeded
152 #undef XNSpotLocation
153 #undef XNColormap
154 #undef XNStdColormap
155 #undef XNForeground
156 #undef XNBackground
157 #undef XNBackgroundPixmap
158 #undef XNFontSet
159 #undef XNLineSpace
160 #undef XNCursor
161 #undef XNQueryIMValuesList
162 #undef XNQueryICValuesList
163 #undef XNVisiblePosition
164 #undef XNR6PreeditCallback
165 #undef XNStringConversionCallback
166 #undef XNStringConversion
167 #undef XNResetState
168 #undef XNHotKey
169 #undef XNHotKeyState
170 #undef XNPreeditState
171 #undef XNSeparatorofNestedList
172 #undef XBufferOverflow
173 #undef XLookupNone
174 #undef XLookupChars
175 #undef XLookupKeySym
176 #undef XLookupBoth
177 #undef XIMReverse
178 #undef XIMUnderline
179 #undef XIMHighlight
180 #undef XIMPrimary
181 #undef XIMSecondary
182 #undef XIMTertiary
183 #undef XIMVisibleToForward
184 #undef XIMVisibleToBackword
185 #undef XIMVisibleToCenter
186 #undef XIMPreeditUnKnown
187 #undef XIMPreeditEnable
188 #undef XIMPreeditDisable
189 #undef XIMInitialState
190 #undef XIMPreserveState
191 #undef XIMStringConversionLeftEdge
192 #undef XIMStringConversionRightEdge
193 #undef XIMStringConversionTopEdge
194 #undef XIMStringConversionBottomEdge
195 #undef XIMStringConversionConcealed
196 #undef XIMStringConversionWrapped
197 #undef XIMStringConversionBuffer
198 #undef XIMStringConversionLine
199 #undef XIMStringConversionWord
200 #undef XIMStringConversionChar
201 #undef XIMStringConversionSubstitution
202 #undef XIMStringConversionRetrieval
203 #undef XIMStringConversionRetrival
204 #undef XIMHotKeyStateON
205 #undef XIMHotKeyStateOFF
206 
207 #undef Status // conflict between X11 usage and MPI++ usage
208 #endif
209 #include <time.h>
210 #include "Realloc.h"
211 #include "eco_strstream.h"
212 #include "error.h"
213 
214 namespace ecolab
215 {
216  using std::string;
217 
218  extern bool interpExiting;
219  void interpExitProc(ClientData cd);
220 
222  inline Tcl_Interp *interp()
223  {
224  // TODO - this idea doesn't seem to work when exit is called in a script
225  // static shared_ptr<Tcl_Interp> interp(Tcl_CreateInterp(), Tcl_DeleteInterp);
226  static Tcl_Interp* interp=Tcl_CreateInterp();
227  Tcl_CreateExitHandler(interpExitProc, 0);
228  return interp;
229  }
231  // extern Tk_Window mainWin;
232 
233 
234  /* these are defined to default values, even if MPI is false */
236  extern unsigned myid, nprocs;
237 
240  extern int processEventsNest;
242  {
243  DisableEventProcessing() {processEventsNest++;}
244  ~DisableEventProcessing() {processEventsNest--;}
245  };
246 
247 #if MPI_SUPPORT
248 #define PARALLEL if (myid==0) parsend(argc,argv);
250 
252 #define MAXPMSG 1024
253 #define TAG_PUSH 1
254  void parsend(int,CONST84 char**);
255  void parsendf(const char*,...);
256  void parsend(const std::string&);
257 #else
258 #define PARALLEL
259 #endif
260 
262  inline int TCL_newcommand(const char *c)
263  {
264  Tcl_CmdInfo dum;
265  return !Tcl_GetCommandInfo(interp(),const_cast<char*>(c),&dum);
266  }
267 
268 
269  int TCL_proc(ClientData cd, Tcl_Interp *interp, int argc, CONST84 char **argv);
270 
271  /* base class for tcl++ and TCL_obj commands */
272  class cmd_data
273  {
274  public:
275  typedef enum {invalid, memvoid, mem, func, nonconst} functor_class;
276  int nargs;
277  string name;
279  bool is_const;
282  virtual void proc(int argc, CONST84 char** argv)=0;
283  // TODO possibly delegate to above?
284  virtual void proc(int argc, Tcl_Obj *const argv[]) {
285  throw error("proc not implemented");};
286  cmd_data(const char* nm, int na=-1):
287  nargs(na), name(nm), is_const(false), is_setterGetter(false)
288  /* by default, don't check arg count */
289  {
290  assert(TCL_newcommand(nm));
291  }
292  cmd_data(): nargs(-1), is_const(false), is_setterGetter(false) {}
293  virtual ~cmd_data() {}
294  };
295 
296 
297  class tclpp_cd: public cmd_data
298  {
299  void (*procptr)(int,CONST84 char**);
300  public:
301  void proc(int argc, CONST84 char** argv) {procptr(argc,argv);}
302  void proc(int argc, Tcl_Obj *const argv[]) {}
303  tclpp_cd(const char* nm, int na, void (*p)(int,CONST84 char**)):
304  cmd_data(nm,na), procptr(p)
305  {Tcl_CreateCommand(interp(),const_cast<char*>(nm),(Tcl_CmdProc*)TCL_proc,(ClientData)this,NULL);}
306  };
307 
309  int setEcoLabLib(const char* path);
310 
312 #ifdef ECOLAB_LIB
313 #define DEFINE_ECOLAB_LIBRARY \
314  namespace { \
315  int dum=ecolab::setEcoLabLib(ECOLAB_LIB); \
316  }
317 #else
318 #define DEFINE_ECOLAB_LIBRARY
319 #endif
320 
321 
327 #define NEWCMD(name,nargs) \
328  static void name(int argc, CONST84 char* argv[]); \
329  namespace name##_ns { \
330  DEFINE_ECOLAB_LIBRARY; \
331  ecolab::tclpp_cd name##data(#name,nargs,name); \
332  } \
333  static void name(int argc,CONST84 char* argv[])
334 
335  class tclindex;
336 
338 
354  class tclvar
355  {
356 
358  string name;
359  inline double dget(void);
360  inline double dput(double x);
361 
362  public:
363 
364  /* constructors */
365  tclvar() {}
367  tclvar(const string& nm, const char* val=NULL): name(nm) {init(val);}
368  tclvar(const string& nm, const string& val): name(nm) {init(val.c_str());}
369  void init(const char* val=NULL);
370 
371 
373  tclvar operator=(double x) {dput(x); return *this;}
374  tclvar operator=(const char* x) {
375  if (!interpExiting) Tcl_SetVar(interp(),name.c_str(),x,TCL_GLOBAL_ONLY);
376  return *this;
377  }
378  tclvar operator=(const string& x) {return (*this)=x.c_str();}
379  tclvar operator+=(const string& x)
380  {return (*this)=(*this)+x;}
381 
382  string operator+(const string& x)
383  {
384  string t(operator const char*());
385  t+=x;
386  return t;
387  }
389  operator double () {return dget();}
391  operator const char* ()
392  {return interpExiting? "": Tcl_GetVar(interp(),name.c_str(),TCL_GLOBAL_ONLY);}
394  operator int() {return (int)dget();}
395  operator unsigned () {return (unsigned)dget();}
396 
398  double operator++() {return dput(dget()+1);}
400  double operator++(int){double tmp; tmp=dget(); dput(tmp+1); return tmp;}
402  double operator--() {return dput(dget()-1);}
404  double operator--(int){double tmp; tmp=dget(); dput(tmp-1); return tmp;}
406  double operator+=(double x) {return dput(dget()+x);}
408  double operator-=(double x) {return dput(dget()-x);}
410  double operator*=(double x) {return dput(dget()*x);}
412  double operator/=(double x) {return dput(dget()/x);}
413 
415  tclvar operator[](int index);
417  tclvar operator[](const string& index);
418 
420  int size();
421 
422  friend bool exists(const tclvar& x);
423  friend class tclindex;
424  };
425 
426  /* space for a char[] variable to hold a double value in text form */
427 #define BUFSIZE 20
428 
429  inline
430  double tclvar::dget(void)
431  {
432  if (interpExiting) return 0;
433  double val;
434  int ival;
435  char* tclval;
436  tclval=const_cast<char*>(Tcl_GetVar(interp(),name.c_str(),TCL_GLOBAL_ONLY));
437  if (tclval!=NULL)
438  {
439  if (Tcl_GetDouble(interp(),tclval,&val)!=TCL_OK)
440  {
441  if (Tcl_GetBoolean(interp(),tclval,&ival)!=TCL_OK)
442  throw error("%s as the value of %s\n",Tcl_GetStringResult(interp()),name.c_str());
443  else
444  return ival;
445  }
446  }
447  else
448  throw error("TCL Variable %s is undefined\n",name.c_str());
449  return val;
450  }
451 
452  inline
453  double tclvar::dput(double x)
454  {
455  if (interpExiting) return x;
456  eco_strstream value;
457  value << x;
458  std::string v(value.str());
459  Tcl_SetVar(interp(),name.c_str(),v.c_str(),TCL_GLOBAL_ONLY);
460  return x;
461  }
462 
464  inline
465  bool exists(const tclvar& x)
466  {return interpExiting? false: Tcl_GetVar(interp(),x.name.c_str(),TCL_GLOBAL_ONLY)!=NULL;}
467 
468  inline void
469  tclvar::init(const char* val)
470  {
471  /* TCL 8.3 or earlier does not declare this stuff const */
472  if (val!=NULL) Tcl_SetVar(interp(),const_cast<char*>(name.c_str()),
473  const_cast<char*>(val),0);
474  }
475 
476  inline
478  {
479  std::ostringstream os;
480  os<<index;
481  return operator[](os.str());
482  }
483 
484  inline
485  tclvar tclvar::operator[](const string& index)
486  {
487  tclvar tmp(name);
488  if (tmp.name.find('(')!=string::npos) /* already an indexed element */
489  tmp.name=tmp.name.substr(0, tmp.name.find(')'))+index+")";
490  else
491  tmp.name+="("+index+")";
492  return tmp;
493  }
494 
495  // enable printing of tclvars through the stream process
496  inline
497  std::ostream& operator<<(std::ostream& stream, tclvar x)
498  { return stream << (const char*) x;}
499 
500 #define DBLSIZ 16 /* enough characters to hold a string rep of a double */
501 #define INTSIZ 12 /* enough characters to hold a string rep of an int */
502 
503  /* remove trailing newline, if any. */
504  inline std::string chomp(const std::string& s)
505  {
506  if (s[s.length()-1]=='\n') return s.substr(0,s.length()-1);
507  else return s;
508  }
509 
510 
511  class tclcmd: public eco_strstream
512  {
514  public:
515  string result; /* The result of the previous command is placed here */
516  void exec()
517  {
518  if (interpExiting) return;
519  std::string s=chomp(str());
520  if (Tcl_Eval(interp(),s.c_str())!=TCL_OK)
521  {
522  error e("%s->%s\n",s.c_str(),Tcl_GetStringResult(interp()));
523  clear();
524  throw e;
525  }
526  result=Tcl_GetStringResult(interp());
527  clear(); /* null out string ready for next command */
528  }
529 
530  template<class T>
531  tclcmd& operator<<(T x)
532  {
533  if (str()[0]=='\0')
534  return (*this)|x;
535  else
536  return (*this)|" "|x;
537  }
538 
539 
540  template <class T>
541  tclcmd& operator|(T x) {eco_strstream::operator|(x); return *this;}
542 
543  tclcmd& operator|(char x)
544  {
545  if (x=='\n')
546  exec();
547  else
548  return (tclcmd&) eco_strstream::operator|(x);
549  return *this;
550  }
551 
552  tclcmd& operator|(const char* cmd)
553  {
554  eco_strstream::operator|(cmd);
555  if (cmd[strlen(cmd)-1]=='\n') exec();
556  return *this;
557  }
558  tclcmd& operator|(char* cmd) {return operator|((const char*) cmd);}
559 
560  };
561 
563  class tclreturn: public eco_strstream
564  {
565  public:
566  ~tclreturn() {
567  if (interpExiting) return;
568  std::string tmps=str();
569  Tcl_SetResult(interp(),const_cast<char*>(tmps.c_str()),TCL_VOLATILE);}
570  };
571 
578  class tclindex
579  {
581  std::string searchid;
582  std::string arrayname;
583  public:
584  ~tclindex() {done();}
585  //start the indexing
586  tclvar start(const tclvar&);
587  //finish up
588  inline void done();
589  //get next element in array
590  inline tclvar incr();
591  tclvar incr(const tclvar& x) {return incr();} /* ignores argument */
592  //return true if this is the last element in array
593  int last();
594  };
595 
596  inline
597  void tclindex::done()
598  {
599  tclcmd cmd;
600  if (!searchid.empty())
601  {
602  cmd << "array donesearch " << arrayname << searchid << "\n";
603  arrayname.clear();
604  searchid.clear();
605  }
606  }
607 
608  inline
609  tclvar tclindex::start(const tclvar& x)
610  {
611  tclcmd cmd;
612  tclvar r;
613  /* check if x is actually an array variable */
614  cmd << "array exists " << x.name << "\n";
615  if (!atoi(cmd.result.c_str())) return x;
616 
617  done(); /* ensure any previous invocation is cleaned up */
618  cmd << "array startsearch " << x.name << "\n";
619  arrayname = x.name;
620  searchid = cmd.result;
621  r=incr(); /* work around a compiler bug in gcc 2.8.1??? */
622  return r;
623  }
624 
625  inline
626  tclvar tclindex::incr()
627  {
628  tclcmd cmd;
629  tclvar r;
630 
631  if (searchid.empty()) throw error("tclindex not initialized");
632  cmd << "array nextelement " << arrayname << searchid << "\n";
633  r.name=arrayname+"("+cmd.result+")";
634  return r;
635  }
636 
637  inline
639  {
640 
641  tclcmd cmd;
642  cmd << "array size " << name << "\n";
643  return atoi(cmd.result.c_str());
644  }
645 
646 
647  inline
648  int tclindex::last()
649  {
650  tclcmd cmd;
651  if (!searchid.empty())
652  {
653  cmd << "array anymore " << arrayname << searchid << "\n";
654  return !atoi(cmd.result.c_str());
655  }
656  else
657  return 1;
658  }
659 }
660 #endif
descriptor access to a class&#39;s privates
Definition: tcl++.h:578
An RAII class for returning values to TCL.
Definition: tcl++.h:563
tclvar(const string &nm, const char *val=NULL)
TCL var name this i sbound to. If val not null, then initialise the var to val.
Definition: tcl++.h:367
unsigned myid
main window of application
bool exists(const tclvar &x)
Check if a TCL variable exists.
Definition: tcl++.h:465
An EcoLab string stream class.
Definition: eco_strstream.h:64
EcoLab exception class.
Definition: error.h:25
Tcl_Interp * interp()
default interpreter. Set to NULL when interp() is destroyed
Definition: tcl++.h:222
int setEcoLabLib(const char *path)
set the value of the TCL variable ecolab_library
serialisation descriptor
tclvar operator=(double x)
tclvars may be freely mixed with arithmetic expressions
Definition: tcl++.h:373
An EcoLab string stream class.
TCL variable class.
Definition: tcl++.h:354
Definition: tcl++.h:272
EcoLab exception class.
tclvar operator[](int index)
arrays can be indexed either by integers, or by strings
Definition: tcl++.h:477
bool is_setterGetter
true if this command is a setter/getter (no argument=getter, 1 or more arguments a setter) ...
Definition: tcl++.h:281
#define CLASSDESC_ACCESS(type)
add friend statements for each accessor function
Definition: classdesc_access.h:36
int processEventsNest
Definition: tcl++.h:241
int TCL_newcommand(const char *c)
test whether command is not already defined
Definition: tcl++.h:262
Contains definitions related to classdesc functionality.
Definition: arrays.h:2514
_OPENMP
Definition: accessor.h:16
Definition: tcl++.h:297
Definition: tcl++.h:511
int size()
size of arrays
Definition: tcl++.h:638
bool is_const
true if this command doesn&#39;t affect the object&#39;s (or global state)
Definition: tcl++.h:279