Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

FV2.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Fri Apr 22 17:24:07 EDT 2005 by ken@xorian.net        
00020 //      modified on Sat Aug 22 17:21:31 PDT 1998 by heydon
00021 
00022 #include <Basics.H>
00023 #include <Generics.H>
00024 #include <SRPC.H>
00025 #include <sstream>
00026 
00027 #include "FV2.H"
00028 
00029 using std::ostream;
00030 using std::ostringstream;
00031 
00032 // delimeter between names of a FV2::T when marshalled/unmarshalled
00033 /* For now, we are using a printing character to make debugging easier,
00034    but for safety, it would probably be better to use a non-printing character
00035    like '\001' that cannot appear in an Arc. */
00036 const char Delim = '/';
00037 
00038 /* FV2::T ------------------------------------------------------------------ */
00039 
00040 // max expected FV::T length
00041 const int MaxLen = 128;
00042 
00043 void FV2::T::FromStr(const char *str, const char delim) throw ()
00044 {
00045     const char *start = str;
00046     while (true) {
00047         const char *match = index(start, (int)delim);
00048         if (match != NULL) {
00049             int subLen = (match - start); // length of the substring
00050             this->addhi(Text(start, subLen));
00051             start = match + 1;
00052         } else {
00053             this->addhi(Text(start));
00054             break;
00055         }
00056     }
00057 }
00058 
00059 char* FV2::T::ToStr(char *buff, const int sz, char delim, char type)
00060   const throw ()
00061 /* We don't know ahead of time how large the string will be, so there are
00062    two cases.
00063 
00064    In the fast case, we attempt to write the Text's into a fixed-length buffer
00065    allocated on the stack. Before writing each string, we test that there is
00066    sufficient space for that string and the 'Delim' character following it.
00067 
00068    In the slow case, we allocate a buffer on the heap and write the string
00069    into it. This requires us to count the lengths of the remaining strings
00070    to see how large the buffer needs to be. */
00071 {
00072     char *res = buff;
00073 
00074     // fast case: attempt to fill in "buff"
00075     int i;
00076     int totalLen;
00077     if (type != '\0') {
00078         assert(sz >= 2);
00079         res[0] = type;
00080         res[1] = delim;
00081         totalLen = 2;
00082     } else {
00083         totalLen = 0;
00084     }
00085     for (i = 0; i < this->size(); i++) {
00086         Text txt = this->get(i);
00087         int len = txt.Length();
00088         if (totalLen + len >= sz) break;
00089         memcpy(res+totalLen, txt.cchars(), len);
00090         totalLen += len;
00091         res[totalLen++] = delim;
00092     }
00093 
00094     // test if fast case succeeded
00095     if (i < this->size()) {
00096         // slow case
00097 
00098         // count total length of string
00099         int curr = totalLen; // current length
00100         for (int j = i; j < this->size(); j++) {
00101             totalLen += this->get(j).Length() + 1; // include 1 for each Delim
00102         }
00103 
00104         // allocate the new buffer and copy strings so far
00105         char *newBuff = NEW_PTRFREE_ARRAY(char, totalLen);
00106         memcpy(newBuff, res, curr);
00107         res = newBuff;
00108 
00109         // copy the remaining strings
00110         for (/*SKIP*/; i < this->size(); i++) {
00111             Text txt = this->get(i);
00112             int len = txt.Length();
00113             assert(curr + len < totalLen);
00114             memcpy(res+curr, txt.cchars(), len);
00115             curr += len;
00116             res[curr++] = delim;
00117         }
00118         assert(curr == totalLen);
00119     }
00120     totalLen--;
00121     res[totalLen] = '\0';
00122     return res;
00123 }
00124 
00125 Text FV2::T::ToText(const char delim) const throw ()
00126 {
00127     char fixedBuff[MaxLen];
00128     char *buff = ToStr(fixedBuff, MaxLen, delim);
00129     return Text(buff);
00130 }
00131 
00132 void FV2::T::Send(SRPC &srpc, char type) const throw (SRPC::failure)
00133 {
00134     char stackBuff[MaxLen];
00135     char *buff = this->ToStr(stackBuff, MaxLen, Delim, type);
00136 
00137     // If any of the arcs contain the delimiter, we're in trouble.
00138     // Should be fixed in a future version by marshallaing in a way
00139     // that allows any character in an arc.
00140     bool l_bad_arc = false;
00141     unsigned int l_bad_arc_index = 0;
00142     for (unsigned int i = 0; !l_bad_arc && (i < this->size()); i++)
00143       {
00144         if(this->get(i).FindChar(Delim) != -1)
00145           {
00146             l_bad_arc = true;
00147             l_bad_arc_index = i;
00148           }
00149       }
00150     // If we found a bad arc, generate a detailed error message and
00151     // throw SRPC::failure with the invalid_parameter error code.
00152     if(l_bad_arc)
00153       {
00154         ostringstream l_msg;
00155         l_msg << "Free variable arc containing delimiter character ('" << Delim << "'):\n"
00156               << "    arc = " << this->get(l_bad_arc_index) << "\n"
00157               << "    path = " << buff;
00158 
00159         throw SRPC::failure(SRPC::invalid_parameter, Text(l_msg.str()));
00160       }
00161 
00162     // send the string
00163     srpc.send_chars(buff);
00164 }
00165 
00166 ostream& operator << (ostream &os, const FV2::T &t) throw ()
00167 {
00168   t.Print(os);
00169   return os;
00170 }
00171 
00172 void FV2::T::Print(ostream &os) const throw()
00173 {
00174     char fixedBuff[MaxLen];
00175     char *buff = this->ToStr(fixedBuff, MaxLen, '/');
00176     os << buff;
00177 }
00178 
00179 /* FV2::List --------------------------------------------------------------- */
00180 
00181 void FV2::List::Send(SRPC &srpc, const char *types) const throw (SRPC::failure)
00182 /* Note: The following must agree with the "FV::List::Recv" method
00183    in "FV.C". This method is only called to send the free variables
00184    for the "AddEntry" method. */
00185 {
00186     srpc.send_seq_start(this->len);
00187     for (int i = 0; i < this->len; i++) {
00188         this->name[i]->Send(srpc, types[i]);
00189     }
00190     srpc.send_seq_end();
00191 }
00192 
00193 int FV2::ListApp::Append(FV2::T *s) throw ()
00194 {
00195     int res;
00196     if (len == maxLen) {
00197         maxLen = max(2, 2 * maxLen);
00198         assert(maxLen > len);
00199         FV2::TPtr *newNames = NEW_ARRAY(FV2::TPtr, maxLen);
00200         if (name != (FV2::TPtr *)NULL) {
00201             for (int i = 0; i < len; i++) newNames[i] = name[i];
00202         }
00203         name = newNames;
00204     }
00205     res = len;
00206     name[len++] = s;
00207     return res;
00208 }
00209 
00210 ostream& operator << (ostream &os, const FV2::List &names) throw ()
00211 {
00212     os << "{ ";
00213     for (int i = 0; i < names.len; i++) {
00214         os << "\"" << names.name[i] << "\"";
00215         if (i < names.len - 1) os << ", ";
00216     }
00217     os << " }";
00218     return os;
00219 }
00220 
00221 inline void Indent(ostream &os, int indent) throw ()
00222 {
00223     for (int i = 0; i < indent; i++) os << " ";
00224 }
00225 
00226 void FV2::List::Print(ostream &os, int indent, const char *types) const
00227   throw ()
00228 {
00229     if (this->len > 0) {
00230         for (int i = 0; i < this->len; i++) {
00231             Indent(os, indent);
00232 #if 0
00233             // Verbose printing code to make each arc distinct, even
00234             // if the arcs contain '/'.
00235             os << "nm[" << i << "] = ";
00236             os << types[i] << " <\"";
00237             for (int j = 0; j < this->name[i]->size(); j++)
00238               {
00239                 if(j > 0)
00240                   {
00241                     os << "\", \"";
00242                   }
00243                 os << this->name[i]->get(j);
00244               }
00245             os << "\">" << endl;
00246 #else
00247             os << "nm[" << i << "] = \"";
00248             os << types[i] << '/' << *(this->name[i]) << "\"\n";
00249 #endif
00250         }
00251     } else {
00252         Indent(os, indent);
00253         os << "<< no names >>\n";
00254     }
00255 }

Generated on Mon May 8 00:48:32 2006 for Vesta by  doxygen 1.4.2