| 1 | //
 | 
|---|
| 2 | // class.cc
 | 
|---|
| 3 | //
 | 
|---|
| 4 | // Copyright (C) 1996 Limit Point Systems, Inc.
 | 
|---|
| 5 | //
 | 
|---|
| 6 | // Author: Curtis Janssen <cljanss@limitpt.com>
 | 
|---|
| 7 | // Maintainer: LPS
 | 
|---|
| 8 | //
 | 
|---|
| 9 | // This file is part of the SC Toolkit.
 | 
|---|
| 10 | //
 | 
|---|
| 11 | // The SC Toolkit is free software; you can redistribute it and/or modify
 | 
|---|
| 12 | // it under the terms of the GNU Library General Public License as published by
 | 
|---|
| 13 | // the Free Software Foundation; either version 2, or (at your option)
 | 
|---|
| 14 | // any later version.
 | 
|---|
| 15 | //
 | 
|---|
| 16 | // The SC Toolkit is distributed in the hope that it will be useful,
 | 
|---|
| 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 19 | // GNU Library General Public License for more details.
 | 
|---|
| 20 | //
 | 
|---|
| 21 | // You should have received a copy of the GNU Library General Public License
 | 
|---|
| 22 | // along with the SC Toolkit; see the file COPYING.LIB.  If not, write to
 | 
|---|
| 23 | // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
|---|
| 24 | //
 | 
|---|
| 25 | // The U.S. Government is granted a limited license as per AL 91-7.
 | 
|---|
| 26 | //
 | 
|---|
| 27 | 
 | 
|---|
| 28 | #ifdef __GNUG__
 | 
|---|
| 29 | #pragma implementation
 | 
|---|
| 30 | #endif
 | 
|---|
| 31 | 
 | 
|---|
| 32 | #ifdef HAVE_CONFIG_H
 | 
|---|
| 33 | #include <scconfig.h>
 | 
|---|
| 34 | #endif
 | 
|---|
| 35 | 
 | 
|---|
| 36 | #include <string>
 | 
|---|
| 37 | 
 | 
|---|
| 38 | #include <stdlib.h>
 | 
|---|
| 39 | #include <string.h>
 | 
|---|
| 40 | #if defined(HAVE_DLFCN_H)
 | 
|---|
| 41 | #include <dlfcn.h>
 | 
|---|
| 42 | #endif // HAVE_DLFCN_H
 | 
|---|
| 43 | 
 | 
|---|
| 44 | #include <util/misc/formio.h>
 | 
|---|
| 45 | 
 | 
|---|
| 46 | #include <util/class/class.h>
 | 
|---|
| 47 | #include <util/class/proxy.h>
 | 
|---|
| 48 | 
 | 
|---|
| 49 | using namespace std;
 | 
|---|
| 50 | using namespace sc;
 | 
|---|
| 51 | 
 | 
|---|
| 52 | std::map<std::string,ClassDescP>* ClassDesc::all_ = 0;
 | 
|---|
| 53 | std::map<type_info_key,ClassDescP>* ClassDesc::type_info_all_ = 0;
 | 
|---|
| 54 | char * ClassDesc::classlib_search_path_ = 0;
 | 
|---|
| 55 | std::set<std::string>* ClassDesc::unresolved_parents_ = 0;
 | 
|---|
| 56 | 
 | 
|---|
| 57 | /////////////////////////////////////////////////////////////////
 | 
|---|
| 58 | 
 | 
|---|
| 59 | static sc::ClassDesc DescribedClassProxy_cd(
 | 
|---|
| 60 |     typeid(sc::DescribedClassProxy), "DescribedClassProxy",1,"public DescribedClass");
 | 
|---|
| 61 | 
 | 
|---|
| 62 | /////////////////////////////////////////////////////////////////
 | 
|---|
| 63 | 
 | 
|---|
| 64 | ParentClass::ParentClass(ClassDesc*classdesc,Access access,int is_virtual):
 | 
|---|
| 65 |   _access(access),
 | 
|---|
| 66 |   _is_virtual(is_virtual),
 | 
|---|
| 67 |   _classdesc(classdesc)
 | 
|---|
| 68 | {
 | 
|---|
| 69 | }
 | 
|---|
| 70 | 
 | 
|---|
| 71 | ParentClass::ParentClass(const ParentClass&p):
 | 
|---|
| 72 |   _access(p._access),
 | 
|---|
| 73 |   _is_virtual(p._is_virtual),
 | 
|---|
| 74 |   _classdesc(p._classdesc)
 | 
|---|
| 75 | {
 | 
|---|
| 76 | }
 | 
|---|
| 77 | 
 | 
|---|
| 78 | ParentClass::~ParentClass()
 | 
|---|
| 79 | {
 | 
|---|
| 80 | }
 | 
|---|
| 81 | 
 | 
|---|
| 82 | int ParentClass::is_virtual() const
 | 
|---|
| 83 | {
 | 
|---|
| 84 |   return _is_virtual;
 | 
|---|
| 85 | }
 | 
|---|
| 86 | 
 | 
|---|
| 87 | const ClassDesc* ParentClass::classdesc() const
 | 
|---|
| 88 | {
 | 
|---|
| 89 |   return _classdesc;
 | 
|---|
| 90 | }
 | 
