// 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 <hyperg/utils/hgunistd.h>
#include <hyperg/hyperg/assert.h>

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



// #define VERBOSE
#include <hyperg/hyperg/verbose.h>



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

File :: File() 
: fd_(-1),
  close_(false) {
     instances_++ ;
}

File :: File (int fd, boolean close)
: fd_(-1) {
   attach (fd, close) ;
   instances_++ ;
}

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

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

int File :: read (char* buf, int nbytes) {
   hgassert (fd()>=0, "File::read(): invalid file number") ;
   int rv ;
   while ((rv = ::read (fd(), buf, nbytes)) < 0  &&  ::errno == EINTR) ;
   if (rv < 0) {
      set_errno_(::errno) ;
#ifdef VERBOSE_SOCKET      
      ::perror ("File::read()") ;
#endif
   }
   return rv ;
}

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

boolean File :: close() {
   DEBUGNL ("File::close()") ;
   if (get_close_() && fd()>=0) {
      DEBUGNL ("File::close(): closing") ;
      if (::close (fd()) < 0) {
         set_errno_(::errno) ;
         return false ;
      }
      // be sure to callback *after* closing (haha)
      FileCloseCallback* c ;
      while (c = callbacks_.removeHead()) {
         boolean rv = c->doIt() ;
         delete (c) ;
         if (rv) 
            break ;
      }
   }
   set_fd_(-1) ;
   set_close_(false) ;
   return true ;
}

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