home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / c++advio 2.3 / Advanced i⁄o / voc.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-05  |  15.4 KB  |  608 lines  |  [TEXT/ttxt]

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *                Vocabulary service
  6.  *
  7.  * Notice: every vocabulary upon construction is inserted somewhere,
  8.  * another vocabulary or vocabulary of vocabularies
  9.  * Vocabulary_of_vocabularies, and, optionally, on the top of Vocabulary_path.
  10.  *                  Package body
  11.  * $Id: voc.cc,v 1.2 1996/02/20 17:31:05 oleg Exp oleg $
  12.  *
  13.  ************************************************************************
  14.  */
  15.  
  16. #ifdef __GNUC__
  17. #pragma implementation
  18. #endif
  19.  
  20. #include "myenv.h"
  21. #include <ctype.h>
  22. #include <std.h>
  23. #include <fstream.h>
  24.  
  25. #include "voc.h"
  26.  
  27. //------------------------------------------------------------------------
  28. //            Vocabulary of Vocabularies
  29. // Every vocabulary that exists must be in some vocabulary, say, the
  30. // Vocabulary_of_vocabularies
  31. // Vocabulary_of_vocabularies is created statically (actually, before the
  32. // main() program ever begins)
  33.  
  34. class VocOfVoc : public Voc
  35. {
  36. public:
  37.   VocOfVoc(void);
  38.   ~VocOfVoc(void);
  39. };
  40.  
  41. static VocOfVoc Vocabulary_of_vocabularies;
  42.  
  43.                 // Constructor. It is called before main()
  44.                 // starts.
  45. VocOfVoc::VocOfVoc(void)
  46.     : Voc("VocOfVoc","Vocabulary of Vocabularies")
  47. {
  48. }
  49.  
  50.                 // Destructor, it is actually called when
  51.                 // main() finished. It ought to save dirty
  52.                 // vocabularies. But for now, we do nothing
  53. VocOfVoc::~VocOfVoc(void)
  54. {
  55. }
  56.  
  57. void print_all_vocabularies(void)
  58. {
  59.   Vocabulary_of_vocabularies.print("");
  60. }
  61.  
  62. //------------------------------------------------------------------------
  63. //                Vocabulary Path
  64. // is a homegeneous vocabulary of references (VocRef) to other vocabularies,
  65. // which makes them (the vocabularies) be "in the path"
  66. //
  67. // Vocabulary_path defines the current system environment.
  68. // The vocabulary on the top of the Vocabulary_path is the current
  69. // vocabulary
  70.  
  71. class VocPathPrivate : public Voc
  72. {
  73.                 // Find a slot with the specified name and
  74.                 // type. Return 0 if not found
  75.   GenericVocItem * find(const char * _name, const Type type) const;
  76. public:
  77.   VocPathPrivate(void);
  78.   void push(const Voc& voc);    // Make the specified vocabulary current
  79.   void pop(void);        // Remove the top (current) vocabulary
  80. };
  81.  
  82. static VocPathPrivate Vocabulary_path;
  83.  
  84.                 // Like the Vocabulary of Vocabularies,
  85.                 // VocPathPrivate is constructed before the
  86.                 // main() gets control
  87. VocPathPrivate::VocPathPrivate(void)
  88.     : Voc("VocPath","Vocabulary Path")
  89. {
  90.   set_option(Voc::Homogeneous);
  91. }
  92.  
  93.                 // Scour through all vocabularies in the path
  94.                 // for a slot with the specified name and
  95.                 // type. Return 0 if not found
  96. GenericVocItem * VocPathPrivate::find(const char * _name,
  97.                       const Type type) const
  98. {
  99.   for(register GenericVocItem * ip = first; ip != 0; ip=ip->next)
  100.   {
  101.     assert( ip->q_type() == VocRef );
  102.     Voc& curr_voc = *(ip->get_value())._voc;
  103.     if( GenericVocItem * found_item = curr_voc.find(_name,type) )
  104.       return found_item;
  105.   }
  106.   return 0;
  107. }
  108.  
  109. void VocPath::print(void)
  110. {
  111.   Vocabulary_path.print("");
  112. }
  113.  
  114.  
  115.                 // Retrieving functions, raise an exception if
  116.                 // the slot is not found
  117. const char * VocPath::find_str(const char * name)
  118. {
  119.   return Vocabulary_path.find_str(name);
  120. }
  121.  
  122. int VocPath::find_int(const char * name)
  123. {
  124.   return Vocabulary_path.find_int(name);
  125. }
  126.  
  127. double VocPath::find_double(const char * name)
  128. {
  129.   return Vocabulary_path.find_double(name);
  130. }
  131.  
  132. Voc& VocPath::find_voc(const char * name)
  133. {
  134.   return Vocabulary_path.find_voc(name);
  135. }
  136.  
  137.                 // Retrieving functions with a default value
  138.                 // (which is returned if the slot is not found)
  139. const char * VocPath::find_with_default(const char * name, 
  140.                  const char * default_val)
  141. {
  142.   return Vocabulary_path.find_with_default(name,default_val);
  143. }
  144.  
  145. int VocPath::find_with_default(const char * name, 
  146.                  const int default_val)
  147. {
  148.   return Vocabulary_path.find_with_default(name,default_val);
  149. }
  150.  
  151. double VocPath::find_with_default(const char * name, 
  152.                  const double default_val)
  153. {
  154.   return Vocabulary_path.find_with_default(name,default_val);
  155. }
  156.  
  157. Voc& VocPath::find_with_default(const char * name, 
  158.                  Voc& default_val)
  159. {
  160.   return Vocabulary_path.find_with_default(name,default_val);
  161. }
  162.  
  163.                 // Find a vocabulary with a specified name
  164.                 // (in all the vocab in the path) and put it
  165.                 // at the top of the stack
  166. void VocPath::push(const char * name) { Vocabulary_path.push(find_voc(name)); }
  167.  
  168. void VocPathPrivate::push(const Voc& new_curr_ref)
  169. {
  170.   Vocabulary_path += *(new VocRefItem(new_curr_ref));
  171. }
  172.  
  173.                 // Remove the top (current) vocabulary
  174. void VocPath::pop(void)        { Vocabulary_path.pop(); }
  175.  
  176. void VocPathPrivate::pop(void)
  177. {
  178.   GenericVocItem& was_current_vocref = remove_top();
  179.   assert( was_current_vocref.q_type() == VocRef );
  180.   delete &was_current_vocref;
  181. }
  182.  
  183.                 // Note the current state of VocPath
  184. VocPathMark::VocPathMark(void)
  185.     : vocpath_count(Vocabulary_path.count())
  186. {
  187. }
  188.  
  189.                 // Back off to the marked state of VPath
  190. void VocPathMark::back_off(void) const
  191. {
  192.   int new_vocpath_count = Vocabulary_path.count();
  193.   if( new_vocpath_count < vocpath_count )
  194.     _error("Vocabulary Path was popped beyond the noted mark %d, "
  195.        "current count %d",vocpath_count,new_vocpath_count);
  196.  
  197.   for(; new_vocpath_count > vocpath_count; new_vocpath_count--)
  198.     Vocabulary_path.pop();
  199.   assert( new_vocpath_count == Vocabulary_path.count() );
  200. }
  201.  
  202. //------------------------------------------------------------------------
  203. //            Constructing vocabularies
  204.  
  205.                 // Make just an empty vocabulary
  206. Voc::Voc(const char * _name, const char * _comment)
  207.     : GenericVocItem(_name,GenericVocItem::Vocab),
  208.       first(0), last(0)
  209. {
  210.   if( _comment == 0 || _comment[0] == '\0' )
  211.     comment = "";
  212.   else
  213.     comment = strdup(_comment);
  214.   (int &)options = 0;
  215. }
  216.  
  217.                 // We ought to destroy vocabulary items, or
  218.                 // at least, unreference/garbage collect them
  219.                 // But for now, we do nothing
  220. Voc::~Voc(void)
  221. {
  222. }
  223.  
  224. Voc& Dummy_Voc = new_Voc("**Dummy Voc**","Dummy Vocabulary");
  225.  
  226.                 // Add this Voc to the VocOfVoc
  227. void Voc::VocOfVoc_catalog(void)
  228. {
  229.   Vocabulary_of_vocabularies += *this;
  230. }
  231.  
  232.                 // Make this vocabulary current, that is,
  233.                 // create a new entry in the vocabulary_path
  234. void Voc::make_current(void)
  235. {
  236.   VocRefItem& vocref = * new VocRefItem(*this);
  237.   Vocabulary_path += vocref;
  238. }
  239.  
  240.                 // Make sure it's ok to insert a new entry
  241.                 // to the vocabulary; set the dirty bit if 
  242.                 // it is so
  243. void Voc::ok_to_modify(void)
  244. {
  245.   if( check_option(ReadOnly) )
  246.     info(), _error("Can't add new elements to the above vocabulary because "
  247.            "it is read-only");
  248.   set_option(Dirty);
  249. }
  250.  
  251.                 // if the dictionary is homogeneous
  252.                 // and non-empty, the item being added
  253.                 // should be structurally equivalent
  254.                 // to the item on the top of the
  255.                 // dictionary
  256. void Voc::homogenity_checking(GenericVocItem& item)
  257. {
  258.   if( !check_option(Homogeneous) )
  259.     return;                // this is not a homogeneous voc
  260.   if( first == 0 )
  261.     return;                // it's empty - everything goes
  262.   if( item.val_type != (*first).val_type )
  263.     info(), item.GenericVocItem::print("item being added"),
  264.     _error("the above item can't be added to the dictionary because\n"
  265.        "the item is of the wrong type");
  266. }
  267.  
  268.                 // Look up the named vocabulary
  269. VocRefItem::VocRefItem(const char * name)
  270.     : GenericVocItem(name,GenericVocItem::VocRef), 
  271.       value(&(Vocabulary_of_vocabularies.find_voc(name))),
  272.       voc_file_name(0)
  273. {
  274. }
  275.  
  276.                 // Create a proxy; don't rush to load though
  277. VocRefItem::VocRefItem(const char * name, const char * file_name)
  278.     : GenericVocItem(name,GenericVocItem::VocRef),
  279.       value(0),
  280.       voc_file_name(file_name == 0 || file_name[0] == '\0' ? 0 :
  281.             strdup(file_name))
  282. {
  283. }
  284.  
  285.                 // Destroy the reference: do not unload the
  286.                 // VocRef at present
  287. VocRefItem::~VocRefItem(void)
  288. {
  289.   if( voc_file_name != 0 )
  290.     free((char *)voc_file_name);
  291. }
  292.  
  293.             // Unreference the VocRef, and load the referred
  294.             // vocabulary when necessary
  295. GenericVocItem::TypeSet VocRefItem::get_value(void) const
  296. {
  297.   if( value == 0 )            // The Voc isn't loaded
  298.   {                    // - try to find it first
  299.     GenericVocItem * ip = Vocabulary_of_vocabularies.find(name,Vocab);
  300.     if( ip != 0 )
  301.       (*(VocRefItem *)this).value = (ip->get_value())._voc;
  302.   }
  303.  
  304.   if( value == 0 )            // The Voc wasn't loaded: do it now
  305.     (*(VocRefItem *)this).value = &Voc::load(voc_file_name);
  306.  
  307.   TypeSet tset; tset._voc = value; 
  308.   return tset;
  309. }
  310.  
  311. //------------------------------------------------------------------------
  312. //                Constructing/Destructing Voc Items
  313.  
  314.                 // A protected constructor
  315.                 // Just constructs the item (but doesn't
  316.                 // enqueue it) - that's why it's protected
  317. GenericVocItem::GenericVocItem(const char * _name, const Type type)
  318.     : next(0), val_type(type)
  319. {
  320.   register char * pnn;
  321.   register const char * pon;
  322.   for(pnn=name, pon=_name; pnn < name + sizeof(name) && *pon != '\0'; pon++)
  323.     if( ! isprint(*pon) || *pon == '=' )
  324.       _error("GenericVocItem: name '%s' contains an illegal character "
  325.          "'%c' (0x%x)",_name, *pon, *pon);
  326.     else
  327.       *pnn++ = *pon;
  328.   if( *pon != '\0' )
  329.     _error("GenericVocItem: name '%.40s' is too big",_name);
  330.   *pnn = '\0';
  331. }
  332.  
  333.                 // Add this item to the current vocabulary
  334. void GenericVocItem::catalog(void)
  335. {
  336.   (Voc&)*(Vocabulary_path.top().get_value()._voc) += *this;
  337. }
  338.  
  339.                 // Print the name and the type of the item
  340. void GenericVocItem::print(const char * title) const
  341. {
  342.   static char * type_names [Last] =
  343.   { "integer", "double", "string", "vocabulary", "voc reference" };
  344.   message("\n%s item named '%s', '%s' ",type_names[val_type],name,title);
  345. }
  346.  
  347. //------------------------------------------------------------------------
  348. //               Handling specific Voc items
  349.  
  350. StrVocItem::StrVocItem(const char * _name, const char * _val)
  351.     : GenericVocItem(_name,GenericVocItem::String)
  352. {
  353.   value = strdup(_val);
  354. }
  355.  
  356. StrVocItem::~StrVocItem(void)
  357. {
  358.   free((char *)value);
  359. }
  360.  
  361.                 // Printing specific Voc items
  362. void IntVocItem::print(const char * title) const
  363. {
  364.   GenericVocItem::print(title);
  365.   message("value %d\n",value);
  366. }
  367.  
  368. void DoubleVocItem::print(const char * title) const
  369. {
  370.   GenericVocItem::print(title);
  371.   message("value %g\n",value);
  372. }
  373.  
  374. void StrVocItem::print(const char * title) const
  375. {
  376.   GenericVocItem::print(title);
  377.   message("value '%s'\n",value);
  378. }
  379.  
  380. void VocRefItem::print(const char * title) const
  381. {
  382.   GenericVocItem::print(title);
  383.   if( value != 0 )
  384.   {
  385.     assert( (*value).q_type() == Vocab );
  386.     message("loaded\n");
  387.   }
  388.   else if( voc_file_name != 0 )
  389.     message("to be loaded from the file '%s'\n",voc_file_name);
  390.   else
  391.     message("to be resolved\n");
  392. }
  393.  
  394. //------------------------------------------------------------------------
  395. //            Vocabulary operations
  396.  
  397.  
  398.                 // Put a vocabulary item at the top of the
  399.                 // vocabulary
  400. void Voc::operator += (GenericVocItem& item)
  401. {
  402.   ok_to_modify();
  403.   homogenity_checking(item);
  404.  
  405.   assert( item.next == 0 );        // Item isn't in any kind of list
  406.                     // already, right?
  407.   item.next = first;
  408.   if( first == 0 )
  409.   {
  410.     assert( last == 0 );
  411.     last = &item;
  412.   }
  413.   first = &item;
  414. }
  415.  
  416.                 // Remove the item at the top
  417. GenericVocItem& Voc::remove_top(void)
  418. {
  419.   ok_to_modify();
  420.   GenericVocItem * ip = first;
  421.   if( ip == 0 )
  422.     info(),
  423.     _error("can't remove the top element: vocabulary is empty");
  424.  
  425.   if( (first = ip->next) == 0 )
  426.   {
  427.     assert( last == ip );
  428.     last = 0;
  429.   }
  430.   ip->next = 0;                // The element isn't in any chain now
  431.  
  432.   return *ip;
  433. }
  434.  
  435.                 // Peek at the item on the top
  436. const GenericVocItem& Voc::top(void) const
  437. {
  438.   assert( first != 0 );
  439.   return *first;
  440. }
  441.  
  442.                 // Peek at the item at the bottom
  443. const GenericVocItem& Voc::bottom(void) const
  444. {
  445.   assert( last != 0 );
  446.   return *last;
  447. }
  448.  
  449.                 // Count the number of items in a dictionary
  450. int Voc::count(void) const
  451. {
  452.   if( first == 0 )
  453.   {
  454.     assert( last == 0 );
  455.     return 0;
  456.   }
  457.  
  458.   register int cnt;
  459.   register GenericVocItem * ip;
  460.   for(ip=first, cnt=1; ip->next != 0; ip = ip->next)
  461.     cnt++;
  462.   assert( ip == last );        // I want to double-check the Voc consistency:
  463.                 // just being paranoid
  464.   return cnt;
  465. }
  466.  
  467.  
  468.                 // Just give brief info about the voc
  469. void Voc::info(void) const
  470. {
  471.   assert( val_type == Vocab );
  472.   message("\nVocabulary '%s', '%s' (",name,comment);
  473.   if( check_option(ReadOnly) )
  474.     message("ReadOnly ");
  475.   if( check_option(Homogeneous) )
  476.     message("Homogeneous ");
  477.   if( check_option(Dirty) )
  478.     message("Dirty ");
  479.   message(")\n");
  480. }
  481.  
  482.                 // Deep printing of all vocabulary entries
  483. void Voc::print(const char * title) const
  484. {
  485.   info();
  486.   message("\n'%s' contains %d elements\n",title,count());
  487.   if( q_empty() )
  488.     return;
  489.   GenericVocItem * ip;
  490.   for(ip=first; ip != 0; ip = ip->next)
  491.     (*ip).print("voc item");
  492.   message("\n===== done printing vocabulary\n");
  493. }
  494.  
  495. //------------------------------------------------------------------------
  496. //                Search functions
  497.  
  498.                 // Generic search function:
  499.                 // finds a slot with the specified name and
  500.                 // type. Returns 0 if nothing was found
  501. GenericVocItem * Voc::find(const char * _name, const Type type) const
  502. {
  503.   GenericVocItem * ip;
  504.   for(ip=first; ip != 0; ip = ip->next)
  505.     if( strcmp(ip->name,_name) == 0 && ip->val_type == type )
  506.       return ip;
  507.   return 0;
  508. }
  509.  
  510.  
  511.             // Retrieving functions: get a value associated
  512.             // with a specific name in the vocabulary and of
  513.             // the specific time. Raise an exception in case
  514.             // of search failure
  515.  
  516.                 // Look up a string value
  517. const char * Voc::find_str(const char * name) const
  518. {
  519.   GenericVocItem * ip = find(name,GenericVocItem::String);
  520.   if( ip == 0 )
  521.     info(),
  522.     _error("Failed to find a string item '%s' in the above vocabulary",
  523.        name);
  524.   return (ip->get_value())._str;
  525. }
  526.  
  527.                 // Look up an int value
  528. int Voc::find_int(const char * name) const
  529. {
  530.   GenericVocItem * ip = find(name,GenericVocItem::Int);
  531.   if( ip == 0 )
  532.     info(),
  533.     _error("Failed to find an int item '%s' in the above vocabulary",
  534.        name);
  535.   return (ip->get_value())._int;
  536. }
  537.  
  538.                 // Look up a floating-point value
  539. double Voc::find_double(const char * name) const
  540. {
  541.   GenericVocItem * ip = find(name,GenericVocItem::Double);
  542.   if( ip == 0 )
  543.     info(),
  544.     _error("Failed to find a double item '%s' in the above vocabulary",
  545.        name);
  546.   return (ip->get_value())._double;
  547. }
  548.  
  549.                 // Look up a vocabulary value
  550. Voc& Voc::find_voc(const char * name) const
  551. {
  552.   GenericVocItem * ip = find(name,GenericVocItem::Vocab);
  553.   if( ip == 0 )
  554.     ip = find(name,GenericVocItem::VocRef);
  555.  
  556.   if( ip == 0 )
  557.     info(),
  558.     _error("Failed to find a vocabulary item '%s' in the above vocabulary",
  559.        name);
  560.   return *(ip->get_value())._voc;
  561. }
  562.  
  563.             // Retrieving functions with a default value
  564.             // (which is returned if the desired slot is not found)
  565.  
  566.                 // Look up a string value
  567. const char * Voc::find_with_default(const char * name, 
  568.                     const char * default_val) const
  569. {
  570.   GenericVocItem * ip = find(name,GenericVocItem::String);
  571.   if( ip == 0 )
  572.     return default_val;
  573.   return (ip->get_value())._str;
  574. }
  575.  
  576.  
  577.                 // Look up an int value
  578. int Voc::find_with_default(const char * name, 
  579.                const int default_val) const
  580. {
  581.   GenericVocItem * ip = find(name,GenericVocItem::Int);
  582.   if( ip == 0 )
  583.     return default_val;
  584.   return (ip->get_value())._int;
  585. }
  586.  
  587.                 // Look up a floating-point value
  588. double Voc::find_with_default(const char * name, 
  589.                   const double default_val) const
  590. {
  591.   GenericVocItem * ip = find(name,GenericVocItem::Double);
  592.   if( ip == 0 )
  593.     return default_val;
  594.   return (ip->get_value())._double;
  595. }
  596.  
  597.                 // Look up a vocabulary value
  598. Voc& Voc::find_with_default(const char * name, 
  599.                 Voc& default_val) const
  600. {
  601.   GenericVocItem * ip = find(name,GenericVocItem::Vocab);
  602.   if( ip == 0 )
  603.     ip = find(name,GenericVocItem::VocRef);
  604.   if( ip == 0 )
  605.     return default_val;
  606.   return *(ip->get_value())._voc;
  607. }
  608.