|---|
| 91 | 
 | 
|---|
| 92 | void ParentClass::change_classdesc(ClassDesc*n)
 | 
|---|
| 93 | {
 | 
|---|
| 94 |   _classdesc = n;
 | 
|---|
| 95 | }
 | 
|---|
| 96 | 
 | 
|---|
| 97 | /////////////////////////////////////////////////////////////////
 | 
|---|
| 98 | 
 | 
|---|
| 99 | ParentClasses::ParentClasses():
 | 
|---|
| 100 |   _n(0),
 | 
|---|
| 101 |   _classes(0)
 | 
|---|
| 102 | {
 | 
|---|
| 103 | }
 | 
|---|
| 104 | 
 | 
|---|
| 105 | void
 | 
|---|
| 106 | ParentClasses::init(const char* parents)
 | 
|---|
| 107 | {
 | 
|---|
| 108 |   // if parents is empty then we are done
 | 
|---|
| 109 |   if (!parents || strlen(parents) == 0) return;
 | 
|---|
| 110 | 
 | 
|---|
| 111 |   char* tokens = ::strcpy(new char[strlen(parents)+1],parents);
 | 
|---|
| 112 |   const char* whitesp = "\t\n,() ";
 | 
|---|
| 113 |   char* token;
 | 
|---|
| 114 |   int is_virtual = 0;
 | 
|---|
| 115 |   ParentClass::Access access = ParentClass::Private;
 | 
|---|
| 116 |   for (token = ::strtok(tokens,whitesp);
 | 
|---|
| 117 |        token;
 | 
|---|
| 118 |        token = ::strtok(0,whitesp)) {
 | 
|---|
| 119 |       if (!strcmp(token,"virtual")) {
 | 
|---|
| 120 |           is_virtual = 1;
 | 
|---|
| 121 |         }
 | 
|---|
| 122 |       else if (!strcmp(token,"public")) {
 | 
|---|
| 123 |           access = ParentClass::Public;
 | 
|---|
| 124 |         }
 | 
|---|
| 125 |       else if (!strcmp(token,"protected")) {
 | 
|---|
| 126 |           access = ParentClass::Protected;
 | 
|---|
| 127 |         }
 | 
|---|
| 128 |       else if (!strcmp(token,"private")) {
 | 
|---|
| 129 |           access = ParentClass::Private;
 | 
|---|
| 130 |         }
 | 
|---|
| 131 |       else {
 | 
|---|
| 132 |           std::string parentkey(token);
 | 
|---|
| 133 |           // if the parents class desc does not exist create a temporary
 | 
|---|
| 134 |           // the temporary will be incorrect,because it does not have the
 | 
|---|
| 135 |           // parent's parents
 | 
|---|
| 136 |           if (ClassDesc::all().find(parentkey) == ClassDesc::all().end()) {
 | 
|---|
| 137 |               ClassDesc *tmp_classdesc = new ClassDesc(token);
 | 
|---|
| 138 |               ClassDesc::all()[parentkey] = tmp_classdesc;
 | 
|---|
| 139 |               if (ClassDesc::unresolved_parents_ == 0) {
 | 
|---|
| 140 |                   ClassDesc::unresolved_parents_ = new std::set<std::string>;
 | 
|---|
| 141 |                 }
 | 
|---|
| 142 |               ClassDesc::unresolved_parents_->insert(token);
 | 
|---|
| 143 |             }
 | 
|---|
| 144 |           ParentClass* p = new ParentClass(ClassDesc::all()[parentkey],
 | 
|---|
| 145 |                                            access,
 | 
|---|
| 146 |                                            is_virtual);
 | 
|---|
| 147 |           add(p);
 | 
|---|
| 148 |           access = ParentClass::Private;
 | 
|---|
| 149 |           is_virtual = 0;
 | 
|---|
| 150 |         }
 | 
|---|
| 151 |     }
 | 
|---|
| 152 |   delete[] tokens;
 | 
|---|
| 153 |   
 | 
|---|
| 154 | }
 | 
|---|
| 155 | 
 | 
|---|
| 156 | ParentClasses::~ParentClasses()
 | 
|---|
| 157 | {
 | 
|---|
| 158 |   for (int i=0; i<_n; i++) delete _classes[i];
 | 
|---|
| 159 |   
 | 
|---|
| 160 |   if (_classes) delete[] _classes;
 | 
|---|
| 161 |   _classes = 0;
 | 
|---|
| 162 |   _n = 0;
 | 
|---|
| 163 | }
 | 
|---|
| 164 | 
 | 
|---|
| 165 | void
 | 
|---|
| 166 | ParentClasses::add(ParentClass*p)
 | 
|---|
| 167 | {
 | 
|---|
| 168 |   ParentClass** newpp = new ParentClass*[_n+1];
 | 
|---|
| 169 |   for (int i=0; i<_n; i++) newpp[i] = _classes[i];
 | 
|---|
| 170 |   newpp[_n] = p;
 | 
|---|
| 171 |   _n++;
 | 
|---|
| 172 |   delete[] _classes;
 | 
|---|
| 173 |   _classes = newpp;
 | 
|---|
| 174 | }
 | 
