home *** CD-ROM | disk | FTP | other *** search
- // This may look like C code, but it is really -*- C++ -*-
- /*
- ************************************************************************
- *
- * Vocabulary service
- *
- * Notice: every vocabulary upon construction is inserted somewhere,
- * another vocabulary or vocabulary of vocabularies
- * Vocabulary_of_vocabularies, and, optionally, on the top of Vocabulary_path.
- * Package body
- * $Id: voc.cc,v 1.2 1996/02/20 17:31:05 oleg Exp oleg $
- *
- ************************************************************************
- */
-
- #ifdef __GNUC__
- #pragma implementation
- #endif
-
- #include "myenv.h"
- #include <ctype.h>
- #include <std.h>
- #include <fstream.h>
-
- #include "voc.h"
-
- //------------------------------------------------------------------------
- // Vocabulary of Vocabularies
- // Every vocabulary that exists must be in some vocabulary, say, the
- // Vocabulary_of_vocabularies
- // Vocabulary_of_vocabularies is created statically (actually, before the
- // main() program ever begins)
-
- class VocOfVoc : public Voc
- {
- public:
- VocOfVoc(void);
- ~VocOfVoc(void);
- };
-
- static VocOfVoc Vocabulary_of_vocabularies;
-
- // Constructor. It is called before main()
- // starts.
- VocOfVoc::VocOfVoc(void)
- : Voc("VocOfVoc","Vocabulary of Vocabularies")
- {
- }
-
- // Destructor, it is actually called when
- // main() finished. It ought to save dirty
- // vocabularies. But for now, we do nothing
- VocOfVoc::~VocOfVoc(void)
- {
- }
-
- void print_all_vocabularies(void)
- {
- Vocabulary_of_vocabularies.print("");
- }
-
- //------------------------------------------------------------------------
- // Vocabulary Path
- // is a homegeneous vocabulary of references (VocRef) to other vocabularies,
- // which makes them (the vocabularies) be "in the path"
- //
- // Vocabulary_path defines the current system environment.
- // The vocabulary on the top of the Vocabulary_path is the current
- // vocabulary
-
- class VocPathPrivate : public Voc
- {
- // Find a slot with the specified name and
- // type. Return 0 if not found
- GenericVocItem * find(const char * _name, const Type type) const;
- public:
- VocPathPrivate(void);
- void push(const Voc& voc); // Make the specified vocabulary current
- void pop(void); // Remove the top (current) vocabulary
- };
-
- static VocPathPrivate Vocabulary_path;
-
- // Like the Vocabulary of Vocabularies,
- // VocPathPrivate is constructed before the
- // main() gets control
- VocPathPrivate::VocPathPrivate(void)
- : Voc("VocPath","Vocabulary Path")
- {
- set_option(Voc::Homogeneous);
- }
-
- // Scour through all vocabularies in the path
- // for a slot with the specified name and
- // type. Return 0 if not found
- GenericVocItem * VocPathPrivate::find(const char * _name,
- const Type type) const
- {
- for(register GenericVocItem * ip = first; ip != 0; ip=ip->next)
- {
- assert( ip->q_type() == VocRef );
- Voc& curr_voc = *(ip->get_value())._voc;
- if( GenericVocItem * found_item = curr_voc.find(_name,type) )
- return found_item;
- }
- return 0;
- }
-
- void VocPath::print(void)
- {
- Vocabulary_path.print("");
- }
-
-
- // Retrieving functions, raise an exception if
- // the slot is not found
- const char * VocPath::find_str(const char * name)
- {
- return Vocabulary_path.find_str(name);
- }
-
- int VocPath::find_int(const char * name)
- {
- return Vocabulary_path.find_int(name);
- }
-
- double VocPath::find_double(const char * name)
- {
- return Vocabulary_path.find_double(name);
- }
-
- Voc& VocPath::find_voc(const char * name)
- {
- return Vocabulary_path.find_voc(name);
- }
-
- // Retrieving functions with a default value
- // (which is returned if the slot is not found)
- const char * VocPath::find_with_default(const char * name,
- const char * default_val)
- {
- return Vocabulary_path.find_with_default(name,default_val);
- }
-
- int VocPath::find_with_default(const char * name,
- const int default_val)
- {
- return Vocabulary_path.find_with_default(name,default_val);
- }
-
- double VocPath::find_with_default(const char * name,
- const double default_val)
- {
- return Vocabulary_path.find_with_default(name,default_val);
- }
-
- Voc& VocPath::find_with_default(const char * name,
- Voc& default_val)
- {
- return Vocabulary_path.find_with_default(name,default_val);
- }
-
- // Find a vocabulary with a specified name
- // (in all the vocab in the path) and put it
- // at the top of the stack
- void VocPath::push(const char * name) { Vocabulary_path.push(find_voc(name)); }
-
- void VocPathPrivate::push(const Voc& new_curr_ref)
- {
- Vocabulary_path += *(new VocRefItem(new_curr_ref));
- }
-
- // Remove the top (current) vocabulary
- void VocPath::pop(void) { Vocabulary_path.pop(); }
-
- void VocPathPrivate::pop(void)
- {
- GenericVocItem& was_current_vocref = remove_top();
- assert( was_current_vocref.q_type() == VocRef );
- delete &was_current_vocref;
- }
-
- // Note the current state of VocPath
- VocPathMark::VocPathMark(void)
- : vocpath_count(Vocabulary_path.count())
- {
- }
-
- // Back off to the marked state of VPath
- void VocPathMark::back_off(void) const
- {
- int new_vocpath_count = Vocabulary_path.count();
- if( new_vocpath_count < vocpath_count )
- _error("Vocabulary Path was popped beyond the noted mark %d, "
- "current count %d",vocpath_count,new_vocpath_count);
-
- for(; new_vocpath_count > vocpath_count; new_vocpath_count--)
- Vocabulary_path.pop();
- assert( new_vocpath_count == Vocabulary_path.count() );
- }
-
- //------------------------------------------------------------------------
- // Constructing vocabularies
-
- // Make just an empty vocabulary
- Voc::Voc(const char * _name, const char * _comment)
- : GenericVocItem(_name,GenericVocItem::Vocab),
- first(0), last(0)
- {
- if( _comment == 0 || _comment[0] == '\0' )
- comment = "";
- else
- comment = strdup(_comment);
- (int &)options = 0;
- }
-
- // We ought to destroy vocabulary items, or
- // at least, unreference/garbage collect them
- // But for now, we do nothing
- Voc::~Voc(void)
- {
- }
-
- Voc& Dummy_Voc = new_Voc("**Dummy Voc**","Dummy Vocabulary");
-
- // Add this Voc to the VocOfVoc
- void Voc::VocOfVoc_catalog(void)
- {
- Vocabulary_of_vocabularies += *this;
- }
-
- // Make this vocabulary current, that is,
- // create a new entry in the vocabulary_path
- void Voc::make_current(void)
- {
- VocRefItem& vocref = * new VocRefItem(*this);
- Vocabulary_path += vocref;
- }
-
- // Make sure it's ok to insert a new entry
- // to the vocabulary; set the dirty bit if
- // it is so
- void Voc::ok_to_modify(void)
- {
- if( check_option(ReadOnly) )
- info(), _error("Can't add new elements to the above vocabulary because "
- "it is read-only");
- set_option(Dirty);
- }
-
- // if the dictionary is homogeneous
- // and non-empty, the item being added
- // should be structurally equivalent
- // to the item on the top of the
- // dictionary
- void Voc::homogenity_checking(GenericVocItem& item)
- {
- if( !check_option(Homogeneous) )
- return; // this is not a homogeneous voc
- if( first == 0 )
- return; // it's empty - everything goes
- if( item.val_type != (*first).val_type )
- info(), item.GenericVocItem::print("item being added"),
- _error("the above item can't be added to the dictionary because\n"
- "the item is of the wrong type");
- }
-
- // Look up the named vocabulary
- VocRefItem::VocRefItem(const char * name)
- : GenericVocItem(name,GenericVocItem::VocRef),
- value(&(Vocabulary_of_vocabularies.find_voc(name))),
- voc_file_name(0)
- {
- }
-
- // Create a proxy; don't rush to load though
- VocRefItem::VocRefItem(const char * name, const char * file_name)
- : GenericVocItem(name,GenericVocItem::VocRef),
- value(0),
- voc_file_name(file_name == 0 || file_name[0] == '\0' ? 0 :
- strdup(file_name))
- {
- }
-
- // Destroy the reference: do not unload the
- // VocRef at present
- VocRefItem::~VocRefItem(void)
- {
- if( voc_file_name != 0 )
- free((char *)voc_file_name);
- }
-
- // Unreference the VocRef, and load the referred
- // vocabulary when necessary
- GenericVocItem::TypeSet VocRefItem::get_value(void) const
- {
- if( value == 0 ) // The Voc isn't loaded
- { // - try to find it first
- GenericVocItem * ip = Vocabulary_of_vocabularies.find(name,Vocab);
- if( ip != 0 )
- (*(VocRefItem *)this).value = (ip->get_value())._voc;
- }
-
- if( value == 0 ) // The Voc wasn't loaded: do it now
- (*(VocRefItem *)this).value = &Voc::load(voc_file_name);
-
- TypeSet tset; tset._voc = value;
- return tset;
- }
-
- //------------------------------------------------------------------------
- // Constructing/Destructing Voc Items
-
- // A protected constructor
- // Just constructs the item (but doesn't
- // enqueue it) - that's why it's protected
- GenericVocItem::GenericVocItem(const char * _name, const Type type)
- : next(0), val_type(type)
- {
- register char * pnn;
- register const char * pon;
- for(pnn=name, pon=_name; pnn < name + sizeof(name) && *pon != '\0'; pon++)
- if( ! isprint(*pon) || *pon == '=' )
- _error("GenericVocItem: name '%s' contains an illegal character "
- "'%c' (0x%x)",_name, *pon, *pon);
- else
- *pnn++ = *pon;
- if( *pon != '\0' )
- _error("GenericVocItem: name '%.40s' is too big",_name);
- *pnn = '\0';
- }
-
- // Add this item to the current vocabulary
- void GenericVocItem::catalog(void)
- {
- (Voc&)*(Vocabulary_path.top().get_value()._voc) += *this;
- }
-
- // Print the name and the type of the item
- void GenericVocItem::print(const char * title) const
- {
- static char * type_names [Last] =
- { "integer", "double", "string", "vocabulary", "voc reference" };
- message("\n%s item named '%s', '%s' ",type_names[val_type],name,title);
- }
-
- //------------------------------------------------------------------------
- // Handling specific Voc items
-
- StrVocItem::StrVocItem(const char * _name, const char * _val)
- : GenericVocItem(_name,GenericVocItem::String)
- {
- value = strdup(_val);
- }
-
- StrVocItem::~StrVocItem(void)
- {
- free((char *)value);
- }
-
- // Printing specific Voc items
- void IntVocItem::print(const char * title) const
- {
- GenericVocItem::print(title);
- message("value %d\n",value);
- }
-
- void DoubleVocItem::print(const char * title) const
- {
- GenericVocItem::print(title);
- message("value %g\n",value);
- }
-
- void StrVocItem::print(const char * title) const
- {
- GenericVocItem::print(title);
- message("value '%s'\n",value);
- }
-
- void VocRefItem::print(const char * title) const
- {
- GenericVocItem::print(title);
- if( value != 0 )
- {
- assert( (*value).q_type() == Vocab );
- message("loaded\n");
- }
- else if( voc_file_name != 0 )
- message("to be loaded from the file '%s'\n",voc_file_name);
- else
- message("to be resolved\n");
- }
-
- //------------------------------------------------------------------------
- // Vocabulary operations
-
-
- // Put a vocabulary item at the top of the
- // vocabulary
- void Voc::operator += (GenericVocItem& item)
- {
- ok_to_modify();
- homogenity_checking(item);
-
- assert( item.next == 0 ); // Item isn't in any kind of list
- // already, right?
- item.next = first;
- if( first == 0 )
- {
- assert( last == 0 );
- last = &item;
- }
- first = &item;
- }
-
- // Remove the item at the top
- GenericVocItem& Voc::remove_top(void)
- {
- ok_to_modify();
- GenericVocItem * ip = first;
- if( ip == 0 )
- info(),
- _error("can't remove the top element: vocabulary is empty");
-
- if( (first = ip->next) == 0 )
- {
- assert( last == ip );
- last = 0;
- }
- ip->next = 0; // The element isn't in any chain now
-
- return *ip;
- }
-
- // Peek at the item on the top
- const GenericVocItem& Voc::top(void) const
- {
- assert( first != 0 );
- return *first;
- }
-
- // Peek at the item at the bottom
- const GenericVocItem& Voc::bottom(void) const
- {
- assert( last != 0 );
- return *last;
- }
-
- // Count the number of items in a dictionary
- int Voc::count(void) const
- {
- if( first == 0 )
- {
- assert( last == 0 );
- return 0;
- }
-
- register int cnt;
- register GenericVocItem * ip;
- for(ip=first, cnt=1; ip->next != 0; ip = ip->next)
- cnt++;
- assert( ip == last ); // I want to double-check the Voc consistency:
- // just being paranoid
- return cnt;
- }
-
-
- // Just give brief info about the voc
- void Voc::info(void) const
- {
- assert( val_type == Vocab );
- message("\nVocabulary '%s', '%s' (",name,comment);
- if( check_option(ReadOnly) )
- message("ReadOnly ");
- if( check_option(Homogeneous) )
- message("Homogeneous ");
- if( check_option(Dirty) )
- message("Dirty ");
- message(")\n");
- }
-
- // Deep printing of all vocabulary entries
- void Voc::print(const char * title) const
- {
- info();
- message("\n'%s' contains %d elements\n",title,count());
- if( q_empty() )
- return;
- GenericVocItem * ip;
- for(ip=first; ip != 0; ip = ip->next)
- (*ip).print("voc item");
- message("\n===== done printing vocabulary\n");
- }
-
- //------------------------------------------------------------------------
- // Search functions
-
- // Generic search function:
- // finds a slot with the specified name and
- // type. Returns 0 if nothing was found
- GenericVocItem * Voc::find(const char * _name, const Type type) const
- {
- GenericVocItem * ip;
- for(ip=first; ip != 0; ip = ip->next)
- if( strcmp(ip->name,_name) == 0 && ip->val_type == type )
- return ip;
- return 0;
- }
-
-
- // Retrieving functions: get a value associated
- // with a specific name in the vocabulary and of
- // the specific time. Raise an exception in case
- // of search failure
-
- // Look up a string value
- const char * Voc::find_str(const char * name) const
- {
- GenericVocItem * ip = find(name,GenericVocItem::String);
- if( ip == 0 )
- info(),
- _error("Failed to find a string item '%s' in the above vocabulary",
- name);
- return (ip->get_value())._str;
- }
-
- // Look up an int value
- int Voc::find_int(const char * name) const
- {
- GenericVocItem * ip = find(name,GenericVocItem::Int);
- if( ip == 0 )
- info(),
- _error("Failed to find an int item '%s' in the above vocabulary",
- name);
- return (ip->get_value())._int;
- }
-
- // Look up a floating-point value
- double Voc::find_double(const char * name) const
- {
- GenericVocItem * ip = find(name,GenericVocItem::Double);
- if( ip == 0 )
- info(),
- _error("Failed to find a double item '%s' in the above vocabulary",
- name);
- return (ip->get_value())._double;
- }
-
- // Look up a vocabulary value
- Voc& Voc::find_voc(const char * name) const
- {
- GenericVocItem * ip = find(name,GenericVocItem::Vocab);
- if( ip == 0 )
- ip = find(name,GenericVocItem::VocRef);
-
- if( ip == 0 )
- info(),
- _error("Failed to find a vocabulary item '%s' in the above vocabulary",
- name);
- return *(ip->get_value())._voc;
- }
-
- // Retrieving functions with a default value
- // (which is returned if the desired slot is not found)
-
- // Look up a string value
- const char * Voc::find_with_default(const char * name,
- const char * default_val) const
- {
- GenericVocItem * ip = find(name,GenericVocItem::String);
- if( ip == 0 )
- return default_val;
- return (ip->get_value())._str;
- }
-
-
- // Look up an int value
- int Voc::find_with_default(const char * name,
- const int default_val) const
- {
- GenericVocItem * ip = find(name,GenericVocItem::Int);
- if( ip == 0 )
- return default_val;
- return (ip->get_value())._int;
- }
-
- // Look up a floating-point value
- double Voc::find_with_default(const char * name,
- const double default_val) const
- {
- GenericVocItem * ip = find(name,GenericVocItem::Double);
- if( ip == 0 )
- return default_val;
- return (ip->get_value())._double;
- }
-
- // Look up a vocabulary value
- Voc& Voc::find_with_default(const char * name,
- Voc& default_val) const
- {
- GenericVocItem * ip = find(name,GenericVocItem::Vocab);
- if( ip == 0 )
- ip = find(name,GenericVocItem::VocRef);
- if( ip == 0 )
- return default_val;
- return *(ip->get_value())._voc;
- }
-