diff --git a/libguile/ChangeLog b/libguile/ChangeLog index 7445c1d9a..93bcc0753 100644 --- a/libguile/ChangeLog +++ b/libguile/ChangeLog @@ -1,3 +1,17 @@ +2001-11-21 Stefan Jahn + + * win32-socket.c (getservent, setservent, endservent, + getprotoent, setprotoent, endprotoent): New functions. + Appropriate replacements for M$-Windows. + + * numbers.c (SIZE_MAX, PTRDIFF_MAX, PTRDIFF_MIN): Reintroduced + these definitions for GUILE_DEBUG. + + * net_db.c: Include "win32-socket.h" if compiling with a native + M$-Windows compiler. Include some pieces of code (protoent and + servent interface) protected by HAVE_* macros when using a + native M$-Windows compiler. + 2001-11-20 Marius Vollmer * modules.c (scm_c_export): Do nothing when the first argument is diff --git a/libguile/net_db.c b/libguile/net_db.c index d32819ee8..fd00a0497 100644 --- a/libguile/net_db.c +++ b/libguile/net_db.c @@ -74,6 +74,10 @@ #include #endif +#ifdef __MINGW32__ +#include "win32-socket.h" +#endif + #if !defined (HAVE_H_ERRNO) && !defined (__MINGW32__) && !defined (__CYGWIN__) /* h_errno not found in netdb.h, maybe this will help. */ extern int h_errno; @@ -266,7 +270,7 @@ SCM_DEFINE (scm_getnet, "getnet", 0, 1, 0, #undef FUNC_NAME #endif -#ifdef HAVE_GETPROTOENT +#if defined (HAVE_GETPROTOENT) || defined (__MINGW32__) SCM_DEFINE (scm_getproto, "getproto", 0, 1, 0, (SCM protocol), "@deffnx {Scheme Procedure} getprotobyname name\n" @@ -314,7 +318,7 @@ SCM_DEFINE (scm_getproto, "getproto", 0, 1, 0, #undef FUNC_NAME #endif -#ifdef HAVE_GETSERVENT +#if defined (HAVE_GETSERVENT) || defined (__MINGW32__) static SCM scm_return_entry (struct servent *entry) { @@ -405,7 +409,7 @@ SCM_DEFINE (scm_setnet, "setnet", 0, 1, 0, #undef FUNC_NAME #endif -#if defined(HAVE_SETPROTOENT) && defined(HAVE_ENDPROTOENT) +#if defined (HAVE_SETPROTOENT) && defined (HAVE_ENDPROTOENT) || defined (__MINGW32__) SCM_DEFINE (scm_setproto, "setproto", 0, 1, 0, (SCM stayopen), "If @var{stayopen} is omitted, this is equivalent to @code{endprotoent}.\n" @@ -421,7 +425,7 @@ SCM_DEFINE (scm_setproto, "setproto", 0, 1, 0, #undef FUNC_NAME #endif -#if defined(HAVE_SETSERVENT) && defined(HAVE_ENDSERVENT) +#if defined (HAVE_SETSERVENT) && defined (HAVE_ENDSERVENT) || defined (__MINGW32__) SCM_DEFINE (scm_setserv, "setserv", 0, 1, 0, (SCM stayopen), "If @var{stayopen} is omitted, this is equivalent to @code{endservent}.\n" diff --git a/libguile/numbers.c b/libguile/numbers.c index 154974d24..4afc1578b 100644 --- a/libguile/numbers.c +++ b/libguile/numbers.c @@ -4390,6 +4390,17 @@ scm_i_big2dbl (SCM b) #ifdef GUILE_DEBUG +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t) (-1)) +#endif +#ifndef PTRDIFF_MIN +#define PTRDIFF_MIN \ + ((ptrdiff_t) ((ptrdiff_t) 1 << (sizeof (ptrdiff_t) * 8 - 1))) +#endif +#ifndef PTRDIFF_MAX +#define PTRDIFF_MAX (~ PTRDIFF_MIN) +#endif + #define CHECK(type, v) \ do { \ if ((v) != scm_num2##type (scm_##type##2num (v), 1, "check_sanity")) \ diff --git a/libguile/win32-socket.c b/libguile/win32-socket.c index 8456ad321..a2556b6d1 100644 --- a/libguile/win32-socket.c +++ b/libguile/win32-socket.c @@ -46,7 +46,16 @@ #include "libguile/modules.h" #include "libguile/numbers.h" +#include +#include +#include +#include #include +#include + +#ifndef PATH_MAX +#define PATH_MAX 255 +#endif #include "win32-socket.h" @@ -62,6 +71,46 @@ typedef struct } socket_error_t; +#define FILE_ETC_SERVICES "services" +#define ENVIRON_ETC_SERVICES "SERVICES" +#define FILE_ETC_NETWORKS "networks" +#define ENVIRON_ETC_NETWORKS "NETWORKS" +#define FILE_ETC_PROTOCOLS "protocol" +#define ENVIRON_ETC_PROTOCOLS "PROTOCOLS" +#define MAX_NAMLEN 256 +#define MAX_ALIASES 4 + +/* Internal structure for a thread's M$-Windows servent interface. */ +typedef struct +{ + FILE *fd; /* Current file. */ + char file[PATH_MAX]; /* File name. */ + struct servent ent; /* Return value. */ + char name[MAX_NAMLEN]; /* Service name. */ + char proto[MAX_NAMLEN]; /* Protocol name. */ + char alias[MAX_ALIASES][MAX_NAMLEN]; /* All aliases. */ + char *aliases[MAX_ALIASES]; /* Alias pointers. */ + int port; /* Network port. */ +} +scm_i_servent_t; + +static scm_i_servent_t scm_i_servent; + +/* Internal structure for a thread's M$-Windows protoent interface. */ +typedef struct +{ + FILE *fd; /* Current file. */ + char file[PATH_MAX]; /* File name. */ + struct protoent ent; /* Return value. */ + char name[MAX_NAMLEN]; /* Protocol name. */ + char alias[MAX_ALIASES][MAX_NAMLEN]; /* All aliases. */ + char *aliases[MAX_ALIASES]; /* Alias pointers. */ + int proto; /* Protocol number. */ +} +scm_i_protoent_t; + +static scm_i_protoent_t scm_i_protoent; + /* Define replacement symbols for most of the WSA* error codes. */ #ifndef EWOULDBLOCK # define EWOULDBLOCK WSAEWOULDBLOCK @@ -375,6 +424,205 @@ scm_i_socket_strerror (int error) return NULL; } +/* Constructs a valid filename for the given file @var{file} in the M$-Windows + directory. This is usually the default location for the network files. */ +char * +scm_i_socket_filename (char *file) +{ + static char dir[PATH_MAX]; + int len = PATH_MAX; + + len = GetWindowsDirectory (dir, len); + if (dir[len - 1] != '\\') + strcat (dir, "\\"); + strcat (dir, file); + return dir; +} + +/* Removes comments and white spaces at end of line and returns a pointer + to the end of the line. */ +static char * +scm_i_socket_uncomment (char *line) +{ + char *end; + + if ((end = strchr (line, '#')) != NULL) + *end-- = '\0'; + else + { + end = line + strlen (line) - 1; + while (end > line && (*end == '\r' || *end == '\n')) + *end-- = '\0'; + } + while (end > line && isspace (*end)) + *end-- = '\0'; + + return end; +} + +/* The getservent() function reads the next line from the file `/etc/services' + and returns a structure servent containing the broken out fields from the + line. The `/etc/services' file is opened if necessary. */ +struct servent * +getservent (void) +{ + char line[MAX_NAMLEN], *end, *p; + int done = 0, i, n, a; + struct servent *e = NULL; + + /* Ensure a open file. */ + if (scm_i_servent.fd == NULL || feof (scm_i_servent.fd)) + { + setservent (1); + if (scm_i_servent.fd == NULL) + return NULL; + } + + while (!done) + { + /* Get new line. */ + if (fgets (line, MAX_NAMLEN, scm_i_servent.fd) != NULL) + { + end = scm_i_socket_uncomment (line); + + /* Scan the line. */ + if ((i = sscanf (line, "%s %d/%s%n", + scm_i_servent.name, + &scm_i_servent.port, + scm_i_servent.proto, &n)) != 3) + continue; + + /* Scan the remaining aliases. */ + p = line + n; + for (a = 0; a < MAX_ALIASES && p < end && i != -1 && n > 1; + a++, p += n) + i = sscanf (p, "%s%n", scm_i_servent.alias[a], &n); + + /* Prepare the return value. */ + e = &scm_i_servent.ent; + e->s_name = scm_i_servent.name; + e->s_port = htons (scm_i_servent.port); + e->s_proto = scm_i_servent.proto; + e->s_aliases = scm_i_servent.aliases; + scm_i_servent.aliases[a] = NULL; + while (a--) + scm_i_servent.aliases[a] = scm_i_servent.alias[a]; + done = 1; + } + else + break; + } + return done ? e : NULL; +} + +/* The setservent() function opens and rewinds the `/etc/services' file. + This file can be set from outside with an environment variable specifying + the file name. */ +void +setservent (int stayopen) +{ + char *file = NULL; + + endservent (); + if ((file = getenv (ENVIRON_ETC_SERVICES)) != NULL) + strcpy (scm_i_servent.file, file); + else if ((file = scm_i_socket_filename (FILE_ETC_SERVICES)) != NULL) + strcpy (scm_i_servent.file, file); + scm_i_servent.fd = fopen (scm_i_servent.file, "rt"); +} + +/* The endservent() function closes the `/etc/services' file. */ +void +endservent (void) +{ + if (scm_i_servent.fd != NULL) + { + fclose (scm_i_servent.fd); + scm_i_servent.fd = NULL; + } +} + +/* The getprotoent() function reads the next line from the file + `/etc/protocols' and returns a structure protoent containing the broken + out fields from the line. The `/etc/protocols' file is opened if + necessary. */ +struct protoent * +getprotoent (void) +{ + char line[MAX_NAMLEN], *end, *p; + int done = 0, i, n, a; + struct protoent *e = NULL; + + /* Ensure a open file. */ + if (scm_i_protoent.fd == NULL || feof (scm_i_protoent.fd)) + { + setprotoent (1); + if (scm_i_protoent.fd == NULL) + return NULL; + } + + while (!done) + { + /* Get new line. */ + if (fgets (line, MAX_NAMLEN, scm_i_protoent.fd) != NULL) + { + end = scm_i_socket_uncomment (line); + + /* Scan the line. */ + if ((i = sscanf (line, "%s %d%n", + scm_i_protoent.name, + &scm_i_protoent.proto, &n)) != 2) + continue; + + /* Scan the remaining aliases. */ + p = line + n; + for (a = 0; a < MAX_ALIASES && p < end && i != -1 && n > 1; + a++, p += n) + i = sscanf (p, "%s%n", scm_i_protoent.alias[a], &n); + + /* Prepare the return value. */ + e = &scm_i_protoent.ent; + e->p_name = scm_i_protoent.name; + e->p_proto = scm_i_protoent.proto; + e->p_aliases = scm_i_protoent.aliases; + scm_i_protoent.aliases[a] = NULL; + while (a--) + scm_i_protoent.aliases[a] = scm_i_protoent.alias[a]; + done = 1; + } + else + break; + } + return done ? e : NULL; +} + +/* The setprotoent() function opens and rewinds the `/etc/protocols' file. + As in setservent() the user can modify the location of the file using + an environment variable. */ +void +setprotoent (int stayopen) +{ + char *file = NULL; + + endprotoent (); + if ((file = getenv (ENVIRON_ETC_PROTOCOLS)) != NULL) + strcpy (scm_i_protoent.file, file); + else if ((file = scm_i_socket_filename (FILE_ETC_PROTOCOLS)) != NULL) + strcpy (scm_i_protoent.file, file); + scm_i_protoent.fd = fopen (scm_i_protoent.file, "rt"); +} + +/* The endprotoent() function closes `/etc/protocols'. */ +void +endprotoent (void) +{ + if (scm_i_protoent.fd != NULL) + { + fclose (scm_i_protoent.fd); + scm_i_protoent.fd = NULL; + } +} + /* Define both the original and replacement error symbol is possible. Thus the user is able to check symbolic errors after unsuccessful networking function calls. */ diff --git a/libguile/win32-socket.h b/libguile/win32-socket.h index 83e1030dd..adbe2c517 100644 --- a/libguile/win32-socket.h +++ b/libguile/win32-socket.h @@ -52,5 +52,13 @@ int scm_i_socket_errno (void); char * scm_i_socket_strerror (int error); void scm_i_init_socket_Win32 (void); +char * scm_i_socket_filename (char *file); + +struct servent * getservent (void); +void setservent (int stayopen); +void endservent (void); +struct protoent * getprotoent (void); +void setprotoent (int stayopen); +void endprotoent (void); #endif /* SCM_WIN32_SOCKET_H */