|---|
| 175 | 
 | 
|---|
| 176 | void
 | 
|---|
| 177 | ParentClasses::change_parent(ClassDesc*oldcd,ClassDesc*newcd)
 | 
|---|
| 178 | {
 | 
|---|
| 179 |   for (int i=0; i<_n; i++) {
 | 
|---|
| 180 |       if (parent(i).classdesc() == oldcd) parent(i).change_classdesc(newcd);
 | 
|---|
| 181 |     }
 | 
|---|
| 182 | }
 | 
|---|
| 183 | 
 | 
|---|
| 184 | ////////////////////////////////////////////////////////////////////////
 | 
|---|
| 185 | 
 | 
|---|
| 186 | type_info_key&
 | 
|---|
| 187 | type_info_key::operator=(const type_info_key&t)
 | 
|---|
| 188 | {
 | 
|---|
| 189 |   ti_ = t.ti_;
 | 
|---|
| 190 |   return *this;
 | 
|---|
| 191 | }
 | 
|---|
| 192 | 
 | 
|---|
| 193 | int
 | 
|---|
| 194 | type_info_key::operator==(const type_info_key&t) const
 | 
|---|
| 195 | {
 | 
|---|
| 196 |   if (!ti_ && !t.ti_) return 1;
 | 
|---|
| 197 |   if (!ti_ || !t.ti_) return 0;
 | 
|---|
| 198 | 
 | 
|---|
| 199 |   return *ti_ == *t.ti_;
 | 
|---|
| 200 | }
 | 
|---|
| 201 | 
 | 
|---|
| 202 | int
 | 
|---|
| 203 | type_info_key::operator<(const type_info_key&t) const
 | 
|---|
| 204 | {
 | 
|---|
| 205 |   if (!ti_ && !t.ti_) return 0;
 | 
|---|
| 206 |   if (!ti_) return 0;
 | 
|---|
| 207 |   if (!t.ti_) return 1;
 | 
|---|
| 208 | 
 | 
|---|
| 209 |   return ti_->before(*t.ti_);
 | 
|---|
| 210 | }
 | 
|---|
| 211 | 
 | 
|---|
| 212 | int
 | 
|---|
| 213 | type_info_key::cmp(const type_info_key&t) const
 | 
|---|
| 214 | {
 | 
|---|
| 215 |   if (*this == t) return 0;
 | 
|---|
| 216 |   if (*this < t) return -1;
 | 
|---|
| 217 |   return 1;
 | 
|---|
| 218 | }
 | 
|---|
| 219 | 
 | 
|---|
| 220 | ////////////////////////////////////////////////////////////////////////
 | 
|---|
| 221 | 
 | 
|---|
| 222 | ClassDesc::ClassDesc(const type_info &ti,
 | 
|---|
| 223 |                      const char* name, int version,
 | 
|---|
| 224 |                      const char* parents,
 | 
|---|
| 225 |                      DescribedClass* (*ctor)(),
 | 
|---|
| 226 |                      DescribedClass* (*keyvalctor)(const Ref<KeyVal>&),
 | 
|---|
| 227 |                      DescribedClass* (*stateinctor)(StateIn&)
 | 
|---|
| 228 |                      )
 | 
|---|
| 229 | {
 | 
|---|
| 230 |   if (!type_info_all_) {
 | 
|---|
| 231 |       type_info_all_ = new std::map<type_info_key,ClassDescP>;
 | 
|---|
| 232 |     }
 | 
|---|
| 233 |   type_info_key key(&ti);
 | 
|---|
| 234 |   if (type_info_all_->find(key) != type_info_all_->end()) {
 | 
|---|
| 235 |       ExEnv::err0() << indent
 | 
|---|
| 236 |                    << "ERROR: duplicate ClassDesc detected for class "
 | 
|---|
| 237 |                    << name << " type_info name = " << ti.name() << endl;
 | 
|---|
| 238 |       abort();
 | 
|---|
| 239 |     }
 | 
|---|
| 240 |   else {
 | 
|---|
| 241 |       if (type_info_all_->find(key) == type_info_all_->end()) {
 | 
|---|
| 242 |           (*type_info_all_)[key] = this;
 | 
|---|
| 243 |         }
 | 
|---|
| 244 |       else {
 | 
|---|
| 245 |           // this should never happen
 | 
|---|
| 246 |         }
 | 
|---|
| 247 |     }
 | 
|---|
| 248 | 
 | 
|---|
| 249 |   // test the version number to see if it is valid
 | 
|---|
| 250 |   if (version <= 0) {
 | 
|---|
| 251 |       ExEnv::errn() << "ERROR: ClassDesc ctor: version <= 0" << endl;
 | 
|---|
| 252 |       exit(1);
 | 
|---|
| 253 |     }
 | 
|---|
| 254 | 
 | 
|---|
| 255 |   init(name,version,parents,&ti,ctor,keyvalctor,stateinctor);
 | 
|---|
| 256 | }
 | 
|---|
| 257 | 
 | 
|---|
| 258 | ClassDesc::ClassDesc(const char* name)
 | 
|---|
| 259 | {
 | 
|---|
| 260 |   init(name, 0);
 | 
|---|
| 261 | }
 | 
