// This may look like C code, but it is really -*- C++ -*-
// 
// <copyright> 
//  
//  Copyright (c) 1994
//  Institute for Information Processing and Computer Supported New Media (IICM), 
//  Graz University of Technology, Austria. 
//  
// </copyright> 
// 
// 
// <file> 
// 
// Name:        file.C
// 
// Purpose:     
// 
// Created:     4 May 95   Joerg Faschingbauer
// 
// Modified:    
// 
// Description: 
// 
// 
// </file> 
#include "file.h"

#include "assert.h"
#include "hgunistd.h"
#include "new.h"
#include "verbose.h"

// both for perror() on the various platforms
#include <stdio.h>
#include <errno.h>

// --------------------------------------------------------------------
Verbose HgFile :: sys_verbose ;
const char* HgFile :: version3 = "$Id: file.C,v 1.11 1997/01/30 08:38:51 jfasch Exp $" ;

FileCloseCallbackList HgFile :: callbacks_ ;
int HgFile :: instances_ = 0 ; // init. not necessary, but ...

HgFile :: HgFile() 
: fd_(-1) {
   instances_++ ;
}

HgFile :: HgFile (int fd)
: fd_(-1) {
   attach (fd) ;
}

HgFile :: ~HgFile() {
   close() ;
   instances_-- ;
}

int HgFile :: write (const char* buf, int nbytes) {
   hgassert (fd()>=0, "HgFile::write(): invalid file number") ;
   int rv ;
   while ((rv = ::write (fd(), buf, nbytes)) < 0  &&  errno == EINTR) ;
   if (rv < 0) {
      set_errno_(errno) ;
      perror_("HgFile::write(): ::write()") ;
   }
   return rv ;
}

int HgFile :: read (char* buf, int nbytes) {
   hgassert (fd()>=0, "HgFile::read(): invalid file number") ;
   int rv ;
   while ((rv = ::read (fd(), buf, nbytes)) < 0  &&  errno == EINTR) ;
   if (rv < 0) {
      set_errno_(errno) ;
      perror_("HgFile::read()") ;
   }
   return rv ;
}

void HgFile :: attach (int thefd) {
   hgassert (thefd>=0, "HgFile::attach(): invalid file number") ;
   hgassert (fd()<0, "HgFile::attach(): already using a file number") ;
   set_fd_(thefd) ;
}

bool HgFile :: close() {
   DEBUGNL ("HgFile::close()") ;
   if (closed())
      return true ;

   DEBUGNL ("HgFile::close(): closing") ;
   if (::close (fd()) < 0) {
      set_errno_(errno) ;
      return false ;
   }
   set_fd_(-1) ;

   // be sure to callback *after* closing (haha)
   FileCloseCallback* c ;
   while ((c = callbacks_.removeHead())) {
      bool rv = c->fileClosed() ;
      if (rv) 
         break ;
   }
   return true ;
}

void HgFile :: registerCallback (FileCloseCallback* c) {
   callbacks_.addTail (c) ;
}

void HgFile :: perror_(const char* msg) {
   if (sys_verbose)
      ::perror (msg) ;
}
