ldmud-3.2.9/doc/
ldmud-3.2.9/doc/efun/
ldmud-3.2.9/mud/
ldmud-3.2.9/mud/heaven7/
ldmud-3.2.9/mud/heaven7/lib/
ldmud-3.2.9/mud/lp-245/
ldmud-3.2.9/mud/lp-245/banish/
ldmud-3.2.9/mud/lp-245/doc/
ldmud-3.2.9/mud/lp-245/doc/examples/
ldmud-3.2.9/mud/lp-245/doc/sefun/
ldmud-3.2.9/mud/lp-245/log/
ldmud-3.2.9/mud/lp-245/obj/Go/
ldmud-3.2.9/mud/lp-245/players/lars/
ldmud-3.2.9/mud/lp-245/room/death/
ldmud-3.2.9/mud/lp-245/room/maze1/
ldmud-3.2.9/mud/lp-245/room/sub/
ldmud-3.2.9/mud/lp-245/secure/
ldmud-3.2.9/mud/morgengrauen/
ldmud-3.2.9/mud/morgengrauen/lib/
ldmud-3.2.9/mud/sticklib/
ldmud-3.2.9/mud/sticklib/src/
ldmud-3.2.9/mudlib/uni-crasher/
ldmud-3.2.9/pkg/
ldmud-3.2.9/pkg/debugger/
ldmud-3.2.9/pkg/diff/
ldmud-3.2.9/pkg/misc/
ldmud-3.2.9/src/autoconf/
ldmud-3.2.9/src/bugs/
ldmud-3.2.9/src/bugs/MudCompress/
ldmud-3.2.9/src/bugs/b-020916-files/
ldmud-3.2.9/src/bugs/doomdark/
ldmud-3.2.9/src/bugs/ferrycode/ferry/
ldmud-3.2.9/src/bugs/ferrycode/obj/
ldmud-3.2.9/src/bugs/psql/
ldmud-3.2.9/src/done/
ldmud-3.2.9/src/done/order_alist/
ldmud-3.2.9/src/done/order_alist/obj/
ldmud-3.2.9/src/done/order_alist/room/
ldmud-3.2.9/src/gcc/
ldmud-3.2.9/src/gcc/2.7.0/
ldmud-3.2.9/src/gcc/2.7.1/
ldmud-3.2.9/src/hosts/
ldmud-3.2.9/src/hosts/GnuWin32/
ldmud-3.2.9/src/hosts/amiga/NetIncl/
ldmud-3.2.9/src/hosts/amiga/NetIncl/netinet/
ldmud-3.2.9/src/hosts/amiga/NetIncl/sys/
ldmud-3.2.9/src/hosts/i386/
ldmud-3.2.9/src/hosts/msdos/byacc/
ldmud-3.2.9/src/hosts/msdos/doc/
ldmud-3.2.9/src/hosts/os2/
ldmud-3.2.9/src/hosts/win32/
ldmud-3.2.9/src/util/
ldmud-3.2.9/src/util/erq/
ldmud-3.2.9/src/util/indent/hosts/next/
ldmud-3.2.9/src/util/xerq/
ldmud-3.2.9/src/util/xerq/lpc/
ldmud-3.2.9/src/util/xerq/lpc/www/
diff -Nur 3-3/src/Makefile.in 3-3.new/src/Makefile.in
--- 3-3/src/Makefile.in	2002-10-17 06:27:03.000000000 +0200
+++ 3-3.new/src/Makefile.in	2002-11-16 00:44:38.000000000 +0100
@@ -74,7 +74,7 @@
       interpret.c \
       lex.c main.c mapping.c md5.c mempools.c mregex.c mstrings.c object.c \
       otable.c\
-      parser.c parse.c pkg-alists.c pkg-mysql.c pkg-pcre.c port.c \
+      parser.c parse.c pkg-alists.c pkg-mysql.c pkg-pcre.c pkg-pgsql.c port.c \
       ptrtable.c \
       random.c regexp.c simulate.c simul_efun.c stdstrings.c \
       strfuns.c sprintf.c swap.c wiz_list.c xalloc.c 
