changeset 9856:b79090e29952 octave-forge

miscellaneous/server.cc: removed from src and into devel since no one seems to know what to do with these
author carandraug
date Sat, 24 Mar 2012 19:36:34 +0000
parents ea494d1e3111
children e22fbfc20f5f
files main/miscellaneous/devel/README main/miscellaneous/devel/listencanfork.c main/miscellaneous/devel/server.cc main/miscellaneous/devel/server.txt main/miscellaneous/devel/stringmatch.c main/miscellaneous/doc/server.txt main/miscellaneous/src/listencanfork.c main/miscellaneous/src/server.cc main/miscellaneous/src/stringmatch.c
diffstat 9 files changed, 1206 insertions(+), 1197 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/miscellaneous/devel/README	Sat Mar 24 19:36:34 2012 +0000
@@ -0,0 +1,9 @@
+On revision 10042 the files server.cc, listencanfork.c and stringmatch.c were
+removed from the src/ directory of the miscellaneous package since no one on the
+mailing list knew what to do with these files. The packages releases were also
+not properly configured to handle it's code and even Debian packages of
+miscellaneous do not include them.
+
+Looking at the code of server.cc, it seems to implement the functions server,
+listen and senderror. Some of these would conflict with the functions in the
+package sockets. Maybe this code should be merged with sockets.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/miscellaneous/devel/listencanfork.c	Sat Mar 24 19:36:34 2012 +0000
@@ -0,0 +1,13 @@
+#if defined(__CYGWIN__)
+#include <windows.h>
+
+int listencanfork()
+{
+  OSVERSIONINFO osvi;
+  osvi.dwOSVersionInfoSize = sizeof(osvi);
+  GetVersionEx (&osvi);
+  return (osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS);
+}
+#else
+int listencanfork() { return 1; }
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/miscellaneous/devel/server.cc	Sat Mar 24 19:36:34 2012 +0000
@@ -0,0 +1,824 @@
+#define STATUS(x) do { if (debug) std::cout << x << std::endl << std::flush; } while (0)
+
+//#define HAVE_OCTAVE_30
+#include <iomanip>
+#include <iostream>
+#include <cstdio>
+#include <cctype>
+#include <cstdlib>
+//#include <unistd.h>
+//#include <stdint.h>
+#include <cerrno>
+// #include <string.h>
+#include <sys/types.h>
+
+#if (defined(_WIN32)||defined(_WIN64)) && !defined(__CYGWIN__)
+# define USE_WINSOCK
+# define CAN_FORK false
+# include <winsock.h>
+# include <io.h>
+  typedef int socklen_t;
+#else
+# define HAVE_FORK 1
+# define USE_SIGNALS
+# if defined(__CYGWIN__)
+#  define CAN_FORK listencanfork()
+# else
+#  define USE_DAEMONIZE
+#  define CAN_FORK true
+# endif
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <sys/wait.h>
+# include <signal.h>
+# define closesocket close
+#endif
+
+
+#include <octave/oct.h>
+#include <octave/parse.h>
+#include <octave/variables.h>
+#if 0
+#include <octave/unwind-prot.h>
+#endif
+#include <octave/oct-syscalls.h>
+#include <octave/oct-time.h>
+#include <octave/lo-mappers.h>
+#include <octave/symtab.h>
+
+static bool debug = false;
+static char* context = NULL;
+
+static double timestamp = 0.0;
+inline void tic(void) { timestamp = octave_time().double_value(); }
+inline double toc(void) {return ceil(-1e6*(timestamp-octave_time().double_value()));}
+
+// XXX FIXME XXX --- surely this is part of the standard library?
+void
+lowercase (std::string& s)
+{
+  for (std::string::iterator i=s.begin(); i != s.end(); i++) *i = tolower(*i);
+}
+
+#if 0
+octave_value
+get_builtin_value (const std::string& nm)
+{
+  octave_value retval;
+
+  symbol_record *sr = fbi_sym_tab->lookup (nm);
+
+  if (sr)
+    {
+      octave_value sr_def = sr->def ();
+
+      if (sr_def.is_undefined ())
+        error ("get_builtin_value: undefined symbol `%s'", nm.c_str ());
+      else
+        retval = sr_def;
+      }
+  else
+    error ("get_builtin_value: unknown symbol `$s'", nm.c_str ());
+
+  return retval;
+}
+#endif
+
+#ifdef USE_WINSOCK
+  bool init_sockets()
+  {
+
+  WSADATA wsaData;
+  WORD version;
+  int error;
+
+  version = MAKEWORD( 2, 0 );
+
+  error = WSAStartup( version, &wsaData );
+
+  /* check for error */
+  if ( error != 0 )
+  {
+    /* error occured */
+    return false;
+  }
+
+  /* check for correct version */
+  if ( LOBYTE( wsaData.wVersion ) != 2 ||
+       HIBYTE( wsaData.wVersion ) != 0 )
+  {
+      /* incorrect WinSock version */
+      WSACleanup();
+      return false;
+  }
+  return true;
+  }
+
+  inline void end_sockets() { WSACleanup(); }
+  inline int socket_errno() { return WSAGetLastError(); }
+#else // !USE_WINSOCK
+# include <cerrno>
+  inline bool init_sockets() { return true; }
+  inline void end_sockets() { }
+  inline int socket_errno() { return errno; }
+#endif // !USE_WINSOCK
+inline void socket_error(const char *context)
+{
+  int err = socket_errno();
+  char errno_str[15];
+  snprintf(errno_str, sizeof(errno_str), " %d: ", err);
+  std::string msg = std::string(context) + std::string(errno_str) 
+                  + std::string (strerror(err));
+  error(msg.c_str());
+}
+
+#ifdef USE_SIGNALS
+static void
+sigchld_handler(int /* sig */)
+{
+  int status;
+  /* Reap all childrens */
+  STATUS("reaping all children");
+  while (waitpid(-1, &status, WNOHANG) > 0)
+    ;
+  STATUS("done reaping children");
+}
+
+/* Posix signal handling, based on the example from the
+ * Unix Programming FAQ 
+ * Copyright (C) 2000 Andrew Gierth
+ */
+static void sigchld_setup(void)
+{
+  struct sigaction act;
+
+  /* Assign sig_chld as our SIGCHLD handler */
+  act.sa_handler = sigchld_handler;
+
+  /* We don't want to block any other signals in this example */
+  sigemptyset(&act.sa_mask);
+  
+  /*
+   * We're only interested in children that have terminated, not ones
+   * which have been stopped (eg user pressing control-Z at terminal)
+   */
+  act.sa_flags = SA_NOCLDSTOP;
+
+  /*
+   * Make these values effective. If we were writing a real 
+   * application, we would probably save the old value instead of 
+   * passing NULL.
+   */
+  if (sigaction(SIGCHLD, &act, NULL) < 0) 
+     error("listen could not set SIGCHLD");
+}
+#else
+inline void sigchld_setup(void) { }
+#endif
+
+
+#ifdef USE_DAEMONIZE
+
+static RETSIGTYPE
+sigterm_handler(int /* sig */)
+{
+  exit(0);
+}
+
+static void
+daemonize(void)
+{
+  if (fork()) exit(0);  // Stop parent
+  // Show child PID
+  std::cout << "Octave pid: " << octave_syscalls::getpid() << std::endl;
+  std::cout.flush();
+  signal(SIGTERM,sigterm_handler);
+  signal(SIGQUIT,sigterm_handler);
+
+
+#if 1
+  const char err[] = "/dev/null";
+  const char out[] = "/dev/null";
+#else
+  const char err[] = "/tmp/octserver.err";
+  const char out[] = "/tmp/octserver.out";
+  std::cout << "redirecting to " << out << " and " << err << std::endl; std::cout.flush();
+#endif
+
+  // Exit silently if I/O redirect fails.
+  if (freopen("/dev/null", "r", stdin) == NULL
+      || freopen(out, "w", stdout) == NULL
+      || freopen(err, "w", stderr) == NULL) {
+    // std::cerr << "ioredirect failed" << std::endl; std::cerr.flush();
+    exit(0);
+  }
+  // std::cout << "ioredirect succeeded" << std::endl; std::cout.flush();
+  //debug = true;
+}
+
+#else
+// Don't daemonize on cygwin just yet.
+inline void daemonize(void) {}
+
+#endif // !DAEMONIZE
+
+
+
+static octave_value get_octave_value(char *name)
+{
+  octave_value def;
+
+  // Copy variable from octave
+#if defined(HAVE_TOP_LEVEL_SYM_TAB)
+  // Octave 3.0
+  symbol_record *sr = top_level_sym_tab->lookup (name);
+  if (sr) def = sr->def();
+#elif defined(HAVE_VARREF)
+  // Octave 2.x
+  def = symbol_table::varref (std::string (name), symbol_table::top_scope ());
+#else
+  // Octave 3.2
+  def = get_global_value(name);
+#endif
+
+  return def;
+}
+
+
+static void channel_error (const int channel, const char *str)
+{
+  STATUS("sending error !!!e (" << strlen(str) << ") " << str);
+
+  uint32_t len = strlen(str);
+  send(channel,"!!!e",4,0);
+  uint32_t t = htonl(len); send(channel,(const char *)&t,4,0);
+  send(channel,str,len,0);
+}
+
+static bool reads (const int channel, void * buf, int n)
+{
+  // STATUS("entering reads loop with size " << n); tic();
+  while (1) {
+    int chunk = recv(channel, (char *)buf, n, 0);
+    if (chunk == 0) STATUS("read socket returned 0");
+    if (chunk < 0) STATUS("read socket error " << socket_errno());
+    if (chunk <= 0) return false;
+    n -= chunk;
+    // if (n == 0) STATUS("done reads loop after " << toc() << "us");
+    if (n == 0) return true;
+    // STATUS("reading remaining " << n << " characters");
+    buf = (void *)((char *)buf + chunk);
+  }
+}
+
+static bool writes (const int channel, const void * buf, int n)
+{
+  // STATUS("entering writes loop");
+  while (1) {
+    int chunk = send(channel, (const char *)buf, n, 0);
+    if (chunk == 0) STATUS("write socket returned 0");
+    if (chunk < 0) STATUS("write socket: " << strerror(errno));
+    if (chunk <= 0) return false;
+    n -= chunk;
+    // if (n == 0) STATUS("done writes loop");
+    if (n == 0) return true;
+    buf = (void *)((char *)buf + chunk);
+  }
+}
+
+static void
+process_commands(int channel)
+{
+  // XXX FIXME XXX check read/write return values
+  assert(sizeof(uint32_t) == 4);
+  char command[5];
+  char def_context[16536];
+  bool ok;
+  STATUS("waiting for command");
+
+  // XXX FIXME XXX do we need to specify the context size?
+  //  int bufsize=sizeof(def_context);
+  //  socklen_t ol;
+  //  ol=sizeof(bufsize);
+  //  setsockopt(channel,SOL_SOCKET,SO_SNDBUF,&bufsize,ol);
+  //  setsockopt(channel,SOL_SOCKET,SO_RCVBUF,&bufsize,ol);
+
+  // XXX FIXME XXX prepare to capture long jumps, because if
+  // we dont, then errors in octave might escape to the prompt
+
+  command[4] = '\0';
+  if (debug) tic();
+  while (reads(channel, &command, 4)) {
+    // XXX FIXME XXX do whatever is require to check if function files
+    // have changed; do we really want to do this for _every_ command?
+    // Maybe we need a 'reload' command.
+    STATUS("received command " << command << " after " << toc() << "us");
+    
+    // Check for magic command code
+    if (command[0] != '!' || command[1] != '!' || command[2] != '!') {
+      STATUS("communication error: closing connection");
+      break;
+    }
+
+    // Get command length
+    if (debug) tic(); // time the read
+    uint32_t len;
+    if (!reads(channel, &len, 4)) break;
+    len = ntohl(len);
+    // STATUS("read 4 byte command length in " << toc() << "us"); 
+
+    // Read the command context, allocating a new one if the default
+    // is too small.
+    if (len > (signed)sizeof(def_context)-1) {
+      // XXX FIXME XXX use octave allocators
+      // XXX FIXME XXX unwind_protect
+      context= new char[len+1];
+      if (context== NULL) {
+	// Requested command is too large --- skip to the next command
+	// XXX FIXME XXX maybe we want to kill the connection instead?
+	channel_error(channel,"out of memory");
+	ok = true;
+	STATUS("skip big command loop");
+	while (ok && len > (signed)sizeof(def_context)) {
+	  ok = reads(channel, def_context, sizeof(def_context));
+	  len -= sizeof(def_context);
+	}
+	STATUS("done skip big command loop");
+	if (!ok) break;
+	ok = reads(channel, def_context, sizeof(def_context));
+	if (!ok) break;
+	continue;
+      }
+    } else {
+      context = def_context;
+    }
+    // if (debug) tic();
+    ok = reads(channel, context, len);
+    context[len] = '\0';
+    STATUS("read " << len << " byte command in " << toc() << "us");
+
+    // Process the command
+    if (ok) switch (command[3]) {
+    case 'm': // send the named matrix 
+      {
+	// XXX FIXME XXX this can be removed: app can do send(name,value)
+	STATUS("sending " << context);
+	uint32_t t;
+	
+	// read the matrix contents
+	octave_value def = get_octave_value(context);
+	if(!def.is_defined() || !def.is_real_matrix()) 
+	  channel_error(channel,"not a matrix");
+	Matrix m = def.matrix_value();
+	
+	// write the matrix transfer header
+	ok = writes(channel,"!!!m",4);                // matrix message
+	t = htonl(12 + sizeof(double)*m.rows()*m.columns());
+	if (ok) ok = writes(channel,&t,4);            // length of message
+	t = htonl(m.rows()); 
+	if (ok) ok = writes(channel,&t,4);            // rows
+	t = htonl(m.columns()); 
+	if (ok) ok = writes(channel,&t,4);            // columns
+	t = htonl(len); 
+	if (ok) ok = writes(channel, &t, 4);          // name length
+	if (ok) ok = writes(channel,context,len);      // name
+	
+	// write the matrix contents
+	const double *v = m.data();                   // data
+	if (ok) ok = writes(channel,v,sizeof(double)*m.rows()*m.columns());
+	if (ok)
+	  STATUS("sent " << m.rows()*m.columns());
+	else
+	  STATUS("failed " << m.rows()*m.columns());
+      }
+      break;
+      
+    case 'x': // silently execute the command
+      {
+	if (debug) 
+	  {
+	    if (len > 500) 
+	      {
+		// XXX FIXME XXX can we limit the maximum output width for a
+		// string?  The setprecision() io manipulator doesn't do it.
+		// In the meantime, a hack ...
+		char t = context[400]; context[400] = '\0';
+		STATUS("evaluating (" << len << ") " 
+		       << context << std::endl 
+		       << "..." << std::endl 
+		       << context+len-100);
+		context[400] = t;
+	      }
+	    else
+	      {
+		STATUS("evaluating (" << len << ") " << context);
+	      }
+	  }
+
+	if (debug) tic();
+#if 1
+        error_state = 0;
+	int parse_status = 0;
+        eval_string(context, true, parse_status, 0);
+        if (parse_status != 0 || error_state)
+            eval_string("senderror(lasterr);", true, parse_status, 0);
+#elif 0
+	octave_value_list evalargs;
+	evalargs(1) = "senderror(lasterr);";
+	evalargs(0) = context;
+	octave_value_list fret = feval("eval",evalargs,0);
+#else
+	evalargs(0) = octave_value(0.);
+#endif
+	STATUS("done command");
+      }
+      STATUS("free evalargs");
+      break;
+      
+    case 'c': // execute the command and capture stdin/stdout
+      STATUS("capture command not yet implemented");
+      break;
+      
+    default:
+      STATUS("ignoring command " << command);
+      break;
+    }
+
+    if (context != def_context) delete[] context;
+    STATUS("done " << command);
+    if (!ok) break;
+    if (debug) tic();
+  }
+}
+
+
+int channel = -1;
+
+DEFUN_DLD(senderror,args,,"\
+Send the given error message across the socket.  The error context\n\
+is taken to be the last command received from the socket.")
+{
+  std::string str;
+  const int nargin = args.length();
+  if (nargin != 1) str="senderror not called with error";
+  else str = args(0).string_value();
+
+  // provide a context for the error (but not too much!)
+  str += "when evaluating:\n";
+  if (strlen(context) > 100) 
+    {	
+      char t=context[100]; 
+      context[100] = '\0'; 
+      str+=context; 
+      context[100]=t;
+    }
+  else
+    str += context;
+ 
+  STATUS("error is " << str);
+  channel_error(channel,str.c_str());
+  return octave_value_list();
+}
+
+DEFUN_DLD(send,args,,"\
+send(str)\n\
+  Send a command on the current connection\n\
+send(name,value)\n\
+  Send a binary value with the given name on the current connection\n\
+")
+{
+  bool ok;
+  uint32_t t;
+  octave_value_list ret;
+  int nargin = args.length();
+  if (nargin < 1 || nargin > 2)
+    {
+      print_usage ();
+      return ret;
+    }
+
+  if (channel < 0) {
+    error("Not presently listening on a port");
+    return ret;
+  }
+
+  std::string cmd(args(0).string_value());
+  if (error_state) return ret;
+
+  // XXX FIXME XXX perhaps process the panalopy of types?
+  if (nargin > 1) {
+    
+    octave_value def = args(1);
+    if (args(1).is_string()) {
+      // Grab the string value from args(1).
+      // Can't use args(1).string_value() because that trims trailing \0
+      charMatrix m(args(1).char_matrix_value());
+      std::string s(m.row_as_string(0,false,true));
+      STATUS("sending string(" << cmd.c_str() << " len " << s.length() << ")");
+      ok = writes(channel,"!!!s",4);               // string message
+      t = htonl(8 + cmd.length() + s.length());
+      if (ok) ok = writes(channel,&t,4);           // length of message
+      t = htonl(s.length());
+      if (ok) ok = writes(channel, &t, 4);         // string length
+      t = htonl(cmd.length());
+      if (ok) ok = writes(channel, &t, 4);         // name length
+      if (cmd.length() && ok) 
+	ok = writes(channel, cmd.c_str(), cmd.length());    // name
+      if (s.length() && ok) 
+	ok = writes(channel, s.c_str(), s.length());        // string
+    } else if (args(1).is_real_type()) {
+      Matrix m(args(1).matrix_value());
+      STATUS("sending matrix(" << cmd.c_str() << " " 
+             <<  m.rows() << "x" << m.columns() << ")");
+      
+      // write the matrix transfer header
+      ok = writes(channel,"!!!m",4);               // matrix message
+      t = htonl(12 + cmd.length() + sizeof(double)*m.rows()*m.columns());
+      if (ok) ok = writes(channel,&t,4);           // length of message
+      t = htonl(m.rows()); 
+      if (ok) ok = writes(channel,&t,4);           // rows
+      t = htonl(m.columns()); 
+      if (ok) ok = writes(channel,&t,4);           // columns
+      t = htonl(cmd.length()); 
+      if (ok) ok = writes(channel, &t, 4);         // name length
+      if (ok) ok = writes(channel, cmd.c_str(), cmd.length());    // name
+      
+      // write the matrix contents
+      const double *v = m.data();                  // data
+      if (m.rows()*m.columns() && ok) 
+	ok = writes(channel,v,sizeof(double)*m.rows()*m.columns());
+    } else {
+      ok = false;
+      error("send expected name and matrix or string value");
+    }
+    if (!ok) error("send could not write to channel");
+  } else {
+    STATUS("sending command(" << cmd.length() << ") " << cmd.c_str());
+    // STATUS("start writing at "<<toc()<<"us");
+    ok = writes(channel, "!!!x", 4);
+    t = htonl(cmd.length()); writes(channel, &t, 4);
+    if (ok) ok = writes(channel, cmd.c_str(), cmd.length());
+    if (!ok) error("send could not write to channel");
+    // STATUS("stop writing at "<<toc()<<"us");
+  }
+
+  return ret;
+}
+
+extern "C" int listencanfork(void);
+extern "C" int StringCaseMatch(const char* s, const char* p, int nocase);
+
+bool ishostglob(const std::string& s)
+{
+  for (unsigned int i=0; i < s.length(); i++) {
+    if (! ( isdigit(s[i]) || s[i]=='*' || s[i]=='-' 
+	   || s[i]=='.' || s[i]=='[' || s[i]==']')) return false;
+  }
+  return true;
+}
+
+bool anyhostglob(const string_vector& hostlist, const char* host)
+{
+  for (int j=0; j < hostlist.length(); j++) {
+    if (StringCaseMatch(host, hostlist[j].c_str(), 0)) return true;
+  }
+  return false;
+}
+
+// Known bug: functions which pass or return structures use a
+// different ABI for gcc and native compilers on some architectures.
+// Whether this is a bug depends on the structure length.  SGI's 64-bit
+// architecture makes this a problem for inet_ntoa.
+#if defined(__GNUC__) && defined(_sgi)
+#define BROKEN_INET_NTOA
+#endif
+
+#ifdef BROKEN_INET_NTOA
+
+/*************************************************
+*         Replacement for broken inet_ntoa()     *
+*************************************************/
+
+
+/* On IRIX systems, gcc uses a different structure passing convention to the
+native libraries. This causes inet_ntoa() to always yield 0.0.0.0 or
+255.255.255.255. To get round this, we provide a private version of the
+function here. It is used only if USE_INET_NTOA_FIX is set, which should
+happen
+only when gcc is in use on an IRIX system. Code send to me by J.T. Breitner,
+with these comments:
+
+
+  code by Stuart Levy
+  as seen in comp.sys.sgi.admin
+
+
+Arguments:  sa  an in_addr structure
+Returns:        pointer to static text string
+*/
+
+
+char *
+inet_ntoa(struct in_addr sa)
+{
+static char addr[20];
+sprintf(addr, "%d.%d.%d.%d",
+        (US &sa.s_addr)[0],
+        (US &sa.s_addr)[1],
+        (US &sa.s_addr)[2],
+        (US &sa.s_addr)[3]);
+  return addr;
+}
+
+#endif /* BROKEN_INET_NTOA */
+
+
+void _autoload(const char name[])
+{
+  octave_value_list evalargs, fret;
+  evalargs(0) = "server";
+  fret = feval("which",evalargs,1);
+  evalargs(0) = name;
+  evalargs(1) = fret(0);
+  fret = feval("autoload",evalargs,0);
+}
+
+DEFUN_DLD(server,args,,"\
+server(port,host,host,...)\n\
+   Listen for connections on the given port.  Normally only accepts\n\
+   connections from localhost (127.0.0.1), but you can specify any\n\
+   dot-separated host name globs.  E.g., '128.2.20.*' or '128.2.2[012].*'\n\
+   Use '?' for '[0123456789]'. Use '*.*.*.*' for any host.\n\
+server(...,'debug'|'nodebug')\n\
+   If debug, echo all commands sent across the connection.  If nodebug,\n\
+   detach the process and don't echo anything.  You will need to use\n\
+   kill directly to end the process. Nodebug is the default.\n\
+server(...,'fork'|'nofork')\n\
+   If fork, start new server for each connection.  If nofork, only allow\n\
+   one connection at a time. Fork is the default (depending on system).\n\
+server(...,'loopback')\n\
+   Use loopback address 127.0.0.1 rather than 0.0.0.0.\n\
+")
+{
+  bool canfork = CAN_FORK;
+
+  _autoload("send");
+  _autoload("senderror");
+  octave_value_list ret;
+  int nargin = args.length();
+  if (nargin < 1)
+    {
+      print_usage ();
+      return ret;
+    }
+  int port = args(0).int_value();
+  if (error_state) return ret;
+
+  // Winsock requires initialization
+  if (!init_sockets())
+	{
+	  socket_error("init");
+	  return ret;
+    }
+
+
+  debug = false;
+  uint32_t inaddr = INADDR_ANY;
+
+  string_vector hostlist;
+  hostlist.append(std::string("127.0.0.1"));
+  for (int k = 1; k < nargin; k++) {
+    std::string lastarg(args(k).string_value());
+    if (error_state) return ret;
+    lowercase(lastarg);
+    if (lastarg == "debug") {
+      debug = true;
+    } else if (lastarg == "nodebug") {
+      debug = false;
+    } else if (lastarg == "fork") {
+      canfork = true;
+    } else if (lastarg == "nofork") {
+      canfork = false;
+    } else if (lastarg == "loopback") {
+      inaddr = INADDR_LOOPBACK;
+    } else if (ishostglob(lastarg)) {
+      hostlist.append(lastarg);
+    } else {
+      print_usage ();
+    }
+  }
+
+  int sockfd;                    // listen on sockfd, new connection channel
+  struct sockaddr_in my_addr;    // my address information
+  struct sockaddr_in their_addr; // connector's address information
+  socklen_t sin_size;
+  int yes=1;
+
+  sockfd = socket(AF_INET, SOCK_STREAM, 0);
+  if (sockfd == -1) {
+	socket_error("socket");
+    return ret;
+  }
+
+  if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(const char *)(&yes),sizeof(yes)) == -1) {
+    socket_error("setsockopt");
+    return ret;
+  }
+
+  my_addr.sin_family = AF_INET;         // host byte order
+  my_addr.sin_port = htons(port);       // short, network byte order
+  my_addr.sin_addr.s_addr = htonl(inaddr); // automatically fill with my IP
+  memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
+  
+  if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))
+      == -1) {
+    socket_error("bind");
+    closesocket(sockfd);
+    return ret;
+  }
+  
+  /* listen for connections (allowing one pending connection) */
+  if (listen(sockfd, canfork?1:0) == -1) { 
+    socket_error("listen");
+    closesocket(sockfd);
+    return ret;
+  }
+
+#if 0
+  unwind_protect::begin_frame("Fserver");
+  unwind_protect_bool (buffer_error_messages);
+  buffer_error_messages = true;
+#endif
+
+  sigchld_setup();
+  if (!debug && canfork) daemonize();
+      
+  // XXX FIXME XXX want a 'sandbox' option which disables fopen, cd, pwd,
+  // system, popen ...  Or maybe just an initial script to run for each
+  // connection, plus a separate command to disable specific functions.
+  STATUS("listening on port " << port);
+  while(1) {  // main accept() loop
+    sin_size = sizeof(struct sockaddr_in);
+    STATUS("trying to accept");
+    if ((channel = accept(sockfd, (struct sockaddr *)&their_addr,
+			 &sin_size)) == -1) {
+      // XXX FIXME XXX
+      // Linux is returning "Interrupted system call" when the
+      // child terminates.  Until I figure out why, I can't use
+      // accept errors as a basis for breaking out of the listen
+      // loop, so instead print the octave PID so that I can kill
+      // it from another terminal.
+      STATUS("failed to accept"  << std::endl 
+	     << "Octave pid: " << octave_syscalls::getpid() );
+      perror("accept");
+#if defined(_sgi)
+      break;
+#else
+      continue;
+#endif
+    }
+    STATUS("connected");
+
+    /* Simulate inet_ntoa */
+    const char *them = inet_ntoa(their_addr.sin_addr);
+    STATUS("server: got connection from " << them);
+
+    if (anyhostglob(hostlist,them)) {
+#ifdef HAVE_FORK
+      if (canfork) {
+        int pid = fork();
+        if (pid == -1) {
+          socket_error("fork");
+          break;
+        } else if (pid == 0) {
+          closesocket(sockfd);      // child doesn't need listener
+          signal(SIGCHLD,SIG_DFL);  // child doesn't need SIGCHLD signal
+          process_commands(channel);
+          STATUS("child is exitting");
+          exit(0);
+        }
+      } else {
+		process_commands(channel);
+        STATUS("server: connection closed");
+      }
+#else // !HAVE_FORK
+      process_commands(channel);
+      STATUS("server: connection closed");
+#endif // !HAVE_FORK
+    } else {
+      STATUS("server: connection refused.");
+    }
+
+    closesocket(channel);
+    channel = -1;
+  }
+
+  STATUS("could not read commands; returning");
+  closesocket(sockfd);
+  end_sockets();
+#if 0
+  unwind_protect::run_frame("Fserver");
+#endif
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/miscellaneous/devel/server.txt	Sat Mar 24 19:36:34 2012 +0000
@@ -0,0 +1,118 @@
+You can talk to octave directly from other environments over the tcp/ip.
+The protocol is not sophisticated.
+
+Here is what you can send to octave: 
+
+!!!x length command
+
+	evaluate command in octave.  
+	length is a 32-bit network order integer.
+	command is a string (without zero-terminator).
+
+!!!m length name
+
+	send matrix back to client.
+	length is a 32-bit network order integer.
+	name is a string (without zero-terminator).
+
+	I don't use the !!!m command to the server because it is the same as
+
+	    !!!x send('name', matrix expression)
+
+	The latter is much more useful because you don't have to name
+	the data that you are sending across.
+
+!!!n length namelen name command
+
+	*** Not implemented ***
+	Evaluate the command in the namespace.  This needs a lookup table
+		Map<string,symbol_table> namespace
+	and a command 
+		evalin(symbol_table,command)
+	The function evalin pushes the given symbol table onto curr_sym_tab,
+	evaluates the command then pops the symbol table.
+
+Here is what you will receive from octave:
+
+!!!m length rows columns namelength name data
+
+	recieve matrix from server.
+	length,rows,columns,namelength are 32-bit network order integers.
+	name is a string (without zero-terminator).
+	data is an array of rows*columns server order double values.
+
+	This is sent in response to a !!!m matrix request or a
+	send('name',matrix) command.
+
+	The first thing I do when I open a connection is request a matrix
+	containing 1.0.  If the result is not 1.0, I know that I need to
+	swap the data to convert from server order to client order doubles.
+
+!!!s length strlen namelen name str
+
+	receive string from server.
+	length, strlen, namelen are 32-bit network order integers.
+	name is a string (without zero-terminator).
+	str is a string (without zero-terminator).
+
+	This is sent in response to a send('name',string) command.
+
+!!!x length str
+
+	evaluate string in client.
+	length is a 32-bit network order integer.
+	str is a string (without zero-terminator).
+
+	This is sent in response to a send('str').  The contents of str
+	are completely arbitrary (and may indeed contain binary data).  It is
+	up to the client to decide how they want to interpret these strings.
+
+!!!e length error
+
+	receive error from octave.
+	length is a 32-bit network order integer.
+	error is a string (without zero-terminator).
+
+	This is sent in response to a !!!x command which produced an error.
+
+Composite values can be decomposed into their constituent parts.  E.g.,
+    structures:
+	for [v,k]=x, send([name,'.',k],v); end
+    complex arrays:
+	send([name,'.real'],real(x));
+	send([name,'.imag'],imag(x));
+    sparse arrays: 
+	[v,i,j] = spfind(x);
+	send([name,'.i'],i);
+	send([name,'.j'],j);
+	send([name,'.v'],v);
+    cell arrays: 
+	[nr,nc]=size(x);
+	for r=1:nr, for c=1:nc, send([name,sprintf('.%d.%d',r,c)],x{r,c}); end
+
+Note that the communication is completely asynchronous.  I have a tcl client
+that processes server responses via fileevent.  That means that responses from
+octave are not processed until tcl enters its event loop.
+
+To be sure that octave has processed a command I follow that command with a
+synchronization sequence:
+
+	set sync[incr syncid] 1
+	octave eval "send('unset sync$syncid')"
+	vwait sync$syncid
+
+In practice it is more complicated than that because I allow the
+syncronization command to time out just in case octave crashed out from
+underneath me, but the idea is the same.
+
+Using sockets gives you platform independence and network transparency,
+which is a big win.  The only caveat is that winsock is slow.  The best I
+can do with dedicated winsock code on my machine is .3 seconds to transfer
+a 1 Mb message.  Under tcl/tk, it was closer to 1 second IIRC.  A memory
+copy of the same size took less than 0.06 seconds IIRC.
+
+That is why I'm working on a way to embed octave into tcl.  Hopefully
+it will be easy to embed in other environments as well.
+
+Paul Kienzle
+2003
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/miscellaneous/devel/stringmatch.c	Sat Mar 24 19:36:34 2012 +0000
@@ -0,0 +1,242 @@
+/* Extracted from tclUtil.c
+
+Copyright (c) 1987-1993 The Regents of the University of California.
+Copyright (c) 1994-1998 Sun Microsystems, Inc.
+Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
+
+
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
+Corporation and other parties.  The following terms apply to all files
+associated with the software unless explicitly disclaimed in
+individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal 
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license. 
+
+ */
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StringCaseMatch --
+ *
+ *	See if a particular string matches a particular pattern.
+ *	Allows case insensitivity.
+ *
+ * Results:
+ *	The return value is 1 if string matches pattern, and
+ *	0 otherwise.  The matching operation permits the following
+ *	special characters in the pattern: *?\[] (see the manual
+ *	entry for details on what these mean).
+ *
+ * Side effects:
+ *	None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+#include <ctype.h> /* PAK: need tolower declaration */
+#define CONST const
+#define UCHAR (unsigned char)
+
+/* Note: restore original code from the Tcl tree if you want unicode
+ * support. */
+
+int
+StringCaseMatch(string, pattern, nocase)
+    CONST char *string;		/* String. */
+    CONST char *pattern;	/* Pattern, which may contain special
+				 * characters. */
+    int nocase;			/* 0 for case sensitive, 1 for insensitive */
+{
+    int p /*, charLen*/;  /* PAK: unused */
+    /* CONST char *pstart = pattern; */  /* PAK: unused */
+    char ch1, ch2;
+    
+    while (1) {
+	p = *pattern;
+	
+	/*
+	 * See if we're at the end of both the pattern and the string.  If
+	 * so, we succeeded.  If we're at the end of the pattern but not at
+	 * the end of the string, we failed.
+	 */
+	
+	if (p == '\0') {
+	    return (*string == '\0');
+	}
+	if ((*string == '\0') && (p != '*')) {
+	    return 0;
+	}
+
+	/*
+	 * Check for a "*" as the next pattern character.  It matches
+	 * any substring.  We handle this by calling ourselves
+	 * recursively for each postfix of string, until either we
+	 * match or we reach the end of the string.
+	 */
+	
+	if (p == '*') {
+	    /*
+	     * Skip all successive *'s in the pattern
+	     */
+	    while (*(++pattern) == '*') {}
+	    p = *pattern;
+	    if (p == '\0') {
+		return 1;
+	    }
+	    ch2 = (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
+	    while (1) {
+		/*
+		 * Optimization for matching - cruise through the string
+		 * quickly if the next char in the pattern isn't a special
+		 * character
+		 */
+		if ((p != '[') && (p != '?') && (p != '\\')) {
+		    if (nocase) {
+			while (*string) {
+			    ch1 = *string;
+			    if (ch2==ch1 || ch2==tolower(ch1)) break;
+			    string++;
+			}
+		    } else {
+			while (*string) {
+			    ch1 = *string;
+			    if (ch2==ch1) break;
+			    string++;
+			}
+		    }
+		}
+		if (StringCaseMatch(string, pattern, nocase)) {
+		    return 1;
+		}
+		if (*string == '\0') {
+		    return 0;
+		}
+		string++;
+	    }
+	}
+
+	/*
+	 * Check for a "?" as the next pattern character.  It matches
+	 * any single character.
+	 */
+
+	if (p == '?') {
+	    pattern++;
+	    string++;
+	    continue;
+	}
+
+	/*
+	 * Check for a "[" as the next pattern character.  It is followed
+	 * by a list of characters that are acceptable, or by a range
+	 * (two characters separated by "-").
+	 */
+
+	if (p == '[') {
+	    char startChar, endChar;
+
+	    pattern++;
+	    ch1 = (nocase ? tolower(UCHAR(*string)) : UCHAR(*string));
+	    string++;
+	    while (1) {
+		if ((*pattern == ']') || (*pattern == '\0')) {
+		    return 0;
+		}
+		startChar = 
+			(nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
+		pattern++;
+		if (*pattern == '-') {
+		    pattern++;
+		    if (*pattern == '\0') {
+			return 0;
+		    }
+		    endChar = 
+		      (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
+		    pattern++;
+		    if (((startChar <= ch1) && (ch1 <= endChar))
+			    || ((endChar <= ch1) && (ch1 <= startChar))) {
+			/*
+			 * Matches ranges of form [a-z] or [z-a].
+			 */
+
+			break;
+		    }
+		} else if (startChar == ch1) {
+		    break;
+		}
+	    }
+	    while (*pattern != ']') {
+	        if (*pattern == '\0') {
+		    pattern--;
+		    break;
+		}
+		pattern++;
+	    }
+	    pattern++;
+	    continue;
+	}
+
+	/*
+	 * If the next pattern character is '\', just strip off the '\'
+	 * so we do exact matching on the character that follows.
+	 */
+
+	if (p == '\\') {
+	    pattern++;
+	    if (*pattern == '\0') {
+		return 0;
+	    }
+	}
+
+	/*
+	 * There's no special character.  Just make sure that the next
+	 * bytes of each string match.
+	 */
+
+	ch1 = *string++;
+	ch2 = *pattern++;
+	if (nocase) {
+	    if (tolower(ch1) != tolower(ch2)) {
+		return 0;
+	    }
+	} else if (ch1 != ch2) {
+	    return 0;
+	}
+    }
+}
--- a/main/miscellaneous/doc/server.txt	Sat Mar 24 19:34:52 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-You can talk to octave directly from other environments over the tcp/ip.
-The protocol is not sophisticated.
-
-Here is what you can send to octave: 
-
-!!!x length command
-
-	evaluate command in octave.  
-	length is a 32-bit network order integer.
-	command is a string (without zero-terminator).
-
-!!!m length name
-
-	send matrix back to client.
-	length is a 32-bit network order integer.
-	name is a string (without zero-terminator).
-
-	I don't use the !!!m command to the server because it is the same as
-
-	    !!!x send('name', matrix expression)
-
-	The latter is much more useful because you don't have to name
-	the data that you are sending across.
-
-!!!n length namelen name command
-
-	*** Not implemented ***
-	Evaluate the command in the namespace.  This needs a lookup table
-		Map<string,symbol_table> namespace
-	and a command 
-		evalin(symbol_table,command)
-	The function evalin pushes the given symbol table onto curr_sym_tab,
-	evaluates the command then pops the symbol table.
-
-Here is what you will receive from octave:
-
-!!!m length rows columns namelength name data
-
-	recieve matrix from server.
-	length,rows,columns,namelength are 32-bit network order integers.
-	name is a string (without zero-terminator).
-	data is an array of rows*columns server order double values.
-
-	This is sent in response to a !!!m matrix request or a
-	send('name',matrix) command.
-
-	The first thing I do when I open a connection is request a matrix
-	containing 1.0.  If the result is not 1.0, I know that I need to
-	swap the data to convert from server order to client order doubles.
-
-!!!s length strlen namelen name str
-
-	receive string from server.
-	length, strlen, namelen are 32-bit network order integers.
-	name is a string (without zero-terminator).
-	str is a string (without zero-terminator).
-
-	This is sent in response to a send('name',string) command.
-
-!!!x length str
-
-	evaluate string in client.
-	length is a 32-bit network order integer.
-	str is a string (without zero-terminator).
-
-	This is sent in response to a send('str').  The contents of str
-	are completely arbitrary (and may indeed contain binary data).  It is
-	up to the client to decide how they want to interpret these strings.
-
-!!!e length error
-
-	receive error from octave.
-	length is a 32-bit network order integer.
-	error is a string (without zero-terminator).
-
-	This is sent in response to a !!!x command which produced an error.
-
-Composite values can be decomposed into their constituent parts.  E.g.,
-    structures:
-	for [v,k]=x, send([name,'.',k],v); end
-    complex arrays:
-	send([name,'.real'],real(x));
-	send([name,'.imag'],imag(x));
-    sparse arrays: 
-	[v,i,j] = spfind(x);
-	send([name,'.i'],i);
-	send([name,'.j'],j);
-	send([name,'.v'],v);
-    cell arrays: 
-	[nr,nc]=size(x);
-	for r=1:nr, for c=1:nc, send([name,sprintf('.%d.%d',r,c)],x{r,c}); end
-
-Note that the communication is completely asynchronous.  I have a tcl client
-that processes server responses via fileevent.  That means that responses from
-octave are not processed until tcl enters its event loop.
-
-To be sure that octave has processed a command I follow that command with a
-synchronization sequence:
-
-	set sync[incr syncid] 1
-	octave eval "send('unset sync$syncid')"
-	vwait sync$syncid
-
-In practice it is more complicated than that because I allow the
-syncronization command to time out just in case octave crashed out from
-underneath me, but the idea is the same.
-
-Using sockets gives you platform independence and network transparency,
-which is a big win.  The only caveat is that winsock is slow.  The best I
-can do with dedicated winsock code on my machine is .3 seconds to transfer
-a 1 Mb message.  Under tcl/tk, it was closer to 1 second IIRC.  A memory
-copy of the same size took less than 0.06 seconds IIRC.
-
-That is why I'm working on a way to embed octave into tcl.  Hopefully
-it will be easy to embed in other environments as well.
-
-Paul Kienzle
-2003
--- a/main/miscellaneous/src/listencanfork.c	Sat Mar 24 19:34:52 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-#if defined(__CYGWIN__)
-#include <windows.h>
-
-int listencanfork()
-{
-  OSVERSIONINFO osvi;
-  osvi.dwOSVersionInfoSize = sizeof(osvi);
-  GetVersionEx (&osvi);
-  return (osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS);
-}
-#else
-int listencanfork() { return 1; }
-#endif
--- a/main/miscellaneous/src/server.cc	Sat Mar 24 19:34:52 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,824 +0,0 @@
-#define STATUS(x) do { if (debug) std::cout << x << std::endl << std::flush; } while (0)
-
-//#define HAVE_OCTAVE_30
-#include <iomanip>
-#include <iostream>
-#include <cstdio>
-#include <cctype>
-#include <cstdlib>
-//#include <unistd.h>
-//#include <stdint.h>
-#include <cerrno>
-// #include <string.h>
-#include <sys/types.h>
-
-#if (defined(_WIN32)||defined(_WIN64)) && !defined(__CYGWIN__)
-# define USE_WINSOCK
-# define CAN_FORK false
-# include <winsock.h>
-# include <io.h>
-  typedef int socklen_t;
-#else
-# define HAVE_FORK 1
-# define USE_SIGNALS
-# if defined(__CYGWIN__)
-#  define CAN_FORK listencanfork()
-# else
-#  define USE_DAEMONIZE
-#  define CAN_FORK true
-# endif
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# include <sys/wait.h>
-# include <signal.h>
-# define closesocket close
-#endif
-
-
-#include <octave/oct.h>
-#include <octave/parse.h>
-#include <octave/variables.h>
-#if 0
-#include <octave/unwind-prot.h>
-#endif
-#include <octave/oct-syscalls.h>
-#include <octave/oct-time.h>
-#include <octave/lo-mappers.h>
-#include <octave/symtab.h>
-
-static bool debug = false;
-static char* context = NULL;
-
-static double timestamp = 0.0;
-inline void tic(void) { timestamp = octave_time().double_value(); }
-inline double toc(void) {return ceil(-1e6*(timestamp-octave_time().double_value()));}
-
-// XXX FIXME XXX --- surely this is part of the standard library?
-void
-lowercase (std::string& s)
-{
-  for (std::string::iterator i=s.begin(); i != s.end(); i++) *i = tolower(*i);
-}
-
-#if 0
-octave_value
-get_builtin_value (const std::string& nm)
-{
-  octave_value retval;
-
-  symbol_record *sr = fbi_sym_tab->lookup (nm);
-
-  if (sr)
-    {
-      octave_value sr_def = sr->def ();
-
-      if (sr_def.is_undefined ())
-        error ("get_builtin_value: undefined symbol `%s'", nm.c_str ());
-      else
-        retval = sr_def;
-      }
-  else
-    error ("get_builtin_value: unknown symbol `$s'", nm.c_str ());
-
-  return retval;
-}
-#endif
-
-#ifdef USE_WINSOCK
-  bool init_sockets()
-  {
-
-  WSADATA wsaData;
-  WORD version;
-  int error;
-
-  version = MAKEWORD( 2, 0 );
-
-  error = WSAStartup( version, &wsaData );
-
-  /* check for error */
-  if ( error != 0 )
-  {
-    /* error occured */
-    return false;
-  }
-
-  /* check for correct version */
-  if ( LOBYTE( wsaData.wVersion ) != 2 ||
-       HIBYTE( wsaData.wVersion ) != 0 )
-  {
-      /* incorrect WinSock version */
-      WSACleanup();
-      return false;
-  }
-  return true;
-  }
-
-  inline void end_sockets() { WSACleanup(); }
-  inline int socket_errno() { return WSAGetLastError(); }
-#else // !USE_WINSOCK
-# include <cerrno>
-  inline bool init_sockets() { return true; }
-  inline void end_sockets() { }
-  inline int socket_errno() { return errno; }
-#endif // !USE_WINSOCK
-inline void socket_error(const char *context)
-{
-  int err = socket_errno();
-  char errno_str[15];
-  snprintf(errno_str, sizeof(errno_str), " %d: ", err);
-  std::string msg = std::string(context) + std::string(errno_str) 
-                  + std::string (strerror(err));
-  error(msg.c_str());
-}
-
-#ifdef USE_SIGNALS
-static void
-sigchld_handler(int /* sig */)
-{
-  int status;
-  /* Reap all childrens */
-  STATUS("reaping all children");
-  while (waitpid(-1, &status, WNOHANG) > 0)
-    ;
-  STATUS("done reaping children");
-}
-
-/* Posix signal handling, based on the example from the
- * Unix Programming FAQ 
- * Copyright (C) 2000 Andrew Gierth
- */
-static void sigchld_setup(void)
-{
-  struct sigaction act;
-
-  /* Assign sig_chld as our SIGCHLD handler */
-  act.sa_handler = sigchld_handler;
-
-  /* We don't want to block any other signals in this example */
-  sigemptyset(&act.sa_mask);
-  
-  /*
-   * We're only interested in children that have terminated, not ones
-   * which have been stopped (eg user pressing control-Z at terminal)
-   */
-  act.sa_flags = SA_NOCLDSTOP;
-
-  /*
-   * Make these values effective. If we were writing a real 
-   * application, we would probably save the old value instead of 
-   * passing NULL.
-   */
-  if (sigaction(SIGCHLD, &act, NULL) < 0) 
-     error("listen could not set SIGCHLD");
-}
-#else
-inline void sigchld_setup(void) { }
-#endif
-
-
-#ifdef USE_DAEMONIZE
-
-static RETSIGTYPE
-sigterm_handler(int /* sig */)
-{
-  exit(0);
-}
-
-static void
-daemonize(void)
-{
-  if (fork()) exit(0);  // Stop parent
-  // Show child PID
-  std::cout << "Octave pid: " << octave_syscalls::getpid() << std::endl;
-  std::cout.flush();
-  signal(SIGTERM,sigterm_handler);
-  signal(SIGQUIT,sigterm_handler);
-
-
-#if 1
-  const char err[] = "/dev/null";
-  const char out[] = "/dev/null";
-#else
-  const char err[] = "/tmp/octserver.err";
-  const char out[] = "/tmp/octserver.out";
-  std::cout << "redirecting to " << out << " and " << err << std::endl; std::cout.flush();
-#endif
-
-  // Exit silently if I/O redirect fails.
-  if (freopen("/dev/null", "r", stdin) == NULL
-      || freopen(out, "w", stdout) == NULL
-      || freopen(err, "w", stderr) == NULL) {
-    // std::cerr << "ioredirect failed" << std::endl; std::cerr.flush();
-    exit(0);
-  }
-  // std::cout << "ioredirect succeeded" << std::endl; std::cout.flush();
-  //debug = true;
-}
-
-#else
-// Don't daemonize on cygwin just yet.
-inline void daemonize(void) {}
-
-#endif // !DAEMONIZE
-
-
-
-static octave_value get_octave_value(char *name)
-{
-  octave_value def;
-
-  // Copy variable from octave
-#if defined(HAVE_TOP_LEVEL_SYM_TAB)
-  // Octave 3.0
-  symbol_record *sr = top_level_sym_tab->lookup (name);
-  if (sr) def = sr->def();
-#elif defined(HAVE_VARREF)
-  // Octave 2.x
-  def = symbol_table::varref (std::string (name), symbol_table::top_scope ());
-#else
-  // Octave 3.2
-  def = get_global_value(name);
-#endif
-
-  return def;
-}
-
-
-static void channel_error (const int channel, const char *str)
-{
-  STATUS("sending error !!!e (" << strlen(str) << ") " << str);
-
-  uint32_t len = strlen(str);
-  send(channel,"!!!e",4,0);
-  uint32_t t = htonl(len); send(channel,(const char *)&t,4,0);
-  send(channel,str,len,0);
-}
-
-static bool reads (const int channel, void * buf, int n)
-{
-  // STATUS("entering reads loop with size " << n); tic();
-  while (1) {
-    int chunk = recv(channel, (char *)buf, n, 0);
-    if (chunk == 0) STATUS("read socket returned 0");
-    if (chunk < 0) STATUS("read socket error " << socket_errno());
-    if (chunk <= 0) return false;
-    n -= chunk;
-    // if (n == 0) STATUS("done reads loop after " << toc() << "us");
-    if (n == 0) return true;
-    // STATUS("reading remaining " << n << " characters");
-    buf = (void *)((char *)buf + chunk);
-  }
-}
-
-static bool writes (const int channel, const void * buf, int n)
-{
-  // STATUS("entering writes loop");
-  while (1) {
-    int chunk = send(channel, (const char *)buf, n, 0);
-    if (chunk == 0) STATUS("write socket returned 0");
-    if (chunk < 0) STATUS("write socket: " << strerror(errno));
-    if (chunk <= 0) return false;
-    n -= chunk;
-    // if (n == 0) STATUS("done writes loop");
-    if (n == 0) return true;
-    buf = (void *)((char *)buf + chunk);
-  }
-}
-
-static void
-process_commands(int channel)
-{
-  // XXX FIXME XXX check read/write return values
-  assert(sizeof(uint32_t) == 4);
-  char command[5];
-  char def_context[16536];
-  bool ok;
-  STATUS("waiting for command");
-
-  // XXX FIXME XXX do we need to specify the context size?
-  //  int bufsize=sizeof(def_context);
-  //  socklen_t ol;
-  //  ol=sizeof(bufsize);
-  //  setsockopt(channel,SOL_SOCKET,SO_SNDBUF,&bufsize,ol);
-  //  setsockopt(channel,SOL_SOCKET,SO_RCVBUF,&bufsize,ol);
-
-  // XXX FIXME XXX prepare to capture long jumps, because if
-  // we dont, then errors in octave might escape to the prompt
-
-  command[4] = '\0';
-  if (debug) tic();
-  while (reads(channel, &command, 4)) {
-    // XXX FIXME XXX do whatever is require to check if function files
-    // have changed; do we really want to do this for _every_ command?
-    // Maybe we need a 'reload' command.
-    STATUS("received command " << command << " after " << toc() << "us");
-    
-    // Check for magic command code
-    if (command[0] != '!' || command[1] != '!' || command[2] != '!') {
-      STATUS("communication error: closing connection");
-      break;
-    }
-
-    // Get command length
-    if (debug) tic(); // time the read
-    uint32_t len;
-    if (!reads(channel, &len, 4)) break;
-    len = ntohl(len);
-    // STATUS("read 4 byte command length in " << toc() << "us"); 
-
-    // Read the command context, allocating a new one if the default
-    // is too small.
-    if (len > (signed)sizeof(def_context)-1) {
-      // XXX FIXME XXX use octave allocators
-      // XXX FIXME XXX unwind_protect
-      context= new char[len+1];
-      if (context== NULL) {
-	// Requested command is too large --- skip to the next command
-	// XXX FIXME XXX maybe we want to kill the connection instead?
-	channel_error(channel,"out of memory");
-	ok = true;
-	STATUS("skip big command loop");
-	while (ok && len > (signed)sizeof(def_context)) {
-	  ok = reads(channel, def_context, sizeof(def_context));
-	  len -= sizeof(def_context);
-	}
-	STATUS("done skip big command loop");
-	if (!ok) break;
-	ok = reads(channel, def_context, sizeof(def_context));
-	if (!ok) break;
-	continue;
-      }
-    } else {
-      context = def_context;
-    }
-    // if (debug) tic();
-    ok = reads(channel, context, len);
-    context[len] = '\0';
-    STATUS("read " << len << " byte command in " << toc() << "us");
-
-    // Process the command
-    if (ok) switch (command[3]) {
-    case 'm': // send the named matrix 
-      {
-	// XXX FIXME XXX this can be removed: app can do send(name,value)
-	STATUS("sending " << context);
-	uint32_t t;
-	
-	// read the matrix contents
-	octave_value def = get_octave_value(context);
-	if(!def.is_defined() || !def.is_real_matrix()) 
-	  channel_error(channel,"not a matrix");
-	Matrix m = def.matrix_value();
-	
-	// write the matrix transfer header
-	ok = writes(channel,"!!!m",4);                // matrix message
-	t = htonl(12 + sizeof(double)*m.rows()*m.columns());
-	if (ok) ok = writes(channel,&t,4);            // length of message
-	t = htonl(m.rows()); 
-	if (ok) ok = writes(channel,&t,4);            // rows
-	t = htonl(m.columns()); 
-	if (ok) ok = writes(channel,&t,4);            // columns
-	t = htonl(len); 
-	if (ok) ok = writes(channel, &t, 4);          // name length
-	if (ok) ok = writes(channel,context,len);      // name
-	
-	// write the matrix contents
-	const double *v = m.data();                   // data
-	if (ok) ok = writes(channel,v,sizeof(double)*m.rows()*m.columns());
-	if (ok)
-	  STATUS("sent " << m.rows()*m.columns());
-	else
-	  STATUS("failed " << m.rows()*m.columns());
-      }
-      break;
-      
-    case 'x': // silently execute the command
-      {
-	if (debug) 
-	  {
-	    if (len > 500) 
-	      {
-		// XXX FIXME XXX can we limit the maximum output width for a
-		// string?  The setprecision() io manipulator doesn't do it.
-		// In the meantime, a hack ...
-		char t = context[400]; context[400] = '\0';
-		STATUS("evaluating (" << len << ") " 
-		       << context << std::endl 
-		       << "..." << std::endl 
-		       << context+len-100);
-		context[400] = t;
-	      }
-	    else
-	      {
-		STATUS("evaluating (" << len << ") " << context);
-	      }
-	  }
-
-	if (debug) tic();
-#if 1
-        error_state = 0;
-	int parse_status = 0;
-        eval_string(context, true, parse_status, 0);
-        if (parse_status != 0 || error_state)
-            eval_string("senderror(lasterr);", true, parse_status, 0);
-#elif 0
-	octave_value_list evalargs;
-	evalargs(1) = "senderror(lasterr);";
-	evalargs(0) = context;
-	octave_value_list fret = feval("eval",evalargs,0);
-#else
-	evalargs(0) = octave_value(0.);
-#endif
-	STATUS("done command");
-      }
-      STATUS("free evalargs");
-      break;
-      
-    case 'c': // execute the command and capture stdin/stdout
-      STATUS("capture command not yet implemented");
-      break;
-      
-    default:
-      STATUS("ignoring command " << command);
-      break;
-    }
-
-    if (context != def_context) delete[] context;
-    STATUS("done " << command);
-    if (!ok) break;
-    if (debug) tic();
-  }
-}
-
-
-int channel = -1;
-
-DEFUN_DLD(senderror,args,,"\
-Send the given error message across the socket.  The error context\n\
-is taken to be the last command received from the socket.")
-{
-  std::string str;
-  const int nargin = args.length();
-  if (nargin != 1) str="senderror not called with error";
-  else str = args(0).string_value();
-
-  // provide a context for the error (but not too much!)
-  str += "when evaluating:\n";
-  if (strlen(context) > 100) 
-    {	
-      char t=context[100]; 
-      context[100] = '\0'; 
-      str+=context; 
-      context[100]=t;
-    }
-  else
-    str += context;
- 
-  STATUS("error is " << str);
-  channel_error(channel,str.c_str());
-  return octave_value_list();
-}
-
-DEFUN_DLD(send,args,,"\
-send(str)\n\
-  Send a command on the current connection\n\
-send(name,value)\n\
-  Send a binary value with the given name on the current connection\n\
-")
-{
-  bool ok;
-  uint32_t t;
-  octave_value_list ret;
-  int nargin = args.length();
-  if (nargin < 1 || nargin > 2)
-    {
-      print_usage ();
-      return ret;
-    }
-
-  if (channel < 0) {
-    error("Not presently listening on a port");
-    return ret;
-  }
-
-  std::string cmd(args(0).string_value());
-  if (error_state) return ret;
-
-  // XXX FIXME XXX perhaps process the panalopy of types?
-  if (nargin > 1) {
-    
-    octave_value def = args(1);
-    if (args(1).is_string()) {
-      // Grab the string value from args(1).
-      // Can't use args(1).string_value() because that trims trailing \0
-      charMatrix m(args(1).char_matrix_value());
-      std::string s(m.row_as_string(0,false,true));
-      STATUS("sending string(" << cmd.c_str() << " len " << s.length() << ")");
-      ok = writes(channel,"!!!s",4);               // string message
-      t = htonl(8 + cmd.length() + s.length());
-      if (ok) ok = writes(channel,&t,4);           // length of message
-      t = htonl(s.length());
-      if (ok) ok = writes(channel, &t, 4);         // string length
-      t = htonl(cmd.length());
-      if (ok) ok = writes(channel, &t, 4);         // name length
-      if (cmd.length() && ok) 
-	ok = writes(channel, cmd.c_str(), cmd.length());    // name
-      if (s.length() && ok) 
-	ok = writes(channel, s.c_str(), s.length());        // string
-    } else if (args(1).is_real_type()) {
-      Matrix m(args(1).matrix_value());
-      STATUS("sending matrix(" << cmd.c_str() << " " 
-             <<  m.rows() << "x" << m.columns() << ")");
-      
-      // write the matrix transfer header
-      ok = writes(channel,"!!!m",4);               // matrix message
-      t = htonl(12 + cmd.length() + sizeof(double)*m.rows()*m.columns());
-      if (ok) ok = writes(channel,&t,4);           // length of message
-      t = htonl(m.rows()); 
-      if (ok) ok = writes(channel,&t,4);           // rows
-      t = htonl(m.columns()); 
-      if (ok) ok = writes(channel,&t,4);           // columns
-      t = htonl(cmd.length()); 
-      if (ok) ok = writes(channel, &t, 4);         // name length
-      if (ok) ok = writes(channel, cmd.c_str(), cmd.length());    // name
-      
-      // write the matrix contents
-      const double *v = m.data();                  // data
-      if (m.rows()*m.columns() && ok) 
-	ok = writes(channel,v,sizeof(double)*m.rows()*m.columns());
-    } else {
-      ok = false;
-      error("send expected name and matrix or string value");
-    }
-    if (!ok) error("send could not write to channel");
-  } else {
-    STATUS("sending command(" << cmd.length() << ") " << cmd.c_str());
-    // STATUS("start writing at "<<toc()<<"us");
-    ok = writes(channel, "!!!x", 4);
-    t = htonl(cmd.length()); writes(channel, &t, 4);
-    if (ok) ok = writes(channel, cmd.c_str(), cmd.length());
-    if (!ok) error("send could not write to channel");
-    // STATUS("stop writing at "<<toc()<<"us");
-  }
-
-  return ret;
-}
-
-extern "C" int listencanfork(void);
-extern "C" int StringCaseMatch(const char* s, const char* p, int nocase);
-
-bool ishostglob(const std::string& s)
-{
-  for (unsigned int i=0; i < s.length(); i++) {
-    if (! ( isdigit(s[i]) || s[i]=='*' || s[i]=='-' 
-	   || s[i]=='.' || s[i]=='[' || s[i]==']')) return false;
-  }
-  return true;
-}
-
-bool anyhostglob(const string_vector& hostlist, const char* host)
-{
-  for (int j=0; j < hostlist.length(); j++) {
-    if (StringCaseMatch(host, hostlist[j].c_str(), 0)) return true;
-  }
-  return false;
-}
-
-// Known bug: functions which pass or return structures use a
-// different ABI for gcc and native compilers on some architectures.
-// Whether this is a bug depends on the structure length.  SGI's 64-bit
-// architecture makes this a problem for inet_ntoa.
-#if defined(__GNUC__) && defined(_sgi)
-#define BROKEN_INET_NTOA
-#endif
-
-#ifdef BROKEN_INET_NTOA
-
-/*************************************************
-*         Replacement for broken inet_ntoa()     *
-*************************************************/
-
-
-/* On IRIX systems, gcc uses a different structure passing convention to the
-native libraries. This causes inet_ntoa() to always yield 0.0.0.0 or
-255.255.255.255. To get round this, we provide a private version of the
-function here. It is used only if USE_INET_NTOA_FIX is set, which should
-happen
-only when gcc is in use on an IRIX system. Code send to me by J.T. Breitner,
-with these comments:
-
-
-  code by Stuart Levy
-  as seen in comp.sys.sgi.admin
-
-
-Arguments:  sa  an in_addr structure
-Returns:        pointer to static text string
-*/
-
-
-char *
-inet_ntoa(struct in_addr sa)
-{
-static char addr[20];
-sprintf(addr, "%d.%d.%d.%d",
-        (US &sa.s_addr)[0],
-        (US &sa.s_addr)[1],
-        (US &sa.s_addr)[2],
-        (US &sa.s_addr)[3]);
-  return addr;
-}
-
-#endif /* BROKEN_INET_NTOA */
-
-
-void _autoload(const char name[])
-{
-  octave_value_list evalargs, fret;
-  evalargs(0) = "server";
-  fret = feval("which",evalargs,1);
-  evalargs(0) = name;
-  evalargs(1) = fret(0);
-  fret = feval("autoload",evalargs,0);
-}
-
-DEFUN_DLD(server,args,,"\
-server(port,host,host,...)\n\
-   Listen for connections on the given port.  Normally only accepts\n\
-   connections from localhost (127.0.0.1), but you can specify any\n\
-   dot-separated host name globs.  E.g., '128.2.20.*' or '128.2.2[012].*'\n\
-   Use '?' for '[0123456789]'. Use '*.*.*.*' for any host.\n\
-server(...,'debug'|'nodebug')\n\
-   If debug, echo all commands sent across the connection.  If nodebug,\n\
-   detach the process and don't echo anything.  You will need to use\n\
-   kill directly to end the process. Nodebug is the default.\n\
-server(...,'fork'|'nofork')\n\
-   If fork, start new server for each connection.  If nofork, only allow\n\
-   one connection at a time. Fork is the default (depending on system).\n\
-server(...,'loopback')\n\
-   Use loopback address 127.0.0.1 rather than 0.0.0.0.\n\
-")
-{
-  bool canfork = CAN_FORK;
-
-  _autoload("send");
-  _autoload("senderror");
-  octave_value_list ret;
-  int nargin = args.length();
-  if (nargin < 1)
-    {
-      print_usage ();
-      return ret;
-    }
-  int port = args(0).int_value();
-  if (error_state) return ret;
-
-  // Winsock requires initialization
-  if (!init_sockets())
-	{
-	  socket_error("init");
-	  return ret;
-    }
-
-
-  debug = false;
-  uint32_t inaddr = INADDR_ANY;
-
-  string_vector hostlist;
-  hostlist.append(std::string("127.0.0.1"));
-  for (int k = 1; k < nargin; k++) {
-    std::string lastarg(args(k).string_value());
-    if (error_state) return ret;
-    lowercase(lastarg);
-    if (lastarg == "debug") {
-      debug = true;
-    } else if (lastarg == "nodebug") {
-      debug = false;
-    } else if (lastarg == "fork") {
-      canfork = true;
-    } else if (lastarg == "nofork") {
-      canfork = false;
-    } else if (lastarg == "loopback") {
-      inaddr = INADDR_LOOPBACK;
-    } else if (ishostglob(lastarg)) {
-      hostlist.append(lastarg);
-    } else {
-      print_usage ();
-    }
-  }
-
-  int sockfd;                    // listen on sockfd, new connection channel
-  struct sockaddr_in my_addr;    // my address information
-  struct sockaddr_in their_addr; // connector's address information
-  socklen_t sin_size;
-  int yes=1;
-
-  sockfd = socket(AF_INET, SOCK_STREAM, 0);
-  if (sockfd == -1) {
-	socket_error("socket");
-    return ret;
-  }
-
-  if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(const char *)(&yes),sizeof(yes)) == -1) {
-    socket_error("setsockopt");
-    return ret;
-  }
-
-  my_addr.sin_family = AF_INET;         // host byte order
-  my_addr.sin_port = htons(port);       // short, network byte order
-  my_addr.sin_addr.s_addr = htonl(inaddr); // automatically fill with my IP
-  memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
-  
-  if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))
-      == -1) {
-    socket_error("bind");
-    closesocket(sockfd);
-    return ret;
-  }
-  
-  /* listen for connections (allowing one pending connection) */
-  if (listen(sockfd, canfork?1:0) == -1) { 
-    socket_error("listen");
-    closesocket(sockfd);
-    return ret;
-  }
-
-#if 0
-  unwind_protect::begin_frame("Fserver");
-  unwind_protect_bool (buffer_error_messages);
-  buffer_error_messages = true;
-#endif
-
-  sigchld_setup();
-  if (!debug && canfork) daemonize();
-      
-  // XXX FIXME XXX want a 'sandbox' option which disables fopen, cd, pwd,
-  // system, popen ...  Or maybe just an initial script to run for each
-  // connection, plus a separate command to disable specific functions.
-  STATUS("listening on port " << port);
-  while(1) {  // main accept() loop
-    sin_size = sizeof(struct sockaddr_in);
-    STATUS("trying to accept");
-    if ((channel = accept(sockfd, (struct sockaddr *)&their_addr,
-			 &sin_size)) == -1) {
-      // XXX FIXME XXX
-      // Linux is returning "Interrupted system call" when the
-      // child terminates.  Until I figure out why, I can't use
-      // accept errors as a basis for breaking out of the listen
-      // loop, so instead print the octave PID so that I can kill
-      // it from another terminal.
-      STATUS("failed to accept"  << std::endl 
-	     << "Octave pid: " << octave_syscalls::getpid() );
-      perror("accept");
-#if defined(_sgi)
-      break;
-#else
-      continue;
-#endif
-    }
-    STATUS("connected");
-
-    /* Simulate inet_ntoa */
-    const char *them = inet_ntoa(their_addr.sin_addr);
-    STATUS("server: got connection from " << them);
-
-    if (anyhostglob(hostlist,them)) {
-#ifdef HAVE_FORK
-      if (canfork) {
-        int pid = fork();
-        if (pid == -1) {
-          socket_error("fork");
-          break;
-        } else if (pid == 0) {
-          closesocket(sockfd);      // child doesn't need listener
-          signal(SIGCHLD,SIG_DFL);  // child doesn't need SIGCHLD signal
-          process_commands(channel);
-          STATUS("child is exitting");
-          exit(0);
-        }
-      } else {
-		process_commands(channel);
-        STATUS("server: connection closed");
-      }
-#else // !HAVE_FORK
-      process_commands(channel);
-      STATUS("server: connection closed");
-#endif // !HAVE_FORK
-    } else {
-      STATUS("server: connection refused.");
-    }
-
-    closesocket(channel);
-    channel = -1;
-  }
-
-  STATUS("could not read commands; returning");
-  closesocket(sockfd);
-  end_sockets();
-#if 0
-  unwind_protect::run_frame("Fserver");
-#endif
-  return ret;
-}
--- a/main/miscellaneous/src/stringmatch.c	Sat Mar 24 19:34:52 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,242 +0,0 @@
-/* Extracted from tclUtil.c
-
-Copyright (c) 1987-1993 The Regents of the University of California.
-Copyright (c) 1994-1998 Sun Microsystems, Inc.
-Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
-
-
-This software is copyrighted by the Regents of the University of
-California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
-Corporation and other parties.  The following terms apply to all files
-associated with the software unless explicitly disclaimed in
-individual files.
-
-The authors hereby grant permission to use, copy, modify, distribute,
-and license this software and its documentation for any purpose, provided
-that existing copyright notices are retained in all copies and that this
-notice is included verbatim in any distributions. No written agreement,
-license, or royalty fee is required for any of the authorized uses.
-Modifications to this software may be copyrighted by their authors
-and need not follow the licensing terms described here, provided that
-the new terms are clearly indicated on the first page of each file where
-they apply.
-
-IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
-FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
-ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
-DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
-IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
-NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
-MODIFICATIONS.
-
-GOVERNMENT USE: If you are acquiring this software on behalf of the
-U.S. government, the Government shall have only "Restricted Rights"
-in the software and related documentation as defined in the Federal 
-Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
-are acquiring the software on behalf of the Department of Defense, the
-software shall be classified as "Commercial Computer Software" and the
-Government shall have only "Restricted Rights" as defined in Clause
-252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
-authors grant the U.S. Government and others acting in its behalf
-permission to use and distribute the software in accordance with the
-terms specified in this license. 
-
- */
-
-
-/*
- *----------------------------------------------------------------------
- *
- * StringCaseMatch --
- *
- *	See if a particular string matches a particular pattern.
- *	Allows case insensitivity.
- *
- * Results:
- *	The return value is 1 if string matches pattern, and
- *	0 otherwise.  The matching operation permits the following
- *	special characters in the pattern: *?\[] (see the manual
- *	entry for details on what these mean).
- *
- * Side effects:
- *	None.
- *
- *----------------------------------------------------------------------
- */
-
-#include <ctype.h> /* PAK: need tolower declaration */
-#define CONST const
-#define UCHAR (unsigned char)
-
-/* Note: restore original code from the Tcl tree if you want unicode
- * support. */
-
-int
-StringCaseMatch(string, pattern, nocase)
-    CONST char *string;		/* String. */
-    CONST char *pattern;	/* Pattern, which may contain special
-				 * characters. */
-    int nocase;			/* 0 for case sensitive, 1 for insensitive */
-{
-    int p /*, charLen*/;  /* PAK: unused */
-    /* CONST char *pstart = pattern; */  /* PAK: unused */
-    char ch1, ch2;
-    
-    while (1) {
-	p = *pattern;
-	
-	/*
-	 * See if we're at the end of both the pattern and the string.  If
-	 * so, we succeeded.  If we're at the end of the pattern but not at
-	 * the end of the string, we failed.
-	 */
-	
-	if (p == '\0') {
-	    return (*string == '\0');
-	}
-	if ((*string == '\0') && (p != '*')) {
-	    return 0;
-	}
-
-	/*
-	 * Check for a "*" as the next pattern character.  It matches
-	 * any substring.  We handle this by calling ourselves
-	 * recursively for each postfix of string, until either we
-	 * match or we reach the end of the string.
-	 */
-	
-	if (p == '*') {
-	    /*
-	     * Skip all successive *'s in the pattern
-	     */
-	    while (*(++pattern) == '*') {}
-	    p = *pattern;
-	    if (p == '\0') {
-		return 1;
-	    }
-	    ch2 = (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
-	    while (1) {
-		/*
-		 * Optimization for matching - cruise through the string
-		 * quickly if the next char in the pattern isn't a special
-		 * character
-		 */
-		if ((p != '[') && (p != '?') && (p != '\\')) {
-		    if (nocase) {
-			while (*string) {
-			    ch1 = *string;
-			    if (ch2==ch1 || ch2==tolower(ch1)) break;
-			    string++;
-			}
-		    } else {
-			while (*string) {
-			    ch1 = *string;
-			    if (ch2==ch1) break;
-			    string++;
-			}
-		    }
-		}
-		if (StringCaseMatch(string, pattern, nocase)) {
-		    return 1;
-		}
-		if (*string == '\0') {
-		    return 0;
-		}
-		string++;
-	    }
-	}
-
-	/*
-	 * Check for a "?" as the next pattern character.  It matches
-	 * any single character.
-	 */
-
-	if (p == '?') {
-	    pattern++;
-	    string++;
-	    continue;
-	}
-
-	/*
-	 * Check for a "[" as the next pattern character.  It is followed
-	 * by a list of characters that are acceptable, or by a range
-	 * (two characters separated by "-").
-	 */
-
-	if (p == '[') {
-	    char startChar, endChar;
-
-	    pattern++;
-	    ch1 = (nocase ? tolower(UCHAR(*string)) : UCHAR(*string));
-	    string++;
-	    while (1) {
-		if ((*pattern == ']') || (*pattern == '\0')) {
-		    return 0;
-		}
-		startChar = 
-			(nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
-		pattern++;
-		if (*pattern == '-') {
-		    pattern++;
-		    if (*pattern == '\0') {
-			return 0;
-		    }
-		    endChar = 
-		      (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
-		    pattern++;
-		    if (((startChar <= ch1) && (ch1 <= endChar))
-			    || ((endChar <= ch1) && (ch1 <= startChar))) {
-			/*
-			 * Matches ranges of form [a-z] or [z-a].
-			 */
-
-			break;
-		    }
-		} else if (startChar == ch1) {
-		    break;
-		}
-	    }
-	    while (*pattern != ']') {
-	        if (*pattern == '\0') {
-		    pattern--;
-		    break;
-		}
-		pattern++;
-	    }
-	    pattern++;
-	    continue;
-	}
-
-	/*
-	 * If the next pattern character is '\', just strip off the '\'
-	 * so we do exact matching on the character that follows.
-	 */
-
-	if (p == '\\') {
-	    pattern++;
-	    if (*pattern == '\0') {
-		return 0;
-	    }
-	}
-
-	/*
-	 * There's no special character.  Just make sure that the next
-	 * bytes of each string match.
-	 */
-
-	ch1 = *string++;
-	ch2 = *pattern++;
-	if (nocase) {
-	    if (tolower(ch1) != tolower(ch2)) {
-		return 0;
-	    }
-	} else if (ch1 != ch2) {
-	    return 0;
-	}
-    }
-}