|---|
| 262 | 
 | 
|---|
| 263 | void
 | 
|---|
| 264 | ClassDesc::init(const char* name, int version,
 | 
|---|
| 265 |                 const char* parents,
 | 
|---|
| 266 |                 const type_info *ti,
 | 
|---|
| 267 |                 DescribedClass* (*ctor)(),
 | 
|---|
| 268 |                 DescribedClass* (*keyvalctor)(const Ref<KeyVal>&),
 | 
|---|
| 269 |                 DescribedClass* (*stateinctor)(StateIn&))
 | 
|---|
| 270 | {
 | 
|---|
| 271 |   classname_ = 0;
 | 
|---|
| 272 |   version_ = version;
 | 
|---|
| 273 |   children_ = 0;
 | 
|---|
| 274 |   ctor_ = ctor;
 | 
|---|
| 275 |   keyvalctor_ = keyvalctor;
 | 
|---|
| 276 |   stateinctor_ = stateinctor;
 | 
|---|
| 277 |   ti_ = ti;
 | 
|---|
| 278 | 
 | 
|---|
| 279 |   // make sure that the static members have been initialized
 | 
|---|
| 280 |   if (!all_) {
 | 
|---|
| 281 |       all_ = new std::map<std::string,ClassDescP>;
 | 
|---|
| 282 |       const char* tmp = getenv("LD_LIBRARY_PATH");
 | 
|---|
| 283 |       if (tmp) {
 | 
|---|
| 284 |           // Needed for misbehaving getenv's.
 | 
|---|
| 285 |           if (strncmp(tmp, "LD_LIBRARY_PATH=", 16) == 0) {
 | 
|---|
| 286 |               tmp = ::strchr(tmp,'=');
 | 
|---|
| 287 |               tmp++;
 | 
|---|
| 288 |             }
 | 
|---|
| 289 |         }
 | 
|---|
| 290 |       else tmp = ".";
 | 
|---|
| 291 |       classlib_search_path_ = ::strcpy(new char[strlen(tmp)+1],tmp);
 | 
|---|
| 292 |     }
 | 
|---|
| 293 |   
 | 
|---|
| 294 |   // see if I'm already in the list
 | 
|---|
| 295 |   ClassDesc *me = name_to_class_desc(name);
 | 
|---|
| 296 |   int temp_copy_present = 0;
 | 
|---|
| 297 |   if (me && me->version() != 0) {
 | 
|---|
| 298 |       ExEnv::err0()
 | 
|---|
| 299 |           << indent
 | 
|---|
| 300 |           << "ERROR: ClassDesc ctor: ClassDesc already initialized for "
 | 
|---|
| 301 |           << name << endl;
 | 
|---|
| 302 |       abort();
 | 
|---|
| 303 |     }
 | 
|---|
| 304 |   else if (me) {
 | 
|---|
| 305 |       temp_copy_present = 1;
 | 
|---|
| 306 |     }
 | 
|---|
| 307 | 
 | 
|---|
| 308 |   parents_.init(parents);
 | 
|---|
| 309 | 
 | 
|---|
| 310 |   if (!temp_copy_present && name_to_class_desc(name)) {
 | 
|---|
| 311 |       // I wasn't in the list before, but am in it now
 | 
|---|
| 312 |       ExEnv::err0()
 | 
|---|
| 313 |           << indent
 | 
|---|
| 314 |           << "ERROR: ClassDesc ctor: inheritance loop detected for "
 | 
|---|
| 315 |           << name << endl;
 | 
|---|
| 316 |       abort();
 | 
|---|
| 317 |     }
 | 
|---|
| 318 | 
 | 
|---|
| 319 |   classname_ = ::strcpy(new char[strlen(name)+1],name);
 | 
|---|
| 320 | 
 | 
|---|
| 321 |   std::string key(name);
 | 
|---|
| 322 | 
 | 
|---|
| 323 |   // let each of the parents know that this is a child
 | 
|---|
| 324 |   for (int i=0; i<parents_.n(); i++) {
 | 
|---|
| 325 |       std::string parentkey(parents_[i].classdesc()->name());
 | 
|---|
| 326 |       if (!(*all_)[parentkey]->children_)
 | 
|---|
| 327 |         (*all_)[parentkey]->children_ = new std::set<std::string>;
 | 
|---|
| 328 |       // let the parents know about the child
 | 
|---|
| 329 |       ((*all_)[parentkey]->children_)->insert(key);
 | 
|---|
| 330 |     }
 | 
|---|
| 331 | 
 | 
|---|
| 332 |   // if this class is aleady in all_, then it was put there by a child
 | 
|---|
| 333 |   // preserve children info, destroy the old entry, and put this there
 | 
|---|
| 334 |   if (all_->find(key) != all_->end()) {
 | 
|---|
| 335 |       children_ = (*all_)[key]->children_;
 | 
|---|
| 336 |       (*all_)[key]->children_ = 0;
 | 
|---|
| 337 | 
 | 
|---|
| 338 |       if (!children_) {
 | 
|---|
| 339 |           ExEnv::err0()
 | 
|---|
| 340 |               << indent
 | 
|---|
| 341 |               << "ERROR: ClassDesc: inconsistency in initialization for "
 | 
|---|
| 342 |               << key
 | 
|---|
| 343 |               << "--perhaps a duplicated CTOR call" << endl;
 | 
|---|
| 344 |           abort();
 | 
|---|
| 345 |         }
 | 
|---|
| 346 | 
 | 
|---|
| 347 |       // go thru the list of children and correct their
 | 
|---|
| 348 |       // parent class descriptors
 | 
|---|
| 349 |       for (std::set<std::string>::iterator i=children_->begin();
 | 
|---|
| 350 |            i!=children_->end(); i++) {
 | 
|---|
| 351 |           (*all_)[*i]->change_parent((*all_)[key],this);
 | 
|---|
| 352 |         }
 | 
|---|
| 353 | 
 | 
|---|
| 354 |       delete (*all_)[key];
 | 
|---|
| 355 |       unresolved_parents_->erase(key);
 | 
|---|
| 356 |       if (unresolved_parents_->size() == 0) {
 | 
|---|
| 357 |           delete unresolved_parents_;
 | 
|---|
| 358 |           unresolved_parents_ = 0;
 | 
|---|
| 359 |         }
 | 
|---|
| 360 |     }
 | 
|---|
| 361 |   (*all_)[key] = this;
 | 
|---|
| 362 | }
 | 