@@ -84,7 +84,7 @@
       interpret.o \
       lex.o main.o mapping.o md5.o mempools.o mregex.o mstrings.o object.o \
       otable.o \
-      parser.o parse.o pkg-alists.o pkg-mysql.o pkg-pcre.o port.o \
+      parser.o parse.o pkg-alists.o pkg-mysql.o pkg-pcre.o pkg-pgsql.o port.o \
       ptrtable.o \
       random.o regexp.o simulate.o simul_efun.o stdstrings.o \
       strfuns.o sprintf.o swap.o wiz_list.o xalloc.o @ALLOCA@ 
diff -Nur 3-3/src/comm.c 3-3.new/src/comm.c
--- 3-3/src/comm.c	2002-11-16 00:44:07.000000000 +0100
+++ 3-3.new/src/comm.c	2002-11-16 00:44:38.000000000 +0100
@@ -2194,7 +2194,7 @@
 
 {
     /* State information: */
-    static fd_set readfds;
+    static fd_set readfds, writefds;
       /* List of sockets with pending data.
        * You can ignore a 'could be used uninitialized' warning.
        */
@@ -2241,6 +2241,7 @@
             /* Set up readfds */
 
             FD_ZERO(&readfds);
+            FD_ZERO(&writefds);
             for (i = 0; i < numports; i++) {
                 FD_SET(sos[i], &readfds);
             } /* for */
@@ -2281,6 +2282,9 @@
                 FD_SET(udp_s, &readfds);
             }
 
+#ifdef USE_PGSQL
+	    pg_setfds(&readfds, &writefds, &nfds);
+#endif
             /* select() until time is up or there is data */
 
             for (retries = 6;;)
@@ -2288,7 +2292,7 @@
                 check_alarm();
                 timeout.tv_sec = twait;
                 timeout.tv_usec = 0;
-                res = socket_select(nfds, &readfds, 0, 0, &timeout);
+                res = socket_select(nfds, &readfds, &writefds, 0, &timeout);
                 if (res == -1)
                 {
                     /* BeOS <= PR2 returns errno -1 instead of EINTR :-( */
@@ -2359,6 +2363,9 @@
                 }
             } /* if (urgent_data) */
 
+#ifdef USE_PGSQL
+	    pg_process_all();
+#endif
             /* Initialise the user scan */
             CmdsGiven = 0;
             NextCmdGiver = StartCmdGiver;
diff -Nur 3-3/src/config.h.in 3-3.new/src/config.h.in
--- 3-3/src/config.h.in	2002-11-16 00:43:50.000000000 +0100
+++ 3-3.new/src/config.h.in	2002-11-16 00:44:38.000000000 +0100
@@ -294,6 +294,10 @@
  */
 @cdef_use_pcre@ USE_PCRE
 
+/* Define this if you want PostgreSQL-EFuns.
+ */
+@cdef_use_pgsql@ USE_PGSQL
+
 /* Define this if you want the obsolete and deprecated efuns.
  */
 @cdef_use_deprecated@ USE_DEPRECATED
diff -Nur 3-3/src/configure 3-3.new/src/configure
--- 3-3/src/configure	2002-11-08 04:36:30.000000000 +0100
+++ 3-3.new/src/configure	2002-11-16 00:44:38.000000000 +0100
@@ -857,6 +857,8 @@
         enable using of threads for socket writes
   --enable-use-pcre                   default=enabled
         Enables PCRE instead of traditional regexps
+  --enable-use-pgsql                  default=disabled
+        Enables PostgreSQL-Efuns
   --enable-use-deprecated             default=enabled
         Enables obsolete and deprecated efuns
   --enable-use-structs                default=enabled
@@ -1466,6 +1468,13 @@
 
 fi;
 
