/*
 * The UDS Collection
 * Copyright (C) 2000, 2001  Julian v. Bock
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *	(See file COPYING for more information)
 */

#ifndef _uds_sys_util_hh
#define _uds_sys_util_hh


// includes

#include <sys/types.h>
#include <uds/stdexcpt.hh>
#include <unistd.h>

using namespace std;


class fstream;
class fstreambase;


namespace uds
{

class SocketStream;


/// holds the default prefix for temporary file names
extern string TmpFileName_Prefix;


/** fd_set wrapper class
	\author Julian v. Bock */
class FD_Set
{
public:
	/** default constructor */
	FD_Set() { Zero(); }
	
	/** destructor */
	~FD_Set() {}
	
	/** sets a file descriptor
		\param fd file descriptor */
	void
	Set( int fd );
	
	/** clears a file descriptor. WARNING: n (the highest numbered file
		descriptor in the set plus 1) becomes undefined if you use this
		method!
		\param fd file descriptor */
	void
	Clear( int fd );
	
	/** clears all file descriptors */
	void
	Zero();
	
	/** checks whether a file descriptor is set
		\param fd file descriptor */
	bool
	IsSet( int fd ) const;
	
	/** \return the highest numbered file descriptor in the set plus 1 */
	int
	N() const { return n; }
	