|---|
| 363 | 
 | 
|---|
| 364 | ClassDesc::~ClassDesc()
 | 
|---|
| 365 | {
 | 
|---|
| 366 |   // remove references to this class descriptor
 | 
|---|
| 367 |   if (children_) {
 | 
|---|
| 368 |       for (std::set<std::string>::iterator i=children_->begin();
 | 
|---|
| 369 |            i!=children_->end(); i++) {
 | 
|---|
| 370 |           if (all_->find(*i) != all_->end()) {
 | 
|---|
| 371 |               (*all_)[*i]->change_parent(this,0);
 | 
|---|
| 372 |             }
 | 
|---|
| 373 |         }
 | 
|---|
| 374 |     }
 | 
|---|
| 375 |   // delete this ClassDesc from the list of all ClassDesc's
 | 
|---|
| 376 |   std::string key(classname_);
 | 
|---|
| 377 |   all_->erase(key);
 | 
|---|
| 378 | 
 | 
|---|
| 379 |   // if the list of all ClassDesc's is empty, delete it
 | 
|---|
| 380 |   if (all_->size() == 0) {
 | 
|---|
| 381 |       delete all_;
 | 
|---|
| 382 |       all_ = 0;
 | 
|---|
| 383 |       delete[] classlib_search_path_;
 | 
|---|
| 384 |       classlib_search_path_ = 0;
 | 
|---|
| 385 |     }
 | 
|---|
| 386 | 
 | 
|---|
| 387 |   // delete this ClassDesc entry from the type_info map
 | 
|---|
| 388 |   if (ti_ != 0) {
 | 
|---|
| 389 |       type_info_key key(ti_);
 | 
|---|
| 390 |       type_info_all_->erase(key);
 | 
|---|
| 391 |       if (type_info_all_->size() == 0) {
 | 
|---|
| 392 |           delete type_info_all_;
 | 
|---|
| 393 |           type_info_all_ = 0;
 | 
|---|
| 394 |         }
 | 
|---|
| 395 |     }
 | 
|---|
| 396 | 
 | 
|---|
| 397 |   // delete local data
 | 
|---|
| 398 |   delete[] classname_;
 | 
|---|
| 399 |   if (children_) delete children_;
 | 
|---|
| 400 | }
 | 
|---|
| 401 | 
 | 
|---|
| 402 | ClassDesc*
 | 
|---|
| 403 | ClassDesc::class_desc(const type_info &ti)
 | 
|---|
| 404 | {
 | 
|---|
| 405 |   if (type_info_all_->find(type_info_key(&ti))
 | 
|---|
| 406 |       == type_info_all_->end()) return 0;
 | 
|---|
| 407 |   return (*type_info_all_)[type_info_key(&ti)];
 | 
|---|
| 408 | }
 | 
|---|
| 409 | 
 | 
|---|
| 410 | std::map<std::string,ClassDescP>&
 | 
|---|
| 411 | ClassDesc::all()
 | 
|---|
| 412 | {
 | 
|---|
| 413 |   if (!all_) {
 | 
|---|
| 414 |       ExEnv::errn() << "ClassDesc::all(): all not initialized" << endl;
 | 
|---|
| 415 |       abort();
 | 
|---|
| 416 |     }
 | 
|---|
| 417 |   return *all_;
 | 
|---|
| 418 | }
 | 
|---|
| 419 | 
 | 
|---|
| 420 | ClassDesc*
 | 
|---|
| 421 | ClassDesc::name_to_class_desc(const char* name)
 | 
|---|
| 422 | {
 | 
|---|
| 423 |   std::string key(name);
 | 
|---|
| 424 |   if (all_->find(key) == all_->end()) return 0;
 | 
|---|
| 425 |   return (*all_)[key];
 | 
|---|
| 426 | }
 | 
|---|
| 427 | 
 | 
|---|
| 428 | DescribedClass*
 | 
|---|
| 429 | ClassDesc::create() const
 | 