+DEFAULTenable_use_pgsql=yes
+# Check whether --enable-use-pgsql or --disable-use-pgsql was given.
+if test "${enable_use_pgsql+set}" = set; then
+  enableval="$enable_use_pgsql"
+
+fi;
+
 DEFAULTenable_use_deprecated=yes
 # Check whether --enable-use-deprecated or --disable-use-deprecated was given.
 if test "${enable_use_deprecated+set}" = set; then
@@ -2202,12 +2211,22 @@
   enable_use_pcre=$DEFAULTenable_use_pcre
 fi
 
+if test "x$enable_use_pgsql" = "x" && test "x$DEFAULTenable_use_pgsql" != "x"; then
+  enable_use_pgsql=$DEFAULTenable_use_pgsql
+fi
+
 if test "x$enable_use_pcre" = "xyes"; then
   cdef_use_pcre="#define"
 else
   cdef_use_pcre="#undef"
 fi
 
+if test "x$enable_use_pgsql" = "xyes"; then
+  cdef_use_pgsql="#define"
+else
+  cdef_use_pgsql="#undef"
+fi
+
 if test "x$enable_use_pthreads" = "x" && test "x$DEFAULTenable_use_pthreads" != "x"; then
   enable_use_pthreads=$DEFAULTenable_use_pthreads
 fi
@@ -9362,6 +9381,10 @@
 
 # ---
 
+if test $enable_use_pgsql = yes; then
+   PKGLIBS="$PKGLIBS -lpq"
+fi
+
 echo "$as_me:$LINENO: checking if rename handles directories" >&5
 echo $ECHO_N "checking if rename handles directories... $ECHO_C" >&6
 if test "${lp_cv_sys_rename_handles_directories+set}" = set; then
@@ -11636,6 +11659,7 @@
 s,@cdef_use_pthreads@,$cdef_use_pthreads,;t t
 s,@cdef_use_alists@,$cdef_use_alists,;t t
 s,@cdef_use_pcre@,$cdef_use_pcre,;t t
+s,@cdef_use_pgsql@,$cdef_use_pgsql,;t t
 s,@cdef_use_deprecated@,$cdef_use_deprecated,;t t
 s,@cdef_use_structs@,$cdef_use_structs,;t t
 s,@cdef_use_new_inlines@,$cdef_use_new_inlines,;t t
diff -Nur 3-3/src/func_spec 3-3.new/src/func_spec
--- 3-3/src/func_spec	2002-10-30 03:35:24.000000000 +0100
+++ 3-3.new/src/func_spec	2002-11-16 00:44:38.000000000 +0100
@@ -673,5 +673,10 @@
 
 #endif /* USE_DEPRECATED */
 
+#ifdef USE_PGSQL
+int  pgconnect (string, string);
+int  pgquery   (string, void|int);
+void pgclose   ();
+#endif
 
 /***************************************************************************/
