util/pup_util.C

Go to the documentation of this file.
00001 /*
00002 Pack/UnPack Library for UIUC Parallel Programming Lab
00003 Orion Sky Lawlor, olawlor@uiuc.edu, 4/5/2000
00004 
00005 This library allows you to easily pack an array, structure,
00006 or object into a memory buffer or disk file, and then read 
00007 the object back later.  The library will also handle translating
00008 between different machine representations.
00009 
00010 This file is needed because virtual function definitions in
00011 header files cause massive code bloat-- hence the PUP library
00012 virtual functions are defined here.
00013 
00014 */
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018 #include <ctype.h>
00019 #include "charm.h"
00020 #include "pup.h"
00021 #include "ckhashtable.h"
00022 
00023 PUP::er::~er() {}
00024 
00025 void PUP::er::operator()(able& a)
00026   {a.pup(*this);}
00027 
00028 void PUP::er::comment(const char *message)
00029   { /* ignored by default */ }
00030 
00031 const char * PUP::er::typeString() const
00032 {
00033   if (isSizing()) return "sizing";
00034   else if (isPacking()) return "packing";
00035   else if (isUnpacking()) return "unpacking";
00036   return "unknown";
00037 }
00038 
00039 void PUP::er::synchronize(unsigned int m)
00040   { /* ignored by default */ }
00041 
00042 /*define CK_CHECK_PUP to get type and bounds checking during Pack and unpack.
00043 This checking substantially slows down PUPing, and increases the space
00044 required by packed objects. It can save hours of debugging, however.
00045 */
00046 #ifdef CK_CHECK_PUP
00047 static int bannerDisplayed=0;
00048 static void showBanner(void) {
00049         bannerDisplayed=1;
00050         fprintf(stderr,"CK_CHECK_PUP pup routine checking enabled\n");
00051         CmiPrintf("CK_CHECK_PUP pup routine checking enabled\n");
00052 }
00053 
00054 class pupCheckRec {
00055         unsigned char magic[4];//Cannot use "int" because of alignment
00056         unsigned char type;
00057         unsigned char length[3];
00058         enum {pupMagic=0xf36c5a21,typeMask=0x75};
00059         int getMagic(void) const {return (magic[3]<<24)+(magic[2]<<16)+(magic[1]<<8)+magic[0];}
00060         void setMagic(int v) {for (int i=0;i<4;i++) magic[i]=(v>>(8*i));}
00061         PUP::dataType getType(void) const {return (PUP::dataType)(type^typeMask);}
00062         void setType(PUP::dataType v) {type=v^typeMask;}
00063         int getLength(void) const {return (length[2]<<16)+(length[1]<<8)+length[0];}
00064         void setLength(int v) {for (int i=0;i<3;i++) length[i]=(v>>(8*i));}
00065         
00066         /*Compare the packed value (from us) and the unpacked value
00067           (from the user).
00068          */
00069         void compare(const char *kind,const char *why,int packed,int unpacked) const
00070         {
00071                 if (packed==unpacked) return;
00072                 //If we get here, there is an error in the user's pack/unpack routine
00073                 fprintf(stderr,"CK_CHECK_PUP error!\nPacked %s (%d, or %08x) does "
00074                         "not equal unpacked value (%d, or %08x)!\nThis means %s\n",
00075                         kind,packed,packed,unpacked,unpacked,why);
00076                 CmiPrintf("CK_CHECK_PUP error! Run with debugger for more info.\n");
00077                 //Invoke the debugger
00078                 abort();
00079         }
00080 public:
00081         void write(PUP::dataType t,int n) {
00082                 if (!bannerDisplayed) showBanner();
00083                 setMagic(pupMagic);
00084                 type=t^typeMask;
00085                 setLength(n);
00086         }
00087         void check(PUP::dataType t,int n) const {
00088                 compare("magic number",
00089                         "you unpacked more than you packed, or the values were corrupted during transport",
00090                         getMagic(),pupMagic);
00091                 compare("data type",
00092                         "the pack and unpack paths do not match up",
00093                         getType(),t);
00094                 compare("length",
00095                         "you may have forgotten to pup the array length",
00096                         getLength(),n);
00097         }
00098 };
00099 #endif
00100 
00101 
00102 void PUP::sizer::bytes(void * /*p*/,int n,size_t itemSize,dataType /*t*/)
00103 {
00104 #ifdef CK_CHECK_PUP
00105         nBytes+=sizeof(pupCheckRec);
00106 #endif
00107 #ifndef CMK_OPTIMIZE
00108         if (n<0) CkAbort("PUP::sizer> Tried to pup a negative number of items!");
00109         const unsigned int maxPupBytes=1024*1024*1024; //Pup 1 GB at a time
00110         if (((unsigned int)(n*itemSize))>maxPupBytes) 
00111                 CkAbort("PUP::sizer> Tried to pup absurdly large number of bytes!");
00112 #endif
00113         nBytes+=n*itemSize;
00114 }
00115 
00116 /*Memory PUP::er's*/
00117 void PUP::toMem::bytes(void *p,int n,size_t itemSize,dataType t)
00118 {
00119 #ifdef CK_CHECK_PUP
00120         ((pupCheckRec *)buf)->write(t,n);
00121         buf+=sizeof(pupCheckRec);
00122 #endif
00123         n*=itemSize;
00124         memcpy((void *)buf,p,n); 
00125         buf+=n;
00126 }
00127 void PUP::fromMem::bytes(void *p,int n,size_t itemSize,dataType t)
00128 {
00129 #ifdef CK_CHECK_PUP
00130         ((pupCheckRec *)buf)->check(t,n);
00131         buf+=sizeof(pupCheckRec);
00132 #endif
00133         n*=itemSize; 
00134         memcpy(p,(const void *)buf,n); 
00135         buf+=n;
00136 }
00137 
00138 /*Disk PUP::er's*/
00139 void PUP::toDisk::bytes(void *p,int n,size_t itemSize,dataType /*t*/)
00140 {/* CkPrintf("writing %d bytes\n",itemSize*n); */ fwrite(p,itemSize,n,F);}
00141 void PUP::fromDisk::bytes(void *p,int n,size_t itemSize,dataType /*t*/)
00142 {/* CkPrintf("reading %d bytes\n",itemSize*n); */ fread(p,itemSize,n,F);}
00143 
00144 /****************** Seek support *******************
00145 For seeking:
00146 Occasionally, one will need to pack and unpack items in different
00147 orders (e.g., pack the user data, then the runtime support; but
00148 unpack the runtime support first, then the user data).  These routines
00149 support this, via the "PUP::seekBlock" class.
00150 
00151 The abstraction is a (nestable) "seek block", which may contain
00152 several "seek sections".  A typical use is:
00153 //Code:
00154         PUP::seekBlock s(p,2);
00155         if (p.isUnpacking()) {s.seek(0); rt.pack(p); }
00156         s.seek(1); ud.pack(p); 
00157         if (p.isPacking()) {s.seek(0); rt.pack(p); }
00158         s.endBlock();
00159 */
00160 PUP::seekBlock::seekBlock(PUP::er &Np,int nSections)
00161         :nSec(nSections),p(Np) 
00162 {
00163         if (nSections<0 || nSections>maxSections)
00164                 CmiAbort("Invalid # of sections passed to PUP::seekBlock!");
00165         p.impl_startSeek(*this);
00166         if (p.isPacking()) 
00167         { //Must fabricate the section table
00168                 secTabOff=p.impl_tell(*this);
00169                 for (int i=0;i<=nSec;i++) secTab[i]=-1;
00170         }
00171         p(secTab,nSec+1);
00172         hasEnded=CmiFalse;
00173 }
00174 PUP::seekBlock::~seekBlock() 
00175 {
00176         if (!hasEnded)
00177                 endBlock();
00178 }
00179 
00180 void PUP::seekBlock::seek(int toSection) 
00181 {
00182         if (toSection<0 || toSection>=nSec)
00183                 CmiAbort("Invalid section # passed to PUP::seekBlock::seek!");
00184         if (p.isPacking()) //Build the section table
00185                 secTab[toSection]=p.impl_tell(*this);
00186         else if (p.isUnpacking()) //Extract the section table
00187                 p.impl_seek(*this,secTab[toSection]);
00188         /*else ignore the seeking*/
00189 }
00190 
00191 void PUP::seekBlock::endBlock(void) 
00192 {
00193         if (p.isPacking()) {
00194                 //Finish off and write out the section table
00195                 secTab[nSec]=p.impl_tell(*this);
00196                 p.impl_seek(*this,secTabOff);
00197                 p(secTab,nSec+1); //Write out the section table
00198         }
00199         //Seek to the end of the seek block
00200         p.impl_seek(*this,secTab[nSec]);
00201         p.impl_endSeek(*this);
00202         hasEnded=CmiTrue;
00203 }
00204 
00206 /*Default seek implementations are empty, which is the 
00207 appropriate behavior for, e.g., sizers.
00208 */
00209 void PUP::er::impl_startSeek(PUP::seekBlock &s) /*Begin a seeking block*/
00210 {}
00211 int PUP::er::impl_tell(seekBlock &s) /*Give the current offset*/
00212 {return 0;}
00213 void PUP::er::impl_seek(seekBlock &s,int off) /*Seek to the given offset*/
00214 {}
00215 void PUP::er::impl_endSeek(seekBlock &s)/*End a seeking block*/
00216 {}
00217 
00218 
00219 /*Memory buffer seeking is trivial*/
00220 void PUP::mem::impl_startSeek(seekBlock &s) /*Begin a seeking block*/
00221   {s.data.ptr=buf;}
00222 int PUP::mem::impl_tell(seekBlock &s) /*Give the current offset*/
00223   {return buf-s.data.ptr;}
00224 void PUP::mem::impl_seek(seekBlock &s,int off) /*Seek to the given offset*/
00225   {buf=s.data.ptr+off;}
00226 
00227 /*Disk buffer seeking is also simple*/
00228 void PUP::disk::impl_startSeek(seekBlock &s) /*Begin a seeking block*/
00229   {s.data.loff=ftell(F);}
00230 int PUP::disk::impl_tell(seekBlock &s) /*Give the current offset*/
00231   {return (int)(ftell(F)-s.data.loff);}
00232 void PUP::disk::impl_seek(seekBlock &s,int off) /*Seek to the given offset*/
00233   {fseek(F,s.data.loff+off,0);}
00234 
00235 /*PUP::wrap_er just forwards seek calls to its wrapped PUP::er.*/
00236 void PUP::wrap_er::impl_startSeek(seekBlock &s) /*Begin a seeking block*/
00237   {p.impl_startSeek(s);}
00238 int PUP::wrap_er::impl_tell(seekBlock &s) /*Give the current offset*/
00239   {return p.impl_tell(s);}
00240 void PUP::wrap_er::impl_seek(seekBlock &s,int off) /*Seek to the given offset*/
00241   {p.impl_seek(s,off);}
00242 void PUP::wrap_er::impl_endSeek(seekBlock &s) /*Finish a seeking block*/
00243   {p.impl_endSeek(s);}
00244   
00245 
00246 /**************** PUP::able support **********************
00247 If a class C inherits from PUP::able, 
00248 and you keep a new/delete pointer to C "C *cptr" somewhere,
00249 you can call "p(cptr)" in your pup routine, and the object
00250 will be saved/delete'd/new'd/restored properly with no 
00251 additional effort, even if C has virtual methods or is actually
00252 a subclass of C.  There is no space or time overhead for C 
00253 objects other than the virtual function.
00254 
00255 This is implemented by registering a constructor and ID
00256 for each PUP::able class.  A packer can then write the ID
00257 before the class; and unpacker can look up the constructor
00258 from the ID.
00259  */
00260 
00261 static PUP::able::PUP_ID null_PUP_ID(0); /*ID of null object*/
00262 
00263 PUP::able *PUP::able::clone(void) const {
00264         // Make a new object to fill out
00265         PUP::able *ret=get_constructor(get_PUP_ID()) ();
00266 
00267         // Save our own state into a buffer
00268         PUP::able *mthis=(PUP::able *)this; /* cast away constness */
00269         int size;
00270         { PUP::sizer ps; mthis->pup(ps); size=ps.size(); }
00271         void *buf=malloc(size);
00272         { PUP::toMem pt(buf); mthis->pup(pt); }
00273         
00274         // Fill the new object with our values
00275         { PUP::fromMem pf(buf); ret->pup(pf); }
00276         free(buf);
00277         
00278         return ret;
00279 }
00280 
00281 //Empty destructor & pup routine
00282 PUP::able::~able() {}
00283 void PUP::able::pup(PUP::er &p) {}
00284 
00285 //Compute a good hash of the given string 
00286 // (registration-time only-- allowed to be slow)
00287 void PUP::able::PUP_ID::setName(const char *name)
00288 {
00289         int i,o,n=strlen(name);
00290         int t[len]={0};
00291         for (o=0;o<n;o++)
00292                 for (i=0;i<len;i++) {
00293                         unsigned char c=name[o];
00294                         int shift1=(((o+2)*(i+1)*5+4)%13);
00295                         int shift2=(((o+2)*(i+1)*3+2)%11)+13;
00296                         t[i]+=(c<<shift1)+(c<<shift2);
00297                 }
00298         for (i=0;i<len;i++) 
00299                 hash[i]=(unsigned char)(t[i]%20117 + t[i]%1217 + t[i]%157);
00300 }
00301 
00302 //Registration routines-- called at global initialization time
00303 class PUP_regEntry {
00304 public:
00305         PUP::able::PUP_ID id;
00306         const char *name;
00307         PUP::able::constructor_function ctor;
00308         PUP_regEntry(const char *Nname,
00309                 const PUP::able::PUP_ID &Nid,PUP::able::constructor_function Nctor)
00310                 :id(Nid),name(Nname),ctor(Nctor) {}
00311         PUP_regEntry(int zero) {
00312                 name=NULL; //For marking "not found"
00313         }
00314 };
00315 
00316 typedef CkHashtableTslow<PUP::able::PUP_ID,PUP_regEntry> PUP_registry;
00317 
00318 static PUP_registry *PUP_getRegistry(void) {
00319         static PUP_registry *reg=NULL;
00320         if (reg==NULL)
00321                 reg=new PUP_registry();
00322         return reg;
00323 }
00324 
00325 const PUP_regEntry *PUP_getRegEntry(const PUP::able::PUP_ID &id)
00326 {
00327         const PUP_regEntry *cur=(const PUP_regEntry *)(
00328                 PUP_getRegistry()->CkHashtable::get((const void *)&id) );
00329         if (cur==NULL)
00330                 CmiAbort("Unrecognized PUP::able::PUP_ID. is there an unregistered module?");
00331         return cur;
00332 }
00333 
00334 PUP::able::PUP_ID PUP::able::register_constructor
00335         (const char *className,constructor_function fn)
00336 {
00337         PUP::able::PUP_ID id(className);
00338         PUP_getRegistry()->put(id)=PUP_regEntry(className,id,fn);
00339         return id;
00340 }
00341 
00342 PUP::able::constructor_function PUP::able::get_constructor
00343         (const PUP::able::PUP_ID &id)
00344 {
00345         return PUP_getRegEntry(id)->ctor;
00346 }
00347 
00348 //For allocatable objects: new/delete object and call pup routine
00349 void PUP::er::object(able** a)
00350 {
00351         const PUP_regEntry *r=NULL;
00352         if (isUnpacking()) 
00353         { //Find the object type & create the object
00354                 PUP::able::PUP_ID id;//The object's id
00355                 id.pup(*this);
00356                 if (id==null_PUP_ID) {*a=NULL; return;}
00357                 r=PUP_getRegEntry(id);
00358                 //Invoke constructor (calls new)
00359                 *a=(r->ctor)();
00360                 
00361         } else {//Just write out the object type
00362                 if (*a==NULL) {
00363                         null_PUP_ID.pup(*this);
00364                         return;
00365                 } else {
00366                         const PUP::able::PUP_ID &id=(*a)->get_PUP_ID();
00367                         id.pup(*this);
00368                         r=PUP_getRegEntry(id);
00369                 }
00370         }
00371         syncComment(PUP::sync_begin_object,r->name);
00372         (*a)->pup(*this);
00373         syncComment(PUP::sync_end_object);
00374 }
00375 
00376 /****************** Text Pup ******************/
00377 
00378 char *PUP::toTextUtil::beginLine(void) {
00379   //Indent level tabs over:
00380   for (int i=0;i<level;i++) cur[i]='\t';
00381   cur[level]=0;
00382   return cur+level;
00383 }
00384 void PUP::toTextUtil::endLine(void) {
00385   cur=advance(cur);
00386 }
00387 void PUP::toTextUtil::beginEnv(const char *type,int n)
00388 {
00389   char *o=beginLine();
00390   sprintf(o,"begin "); o+=strlen(o);
00391   sprintf(o,type,n); o+=strlen(o);
00392   sprintf(o," {\n");
00393   endLine();
00394   level++;
00395 }
00396 void PUP::toTextUtil::endEnv(const char *type)
00397 {
00398   level--;
00399   sprintf(beginLine(),"} end %s;\n",type);
00400   endLine();
00401 }
00402 PUP::toTextUtil::toTextUtil(unsigned int inType,char *buf)
00403   :er(inType)
00404 {
00405   cur=buf;
00406   level=0;
00407 }
00408 
00409 void PUP::toTextUtil::comment(const char *message)
00410 {
00411   sprintf(beginLine(),"//%s\n",message); endLine();
00412 }
00413 
00414 void PUP::toTextUtil::synchronize(unsigned int m)
00415 {
00416   sprintf(beginLine(),"sync=0x%08x\n",m); endLine();
00417 #if 0 /* text people don't care this much about synchronization */
00418   char *o=beginLine();
00419   sprintf(o,"sync=");o+=strlen(o);
00420   const char *consonants="bcdfgjklmprstvxz";
00421   const char *vowels="aeou";
00422   for (int firstBit=0;firstBit<32;firstBit+=6) {
00423         sprintf(o,"%c%c%c", consonants[0xf&(m>>firstBit)],
00424                 vowels[0x3&(m>>(firstBit+4))], 
00425                 (firstBit==30)?';':'-');
00426         o+=strlen(o);
00427   }
00428   sprintf(o,"\n"); endLine();
00429 #endif
00430 }
00431 
00432 void PUP::toTextUtil::bytes(void *p,int n,size_t itemSize,dataType t) {
00433   if (t==Tchar) 
00434   { /*Character data is written out directly (rather than numerically)*/
00435     char *o=beginLine();
00436     sprintf(o,"string=");o+=strlen(o);
00437     *o++='\"'; /*Leading quote*/
00438     /*Copy each character, possibly escaped*/
00439     const char *c=(const char *)p;
00440     for (int i=0;i<n;i++) {
00441       if (c[i]=='\n') {
00442         sprintf(o,"\\n");o+=strlen(o);
00443       } else if (iscntrl(c[i])) {
00444         sprintf(o,"\\x%02X",(unsigned char)c[i]);o+=strlen(o);
00445       } else if (c[i]=='\\' || c[i]=='\"') {
00446         sprintf(o,"\\%c",c[i]);o+=strlen(o);
00447       } else
00448         *o++=c[i];
00449     }
00450     /*Add trailing quote and newline*/
00451     sprintf(o,"\";\n");o+=strlen(o);
00452     endLine();
00453   } else if (t==Tbyte || t==Tuchar)
00454   { /*Byte data is written out in hex (rather than decimal) */
00455     beginEnv("byte %d",n);
00456     const unsigned char *c=(const unsigned char *)p;
00457     char *o=beginLine();
00458     for (int i=0;i<n;i++) {
00459       sprintf(o,"%02X ",c[i]);o+=strlen(o);
00460       if (i%25==24 && (i+1!=n)) 
00461       { /* This line is too long-- wrap it */
00462         sprintf(o,"\n"); o+=strlen(o);
00463         endLine(); o=beginLine();
00464       }
00465     }
00466     sprintf(o,"\n");
00467     endLine();
00468     endEnv("byte");
00469   }
00470   else
00471   { /*Ordinary number-- write out in decimal */
00472     if (n!=1) beginEnv("array %d",n);
00473     for (int i=0;i<n;i++) {
00474       char *o=beginLine();
00475       switch(t) {
00476       case Tshort: sprintf(o,"short=%d;\n",((short *)p)[i]); break;
00477       case Tushort: sprintf(o,"ushort=%u;\n",((unsigned short *)p)[i]); break;
00478       case Tint: sprintf(o,"int=%d;\n",((int *)p)[i]); break;
00479       case Tuint: sprintf(o,"uint=%u;\n",((unsigned int *)p)[i]); break;
00480       case Tlong: sprintf(o,"long=%ld;\n",((long *)p)[i]); break;
00481       case Tulong: sprintf(o,"ulong=%lu;\n",((unsigned long *)p)[i]); break;
00482       case Tfloat: sprintf(o,"float=%.7g;\n",((float *)p)[i]); break;
00483       case Tdouble: sprintf(o,"double=%.15g;\n",((double *)p)[i]); break;
00484       case Tbool: sprintf(o,"bool=%s;\n",((CmiBool *)p)[i]?"true":"false"); break;
00485 #if CMK_LONG_DOUBLE_DEFINED
00486       case Tlongdouble: sprintf(o,"longdouble=%Lg;\n",((long double *)p)[i]);break;
00487 #endif
00488 #ifdef CMK_PUP_LONG_LONG
00489       case Tlonglong: sprintf(o,"longlong=%lld;\n",((CMK_PUP_LONG_LONG *)p)[i]);break;
00490       case Tulonglong: sprintf(o,"ulonglong=%llu;\n",((unsigned CMK_PUP_LONG_LONG *)p)[i]);break;
00491 #endif
00492       case Tpointer: sprintf(o,"pointer=%p;\n",((void **)p)[i]); break;
00493       default: CmiAbort("Unrecognized pup type code!");
00494       }
00495       endLine();
00496     }
00497     if (n!=1) endEnv("array");
00498   }
00499 }
00500 void PUP::toTextUtil::object(able** a) {
00501   beginEnv("object");
00502   er::object(a);
00503   endEnv("object");
00504 }
00505 
00506 
00507 //Text sizer
00508 char *PUP::sizerText::advance(char *cur) {
00509   charCount+=strlen(cur);
00510   return line;
00511 }
00512 
00513 PUP::sizerText::sizerText(void)
00514   :toTextUtil(IS_SIZING+IS_COMMENTS,line),charCount(0) { }
00515 
00516 //Text packer
00517 char *PUP::toText::advance(char *cur) {
00518   charCount+=strlen(cur);
00519   return buf+charCount;
00520 }
00521 
00522 PUP::toText::toText(char *outBuf)
00523   :toTextUtil(IS_PACKING+IS_COMMENTS,outBuf),buf(outBuf),charCount(0) { }
00524 
00525 /************** To/from text FILE ****************/
00526 void PUP::toTextFile::bytes(void *p,int n,size_t itemSize,dataType t)
00527 {
00528   for (int i=0;i<n;i++) 
00529     switch(t) {
00530     case Tchar: fprintf(f," '%c'",((char *)p)[i]); break;
00531     case Tuchar:
00532     case Tbyte: fprintf(f," %02X",((unsigned char *)p)[i]); break;
00533     case Tshort: fprintf(f," %d",((short *)p)[i]); break;
00534     case Tushort: fprintf(f," %u",((unsigned short *)p)[i]); break;
00535     case Tint: fprintf(f," %d",((int *)p)[i]); break;
00536     case Tuint: fprintf(f," %u",((unsigned int *)p)[i]); break;
00537     case Tlong: fprintf(f," %ld",((long *)p)[i]); break;
00538     case Tulong: fprintf(f," %lu",((unsigned long *)p)[i]); break;
00539     case Tfloat: fprintf(f," %.7g",((float *)p)[i]); break;
00540     case Tdouble: fprintf(f," %.15g",((double *)p)[i]); break;
00541     case Tbool: fprintf(f," %s",((CmiBool *)p)[i]?"true":"false"); break;
00542 #if CMK_LONG_DOUBLE_DEFINED
00543     case Tlongdouble: fprintf(f," %Lg",((long double *)p)[i]);break;
00544 #endif
00545 #ifdef CMK_PUP_LONG_LONG
00546     case Tlonglong: fprintf(f," %lld",((CMK_PUP_LONG_LONG *)p)[i]);break;
00547     case Tulonglong: fprintf(f," %llu",((unsigned CMK_PUP_LONG_LONG *)p)[i]);break;
00548 #endif
00549     case Tpointer: fprintf(f," %p",((void **)p)[i]); break;
00550     default: CmiAbort("Unrecognized pup type code!");
00551     };
00552   fprintf(f,"\n");
00553 }
00554 void PUP::toTextFile::comment(const char *message)
00555 {
00556   fprintf(f,"! %s\n",message);
00557 }
00558 
00559 void PUP::fromTextFile::parseError(const char *what) {
00560   // find line number by counting how many returns
00561   long cur = ftell(f);
00562   int lineno=0;
00563   rewind(f);
00564   while (!feof(f)) {
00565      char c;
00566      fscanf(f,"%c",&c);
00567      if (c=='\n') lineno++;
00568      if (ftell(f) > cur) break;
00569   }
00570   fprintf(stderr,"Parse error during pup from text file: %s at line: %d\n",what, lineno);
00571   CmiAbort("Parse error during pup from text file!\n");
00572 }
00573 int PUP::fromTextFile::readInt(const char *fmt) {
00574   int ret=0;
00575   if (1!=fscanf(f,fmt,&ret)) {
00576         if (feof(f)) return 0; /* start spitting out zeros at EOF */
00577         else parseError("could not match integer");
00578   }
00579   return ret;
00580 }
00581 unsigned int PUP::fromTextFile::readUint(const char *fmt) {
00582   unsigned int ret=0;
00583   if (1!=fscanf(f,fmt,&ret))  {
00584         if (feof(f)) return 0u; /* start spitting out zeros at EOF */
00585         else parseError("could not match unsigned integer");
00586   }
00587   return ret;  
00588 }
00589 CMK_TYPEDEF_INT8 PUP::fromTextFile::readLongInt(const char *fmt) {
00590   CMK_TYPEDEF_INT8 ret=0;
00591   if (1!=fscanf(f,fmt,&ret)) {
00592     if (feof(f)) return 0u;
00593     else parseError("could not match large integer");
00594   }
00595   return ret;
00596 }
00597 double PUP::fromTextFile::readDouble(void) {
00598   double ret=0;
00599   if (1!=fscanf(f,"%lg",&ret)) {
00600         if (feof(f)) return 0.0; /* start spitting out zeros at EOF */
00601         else parseError("could not match double");
00602   }
00603   return ret;
00604 }
00605 void PUP::fromTextFile::bytes(void *p,int n,size_t itemSize,dataType t)
00606 {
00607   for (int i=0;i<n;i++) 
00608     switch(t) {
00609     case Tchar: 
00610       if (1!=fscanf(f," '%c'",&((char *)p)[i]))
00611         parseError("Could not match character");
00612       break;
00613     case Tuchar:
00614     case Tbyte: ((unsigned char *)p)[i]=(unsigned char)readInt("%02X"); break;
00615     case Tshort:((short *)p)[i]=(short)readInt(); break;
00616     case Tushort: ((unsigned short *)p)[i]=(unsigned short)readUint(); break;
00617     case Tint:  ((int *)p)[i]=readInt(); break;
00618     case Tuint: ((unsigned int *)p)[i]=readUint(); break;
00619     case Tlong: ((long *)p)[i]=readInt(); break;
00620     case Tulong:((unsigned long *)p)[i]=readUint(); break;
00621     case Tfloat: ((float *)p)[i]=(float)readDouble(); break;
00622     case Tdouble:((double *)p)[i]=readDouble(); break;
00623 #if CMK_LONG_DOUBLE_DEFINED
00624     case Tlongdouble: {
00625       long double ret=0;
00626       if (1!=fscanf(f,"%Lg",&ret)) parseError("could not match long double");
00627       ((long double *)p)[i]=ret;
00628     } break;
00629 #endif
00630 #ifdef CMK_PUP_LONG_LONG
00631     case Tlonglong: {
00632       CMK_PUP_LONG_LONG ret=0;
00633       if (1!=fscanf(f,"%lld",&ret)) parseError("could not match long long");
00634       ((CMK_PUP_LONG_LONG *)p)[i]=ret;
00635     } break;
00636     case Tulonglong: {
00637       unsigned CMK_PUP_LONG_LONG ret=0;
00638       if (1!=fscanf(f,"%llu",&ret)) parseError("could not match unsigned long long");
00639       ((unsigned CMK_PUP_LONG_LONG *)p)[i]=ret;
00640     } break;
00641 #endif
00642     case Tbool: {
00643       char tmp[20];
00644       if (1!=fscanf(f," %20s",tmp)) parseError("could not read boolean string");
00645       CmiBool val=CmiFalse;
00646       if (0==strcmp(tmp,"true")) val=CmiTrue;
00647       else if (0==strcmp(tmp,"false")) val=CmiFalse;
00648       else parseError("could not recognize boolean string");
00649       ((CmiBool *)p)[i]=val; 
00650     }
00651       break;
00652     case Tpointer: {
00653       void *ret=0;
00654       if (1!=fscanf(f,"%p",&ret)) parseError("could not match pointer");
00655       ((void **)p)[i]=ret;
00656     } break;
00657     default: CmiAbort("Unrecognized pup type code!");
00658     };
00659 }
00660 void PUP::fromTextFile::comment(const char *message)
00661 {
00662   char c;
00663   //Skip to the start of the message:
00664   while (isspace(c=fgetc(f))) {}
00665   
00666   if (c!='!') return; //This isn't the start of a comment
00667   //Skip over the whole line containing the comment:
00668   char *commentBuf=(char *)CmiTmpAlloc(1024);
00669   fgets(commentBuf,1024,f);
00670   CmiTmpFree(commentBuf);
00671 }
00672 
00673 
00674 
00675 
00676 
00677 
00678 

Generated on Sun Jun 29 13:29:27 2008 for Charm++ by  doxygen 1.5.1