|---|
| 430 | {
 | 
|---|
| 431 |   if (ctor_) return (*ctor_)();
 | 
|---|
| 432 |   return 0;
 | 
|---|
| 433 | }
 | 
|---|
| 434 | 
 | 
|---|
| 435 | DescribedClass*
 | 
|---|
| 436 | ClassDesc::create(const Ref<KeyVal>&keyval) const
 | 
|---|
| 437 | {
 | 
|---|
| 438 |   DescribedClass* result;
 | 
|---|
| 439 |   if (keyvalctor_) {
 | 
|---|
| 440 |       result = (*keyvalctor_)(keyval);
 | 
|---|
| 441 |     }
 | 
|---|
| 442 |   else result = 0;
 | 
|---|
| 443 |   return result;
 | 
|---|
| 444 | }
 | 
|---|
| 445 | 
 | 
|---|
| 446 | DescribedClass*
 | 
|---|
| 447 | ClassDesc::create(StateIn&statein) const
 | 
|---|
| 448 | {
 | 
|---|
| 449 |   if (stateinctor_) return (*stateinctor_)(statein);
 | 
|---|
| 450 |   return 0;
 | 
|---|
| 451 | }
 | 
|---|
| 452 | 
 | 
|---|
| 453 | void
 | 
|---|
| 454 | ClassDesc::change_parent(ClassDesc*oldcd,ClassDesc*newcd)
 | 
|---|
| 455 | {
 | 
|---|
| 456 |   parents_.change_parent(oldcd,newcd);
 | 
|---|
| 457 | }
 | 
|---|
| 458 | 
 | 
|---|
| 459 | void
 | 
|---|
| 460 | ClassDesc::list_all_classes()
 | 
|---|
| 461 | {
 | 
|---|
| 462 |   ExEnv::out0() << "Listing all classes:" << endl;
 | 
|---|
| 463 |   for (std::map<std::string,ClassDescP>::iterator ind=all_->begin();
 | 
|---|
| 464 |        ind!=all_->end(); ind++) {
 | 
|---|
| 465 |       ClassDesc* classdesc = ind->second;
 | 
|---|
| 466 |       ExEnv::out0() << "class " << classdesc->name() << endl;
 | 
|---|
| 467 |       ParentClasses& parents = classdesc->parents_;
 | 
|---|
| 468 |       if (parents.n()) {
 | 
|---|
| 469 |           ExEnv::out0() << "  parents:";
 | 
|---|
| 470 |           for (int i=0; i<parents.n(); i++) {
 | 
|---|
| 471 |               if (parents[i].is_virtual()) {
 | 
|---|
| 472 |                   ExEnv::out0() << " virtual";
 | 
|---|
| 473 |                 }
 | 
|---|
| 474 |               if (parents[i].access() == ParentClass::Public) {
 | 
|---|
| 475 |                   ExEnv::out0() << " public";
 | 
|---|
| 476 |                 }
 | 
|---|
| 477 |               else if (parents[i].access() == ParentClass::Protected) {
 | 
|---|
| 478 |                   ExEnv::out0() << " protected";
 | 
|---|
| 479 |                 }
 | 
|---|
| 480 |               if (parents[i].classdesc() == 0) {
 | 
|---|
| 481 |                   ExEnv::errn() << endl
 | 
|---|
| 482 |                                << "ERROR: parent " << i
 | 
|---|
| 483 |                                << " for " << classdesc->name()
 | 
|---|
| 484 |                                << " is missing" << endl;
 | 
|---|
| 485 |                   abort();
 | 
|---|
| 486 |                 }
 | 
|---|
| 487 |               const char *n = parents[i].classdesc()->name();
 | 
|---|
| 488 |               ExEnv::out0() << " " << parents[i].classdesc()->name();
 | 
|---|
| 489 |             }
 | 
|---|
| 490 |           ExEnv::out0() << endl;
 | 
|---|
| 491 |         }
 | 
|---|
| 492 |       std::set<std::string>* children = classdesc->children_;
 | 
|---|
| 493 |       if (children) {
 | 
|---|
| 494 |           ExEnv::out0() << "  children:";
 | 
|---|
| 495 |           for (std::set<std::string>::iterator pind=children->begin();
 | 
|---|
| 496 |                pind!=children->end(); pind++) {
 | 
|---|
| 497 |               ExEnv::out0() << " " << (*pind);
 | 
|---|
| 498 |             }
 | 
|---|
| 499 |           ExEnv::out0() << endl;
 | 
|---|
| 500 |         }
 | 
|---|
| 501 |     }
 | 
|---|
| 502 | }
 | 
|---|
| 503 | 
 | 
|---|
| 504 | DescribedClass* ClassDesc::create_described_class() const
 | 
|---|
| 505 | {
 | 
|---|
| 506 |     return create();
 | 
|---|
| 507 | }
 | 
|---|
| 508 | 
 | 
|---|
| 509 | // Returns 0 for success and -1 for failure.
 | 
|---|
| 510 | int
 | 
|---|
| 511 | ClassDesc::load_class(const char* classname)
 | 