diff -Nur 3-3/src/pkg-pgsql.c 3-3.new/src/pkg-pgsql.c
--- 3-3/src/pkg-pgsql.c	1970-01-01 01:00:00.000000000 +0100
+++ 3-3.new/src/pkg-pgsql.c	2002-11-16 00:44:38.000000000 +0100
@@ -0,0 +1,631 @@
+ /***************************************************************************
+ * Async Postgres-DB EFUNS                                                  *
+ *                                                                          *
+ * Entries in func_spec:                                                    *
+ * int pgconnect (string, string)                                           *
+ * int pgquery (string)                                                     *
+ * void pgclose (void)                                                      *
+ *                                                                          *
+ * pgconnect: params:  int pgconnect(string callback, string connstr)       *
+ *            returns: 0 (OK);  -1 (FAILED)                                 *
+ *            connstr an in pglib-function PQconnectdb()                    *
+ *            callback-function <callback>(int type, mixed ret, int id)     *
+ *              <type> is the type of the return-value:                     *
+ *                PGRES_TUPLES_OK: ret is a mapping containing the returned *
+ *                                 rows. The key is the field-name which    *
+ *                                 indexes n values (for n returned tuples) *
+ *                PGRES_COMMAND_OK: ret is a string which contains the      *
+ *                                  server response (e.g. on INSERT         *
+ *                                  or DELETE)                              *
+ *                PGRES_BAD_RESPONSE or                                     *
+ *                PGRES_NONFATAL_ERROR or                                   *
+ *                PGRES_FATAL_ERROR: ret is the error-string                *
+ *              additionally the following non-standard types may be        *
+ *              returned (id is ignored):                                   *
+ *                PGRES_NOTICE: ret is a notification-string                *
+ *                PGCONN_SUCCESS: The database-connection was established.  *
+ *                PGCONN_FAILED:  The database-connection failed.           *
+ *                  One of these two is the first message to the callback   *
+ *                  after a successful call to pgconnect()                  *
+ *                PGCONN_ABORTED: If the connection to the backend fails    *
+ *                                we try to re-establish (reset) it. If the *
+ *                                reset fails, the connection is closed and *
+ *                                this value is returned. Consider the      *
+ *                                connection gone and don't try to close or *
+ *                                otherwise operate further on it.          *
+ *              <id> is the query-id returned by pgquery()                  *
+ * pgconnect throws a privilege violation "pgconnect" with the connect-     *
+ * string as argument.                                                      *
+ *                                                                          *
+ * pgquery: params:  pgquery(string query)                                  *
+ *          returns the query-id, which will be passed to the callback      *
+ *                                                                          *
+ * pgclose: params: none                                                    *
+ *          returns: nothing                                                *
+ *          closes the connection to the backend.                           *
+ ***************************************************************************/
+
+#include "driver.h"
+
+#ifdef USE_PGSQL
+
+#include "typedefs.h"
+
+#include "my-alloca.h"
+#include <stddef.h>
+#include <time.h>
+#include <sys/poll.h>
+#include <postgresql/libpq-fe.h>
+
+#include "simulate.h"
+
+#include "actions.h"
+#include "array.h"
+#include "backend.h"
+#include "interpret.h"
+#include "mstrings.h"
+#include "mapping.h"
+#include "object.h"
+#include "smalloc.h"
+#include "stdstrings.h"
+#include "svalue.h"
+#include "xalloc.h"
+
+#define PG_UNCONNECTED 0
+#define PG_CONNECTING  1
+#define PG_RESETTING   2
+#define PG_RESET_NEXT  3
+#define PG_IDLE        4
+#define PG_SENDQUERY   5
+#define PG_WAITREPLY   6
+#define PG_REPLYREADY  7
+
+
+#define PG_NOTICE  99
+
+#define PGCONN_SUCCESS 100
+#define PGCONN_FAILED  101
+#define PGCONN_ABORTED 102
+
+#define RESULT_ARRAY 0x00
+#define RESULT_ASSOC 0x01
+
+#define MAX_RESETS 5   // We try x resets, max. one per second
+
+#define optfree(x) do {            \
+                      if (x) {     \
+			 free(x);  \
+                         x = NULL; \
+		      }            \
+                   } while (0)
+
+struct query_queue {
+   int id;
+   char *str;
+   int flags;
+   struct query_queue *next;
+};
+
+static struct dbconn {
+   string_t *callback;
+   
+   PGconn *conn;
+   PostgresPollingStatusType pgstate;
+   
+   int state;
+   int fd;
+   int resets;
+
+   time_t lastreset;
+   time_t lastreply;
+
+   object_t *object;
+   struct query_queue *queue;
+   
+   struct dbconn *next;
+} *head = NULL;
+
+static int query_id = 1;
+
+static void pgnotice (struct dbconn *pgconn, const char *msg);
+
+
+/*************************************************************************/
+/*************************   Queue management ****************************/
+/*************************************************************************/
+
+struct query_queue *queue(struct dbconn *db, char *query) {
+   struct query_queue *tmp;
+   
+   tmp = db->queue;
+   if (!tmp)
+     tmp = db->queue = malloc(sizeof(struct query_queue));
+   else {
+      while (tmp->next)
+	tmp = tmp->next;
+      tmp->next = malloc(sizeof(struct query_queue));
+      tmp = tmp->next;
+   }
+   if (!tmp) {
+      outofmemory("Queueing PG-Query");
+      /* NOTREACHED */
+      return NULL;
+   }
+   memset(tmp, 0, sizeof(struct query_queue));
+   tmp->id  = query_id++;
+   tmp->str = strdup(query);
+   tmp->flags = 0;
+   
+   return tmp;
+}
+
+void dequeue (struct dbconn *db) {
+   struct query_queue *tmp;
+   
+   tmp = db->queue;
+   db->queue = tmp->next;
+   optfree(tmp->str);
+   free(tmp);
+}
+
+static struct dbconn *alloc_dbconn (void) {
+   struct dbconn *ret;
+   
+   ret = malloc(sizeof(struct dbconn));
+   if (!ret) {
+      outofmemory("Allocating new DB-connection");
+      /* NOTREACHED */
+      return NULL;
+   }
+   
+   memset(ret, 0, sizeof(struct dbconn));
+   ret->next = head;
+   ret->fd = -1;
+   ret->state = PG_UNCONNECTED;
+   head = ret;
+   
+   return ret;
+}
+
+static void dealloc_dbconn (struct dbconn *del) {
+   struct dbconn *ptr;
+   
+   if (!del)
+     return;
+   mstring_free(del->callback);
+   if (del == head)
+     head = head->next;
+   else {
+      ptr = head;
+      while (ptr->next && (ptr->next != del))
+	ptr = ptr->next;
+      if (ptr->next)
+	ptr->next = ptr->next->next;
+   }
+   while (del->queue)
+     dequeue(del);
+   free(del);
+}
+
+/*************************************************************************/
+
+
+
+
+/*************************************************************************/
+/*******************  Connection-handling functions  *********************/
+/*************************************************************************/
+
+static int pgconnect(struct dbconn *db, char *connstr) {
+   db->conn = PQconnectStart(connstr);
+   if (!db->conn)
+     return -1;
+   if (PQstatus(db->conn) == CONNECTION_BAD)
+     return -1;
+   
+   PQsetNoticeProcessor(db->conn, (void*) pgnotice, db);
+   db->fd = PQsocket(db->conn);
+   db->state = PG_CONNECTING;
+   db->pgstate = PGRES_POLLING_WRITING;
+   return 0;
+}
+
+static void pgclose (struct dbconn *pgconn) {
+   pgconn->state = PG_UNCONNECTED;
+   if (pgconn->conn)
+     PQfinish(pgconn->conn);
+   pgconn->conn = NULL;
+   pgconn->fd = -1;
+}
+
+static void pgreset (struct dbconn *pgconn) {
+
+   if (!PQresetStart(pgconn->conn)) {
+      pgclose(pgconn);
+      
+      push_number(inter_sp, PGCONN_ABORTED);
+      push_c_string(inter_sp, "Reset failed, connection aborted.");
+      secure_apply(pgconn->callback, pgconn->object, 2);
+      
+      return;
+   }
+   
+   pgconn->state = PG_RESETTING;
+   pgconn->pgstate = PGRES_POLLING_WRITING;
+}
+
+/*************************************************************************/
+
+
+
+
+/*************************************************************************/
+/********************  Database result handling  *************************/
+/*************************************************************************/
+
+static void pgnotice (struct dbconn *pgconn, const char *msg) {
+   current_object = pgconn->object;
+   command_giver = 0;
+   current_interactive = 0;
+   
+   push_number(inter_sp, PG_NOTICE);
+   push_c_string(inter_sp, msg);
+   secure_apply(pgconn->callback, pgconn->object, 2);
+}
+
+static void pgresult (struct dbconn *pgconn, PGresult *res) {
+   int type, nfields, ntuples, i, j;
+   svalue_t *entry, fname;
+   mapping_t *map;
+   vector_t *array;
+   
+   current_object = pgconn->object;
+   command_giver = 0;
+   current_interactive = 0;
+   
+   type = PQresultStatus(res);
+   
+   push_number(inter_sp, type);
+   
+   switch (type) {
+    case PGRES_TUPLES_OK:
+      nfields = PQnfields(res);
+      ntuples = PQntuples(res);
+      
+      if (pgconn->queue->flags & RESULT_ASSOC) {
+	 if ((nfields * (ntuples + 1)) > max_mapping_size) {
+	    PQclear(res);
+	    dequeue(pgconn);
+	    error("Query exceeded mappingsize-limit.\n");
+	 }
+	 
+	 map = allocate_mapping(nfields, ntuples);
+	 if (!map) {
+	    push_number(inter_sp, 0);
+	    break;
+	 }
+	 
+	 for (i = 0; i < nfields; i++) {
+	    put_c_string(&fname, PQfname(res, i));
+	    entry = get_map_lvalue(map, &fname);
+	    free_svalue(&fname);
+	    if (!entry)
+	      break;
+	    for (j = 0; j < ntuples; j++)
+	      put_c_string(&entry[j], PQgetvalue(res, j, i));
+	 }
+	 
+	 push_mapping(inter_sp, map);
+      } else {
+	 if ((ntuples >= max_array_size) || (nfields >= max_array_size)) {
+	    PQclear(res);
+	    dequeue(pgconn);
+	    error("Query exceeded array-limit.\n");
+	 }
+	 array = allocate_array(ntuples+1);
+	 if (!array) {
+	    push_number(inter_sp, 0);
+	    break;
+	 }
+	 
+	 entry = &array->item[0];
+	 put_array(entry, allocate_array(nfields));
+	 for (j = 0; j < nfields; j++)
+	   put_c_string(&entry->u.vec->item[j], PQfname(res, j));
+	 
+	 for (i = 0; i < ntuples; i++) {
+	    entry = &array->item[i+1];
+	    put_array(entry, allocate_array(nfields));
+	    for (j = 0; j < nfields; j++)
+	      put_c_string(&entry->u.vec->item[j], PQgetvalue(res, i, j));
+	 }
+	 push_array(inter_sp, array);
+      }
+      break;
+      
+    case PGRES_COMMAND_OK:
+//      push_number(inter_sp, atoi(PQcmdTuples(res)));
+      push_c_string(inter_sp, PQcmdStatus(res));
+      break;
+      
+    case PGRES_BAD_RESPONSE:
+      push_c_string(inter_sp, PQerrorMessage(pgconn->conn));
+      break;
+      
+    case PGRES_FATAL_ERROR:
+    case PGRES_NONFATAL_ERROR:
+      push_c_string(inter_sp, PQerrorMessage(pgconn->conn));
+      break;
+      
+    default:
+      PQclear(res);
+      return;
+   }
+   
+   push_number(inter_sp, pgconn->queue->id);
+
+   secure_apply(pgconn->callback, pgconn->object, 3);
+   dequeue(pgconn);
+   PQclear(res);
+}
+
+/*************************************************************************/
+
+
+
+
+/*************************************************************************/
+/*******************  Database Connection-processing  ********************/
+/*************************************************************************/
+
+static void pg_process_connect_reset (struct dbconn *pgconn) {
+   struct pollfd ufd;
+   int reset;
+   PostgresPollingStatusType (*pqpollhandler)(PGconn *);
+   
+   reset = (pgconn->state == PG_RESETTING);
+   
+   if (reset)
+     printf("Connection resetting...\n");
+   
+   pqpollhandler = reset ? PQresetPoll : PQconnectPoll;
+   
+   if (pgconn->pgstate != PGRES_POLLING_ACTIVE) {
+      ufd.fd = pgconn->fd;
+      switch (pgconn->pgstate) {
+       case PGRES_POLLING_READING:
+	 ufd.events = POLLIN;
+	 break;
+       case PGRES_POLLING_WRITING:
+	 ufd.events = POLLOUT;
+	 break;
+       default:    // To keep the compiler happy...
+	 break;
+      }
+      if (poll(&ufd, 1, 0) > 0) {
+	 pgconn->pgstate = PGRES_POLLING_ACTIVE;
+	 if (ufd.revents | POLLIN)
+	   pgconn->lastreply = time(NULL);
+      }
+   }
+   
+   if (pgconn->pgstate == PGRES_POLLING_ACTIVE)
+     pgconn->pgstate = pqpollhandler(pgconn->conn);
+   
+   if (pgconn->pgstate == PGRES_POLLING_FAILED) {
+      if (reset && (pgconn->resets < MAX_RESETS)) {
+	 pgconn->resets++;
+	 pgconn->state = PG_RESET_NEXT;
+	 pgconn->lastreset = time(NULL);
+      } else {
+	 push_number(inter_sp, reset ? PGCONN_ABORTED : PGCONN_FAILED);
+	 push_c_string(inter_sp, PQerrorMessage(pgconn->conn));
+	 secure_apply(pgconn->callback, pgconn->object, 2);
+	 pgclose(pgconn);
+      }
+   } else if (pgconn->pgstate == PGRES_POLLING_OK) {
+      if (!reset) {  // The program should not notice a successful reset
+	 push_number(inter_sp, PGCONN_SUCCESS);
+	 push_c_string(inter_sp, "success");
+	 secure_apply(pgconn->callback, pgconn->object, 2);
+      }
+      pgconn->resets = 0;
+      if (pgconn->queue)
+	pgconn->state = PG_SENDQUERY;
+      else
+	pgconn->state = PG_IDLE;
+   }
+}
+
+static void pg_process_query (struct dbconn *pgconn) {
+   struct pollfd ufd;
+   
+   ufd.fd = pgconn->fd;
+   ufd.events = POLLIN;
+   
+   PQflush(pgconn->conn);
+   if (poll(&ufd, 1, 0) > 0) {
+      pgconn->lastreply = time(NULL);
+      PQconsumeInput(pgconn->conn);
+      if (!PQisBusy(pgconn->conn))
+	pgconn->state = PG_REPLYREADY;
+   }
+}
+
+static void pg_process_one(struct dbconn *pgconn) {
+   PGresult *res;
+   
+   switch(pgconn->state) {
+    case PG_CONNECTING:
+    case PG_RESETTING:
+      pg_process_connect_reset(pgconn);
+      break;
+    case PG_SENDQUERY:
+    case PG_IDLE:
+      if (pgconn->queue) {
+	 pgconn->lastreply = time(NULL);
+	 PQsendQuery(pgconn->conn, pgconn->queue->str);
+	 pgconn->state = PG_WAITREPLY;
+      }
+    case PG_WAITREPLY:
+      pg_process_query(pgconn);
+      break;
+    case PG_UNCONNECTED:
+      dealloc_dbconn(pgconn);
+      break;
+    case PG_RESET_NEXT:
+      if (pgconn->lastreset != time(NULL))
+	pgreset(pgconn);
+      break;
+   }
+   
+   if ((PQstatus(pgconn->conn) != CONNECTION_OK) &&
+       (pgconn->state >= PG_IDLE))
+     pgreset(pgconn);
+   
+   if (pgconn->state == PG_REPLYREADY) {
+      do {
+	 res = PQgetResult(pgconn->conn);
+	 if (!res) {
+	    pgconn->state = PG_IDLE;
+	    pg_process_one(pgconn);
+	    break;
+	 } else
+	   pgresult(pgconn, res);
+      } while (!PQisBusy(pgconn->conn));
+   }
+}
+
+void pg_process_all (void) {
+   struct dbconn *ptr = head;
+   
+   while (ptr) {
+      if (ptr->object && (check_object(ptr->object) == NULL)) {
+	 free_object(ptr->object, "pg_process_all");
+	 ptr->object = NULL;
+	 pgclose(ptr);
+      } else
+	pg_process_one(ptr);
+      ptr = ptr->next;
+   }
+}
+
+/*************************************************************************/
+
+
+
+
+/*************************************************************************/
+/************************ Helper-functions *******************************/
+/*************************************************************************/
+
+void pg_setfds (fd_set *readfds, fd_set *writefds, int *nfds) {
+   struct dbconn *ptr;
+   
+   for (ptr = head; ptr; ptr = ptr->next) {
+      if (ptr->fd < 0)
+	continue;
+      if ((ptr->pgstate == PGRES_POLLING_WRITING) ||
+	  (ptr->state == PG_SENDQUERY))
+	FD_SET(ptr->fd, writefds);
+      FD_SET(ptr->fd, readfds);
+      if (*nfds <= ptr->fd)
+	*nfds = ptr->fd + 1;
+   }
+}
+
+static struct dbconn *find_current_connection(void) {
+   struct dbconn *ptr = head;
+   
+   while (ptr && (ptr->object != current_object))
+     ptr = ptr->next;
+   
+   return ptr;
+}
+
+/*************************************************************************/
+
+
+
+/*************************************************************************/
+/********************************* EFUNS *********************************/
+/*************************************************************************/
+
+
+/* int pgconnect(string callback, string connstr) */
+
+svalue_t *
+f_pgconnect(sp, argc)
+svalue_t *sp;
+int argc;
+{
+   struct dbconn *db;
+   int st;
+   
+   if (!privilege_violation(STR_PGCONNECT, &const0, sp))
+     error("pgconnect(): privilege violation.");
+   
+   db = find_current_connection();
+   if (db) {
+      if (db->state == PG_UNCONNECTED)
+	dealloc_dbconn(db);
+      else
+	error("pgconnect(): Already connected\n");
+   }
+   db = alloc_dbconn();
+   db->object = current_object;
+   db->callback = dup_mstring(sp[-1].u.str);
+   ref_object(current_object, "f_pgconnect");
+   
+   st = pgconnect(db, sp[0].u.str->str->txt);
+   if (st < 0)
+     pgclose(db);
+   free_svalue(sp--);
+   free_svalue(sp);
+   put_number(sp, st);
+   return sp;
+}
+
+
+/* int pgquery (string query, void|int flags) */
+
+svalue_t *v_pgquery (svalue_t *sp, int argc) {
+   struct dbconn *db;
+   struct query_queue *q;
+   int flags = 0;
+   
+   if (argc == 2)
+     flags = (sp--)->u.number;
+   
+   db = find_current_connection();
+   if (!db)
+     error("pgquery(): not connected\n");
+
+   q = queue(db, sp->u.str->str->txt);
+   q->flags = flags;
+   if (db->state == PG_IDLE)
+     db->state = PG_SENDQUERY;
+
+   free_svalue(sp);
+   put_number(sp, q->id);
+   return sp;
+}
+
+
+/* void pgclose (void) */
+
+svalue_t *f_pgclose (svalue_t *sp, int argc) {
+   struct dbconn *db;
+   
+   db = find_current_connection();
+   if (!db)
+     error("pgclose: not connected\n");
+   
+   pgclose(db);
+   
+   return sp;
+}
+
+/*************************************************************************/
+
+#endif /* USE_PGSQL */
diff -Nur 3-3/src/string_spec 3-3.new/src/string_spec
--- 3-3/src/string_spec	2002-11-16 00:43:50.000000000 +0100
+++ 3-3.new/src/string_spec	2002-11-16 00:44:38.000000000 +0100
@@ -201,4 +201,8 @@
 
 #endif /* SUPPLY_PARSE_COMMAND */
 
+#ifdef USE_PGSQL
+PGCONNECT	"pgconnect"
+#endif
+
 /***************************************************************************/