Cleanup sources of various compiler warnings
[charm.git] / src / util / pup_util.C
blobeffa0867fc0092f954eaaa1d8a1aa0583cca733f
1 /*
2 Pack/UnPack Library for UIUC Parallel Programming Lab
3 Orion Sky Lawlor, olawlor@uiuc.edu, 4/5/2000
5 This library allows you to easily pack an array, structure,
6 or object into a memory buffer or disk file, and then read 
7 the object back later.  The library will also handle translating
8 between different machine representations.
10 This file is needed because virtual function definitions in
11 header files cause massive code bloat-- hence the PUP library
12 virtual functions are defined here.
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <errno.h>
20 #include <fcntl.h>
22 #include "converse.h"
23 #include "pup.h"
24 #include "ckhashtable.h"
26 #if defined(_WIN32)
27 #include <io.h>
29 int pwrite(int fd, const void *buf, size_t nbytes, __int64 offset)
31   __int64 ret = _lseek(fd, offset, SEEK_SET);
33   if (ret == -1) {
34     return(-1);
35   }
36   return(_write(fd, buf, nbytes));
38 #define NO_UNISTD_NEEDED
39 #endif
41 #if defined(__PGIC__)
42 // PGI compilers define funny feature flags that lead to standard
43 // headers omitting this prototype
45 extern "C" {
47 extern ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
49 #define NO_UNISTD_NEEDED
50 #endif
52 #if !defined(NO_UNISTD_NEEDED)
53 #include <unistd.h>
54 #endif
56 PUP::er::~er() {}
58 void PUP::er::operator()(able& a)
59   {a.pup(*this);}
61 void PUP::er::comment(const char *message)
62   { /* ignored by default */ }
64 const char * PUP::er::typeString() const
66   if (isSizing()) return "sizing";
67   else if (isPacking()) return "packing";
68   else if (isUnpacking()) return "unpacking";
69   return "unknown";
72 void PUP::er::synchronize(unsigned int m)
73   { /* ignored by default */ }
75 /*define CK_CHECK_PUP to get type and bounds checking during Pack and unpack.
76 This checking substantially slows down PUPing, and increases the space
77 required by packed objects. It can save hours of debugging, however.
79 #ifdef CK_CHECK_PUP
80 static int bannerDisplayed=0;
81 static void showBanner(void) {
82         bannerDisplayed=1;
83         fprintf(stderr,"CK_CHECK_PUP pup routine checking enabled\n");
84         CmiPrintf("CK_CHECK_PUP pup routine checking enabled\n");
87 class pupCheckRec {
88         unsigned char magic[4];//Cannot use "int" because of alignment
89         unsigned char type;
90         unsigned char length[8];
91         enum {pupMagic=0xf36c5a21,typeMask=0x75};
92         int getMagic(void) const {return (magic[3]<<24)+(magic[2]<<16)+(magic[1]<<8)+magic[0];}
93         void setMagic(int v) {for (int i=0;i<4;i++) magic[i]=(v>>(8*i));}
94         PUP::dataType getType(void) const {return (PUP::dataType)(type^typeMask);}
95         void setType(PUP::dataType v) {type=v^typeMask;}
96         size_t getLength(void) const {
97           size_t v = 0;
98           for (int i=0;i<8;i++) v += (length[i]<<(8*i));
99           return v;
100         }
101         void setLength(size_t v) {for (int i=0;i<8;i++) length[i]=(v>>(8*i));}
102         
103         /*Compare the packed value (from us) and the unpacked value
104           (from the user).
105          */
106         void compare(const char *kind,const char *why,int packed,int unpacked) const
107         {
108                 if (packed==unpacked) return;
109                 //If we get here, there is an error in the user's pack/unpack routine
110                 fprintf(stderr,"CK_CHECK_PUP error!\nPacked %s (%d, or %08x) does "
111                         "not equal unpacked value (%d, or %08x)!\nThis means %s\n",
112                         kind,packed,packed,unpacked,unpacked,why);
113                 CmiPrintf("CK_CHECK_PUP error! Run with debugger for more info.\n");
114                 //Invoke the debugger
115                 abort();
116         }
117 public:
118         void write(PUP::dataType t,size_t n) {
119                 if (!bannerDisplayed) showBanner();
120                 setMagic(pupMagic);
121                 type=t^typeMask;
122                 setLength(n);
123         }
124         void check(PUP::dataType t,size_t n) const {
125                 compare("magic number",
126                         "you unpacked more than you packed, or the values were corrupted during transport",
127                         getMagic(),pupMagic);
128                 compare("data type",
129                         "the pack and unpack paths do not match up",
130                         getType(),t);
131                 compare("length",
132                         "you may have forgotten to pup the array length",
133                         getLength(),n);
134         }
136 #endif
139 void PUP::sizer::bytes(void * /*p*/,size_t n,size_t itemSize,dataType /*t*/)
141 #ifdef CK_CHECK_PUP
142         nBytes+=sizeof(pupCheckRec);
143 #endif
144         nBytes+=n*itemSize;
147 /*Memory PUP::er's*/
148 void PUP::toMem::bytes(void *p,size_t n,size_t itemSize,dataType t)
150 #ifdef CK_CHECK_PUP
151         ((pupCheckRec *)buf)->write(t,n);
152         buf+=sizeof(pupCheckRec);
153 #endif
154         n*=itemSize;
155         memcpy((void *)buf,p,n); 
156         buf+=n;
158 void PUP::fromMem::bytes(void *p,size_t n,size_t itemSize,dataType t)
160 #ifdef CK_CHECK_PUP
161         ((pupCheckRec *)buf)->check(t,n);
162         buf+=sizeof(pupCheckRec);
163 #endif
164         n*=itemSize; 
165         memcpy(p,(const void *)buf,n); 
166         buf+=n;
169 extern "C" {
171 int CmiOpen(const char *pathname, int flags, int mode)
173         int fd = -1;
174         while (1) {
175 #if defined(_WIN32)
176           fd = _open(pathname, flags, mode);
177 #else
178           fd = open(pathname, flags, mode);
179 #endif
180           if (fd == -1 && errno==EINTR) {
181             CmiError("Warning: CmiOpen retrying on %s\n", pathname);
182             continue;
183           }
184           else
185             break;
186         }
187         return fd;
190 // dealing with short write
191 size_t CmiFwrite(const void *ptr, size_t size, size_t nmemb, FILE *f)
193         size_t nwritten = 0;
194         const char *buf = (const char *)ptr;
195         double firsttime = 0;
196         while (nwritten < nmemb) {
197           size_t ncur = fwrite(buf+nwritten*size,size,nmemb-nwritten,f);
198           if (ncur <= 0) {
199             if  (errno == EINTR)
200               CmiError("Warning: CmiFwrite retrying ...\n");
201             else if(errno == ENOMEM)
202             {
203 #ifndef CMK_BIGSIM_CHARM
204               if(firsttime == 0) firsttime = CmiWallTimer();
205               if(CmiWallTimer()-firsttime > 300)
206                 break;
207 #endif
208             }
209             else
210               break;
211           }
212           else
213             nwritten += ncur;
214         }
215 #ifndef CMK_BIGSIM_CHARM
216         if(firsttime != 0)
217           CmiError("Warning: CmiFwrite retried for %lf ...\n", CmiWallTimer() - firsttime);
218 #endif
220         return nwritten;
223 CmiInt8 CmiPwrite(int fd, const char *buf, size_t bytes, size_t offset)
225   size_t origBytes = bytes;
226   while (bytes > 0) {
227     CmiInt8 ret = pwrite(fd, buf, bytes, offset);
228     if (ret < 0) {
229       if (errno == EINTR) {
230         continue;
231       } else {
232         return ret;
233       }
234     }
235     bytes -= ret;
236     buf += ret;
237     offset += ret;
238   }
239   return origBytes;
242 size_t CmiFread(void *ptr, size_t size, size_t nmemb, FILE *f)
244         size_t nread = 0;
245         char *buf = (char *)ptr;
246         while (nread < nmemb) {
247           size_t ncur = fread(buf + nread*size, size, nmemb-nread, f);
248           if (ncur <= 0) {
249             if  (errno == EINTR)
250               CmiError("Warning: CmiFread retrying ...\n");
251             else
252               break;
253           }
254           else
255             nread += ncur;
256         }
257         return nread;
260 FILE *CmiFopen(const char *path, const char *mode)
262         FILE *fp = NULL;
263         while (1) {
264           fp = fopen(path, mode);
265           if (fp == 0 && errno==EINTR) {
266             CmiError("Warning: CmiFopen retrying on %s\n", path);
267             continue;
268           }
269           else
270             break;
271         }
272         return fp;
275 // more robust fclose that handling interrupt
276 int CmiFclose(FILE *fp)
278         int status = 0;
279         while (1) {
280           status = fflush(fp);
281           if (status != 0 && errno==EINTR) {
282             CmiError("Warning: CmiFclose flush retrying ...\n");
283             continue;
284           }
285           else
286             break;
287         }
288         if (status != 0) return status;
289         while (1) {
290           status = fclose(fp);
291           if (status != 0 && errno==EINTR) {
292             CmiError("Warning: CmiFclose retrying ...\n");
293             continue;
294           }
295           else
296             break;
297         }
298         return status;
301 } // extern "C"
303 /*Disk PUP::er's*/
304 void PUP::toDisk::bytes(void *p,size_t n,size_t itemSize,dataType /*t*/)
305 {/* CkPrintf("writing %d bytes\n",itemSize*n); */ 
306   if(CmiFwrite(p,itemSize,n,F) != n)
307   {
308     error = true;
309   }
311 void PUP::fromDisk::bytes(void *p,size_t n,size_t itemSize,dataType /*t*/)
312 {/* CkPrintf("reading %d bytes\n",itemSize*n); */ CmiFread(p,itemSize,n,F);}
314 /****************** Seek support *******************
315 For seeking:
316 Occasionally, one will need to pack and unpack items in different
317 orders (e.g., pack the user data, then the runtime support; but
318 unpack the runtime support first, then the user data).  These routines
319 support this, via the "PUP::seekBlock" class.
321 The abstraction is a (nestable) "seek block", which may contain
322 several "seek sections".  A typical use is:
323 //Code:
324         PUP::seekBlock s(p,2);
325         if (p.isUnpacking()) {s.seek(0); rt.pack(p); }
326         s.seek(1); ud.pack(p); 
327         if (p.isPacking()) {s.seek(0); rt.pack(p); }
328         s.endBlock();
330 PUP::seekBlock::seekBlock(PUP::er &Np,int nSections)
331         :nSec(nSections),p(Np) 
333         if (nSections<0 || nSections>maxSections)
334                 CmiAbort("Invalid # of sections passed to PUP::seekBlock!");
335         p.impl_startSeek(*this);
336         if (p.isPacking()) 
337         { //Must fabricate the section table
338                 secTabOff=p.impl_tell(*this);
339                 for (int i=0;i<=nSec;i++) secTab[i]=-1;
340         }
341         p(secTab,nSec+1);
342         hasEnded=false;
344 PUP::seekBlock::~seekBlock() 
346         if (!hasEnded)
347                 endBlock();
350 void PUP::seekBlock::seek(int toSection) 
352         if (toSection<0 || toSection>=nSec)
353                 CmiAbort("Invalid section # passed to PUP::seekBlock::seek!");
354         if (p.isPacking()) //Build the section table
355                 secTab[toSection]=p.impl_tell(*this);
356         else if (p.isUnpacking()) //Extract the section table
357                 p.impl_seek(*this,secTab[toSection]);
358         /*else ignore the seeking*/
361 void PUP::seekBlock::endBlock(void) 
363         if (p.isPacking()) {
364                 //Finish off and write out the section table
365                 secTab[nSec]=p.impl_tell(*this);
366                 p.impl_seek(*this,secTabOff);
367                 p(secTab,nSec+1); //Write out the section table
368         }
369         //Seek to the end of the seek block
370         p.impl_seek(*this,secTab[nSec]);
371         p.impl_endSeek(*this);
372         hasEnded=true;
375 /** PUP::er seek implementation routines **/
376 /*Default seek implementations are empty, which is the 
377 appropriate behavior for, e.g., sizers.
379 void PUP::er::impl_startSeek(PUP::seekBlock &s) /*Begin a seeking block*/
381 size_t PUP::er::impl_tell(seekBlock &s) /*Give the current offset*/
382 {return 0;}
383 void PUP::er::impl_seek(seekBlock &s,size_t off) /*Seek to the given offset*/
385 void PUP::er::impl_endSeek(seekBlock &s)/*End a seeking block*/
389 /*Memory buffer seeking is trivial*/
390 void PUP::mem::impl_startSeek(seekBlock &s) /*Begin a seeking block*/
391   {s.data.ptr=buf;}
392 size_t PUP::mem::impl_tell(seekBlock &s) /*Give the current offset*/
393   {return buf-s.data.ptr;}
394 void PUP::mem::impl_seek(seekBlock &s,size_t off) /*Seek to the given offset*/
395   {buf=s.data.ptr+off;}
397 /*Disk buffer seeking is also simple*/
398 void PUP::disk::impl_startSeek(seekBlock &s) /*Begin a seeking block*/
399   {s.data.loff=ftell(F);}
400 size_t PUP::disk::impl_tell(seekBlock &s) /*Give the current offset*/
401   {return (int)(ftell(F)-s.data.loff);}
402 void PUP::disk::impl_seek(seekBlock &s,size_t off) /*Seek to the given offset*/
403   {fseek(F,s.data.loff+off,0);}
405 /*PUP::wrap_er just forwards seek calls to its wrapped PUP::er.*/
406 void PUP::wrap_er::impl_startSeek(seekBlock &s) /*Begin a seeking block*/
407   {p.impl_startSeek(s);}
408 size_t PUP::wrap_er::impl_tell(seekBlock &s) /*Give the current offset*/
409   {return p.impl_tell(s);}
410 void PUP::wrap_er::impl_seek(seekBlock &s,size_t off) /*Seek to the given offset*/
411   {p.impl_seek(s,off);}
412 void PUP::wrap_er::impl_endSeek(seekBlock &s) /*Finish a seeking block*/
413   {p.impl_endSeek(s);}
414   
416 /**************** PUP::able support **********************
417 If a class C inherits from PUP::able, 
418 and you keep a new/delete pointer to C "C *cptr" somewhere,
419 you can call "p(cptr)" in your pup routine, and the object
420 will be saved/delete'd/new'd/restored properly with no 
421 additional effort, even if C has virtual methods or is actually
422 a subclass of C.  There is no space or time overhead for C 
423 objects other than the virtual function.
425 This is implemented by registering a constructor and ID
426 for each PUP::able class.  A packer can then write the ID
427 before the class; and unpacker can look up the constructor
428 from the ID.
429  */
431 static PUP::able::PUP_ID null_PUP_ID(0); /*ID of null object*/
433 PUP::able *PUP::able::clone(void) const {
434         // Make a new object to fill out
435         PUP::able *ret=get_constructor(get_PUP_ID()) ();
437         // Save our own state into a buffer
438         PUP::able *mthis=(PUP::able *)this; /* cast away constness */
439         size_t size;
440         { PUP::sizer ps; mthis->pup(ps); size=ps.size(); }
441         void *buf=malloc(size);
442         { PUP::toMem pt(buf); mthis->pup(pt); }
443         
444         // Fill the new object with our values
445         { PUP::fromMem pf(buf); ret->pup(pf); }
446         free(buf);
447         
448         return ret;
451 //Empty destructor & pup routine
452 PUP::able::~able() {}
453 void PUP::able::pup(PUP::er &p) {}
455 //Compute a good hash of the given string 
456 // (registration-time only-- allowed to be slow)
457 void PUP::able::PUP_ID::setName(const char *name)
459         int i,o,n=strlen(name);
460         unsigned int t[len]={0};
461         for (o=0;o<n;o++)
462                 for (i=0;i<len;i++) {
463                         unsigned char c=name[o];
464                         unsigned int shift1=(((o+2)*(i+1)*5+4)%13);
465                         unsigned int shift2=(((o+2)*(i+1)*3+2)%11)+13;
466                         t[i]+=(c<<shift1)+(c<<shift2);
467                 }
468         for (i=0;i<len;i++) 
469                 hash[i]=(unsigned char)(t[i]%20117 + t[i]%1217 + t[i]%157);
472 //Registration routines-- called at global initialization time
473 class PUP_regEntry {
474 public:
475         PUP::able::PUP_ID id;
476         const char *name;
477         PUP::able::constructor_function ctor;
478         PUP_regEntry(const char *Nname,
479                 const PUP::able::PUP_ID &Nid,PUP::able::constructor_function Nctor)
480                 :id(Nid),name(Nname),ctor(Nctor) {}
481         PUP_regEntry(int zero) {
482                 name=NULL; //For marking "not found"
483         }
486 typedef CkHashtableTslow<PUP::able::PUP_ID,PUP_regEntry> PUP_registry;
488 // FIXME: not SMP safe!    // gzheng
489 static PUP_registry *PUP_getRegistry(void) {
490         static PUP_registry *reg = NULL;
491         if (reg==NULL)
492                 reg=new PUP_registry();
493         return reg;
496 const PUP_regEntry *PUP_getRegEntry(const PUP::able::PUP_ID &id)
498         const PUP_regEntry *cur=(const PUP_regEntry *)(
499                 PUP_getRegistry()->CkHashtable::get((const void *)&id) );
500         if (cur==NULL)
501                 CmiAbort("Unrecognized PUP::able::PUP_ID. is there an unregistered module?");
502         return cur;
505 PUP::able::PUP_ID PUP::able::register_constructor
506         (const char *className,constructor_function fn)
508         PUP::able::PUP_ID id(className);
509         PUP_getRegistry()->put(id)=PUP_regEntry(className,id,fn);
510         return id;
513 PUP::able::constructor_function PUP::able::get_constructor
514         (const PUP::able::PUP_ID &id)
516         return PUP_getRegEntry(id)->ctor;
519 //For allocatable objects: new/delete object and call pup routine
520 void PUP::er::object(able** a)
522         const PUP_regEntry *r=NULL;
523         if (isUnpacking()) 
524         { //Find the object type & create the object
525                 PUP::able::PUP_ID id;//The object's id
526                 id.pup(*this);
527                 if (id==null_PUP_ID) {*a=NULL; return;}
528                 r=PUP_getRegEntry(id);
529                 //Invoke constructor (calls new)
530                 *a=(r->ctor)();
531                 
532         } else {//Just write out the object type
533                 if (*a==NULL) {
534                         null_PUP_ID.pup(*this);
535                         return;
536                 } else {
537                         const PUP::able::PUP_ID &id=(*a)->get_PUP_ID();
538                         id.pup(*this);
539                         r=PUP_getRegEntry(id);
540                 }
541         }
542         syncComment(PUP::sync_begin_object,r->name);
543         (*a)->pup(*this);
544         syncComment(PUP::sync_end_object);
547 /****************** Text Pup ******************/
549 char *PUP::toTextUtil::beginLine(void) {
550   //Indent level tabs over:
551   for (int i=0;i<level;i++) cur[i]='\t';
552   cur[level]=0;
553   return cur+level;
555 void PUP::toTextUtil::endLine(void) {
556   cur=advance(cur);
558 void PUP::toTextUtil::beginEnv(const char *type,int n)
560   char *o=beginLine();
561   sprintf(o,"begin "); o+=strlen(o);
562   sprintf(o,type,n); o+=strlen(o);
563   sprintf(o," {\n");
564   endLine();
565   level++;
567 void PUP::toTextUtil::endEnv(const char *type)
569   level--;
570   sprintf(beginLine(),"} end %s;\n",type);
571   endLine();
573 PUP::toTextUtil::toTextUtil(unsigned int inType,char *buf)
574   :er(inType)
576   cur=buf;
577   level=0;
580 void PUP::toTextUtil::comment(const char *message)
582   sprintf(beginLine(),"//%s\n",message); endLine();
585 void PUP::toTextUtil::synchronize(unsigned int m)
587   sprintf(beginLine(),"sync=0x%08x\n",m); endLine();
588 #if 0 /* text people don't care this much about synchronization */
589   char *o=beginLine();
590   sprintf(o,"sync=");o+=strlen(o);
591   const char *consonants="bcdfgjklmprstvxz";
592   const char *vowels="aeou";
593   for (int firstBit=0;firstBit<32;firstBit+=6) {
594         sprintf(o,"%c%c%c", consonants[0xf&(m>>firstBit)],
595                 vowels[0x3&(m>>(firstBit+4))], 
596                 (firstBit==30)?';':'-');
597         o+=strlen(o);
598   }
599   sprintf(o,"\n"); endLine();
600 #endif
603 void PUP::toTextUtil::bytes(void *p,size_t n,size_t itemSize,dataType t) {
604   if (t==Tchar) 
605   { /*Character data is written out directly (rather than numerically)*/
606     char *o=beginLine();
607     sprintf(o,"string=");o+=strlen(o);
608     *o++='\"'; /*Leading quote*/
609     /*Copy each character, possibly escaped*/
610     const char *c=(const char *)p;
611     for (size_t i=0;i<n;i++) {
612       if (c[i]=='\n') {
613         sprintf(o,"\\n");o+=strlen(o);
614       } else if (iscntrl(c[i])) {
615         sprintf(o,"\\x%02X",(unsigned char)c[i]);o+=strlen(o);
616       } else if (c[i]=='\\' || c[i]=='\"') {
617         sprintf(o,"\\%c",c[i]);o+=strlen(o);
618       } else
619         *o++=c[i];
620     }
621     /*Add trailing quote and newline*/
622     sprintf(o,"\";\n");o+=strlen(o);
623     endLine();
624   } else if (t==Tbyte || t==Tuchar)
625   { /*Byte data is written out in hex (rather than decimal) */
626     beginEnv("byte %d",n);
627     const unsigned char *c=(const unsigned char *)p;
628     char *o=beginLine();
629     for (size_t i=0;i<n;i++) {
630       sprintf(o,"%02X ",c[i]);o+=strlen(o);
631       if (i%25==24 && (i+1!=n)) 
632       { /* This line is too long-- wrap it */
633         sprintf(o,"\n"); o+=strlen(o);
634         endLine(); o=beginLine();
635       }
636     }
637     sprintf(o,"\n");
638     endLine();
639     endEnv("byte");
640   }
641   else
642   { /*Ordinary number-- write out in decimal */
643     if (n!=1) beginEnv("array %d",n);
644     for (size_t i=0;i<n;i++) {
645       char *o=beginLine();
646       switch(t) {
647       case Tshort: sprintf(o,"short=%d;\n",((short *)p)[i]); break;
648       case Tushort: sprintf(o,"ushort=%u;\n",((unsigned short *)p)[i]); break;
649       case Tint: sprintf(o,"int=%d;\n",((int *)p)[i]); break;
650       case Tuint: sprintf(o,"uint=%u;\n",((unsigned int *)p)[i]); break;
651       case Tlong: sprintf(o,"long=%ld;\n",((long *)p)[i]); break;
652       case Tulong: sprintf(o,"ulong=%lu;\n",((unsigned long *)p)[i]); break;
653       case Tfloat: sprintf(o,"float=%.7g;\n",((float *)p)[i]); break;
654       case Tdouble: sprintf(o,"double=%.15g;\n",((double *)p)[i]); break;
655       case Tbool: sprintf(o,"bool=%s;\n",((bool *)p)[i]?"true":"false"); break;
656 #if CMK_LONG_DOUBLE_DEFINED
657       case Tlongdouble: sprintf(o,"longdouble=%Lg;\n",((long double *)p)[i]);break;
658 #endif
659 #ifdef CMK_PUP_LONG_LONG
660       case Tlonglong: sprintf(o,"longlong=%lld;\n",((CMK_PUP_LONG_LONG *)p)[i]);break;
661       case Tulonglong: sprintf(o,"ulonglong=%llu;\n",((unsigned CMK_PUP_LONG_LONG *)p)[i]);break;
662 #endif
663       case Tpointer: sprintf(o,"pointer=%p;\n",((void **)p)[i]); break;
664       default: CmiAbort("Unrecognized pup type code!");
665       }
666       endLine();
667     }
668     if (n!=1) endEnv("array");
669   }
671 void PUP::toTextUtil::object(able** a) {
672   beginEnv("object");
673   er::object(a);
674   endEnv("object");
678 //Text sizer
679 char *PUP::sizerText::advance(char *cur) {
680   charCount+=strlen(cur);
681   return line;
684 PUP::sizerText::sizerText(void)
685   :toTextUtil(IS_SIZING+IS_COMMENTS,line),charCount(0) { }
687 //Text packer
688 char *PUP::toText::advance(char *cur) {
689   charCount+=strlen(cur);
690   return buf+charCount;
693 PUP::toText::toText(char *outBuf)
694   :toTextUtil(IS_PACKING+IS_COMMENTS,outBuf),buf(outBuf),charCount(0) { }
696 /************** To/from text FILE ****************/
697 void PUP::toTextFile::bytes(void *p,size_t n,size_t itemSize,dataType t)
699   for (size_t i=0;i<n;i++) 
700     switch(t) {
701     case Tchar: fprintf(f," '%c'",((char *)p)[i]); break;
702     case Tuchar:
703     case Tbyte: fprintf(f," %02X",((unsigned char *)p)[i]); break;
704     case Tshort: fprintf(f," %d",((short *)p)[i]); break;
705     case Tushort: fprintf(f," %u",((unsigned short *)p)[i]); break;
706     case Tint: fprintf(f," %d",((int *)p)[i]); break;
707     case Tuint: fprintf(f," %u",((unsigned int *)p)[i]); break;
708     case Tlong: fprintf(f," %ld",((long *)p)[i]); break;
709     case Tulong: fprintf(f," %lu",((unsigned long *)p)[i]); break;
710     case Tfloat: fprintf(f," %.7g",((float *)p)[i]); break;
711     case Tdouble: fprintf(f," %.15g",((double *)p)[i]); break;
712     case Tbool: fprintf(f," %s",((bool *)p)[i]?"true":"false"); break;
713 #if CMK_LONG_DOUBLE_DEFINED
714     case Tlongdouble: fprintf(f," %Lg",((long double *)p)[i]);break;
715 #endif
716 #ifdef CMK_PUP_LONG_LONG
717     case Tlonglong: fprintf(f," %lld",((CMK_PUP_LONG_LONG *)p)[i]);break;
718     case Tulonglong: fprintf(f," %llu",((unsigned CMK_PUP_LONG_LONG *)p)[i]);break;
719 #endif
720     case Tpointer: fprintf(f," %p",((void **)p)[i]); break;
721     default: CmiAbort("Unrecognized pup type code!");
722     };
723   fprintf(f,"\n");
725 void PUP::toTextFile::comment(const char *message)
727   fprintf(f,"! %s\n",message);
730 void PUP::fromTextFile::parseError(const char *what) {
731   // find line number by counting how many returns
732   long cur = ftell(f);
733   int lineno=0;
734   rewind(f);
735   while (!feof(f)) {
736      char c;
737      fscanf(f,"%c",&c);
738      if (c=='\n') lineno++;
739      if (ftell(f) > cur) break;
740   }
741   fprintf(stderr,"Parse error during pup from text file: %s at line: %d\n",what, lineno);
742   CmiAbort("Parse error during pup from text file!\n");
744 int PUP::fromTextFile::readInt(const char *fmt) {
745   int ret=0;
746   if (1!=fscanf(f,fmt,&ret)) {
747         if (feof(f)) return 0; /* start spitting out zeros at EOF */
748         else parseError("could not match integer");
749   }
750   return ret;
752 unsigned int PUP::fromTextFile::readUint(const char *fmt) {
753   unsigned int ret=0;
754   if (1!=fscanf(f,fmt,&ret))  {
755         if (feof(f)) return 0u; /* start spitting out zeros at EOF */
756         else parseError("could not match unsigned integer");
757   }
758   return ret;  
760 CMK_TYPEDEF_INT8 PUP::fromTextFile::readLongInt(const char *fmt) {
761   CMK_TYPEDEF_INT8 ret=0;
762   if (1!=fscanf(f,fmt,&ret)) {
763     if (feof(f)) return 0u;
764     else parseError("could not match large integer");
765   }
766   return ret;
768 double PUP::fromTextFile::readDouble(void) {
769   double ret=0;
770   if (1!=fscanf(f,"%lg",&ret)) {
771         if (feof(f)) return 0.0; /* start spitting out zeros at EOF */
772         else parseError("could not match double");
773   }
774   return ret;
776 void PUP::fromTextFile::bytes(void *p,size_t n,size_t itemSize,dataType t)
778   for (size_t i=0;i<n;i++) 
779     switch(t) {
780     case Tchar: 
781       if (1!=fscanf(f," '%c'",&((char *)p)[i]))
782         parseError("Could not match character");
783       break;
784     case Tuchar:
785     case Tbyte: ((unsigned char *)p)[i]=(unsigned char)readInt("%02X"); break;
786     case Tshort:((short *)p)[i]=(short)readInt(); break;
787     case Tushort: ((unsigned short *)p)[i]=(unsigned short)readUint(); break;
788     case Tint:  ((int *)p)[i]=readInt(); break;
789     case Tuint: ((unsigned int *)p)[i]=readUint(); break;
790     case Tlong: ((long *)p)[i]=readInt(); break;
791     case Tulong:((unsigned long *)p)[i]=readUint(); break;
792     case Tfloat: ((float *)p)[i]=(float)readDouble(); break;
793     case Tdouble:((double *)p)[i]=readDouble(); break;
794 #if CMK_LONG_DOUBLE_DEFINED
795     case Tlongdouble: {
796       long double ret=0;
797       if (1!=fscanf(f,"%Lg",&ret)) parseError("could not match long double");
798       ((long double *)p)[i]=ret;
799     } break;
800 #endif
801 #ifdef CMK_PUP_LONG_LONG
802     case Tlonglong: {
803       CMK_PUP_LONG_LONG ret=0;
804       if (1!=fscanf(f,"%lld",&ret)) parseError("could not match long long");
805       ((CMK_PUP_LONG_LONG *)p)[i]=ret;
806     } break;
807     case Tulonglong: {
808       unsigned CMK_PUP_LONG_LONG ret=0;
809       if (1!=fscanf(f,"%llu",&ret)) parseError("could not match unsigned long long");
810       ((unsigned CMK_PUP_LONG_LONG *)p)[i]=ret;
811     } break;
812 #endif
813     case Tbool: {
814       char tmp[20];
815       if (1!=fscanf(f," %19s",tmp)) parseError("could not read boolean string");
816       bool val=false;
817       if (0==strcmp(tmp,"true")) val=true;
818       else if (0==strcmp(tmp,"false")) val=false;
819       else parseError("could not recognize boolean string");
820       ((bool *)p)[i]=val; 
821     }
822       break;
823     case Tpointer: {
824       void *ret=0;
825       if (1!=fscanf(f,"%p",&ret)) parseError("could not match pointer");
826       ((void **)p)[i]=ret;
827     } break;
828     default: CmiAbort("Unrecognized pup type code!");
829     };
831 void PUP::fromTextFile::comment(const char *message)
833   char c;
834   //Skip to the start of the message:
835   while (isspace(c=fgetc(f))) {}
836   
837   if (c!='!') return; //This isn't the start of a comment
838   //Skip over the whole line containing the comment:
839   char *commentBuf=(char *)CmiTmpAlloc(1024);
840   fgets(commentBuf,1024,f);
841   CmiTmpFree(commentBuf);