|---|
| 512 | {
 | 
|---|
| 513 |   // See if the class has already been loaded.
 | 
|---|
| 514 |   if (name_to_class_desc(classname) != 0) {
 | 
|---|
| 515 |       return 0;
 | 
|---|
| 516 |     }
 | 
|---|
| 517 |   
 | 
|---|
| 518 | #if HAVE_DLFCN_H
 | 
|---|
| 519 |   // make a copy of the library search list
 | 
|---|
| 520 |   char* path = new char[strlen(classlib_search_path_) + 1];
 | 
|---|
| 521 |   strcpy(path, classlib_search_path_);
 | 
|---|
| 522 | 
 | 
|---|
| 523 |   // go through each directory in the library search list
 | 
|---|
| 524 |   char* dir = strtok(path,":");
 | 
|---|
| 525 |   while (dir) {
 | 
|---|
| 526 |       // find the 'classes' files
 | 
|---|
| 527 |       char* filename = new char[strlen(dir) + 8 + 1];
 | 
|---|
| 528 |       strcpy(filename,dir);
 | 
|---|
| 529 |       strcat(filename,"/classes");
 | 
|---|
| 530 |       ExEnv::outn() << "ClassDesc::load_class looking for \"" << filename << "\""
 | 
|---|
| 531 |            << endl;
 | 
|---|
| 532 |       FILE* fp = fopen(filename, "r");
 | 
|---|
| 533 |       delete[] filename;
 | 
|---|
| 534 | 
 | 
|---|
| 535 |       if (fp) {
 | 
|---|
| 536 |           // read the lines in the classes file
 | 
|---|
| 537 |           const int bufsize = 10000;
 | 
|---|
| 538 |           char buf[bufsize];
 | 
|---|
| 539 |           while(fgets(buf, bufsize, fp)) {
 | 
|---|
| 540 |               if (buf[0] != '\0' && buf[strlen(buf)-1] == '\n') {
 | 
|---|
| 541 |                   buf[strlen(buf)-1] = '\0';
 | 
|---|
| 542 |                 }
 | 
|---|
| 543 |               char* lib = strtok(buf," ");
 | 
|---|
| 544 |               char* testclassname = strtok(0," ");
 | 
|---|
| 545 |               ExEnv::outn() << "lib = \"" << lib << "\"" << endl;
 | 
|---|
| 546 |               while(testclassname) {
 | 
|---|
| 547 |                   ExEnv::outn() << "classname = \"" << testclassname << "\"" << endl;
 | 
|---|
| 548 |                   if (strcmp(testclassname,classname) == 0) {
 | 
|---|
| 549 |                       // found it
 | 
|---|
| 550 |                       char* libname = new char[strlen(lib) + strlen(dir) + 2];
 | 
|---|
| 551 |                       strcpy(libname, dir);
 | 
|---|
| 552 |                       strcat(libname, "/");
 | 
|---|
| 553 |                       strcat(libname, lib);
 | 
|---|
| 554 |                       // load the libraries this lib depends upon
 | 
|---|
| 555 | 
 | 
|---|
| 556 |                       // i should look in the library's .dep file to
 | 
|---|
| 557 |                       // get the dependencies, but this makes it a little
 | 
|---|
| 558 |                       // difficult to make sure the same library doesn't
 | 
|---|
| 559 |                       // get loaded twice (which is important) so for now
 | 
|---|
| 560 |                       // i'll just wait until after i load the library and
 | 
|---|
| 561 |                       // then look in the unresolved parents set
 | 
|---|
| 562 |                       // and load parents until nothing is left
 | 
|---|
| 563 | 
 | 
|---|
| 564 |                       // load the library
 | 
|---|
| 565 |                       ExEnv::outn() << "loading \"" << libname << "\"" << endl;
 | 
|---|
| 566 |                       dlopen(libname, RTLD_LAZY);
 | 
|---|
| 567 | 
 | 
|---|
| 568 |                       // load code for parents
 | 
|---|
| 569 |                       while (unresolved_parents_
 | 
|---|
| 570 |                              && unresolved_parents_->size()) {
 | 
|---|
| 571 |                           load_class((*unresolved_parents_->begin()).c_str());
 | 
|---|
| 572 |                         }
 | 
|---|
| 573 | 
 | 
|---|
| 574 |                       fclose(fp);
 | 
|---|
| 575 |                       delete[] path;
 | 
|---|
| 576 |                       // make sure it worked.
 | 
|---|
| 577 |                       if (name_to_class_desc(classname) == 0) {
 | 
|---|
| 578 |                           ExEnv::errn() << "load of \"" << classname << "\" from \""
 | 
|---|
| 579 |                                << libname << "\" failed" << endl;
 | 
|---|
| 580 |                           delete[] libname;
 | 
|---|
| 581 |                           return -1;
 | 
|---|
| 582 |                         }
 | 
|---|
| 583 |                       ExEnv::outn() << "loaded \"" << classname << "\" from \""
 | 
|---|
| 584 |                            << libname << "\"" << endl;
 | 
|---|
| 585 |                       delete[] libname;
 | 
|---|
| 586 |                       return 0;
 | 
|---|
| 587 |                     }
 | 
|---|
| 588 |                   testclassname = strtok(0," ");
 | 
|---|
| 589 |                 }
 | 
|---|
| 590 |             }
 | 
|---|
| 591 |           fclose(fp);
 | 
|---|
| 592 |         }
 | 
|---|
| 593 |       
 | 
|---|
| 594 |       dir = strtok(0, ":");
 | 
|---|
| 595 |     }
 | 
|---|
| 596 | 
 | 
|---|
| 597 |   delete[] path;
 | 
|---|
| 598 | #endif // HAVE_DLFCN_H
 | 
|---|
| 599 | 
 | 
|---|
| 600 |   ExEnv::outn() << "ClassDesc::load_class(\"" << classname << "\"): load failed"
 | 
|---|
| 601 |        << endl
 | 
|---|
| 602 |        << "Either \"" << classname << "\" is an invalid class name or the code"
 | 
|---|
| 603 |        << endl
 | 
|---|
| 604 |        << "for \"" << classname << "\" was not linked into the executable."
 | 
|---|
| 605 |        << endl;
 | 
|---|
| 606 | 
 | 
|---|
| 607 |   return -1;
 | 
|---|
| 608 | }
 | 
