// This may look like C code, but it is really -*- C++ -*-
// 
// <copyright> 
//  
//  Copyright (c) 1995
//  Institute for Information Processing and Computer Supported New Media (IICM), 
//  Graz University of Technology, Austria. 
//  
// </copyright> 
// 
// 
// <file> 
// 
// Name:        buffer.C
// 
// Purpose:     
// 
// Created:     27 Nov 95   Joerg Faschingbauer
// 
// Modified:    
// 
// Description: 
// 
// $Id: buffer.C,v 1.14 1997/03/01 12:54:30 jfasch Exp $
//
// $Log: buffer.C,v $
// Revision 1.14  1997/03/01 12:54:30  jfasch
// version5
//
// Revision 1.13  1997/03/01 12:53:29  jfasch
// another one in fixup
//
// Revision 1.12  1997/03/01 12:21:19  jfasch
// bug fix in fixup(): call do_enlarge_() instead of enlarge_()
//
// Revision 1.11  1997/02/28 16:18:18  bheide
// OBuffer :: version4
//   o new RString: new OBuffer :: fixup
//
// Revision 1.2  1996/10/30 16:40:07  tvollmer
// first new version with enlargement and obuffer
//
// Revision 1.9  1996/10/29 11:26:31  jfasch
// init(), reset() added
//
// Revision 1.8  1996/10/24 10:56:16  jfasch
// adapted to the new location (previous was dc-common)
//
// Revision 1.7  1996/10/03 12:02:50  jfasch
// verbose.h and assert.h moved
//
// Revision 1.6  1996/08/29 08:22:36  jfasch
// forgot to include str.h (ahem)
//
// Revision 1.5  1996/08/28 14:56:24  jfasch
// OBuffer::operator<<(const RString&)
//
// Revision 1.4  1996/08/23 17:06:23  jfasch
// ignore null length writes instead of asserting the length
//
// Revision 1.3  1996/07/11 14:54:22  jfasch
// added checking message output if more than 1 Mb is allocated
//
// Revision 1.2  1996/07/11 14:03:05  jfasch
// made it refcounted
//
// 
// </file> 
#include "buffer.h"

#include "assert.h"
#include "new.h"
#include "str.h"

#include <string.h>

// --------------------------------------------------------------------
const char* OBuffer :: version5 = "$Id: buffer.C,v 1.14 1997/03/01 12:54:30 jfasch Exp $" ;

OBuffer :: OBuffer (int size) 
: data_(size? HGNEW(char[size]): nil),
  size_(size),
  count_(0) {}

OBuffer :: ~OBuffer() {
   HGDELETE_ARR (data_) ;
}

OBuffer& OBuffer :: write (char c) {
   enlarge_(1) ;
   *(data_+count_++) = c ;
   return *this ;
}

OBuffer& OBuffer :: write (const char* d, int l) {
   if (l) {
      enlarge_(l) ;
      ::memcpy (data_+count_, d, l) ;
      count_ += l ;
   }
   return *this ;
}

OBuffer& OBuffer :: operator << (const char* s) {
    if (!s) return *this;
    return write (s, ::strlen(s)) ;
}

OBuffer& OBuffer :: operator << (const RString& s) {
   return write (s.string(), s.length()) ;
}

OBuffer& OBuffer :: fixup (int pos, const char* d, int l) {
    hgassert(pos<count_,"OBuffer::fixup() pos is not in range");
    if (!pos && !l) return *this;
    if (pos+l>size_)
       do_enlarge_(pos+l-count_) ;
    ::memcpy (data_+pos, d, l) ;
    if (pos+l > count_) 
        count_=pos+l;
    return *this ;
}

char* OBuffer :: freeze() {
   char* ret = data_ ;
   if (data_) {
      data_ = nil ;
      size_ = 0 ;
      count_ = 0 ;
   }
   return ret ;
}

void OBuffer :: free() {
   if (data_) {
      HGDELETE_ARR (data_) ;
      data_ = nil ;
      size_ = 0 ;
      count_ = 0 ;
   }
}

void OBuffer :: init (int count, char* data, int size) {
   free() ;
   count_ = count ;
   size_ = (size>count) ? size : count ;
   data_ = size ? data : nil ;
}

void OBuffer :: do_enlarge_(int amount) {
   int newsize = count_ + amount ;
   if (size_ == 0)
      // suppose one enters just one character. if I began with
      // size_=1, then I would actually allocate *1*. aint that
      // inefficient? 16 sounds great to me.
      size_ = 16 ; 
   while (size_ < newsize)
      size_ *= 2 ;
   if (size_ > 1024*1024)
      cerr << "OBuffer:: size exceeds 1 Mb!" << endl ;
   char* old = data_ ;
   data_ = HGNEW (char [size_]) ;
   if (count_) 
      ::memcpy (data_, old, count_) ;
   HGDELETE_ARR (old) ;
}

