Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TMethod.cxx
Go to the documentation of this file.
1 // @(#)root/meta:$Id$
2 // Author: Rene Brun 09/02/95
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TMethod
13  Each ROOT class (see TClass) has a linked list of methods.
14  This class describes one single method (member function).
15  The method info is obtained via the CINT api. See class TCling.
16 
17  The method information is used a.o. by the THml class and by the
18  TTree class.
19 */
20 
21 #include "TClass.h"
22 #include "TMethod.h"
23 #include "TMethodArg.h"
24 #include "TMethodCall.h"
25 #include "TROOT.h"
26 #include "TApplication.h"
27 #include "TInterpreter.h"
28 #include "Strlen.h"
29 #include "TDataMember.h"
30 
31 
32 ClassImp(TMethod);
33 
34 ////////////////////////////////////////////////////////////////////////////////
35 /// Default TMethod ctor. TMethods are constructed in TClass.
36 /// Comment strings are pre-parsed to find out whether the method is
37 /// a context-menu item.
38 
39 TMethod::TMethod(MethodInfo_t *info, TClass *cl) : TFunction(info)
40 {
41  fClass = cl;
42  fGetterMethod = 0;
43  fSetterMethod = 0;
44  fMenuItem = kMenuNoMenu;
45 
46  if (fInfo) {
47  SetMenuItem(gCling->MethodInfo_Title(fInfo));
48  }
49 }
50 
51 ////////////////////////////////////////////////////////////////////////////////
52 /// Copy ctor.
53 
54 TMethod::TMethod(const TMethod& orig) : TFunction(orig)
55 {
56  fClass = orig.fClass;
57  fMenuItem = orig.fMenuItem;
58  fGetter = orig.fGetter;
59  fGetterMethod = 0;
60  fSetterMethod = 0;
61 }
62 
63 ////////////////////////////////////////////////////////////////////////////////
64 /// Assignment operator.
65 
66 TMethod& TMethod::operator=(const TMethod& rhs)
67 {
68  if (this != &rhs) {
69  TFunction::operator=(rhs);
70  fClass = rhs.fClass;
71  fMenuItem = rhs.fMenuItem;
72  fGetter = rhs.fGetter;
73  if (fGetterMethod)
74  delete fGetterMethod;
75  fGetterMethod = 0;
76  if (fSetterMethod)
77  delete fSetterMethod;
78  fSetterMethod = 0;
79  }
80  return *this;
81 }
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 /// Cleanup.
85 
86 TMethod::~TMethod()
87 {
88  delete fGetterMethod;
89  delete fSetterMethod;
90 }
91 
92 ////////////////////////////////////////////////////////////////////////////////
93 /// Clone method.
94 
95 TObject *TMethod::Clone(const char *newname) const
96 {
97  TNamed *newobj = new TMethod(*this);
98  if (newname && strlen(newname)) newobj->SetName(newname);
99  return newobj;
100 }
101 
102 ////////////////////////////////////////////////////////////////////////////////
103 /// Returns a comment string from the class declaration.
104 
105 const char *TMethod::GetCommentString()
106 {
107  return fInfo ? gCling->MethodInfo_Title(fInfo) : "";
108 }
109 
110 
111 ////////////////////////////////////////////////////////////////////////////////
112 /// Using the CINT method arg information create a complete signature string.
113 
114 void TMethod::CreateSignature()
115 {
116  TFunction::CreateSignature();
117 
118  if (Property() & kIsConstMethod) fSignature += " const";
119 }
120 
121 ////////////////////////////////////////////////////////////////////////////////
122 /// Tries to guess DataMember from comment string
123 /// and Method's name <==(only if 1 Argument!).
124 /// If more then one argument=> returns pointer to the last argument.
125 /// It also sets MethodArgs' pointers to point to specified data members.
126 ///
127 /// The form of comment string defining arguments is:
128 /// void XXX(Int_t x1, Float_t y2) //*ARGS={x1=>fX1,y2=>fY2}
129 /// where fX1, fY2 are data fields in the same class.
130 /// ("pointers" to data members)
131 
132 TDataMember *TMethod::FindDataMember()
133 {
134  Char_t *argstring = (char*)strstr(GetCommentString(),"*ARGS={");
135 
136  // the following statement has been commented (Rene). Not needed
137  // it was making troubles in BuildRealData for classes with protected
138  // default constructors.
139  // if (!(GetClass()->GetListOfRealData())) GetClass()->BuildRealData();
140 
141  if (argstring) {
142 
143  // if we found any argument-specifying hints - parse it
144 
145  if (!fMethodArgs) return 0;
146 
147  Int_t nchs = strlen(argstring); // workspace...
148  char *argstr = new char[nchs+1]; // workspace...
149  char *ptr1 = 0;
150  char *tok = 0;
151  char *ptr2 = 0;
152  Int_t i;
153 
154  strlcpy(argstr,argstring,nchs+1); //let's move it to "workspace" copy
155  char *rest;
156  ptr2 = R__STRTOK_R(argstr, "{}", &rest); // extract the data!
157  if (ptr2 == 0) {
158  Fatal("FindDataMember","Internal error found '*ARGS=\"' but not \"{}\" in %s",GetCommentString());
159  delete [] argstr;
160  return 0;
161  }
162  ptr2 = R__STRTOK_R((char *)0, "{}", &rest);
163 
164  //extract argument tokens//
165  char *tokens[20];
166  Int_t cnt = 0;
167  Int_t token_cnt = 0;
168  do {
169  ptr1 = R__STRTOK_R((char *)(cnt++ ? 0 : ptr2), ",;", &rest); // extract tokens
170  // separated by , or ;
171  if (ptr1) {
172  Int_t nch = strlen(ptr1);
173  tok = new char[nch+1];
174  strlcpy(tok,ptr1,nch+1);
175  tokens[token_cnt] = tok; //store this token.
176  token_cnt++;
177  }
178  } while (ptr1);
179 
180  //now let's parse all argument tokens...
181  TClass *cl = 0;
182  TMethodArg *a = 0;
183  TMethodArg *ar = 0;
184  TDataMember *member = 0;
185 
186  for (i=0; i<token_cnt;i++) {
187  cnt = 0;
188  ptr1 = R__STRTOK_R(tokens[i], "=>", &rest); // LeftHandedSide=methodarg
189  ptr2 = R__STRTOK_R((char *)0, "=>", &rest); // RightHandedSide-points to datamember
190 
191  //find the MethodArg
192  a = 0;
193  ar = 0;
194  member = 0;
195  TIter nextarg(fMethodArgs); // iterate through all arguments.
196  while ((ar = (TMethodArg*)nextarg())) {
197  if (!strcmp(ptr1,ar->GetName())) {
198  a = ar;
199  break;
200  }
201  }
202 
203  //now find the data member
204  cl = GetClass()->GetBaseDataMember(ptr2);
205  if (cl) {
206  member = cl->GetDataMember(ptr2);
207  if (a) a->fDataMember = member; //SET THE APROPRIATE FIELD !!!
208  //We can do it - friend decl. in MethodArg
209  }
210  delete [] tokens[i];
211  }
212  delete [] argstr;
213  return member; // nothing else to do! We return a pointer to the last
214  // found data member
215 
216  // if not found in comment string - try to guess it from name!
217  } else {
218  if (fMethodArgs)
219  if (fMethodArgs->GetSize() != 1) return 0;
220 
221  TMethodArg *a = 0;
222  if (fMethodArgs) a = (TMethodArg*)(fMethodArgs->First());
223 
224  char dataname[67] = "";
225  char basename[64] = "";
226  const char *funcname = GetName();
227  if ( strncmp(funcname,"Get",3) == 0 || strncmp(funcname,"Set",3) == 0 )
228  snprintf(basename,64,"%s",funcname+3);
229  else if ( strncmp(funcname,"Is",2) == 0 )
230  snprintf(basename,64,"%s",funcname+2);
231  else if (strncmp(funcname, "Has", 3) == 0)
232  snprintf(basename,64,"%s", funcname+3);
233  else
234  return 0;
235 
236  snprintf(dataname,67,"f%s",basename);
237 
238  TClass *cl = GetClass()->GetBaseDataMember(dataname);
239  if (cl) {
240  TDataMember *member = cl->GetDataMember(dataname);
241  if (a) a->fDataMember = member;
242  return member;
243  } else {
244  snprintf(dataname,67,"fIs%s",basename); //in case of IsEditable()
245  //and fIsEditable
246  cl = GetClass()->GetBaseDataMember(dataname);
247  if (cl) {
248  TDataMember *member = cl->GetDataMember(dataname);
249  if (a) a->fDataMember = member;
250  return member;
251  }
252  }
253  }
254 
255  //if nothing found - return null -pointer:
256  return 0;
257 }
258 
259 ////////////////////////////////////////////////////////////////////////////////
260 /// Return call environment for the getter method in case this is a
261 /// *TOGGLE method (for the context menu).
262 
263 TMethodCall *TMethod::GetterMethod()
264 {
265  if (!fGetterMethod && fMenuItem == kMenuToggle && fGetter != "" && fClass) {
266  fGetterMethod = new TMethodCall(fClass, Getter(), "");
267  }
268  return fGetterMethod;
269 }
270 
271 ////////////////////////////////////////////////////////////////////////////////
272 /// Return true if this function object is pointing to a currently
273 /// loaded function. If a function is unloaded after the TMethod
274 /// is created, the TMethod will be set to be invalid.
275 
276 Bool_t TMethod::IsValid()
277 {
278  // Register the transaction when checking the validity of the object.
279  if (!fInfo && UpdateInterpreterStateMarker()) {
280  DeclId_t newId = gInterpreter->GetFunction(fClass->GetClassInfo(), fName);
281  if (newId) {
282  MethodInfo_t *info = gInterpreter->MethodInfo_Factory(newId);
283  Update(info);
284  }
285  return newId != 0;
286  }
287  return fInfo != 0;
288 }
289 
290 ////////////////////////////////////////////////////////////////////////////////
291 /// Return call environment for this method in case this is a
292 /// *TOGGLE method which takes a single boolean or integer argument.
293 
294 TMethodCall *TMethod::SetterMethod()
295 {
296  if (!fSetterMethod && fMenuItem == kMenuToggle && fClass) {
297  fSetterMethod = new TMethodCall(fClass, GetName(), "1");
298  }
299  return fSetterMethod;
300 }
301 
302 ////////////////////////////////////////////////////////////////////////////////
303 /// Returns methodarg list and additionally updates fDataMember in TMethod by
304 /// calling FindDataMember();
305 
306 TList *TMethod::GetListOfMethodArgs()
307 {
308  if (!fMethodArgs){
309  TFunction::GetListOfMethodArgs();
310  FindDataMember();
311  }
312  return fMethodArgs;
313 }
314 
315 ////////////////////////////////////////////////////////////////////////////////
316 /// Set the menu item as prescribed in the doctstring.
317 
318 void TMethod::SetMenuItem(const char *docstring)
319 {
320  if (docstring && strstr(docstring, "*TOGGLE")) {
321  fMenuItem = kMenuToggle;
322  const char *s;
323  if ((s = strstr(docstring, "*GETTER="))) {
324  fGetter = s+8;
325  fGetter = fGetter.Strip(TString::kBoth);
326  }
327  } else
328  if (docstring && strstr(docstring, "*MENU"))
329  fMenuItem = kMenuDialog;
330  else
331  if (docstring && strstr(docstring, "*SUBMENU"))
332  fMenuItem = kMenuSubMenu;
333  else
334  fMenuItem = kMenuNoMenu;
335 }
336 
337 ////////////////////////////////////////////////////////////////////////////////
338 /// Update the TMethod to reflect the new info.
339 ///
340 /// This can be used to implement unloading (info == 0) and then reloading
341 /// (info being the 'new' decl address).
342 
343 Bool_t TMethod::Update(MethodInfo_t *info)
344 {
345  if (TFunction::Update(info)) {
346  delete fGetterMethod; fGetterMethod = 0;
347  delete fSetterMethod; fSetterMethod = 0;
348  if (fInfo) {
349  SetMenuItem(gCling->MethodInfo_Title(fInfo));
350  }
351  return kTRUE;
352  } else {
353  return kFALSE;
354  }
355 }