/* $Header: /home/jcb/newmj/RCS/sysdep.h,v 11.13 2003/10/07 21:18:47 jcb Rel $
 * sysdep.h
 * Miscellaneous system stuff that may require attention
 * by configuration procedures.
 */
/****************** COPYRIGHT STATEMENT **********************
 * This file is Copyright (c) 2000 by J. C. Bradfield.       *
 * Distribution and use is governed by the LICENCE file that *
 * accompanies this file.                                    *
 * The moral rights of the author are asserted.              *
 *                                                           *
 ***************** DISCLAIMER OF WARRANTY ********************
 * This code is not warranted fit for any purpose. See the   *
 * LICENCE file for further information.                     *
 *                                                           *
 *************************************************************/

/* network conversion utilities */

#ifndef SYSDEP_H_INCLUDED
#define SYSDEP_H_INCLUDED

#include <unistd.h>
/* The following define prevents HP-UX from using the antiquated
   version of select() with ints instead of fd_sets */
#define _XOPEN_SOURCE_EXTENDED 1
#include <time.h>
#ifdef WIN32
#include <winsock.h>
typedef int socklen_t;
/* following functions don't exist in Windows, so we need to emulate them */
/* Windows doesn't define the struct timezone, so just use void * */
int gettimeofday(struct timeval *tv, void *tz);
char *getlogin(void);
unsigned int sleep(unsigned int t);
unsigned int usleep(unsigned int t);
int getpid(void);
int unlink(const char *f);
/* snprintf is not in my Windows/Mingw. The "implementation" in
   sysdep.c is NOT safe; it just ignores the length. */
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
int snprintf(char *str, size_t size, const char *format, ...);
#else
#include <netinet/in.h>
/* need this for gettimeofday */
#include <sys/time.h>
#endif /* WIN32 */

#include <stdlib.h>
#include <stdio.h>
/* for memset and friends */
#include <string.h>
#include <assert.h>
#include <ctype.h>

/* define SOCKET types so we can also work with windows */
#ifndef WIN32
typedef int SOCKET;
#define INVALID_SOCKET -1
#define closesocket close
#endif

/* If we're using GNU CC, we can suppress warnings for unused variables
   with this.
*/
#if defined( __GNUC__) && !defined(__GNUG__)
# define UNUSED __attribute ((unused))
#else
# define UNUSED
#endif

/* functions in sysdep.c */

/* warn is  fprintf(stderr,...) .
*/

typedef enum { LogInfo = 1, LogWarning = 2 } LogLevel;

/* If the global variable log_msg_hook is non-null, it should
   be a pointer to a function which will be passed the formatted
   warning. If the hook returns non-zero, the warning will not
   be printed to stderr.
*/
extern int (*log_msg_hook)(LogLevel l,char *);

int warn(char *format,...);

/* log_msg is a generalized version with a syslog like warning
   level. Currently only two levels are defined by the
   LogLevel enum, LogWarning and LogInfo. */
int log_msg(LogLevel l, char *format,...);

/* and info is a log at info level */
int info(char *format,...);

/* ignore the SIGPIPE signal. Return 0 on success, -1 on error */
int ignore_sigpipe(void);

/* Initialize the socket library functions. This is only needed
   under Windows. It need not be called explicitly, as the library
   functions will call it (with null arguments) if necessary.
   The arguments, if non-NULL, are used by programs that need to do strange
   things to the sockets, such as gtk applications under windows.
   open_transform is a function which is applied to all sockets created,
   and had better return something that fits in
   a (void *); all functions that return or store SOCKET, will instead
   return or store the result of open_transform, cast to a SOCKET.
   (So SOCKET had better fit a void*; this is true on all systems
   I know of.)
   closer is a function to close the resulting object;
   reader is a function to read from it; it should have the same
   type as the system read function, mutatis mutandis;
   writer is a function to write. */
int initialize_sockets(void *(*open_transform)(SOCKET),
		       int (*closer)(void *),
		       int (*reader)(void *, void *, size_t),
		       int (*writer)(void *, const void *,size_t));

/* In the following function, a socket address is a string.
   If it contains a colon, then it is assumed to be a TCP
   address host:port (if host is omitted, it is localhost).
   Otherwise, it is assumed to be a Unix filename, and 
   Unix domain sockets are used.
*/

/* set_up_listening_socket:
   Set up a socket, listening on the given address.
   Return its system level SOCKET.
*/
SOCKET set_up_listening_socket(const char *address);

/* accept_new_connection:
   A connection has arrived on the socket fd.
   Accept the connection, and return the new fd,
   or INVALID_SOCKET on error.
*/

SOCKET accept_new_connection(SOCKET fd);

/* connect_to_host:
   Establish a connection to the given address.
   Return the file descriptor or INVALID_SOCKET on error.
   The file descriptor is marked close-on-exec.
*/
SOCKET connect_to_host(const char *address);

/* close a network connection */
int close_socket(SOCKET s);

/* read a line, up to lf/crlf terminator, from the socket,
   and return it.
   If there is an error or end of file before seeing a terminator,
   NULL is returned. At present, error includes reading a partial line.
   The returned string is valid until the next call of get_line.
   As a special hack, if fd is STDOUT_FILENO, then read from
   STDIN_FILENO as an fd.
*/
char *get_line(SOCKET fd);

/* write a line (which should include any terminator) to a socket.
   Return -1 on error, length of line on success.
   If fd is equal to STDOUT_FILENO, then print to it as an fd.
*/
int put_line(SOCKET fd,char *line);

/* These are the same, but they take a file descriptor
   rather than a socket. (I hate Windows) */

char *fd_get_line(int fd);
int fd_put_line(int fd, char *line);

/* rand_index: return a random integer from 0 to arg (inclusive).
 */
unsigned int rand_index(int top);

/* rand_seed: if the random number generation has a seed value,
   use this argument, if non-zero; if zero, seed with a system
   dependent variable value (actually time(), but needn't be).
   If this function is not called explicitly, it will be called
   with arg 0 on first use of rand_index.
*/
void rand_seed(int seed);

/* utility function: this is just like strncpy, except that it 
   guarantees that the target is null-terminated.
   The m parameter is the length of the target field INCLUDING
   the terminating null.
*/
#define strmcpy(dest,src,m) { strncpy(dest,src,m) ; dest[m-1] = '\000' ; }

/* feed a command to the system to be started in background.
   No fancy argument processing, just pass to shell or equiv
   Return 1 on success, 0 on failure */
int start_background_program(const char *cmd);

/* unfortunately we need a slightly more sophisticated one where
   we can get at the output. This passes out a write handle for the
   new process's stdin, and a read handle for its stdout */
/* Under Windows, this is fiddled to return "file descriptors" */
int start_background_program_with_io(const char *cmd,int *childin,
  int *childout);

/* return a path for the home directory, or equivalent concept.
   Returns NULL if no sensible homedir is available
   (i.e. HOME is unset on Unix, or HOMEPATH is unset on Windows) */
char *get_homedir(void);

#endif /* SYSDEP_H_INCLUDED */
