| [0b990d] | 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:
 | 
|---|