|---|
| 609 | 
 | 
|---|
| 610 | ////////////////////////////////////////////////////
 | 
|---|
| 611 | 
 | 
|---|
| 612 | static ClassDesc DescribedClass_cd(
 | 
|---|
| 613 |     typeid(DescribedClass),"DescribedClass");
 | 
|---|
| 614 | 
 | 
|---|
| 615 | DescribedClass::DescribedClass()
 | 
|---|
| 616 | {
 | 
|---|
| 617 | }
 | 
|---|
| 618 | 
 | 
|---|
| 619 | DescribedClass::DescribedClass(const DescribedClass&) {}
 | 
|---|
| 620 | DescribedClass& DescribedClass::operator=(const DescribedClass&)
 | 
|---|
| 621 | {
 | 
|---|
| 622 |   return *this;
 | 
|---|
| 623 | }
 | 
|---|
| 624 | 
 | 
|---|
| 625 | DescribedClass::~DescribedClass()
 | 
|---|
| 626 | {
 | 
|---|
| 627 | }
 | 
|---|
| 628 | 
 | 
|---|
| 629 | ClassDesc*
 | 
|---|
| 630 | DescribedClass::class_desc() const throw()
 | 
|---|
| 631 | {
 | 
|---|
| 632 |   ClassDesc *cd;
 | 
|---|
| 633 |   try {
 | 
|---|
| 634 |       cd = ClassDesc::class_desc(typeid(*this));
 | 
|---|
| 635 |     }
 | 
|---|
| 636 |   catch (...) {
 | 
|---|
| 637 |       cd = 0;
 | 
|---|
| 638 |     }
 | 
|---|
| 639 |   return cd;
 | 
|---|
| 640 | }
 | 
|---|
| 641 | 
 | 
|---|
| 642 | const char* DescribedClass::class_name() const
 | 
|---|
| 643 | {
 | 
|---|
| 644 |     return class_desc()->name();
 | 
|---|
| 645 | }
 | 
|---|
| 646 | 
 | 
|---|
| 647 | int DescribedClass::class_version() const
 | 
|---|
| 648 | {
 | 
|---|
| 649 |     return class_desc()->version();
 | 
|---|
| 650 | }
 | 
|---|
| 651 | 
 | 
|---|
| 652 | void
 | 
|---|
| 653 | DescribedClass::print(ostream &o) const
 | 
|---|
| 654 | {
 | 
|---|
| 655 |   o << indent << "Object of type " << class_name() << endl;
 | 
|---|
| 656 | }
 | 
|---|
| 657 | 
 | 
|---|
| 658 | ostream &
 | 
|---|
| 659 | operator <<(ostream&o, const RefBase &ref)
 | 
|---|
| 660 | {
 | 
|---|
| 661 |   DescribedClass *dc = dynamic_cast<DescribedClass*>(ref.parentpointer());
 | 
|---|
| 662 |   if (dc) {
 | 
|---|
| 663 |       dc->print(o);
 | 
|---|
| 664 |     }
 | 
|---|
| 665 |   else {
 | 
|---|
| 666 |       o << indent << "reference to null" << endl;
 | 
|---|
| 667 |     }
 | 
|---|
| 668 | 
 | 
|---|
| 669 |   return o;
 | 
|---|
| 670 | }
 | 
|---|
| 671 | 
 | 
|---|
| 672 | #ifdef EXPLICIT_TEMPLATE_INSTANTIATION
 | 
|---|
| 673 | 
 | 
|---|
| 674 | template class std::map<std::string,ClassDescP>;
 | 
|---|
| 675 |                
 | 
|---|
| 676 | template class std::map<std::string,int>;
 | 
|---|
| 677 | template class std::set<std::string>;
 | 
|---|
| 678 | 
 | 
|---|
| 679 | #endif
 | 
|---|
| 680 | 
 | 
|---|
| 681 | /////////////////////////////////////////////////////////////////////////////
 | 
|---|
| 682 | 
 | 
|---|
| 683 | // Local Variables:
 | 
|---|
| 684 | // mode: c++
 | 
|---|
| 685 | // c-file-style: "CLJ"
 | 
|---|
| 686 | // End:
 | 
|---|