/*
 * cccc_stg.h
 *
 * a dynamic length character string class for CCCC
 * its a shame that there isn't a standardized bug free class to do this
 * job, but there doesn't seem to be, so here goes
 */

#ifndef _CCCC_STG_H_
#define _CCCC_STG_H_
 
#include <stdlib.h>
#include <string.h>
#include <iostream.h>
#include <strstream.h>

class CCCC_String {
  char *cptr;
  void release() { free(cptr); cptr=NULL; }
public:
  operator char*() const { return cptr; } 
  CCCC_String(const char* s="") { cptr=strdup((char*)s); }
  CCCC_String(const CCCC_String& cs) { cptr=strdup((char*)cs); }
  ~CCCC_String() { release(); }
  CCCC_String& operator =(const CCCC_String& cs) { 
    if(&cs != this)
      {
	release(); 
	cptr=strdup(cs);
      }
    return *this;
  }

  const CCCC_String& operator +(const CCCC_String& cs) const {
    static CCCC_String retval;
    retval="";
    if(strlen(*this)+strlen(cs)<1023)
      {
	char buf[1024];
	strcpy(buf,*this);
	strcat(buf,cs);
	retval=buf;
      }
    else
      {
	cerr << "Attempt to concatenate overlength strings" << endl;
      }
    return retval;
  }
};

inline ostream& operator <<(ostream& os, const CCCC_String& cs) {
  os << (const char*) cs;
  return os;
}

// for extraction to work correctly we need
// to preallocate a large enough character buffer to hold the incoming
// data
#define MAX_IN_SIZE 1024
inline istream& operator >>(istream& is, CCCC_String& cs) {

  // we will deliberately read too many characters from the stream, 
  // so the first thing we do is to mark our current position
  streampos start=is.tellg();
  int state=is.rdstate();
   
  char buffer[MAX_IN_SIZE];
  memset(buffer,0,MAX_IN_SIZE);
  is.getline(buffer,MAX_IN_SIZE-1,' ');

  // we are now guaranteed that buffer contains no more than MAX_IN_SIZE-1
  // characters, terminated with a null
  // we use strtok to pick off up to the next whitespace character
  cs=strtok(buffer," \t\r\n\f");
  

  // finally, we reset the stream's error state, seek to the original marker, 
// then offset by the number of bytes actually read
is.clear(state);
is.seekg(start,ios::beg);
is.seekg(strlen(buffer),ios::cur);
   
return is;
}  



// CCCC_Field is a very thin increment on CCCC_String
// its main distinction is that its istream extractor
// searches up to the defined field separator in the input 
// stream
class CCCC_Field : public CCCC_String 
{
public:
CCCC_Field() {}
CCCC_Field(const char* s) : CCCC_String(s) {}
};

inline istream& operator >> (istream& is, CCCC_Field& f) 
{
  const int bufsize=1024;
  const char field_sep='@';
  static char buf[bufsize];
  memset(buf,0,bufsize);
  is.getline(buf,bufsize-1,field_sep);
  f=buf;
  return is;
}

#endif  