	fd_set*
	operator () () { return &fds; }
	
private:
	/// file descriptor set
	fd_set	fds;
	/// highest numbered file descriptor in the set plus 1
	int		n;
};


/** generic wrapper function for standard library function calls. If the
	argument is negative, a system_call exception is thrown.
	\param rv return value of called function
	\return the specified return value */
inline int
CkStdCall( int rv )
{
	if ( rv < 0 )
		Throw( system_error() );
	return rv;
}

/** generic wrapper function for standard library function calls. If the
	argument is negative, a system_call exception is thrown.
	\param rv return value of called function
	\param s additional error string (eg function name)
	\return the specified return value */
inline int
CkStdCall( int rv, const string& s )
{
	if ( rv < 0 )
		Throw( system_error( s ) );
	return rv;
}

/** checks whether a file exists
	\param f file name
	\return true if the file exists */
bool
FileExist( const char* name );

/** checks whether a file can be accessed
	\param f file name
	\param m file mode (see man 2 access for available flags)
	\return true if the file can be accessed */
bool
FileAccess( const char* f, int m );

/** \return current working directory path */
string
CurrentWD();

/** opens a file. If the file could not be opened, a file_error exception
	is thrown.
	\param s file stream
	\param name name of the file to be opened
	\param mode open mode
	\param prot permission bits
	\arg throws file_error */
void
OpenFile( fstream& s, const char *name, int mode, int prot = 0664 );

/** retrieves a file descriptor from an ios
	\param s ios
	\return file descriptor */
int
FileDes( const ios& s );

/** creates a unique temporary file name. For security reasons, a file with
	the temporary name and 0600 permissions is created (and closed).
	\param pre file name prefix
	\return temporary file name */
string
TmpFileName( const string& pre );

/** creates a unique temporary file name. For security reasons, a file with
	the temporary name and 0600 permissions is created (and closed).
	\return temporary file name */
string
TmpFileName();

/** creates a unique temporary file with permission 0600.
	\param pre file name prefix
	\return file descriptor of the temporary file */
int
TmpFile( const string& pre );

/** creates a unique temporary file with permission 0600.
	\return file descriptor of the temporary file */
int
TmpFile();

/** forks the process. If the call to fork() fails, a fork_error exception
	is thrown
	\return the PID of the child process is returned in the parent's thread
	of execution, and a 0 is returned in the child's thread of
	execution.
	\arg throws fork_error */
int
Fork();

/** suspends the execution until a child process exited. If the child process
	exited abnormally, a child_error exception is thrown. If the call to
	waitpid fails, a system_error exception is thrown.
	\param pid the same as the pid option of the waitpid function
	\param iv if this value is returned by the child process, no exception is
	thrown. Exit( iv ) is called instead.
	\param opt wait() options. see man 2 wait.
	\param strict if this flags is set an exception is always thrown if the
	exit status is not zero
	\return pid of the child process that exited
	\arg throws child_error, system_error */
int
Wait( int pid = -1, int iv = -1, int opt = 0 );

/** reads a line from an input stream
	\param in input stream
	\param o is filled with the line
	\param app 'append eol character' flag
	\param ign 'ignore eol character' flag
	\param eol end-of-line character */
void
ReadLine( istream& in, string& o, bool app = false, bool ign = true,
		  char eol = '\n' );

/** reads a line from an input stream
	\param in input stream
	\param app 'append eol character' flag
	\param ign 'ignore eol character' flag
	\param eol end-of-line character
	\return line */
string
ReadLine( istream& in, bool app = false, bool ign = true, char eol = '\n' );

/** reads data from an input stream. If the 'wait' flag is set, the function
	does not return until len bytes have been read.
	\param in input stream
	\param buf buffer
	\param len length
	\param wait 'wait' flag
	\return number of bytes read */
size_t
BRead( istream& in, void* buf, size_t len, bool wait = true );

/** reads the binary representation of an object from a stream. The function
	does not return until len bytes have been read.
	\param in input stream
	\param v object
	\param wait 'wait' flag */
template < class Tp >
inline size_t
BRead( istream& in, Tp& v )
{
	return BRead( in, &v, sizeof( v ) );
}

/** reads a binary representation of a string from a stream. The binary string
	representation must consist of the string length (size_t) and the
	string data. If the 'wait' flag is set, the function
	does not return until len bytes have been read.
	\param in input stream
	\param v string
	\param wait 'wait' flag
	\return number of bytes read */
size_t
BRead( istream& in, string& v, bool wait = true );

/** reads data from an input stream. If the 'wait' flag is set, the function
	does not return until len bytes have been read.
	\param in file descriptor
	\param buf buffer
	\param len length
	\param wait 'wait' flag
	\return number of bytes read */
size_t
BRead( int in, void* buf, size_t len, bool wait = true );

/** reads the binary representation of an object from a stream. The function
	does not return until len bytes have been read.
	\param in file descriptor
	\param v object
	\param wait 'wait' flag */
template < class Tp >
inline size_t
BRead( int in, Tp& v )
{
	return BRead( in, &v, sizeof( v ) );
}

/** reads a binary representation of a string from a stream. The binary string
	representation must consist of the string length (size_t) and the
	string data. If the 'wait' flag is set, the function
	does not return until len bytes have been read.
	\param in file descriptor
	\param v string
	\param wait 'wait' flag
	\return number of bytes read */
size_t
BRead( int in, string& v, bool wait = true );

/** writes the binary representation of an object to a stream
	\param out output stream
	\param v object */
template < class Tp >
inline void
BWrite( ostream& out, const Tp& v )
{
	out.write( reinterpret_cast< const char* >( &v ), sizeof( v ) );
}

/** writes the binary representation of a string to a stream
	\param out output stream
	\param v object */
inline void
BWrite( ostream& out, const string& v )
{
	BWrite( out, v.size() );
	out.write( v.data(), v.size() );
}

/** writes the binary representation of an object to a stream
	\param out file descriptor
	\param v object */
template < class Tp >
inline void
BWrite( int out, const Tp& v )
{
	write( out, reinterpret_cast< const char* >( &v ), sizeof( v ) );
}

/** writes the binary representation of a string to a stream
	\param out file descriptor
	\param v object */
inline void
BWrite( int out, const string& v )
{
	BWrite( out, v.size() );
	write( out, v.data(), v.size() );
}

}


#define _uds_CkStdCall( x ) \
	::uds::CkStdCall( x, _uds_SourceLocation )

#endif // _uds_sys_util_hh
