]> sourceware.org Git - newlib-cygwin.git/commitdiff
import winsup-2000-02-17 snapshot
authorChristopher Faylor <me@cgf.cx>
Thu, 17 Feb 2000 19:38:31 +0000 (19:38 +0000)
committerChristopher Faylor <me@cgf.cx>
Thu, 17 Feb 2000 19:38:31 +0000 (19:38 +0000)
31 files changed:
winsup/cygwin/autoload.h [new file with mode: 0644]
winsup/cygwin/cygrun.c [new file with mode: 0644]
winsup/cygwin/dll_entry.cc [new file with mode: 0644]
winsup/cygwin/dll_main.cc [new file with mode: 0644]
winsup/cygwin/external.h [new file with mode: 0644]
winsup/cygwin/include/cygwin/ip.h [new file with mode: 0644]
winsup/cygwin/include/rapi.h [new file with mode: 0644]
winsup/cygwin/include/wchar.h [new file with mode: 0644]
winsup/cygwin/libc/getopt.c [new file with mode: 0644]
winsup/cygwin/libccrt0.cc [new file with mode: 0644]
winsup/cygwin/libcmain.cc [new file with mode: 0644]
winsup/cygwin/localtime.c [new file with mode: 0644]
winsup/cygwin/regexp/regerror.c [new file with mode: 0644]
winsup/cygwin/regexp/regexp.3 [new file with mode: 0644]
winsup/cygwin/regexp/regexp.c [new file with mode: 0644]
winsup/cygwin/regexp/regsub.c [new file with mode: 0644]
winsup/cygwin/shared.h [new file with mode: 0644]
winsup/cygwin/test.c [new file with mode: 0644]
winsup/cygwin/testsuite/README [new file with mode: 0644]
winsup/cygwin/testsuite/config/default.exp [new file with mode: 0644]
winsup/cygwin/testsuite/winsup.api/devzero.c [new file with mode: 0644]
winsup/cygwin/testsuite/winsup.api/samples/sample-pass.c [new file with mode: 0644]
winsup/cygwin/testsuite/winsup.api/samples/xf-sample-fail.c [new file with mode: 0644]
winsup/cygwin/testsuite/winsup.api/samples/xf-sample-miscompile.c [new file with mode: 0644]
winsup/cygwin/testsuite/winsup.api/winsup.exp [new file with mode: 0644]
winsup/doc/sites.texinfo [new file with mode: 0644]
winsup/mingw/dirent.c [new file with mode: 0644]
winsup/mingw/profile/ChangeLog [new file with mode: 0644]
winsup/utils/cygwin.cc [new file with mode: 0644]
winsup/w32api/README [new file with mode: 0644]
winsup/w32api/include/excpt.h [new file with mode: 0644]

diff --git a/winsup/cygwin/autoload.h b/winsup/cygwin/autoload.h
new file mode 100644 (file)
index 0000000..262eaa0
--- /dev/null
@@ -0,0 +1,76 @@
+/* autoload.h: Define functions for auto-loading symbols from a DLL.
+
+   Copyright 1999 Cygnus Solutions.
+
+   Written by Christopher Faylor <cgf@cygnus.com>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#define LoadDLLinitfunc(dllname) \
+HANDLE NO_COPY dllname ## _handle = NULL; \
+static int dllname ## _init () __asm__ (#dllname "_init") __attribute__ ((unused)); \
+static int dllname ## _init ()
+
+#define LoadDLLinitnow(dllname) \
+  ({__asm__ ("movl $cygwin_dll_func_load, " #dllname "_init_holder"); dllname##_init ();})
+
+#define _LoadDLLinitnow(dllname) \
+  __asm__ ("movl $cygwin_dll_func_load, " #dllname "_init_holder"); \
+  __asm__ ("call " #dllname "_init"); \
+
+#define LoadDLLinit(dllname) \
+  __asm__ (".section .data_cygwin_nocopy,\"w\""); \
+  __asm__ (#dllname "_init_holder: .long " #dllname "_init_and_load"); \
+  __asm__ (".text"); \
+  __asm__ (#dllname "_init_and_load:"); \
+  _LoadDLLinitnow (dllname); \
+  __asm__ ("jmp cygwin_dll_func_load");
+
+
+/* Macro for defining "auto-load" functions.
+ * Note that this is self-modifying code *gasp*.
+ * The first invocation of a routine will trigger the loading of
+ * the DLL.  This will then be followed by the discovery of
+ * the procedure's entry point, which is placed into the location
+ * pointed to by the stack pointer.  This code then changes
+ * the "call" operand which invoked it to a "jmp" which will
+ * transfer directly to the DLL function on the next invocation.
+ *
+ * Subsequent calls to routines whose transfer address has not been
+ * determined will skip the "load the dll" step, starting at the
+ * "discovery of the DLL" step.
+ *
+ * So, immediately following the the call to one of the above routines
+ * we have:
+ *  foojmp (4 bytes)    Pointer to a word containing the routine used
+ *                      to eventually invokethe function.  Initially
+ *                      points to an init function which loads the
+ *                      DLL, gets the processes load address,
+ *                      changes the contents here to point to the
+ *                      function address, and changes the call *(%eax)
+ *                      to a jmp %eax.  If the initialization has been
+ *                      done, only the load part is done.
+ *  DLL handle (4 bytes) The handle to use when loading the DLL.
+ *  func name (n bytes)         asciz string containing the name of the function
+ *                      to be loaded.
+ */
+
+#define LoadDLLfunc(name, mangled, dllname) \
+__asm__ (".section .data_cygwin_nocopy,\"w\""); \
+__asm__ (".global _" #mangled); \
+__asm__ (".global _win32_" #mangled); \
+__asm__ (".align 8"); \
+__asm__ ("_" #mangled ":"); \
+__asm__ ("_win32_" #mangled ":"); \
+__asm__ ("movl (" #name "jump),%eax"); \
+__asm__ ("call *(%eax)"); \
+__asm__ (#name "jump: .long " #dllname "_init_holder"); \
+__asm__ (" .long _" #dllname "_handle"); \
+__asm__ (".asciz \"" #name "\""); \
+__asm__ (".text");
+
+extern "C" void cygwin_dll_func_load () __asm__ ("cygwin_dll_func_load");
diff --git a/winsup/cygwin/cygrun.c b/winsup/cygwin/cygrun.c
new file mode 100644 (file)
index 0000000..8aa3e30
--- /dev/null
@@ -0,0 +1,50 @@
+/* cygrun.c: testsuite support program
+
+   Copyright 1999 Cygnus Solutions.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+/* This program is intended to be used only by the testsuite.  It runs
+   programs without using the cygwin api, so that the just-built dll
+   can be tested without interference from the currently installed
+   dll. */
+
+#include <stdio.h>
+#include <windows.h>
+
+int
+main(int argc, char **argv)
+{
+  STARTUPINFO sa;
+  PROCESS_INFORMATION pi;
+  DWORD ec = 1;
+
+  if (argc < 2)
+    {
+      fprintf(stderr, "Usage: cygrun [program]\n");
+      exit (0);
+    }
+
+  setenv("CYGWIN_TESTING", "1");
+  SetEnvironmentVariable("CYGWIN_TESTING", "1");
+
+  memset(&sa, 0, sizeof(sa));
+  memset(&pi, 0, sizeof(pi));
+  if (!CreateProcess(0, argv[1], 0, 0, 1, 0, 0, 0, &sa, &pi))
+    {
+      fprintf(stderr, "CreateProcess %s failed\n", argv[1]);
+      exit(1);
+    }
+
+  WaitForSingleObject(pi.hProcess, INFINITE);
+
+  GetExitCodeProcess(pi.hProcess, &ec);
+
+  CloseHandle(pi.hProcess);
+  CloseHandle(pi.hThread);
+  return ec;
+}
diff --git a/winsup/cygwin/dll_entry.cc b/winsup/cygwin/dll_entry.cc
new file mode 100644 (file)
index 0000000..6d405b6
--- /dev/null
@@ -0,0 +1,17 @@
+/* dll_entry.cc: Provide the default user DLL linker entry point.
+
+   Copyright 1998, 2000 Cygnus Solutions.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+/* Here we simply instantiate the DECLARE_CYGWIN_DLL to define the
+   linker entry point, __cygwin_dll_entry@12, which in turn calls
+   _DllMain@12 to do user-specific initialization, if any. There is a
+   default DllMain stub in the library if there is no user supplied
+   one. */
+
+#include "cygwin/cygwin_dll.h"
+
+DECLARE_CYGWIN_DLL (DllMain);
diff --git a/winsup/cygwin/dll_main.cc b/winsup/cygwin/dll_main.cc
new file mode 100644 (file)
index 0000000..44ed13e
--- /dev/null
@@ -0,0 +1,42 @@
+/* dll_main.cc: Provide the DllMain stub that the user can override.
+
+   Copyright 1998, 2000 Cygnus Solutions.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <windows.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <stdio.h>
+
+extern "C"
+BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason,
+                       LPVOID reserved /* Not used. */ );
+
+BOOL APIENTRY
+DllMain (
+        HINSTANCE hInst /* Library instance handle. */ ,
+        DWORD reason /* Reason this function is being called. */ ,
+        LPVOID reserved /* Not used. */ )
+{
+  switch (reason)
+    {
+    case DLL_PROCESS_ATTACH:
+      break;
+
+    case DLL_PROCESS_DETACH:
+      break;
+
+    case DLL_THREAD_ATTACH:
+      break;
+
+    case DLL_THREAD_DETACH:
+      break;
+    }
+  return TRUE;
+}
+
diff --git a/winsup/cygwin/external.h b/winsup/cygwin/external.h
new file mode 100644 (file)
index 0000000..745c6a8
--- /dev/null
@@ -0,0 +1,50 @@
+/* external.h: interface to Cygwin internals from external programs.
+
+   Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+typedef enum
+  {
+    CW_LOCK_PINFO,
+    CW_UNLOCK_PINFO,
+    CW_GETTHREADNAME,
+    CW_GETPINFO,
+    CW_SETPINFO,
+    CW_SETTHREADNAME,
+    CW_GETVERSIONINFO,
+    CW_READ_V1_MOUNT_TABLES
+  } cygwin_getinfo_types;
+
+struct external_pinfo
+  {
+  pid_t pid;
+  pid_t ppid;
+  HANDLE hProcess;
+  DWORD dwProcessId, dwSpawnedProcessId;
+  uid_t uid;
+  gid_t gid;
+  pid_t pgid;
+  pid_t sid;
+  int ctty;
+  mode_t umask;
+
+  long start_time;
+  struct rusage rusage_self;
+  struct rusage rusage_children;
+
+  char progname[MAX_PATH];
+
+  DWORD strace_mask;
+  HANDLE strace_file;
+
+  DWORD process_state;
+};
+
+extern "C" DWORD cygwin_internal (cygwin_getinfo_types, ...);
+
+#define CW_NEXTPID 0x80000000  // or with pid to get next one
diff --git a/winsup/cygwin/include/cygwin/ip.h b/winsup/cygwin/include/cygwin/ip.h
new file mode 100644 (file)
index 0000000..e4f23c7
--- /dev/null
@@ -0,0 +1 @@
+/* ip.h */
diff --git a/winsup/cygwin/include/rapi.h b/winsup/cygwin/include/rapi.h
new file mode 100644 (file)
index 0000000..9d63d06
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+       rapi.h - main header file for the RAPI API
+
+       Copyright 1999 Cygnus Solutions.
+
+       This file is part of Cygwin.
+
+       This software is a copyrighted work licensed under the terms of the
+       Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+       details.
+*/
+
+#ifndef _RAPI_H
+#define _RAPI_H
+
+typedef struct IRAPIStream
+{
+  struct IRAPIStreamVtbl * lpVtbl;
+} IRAPIStream;
+
+typedef struct IRAPIStreamVtbl IRAPIStreamVtbl;
+
+typedef enum tagRAPISTREAMFLAG
+{
+       STREAM_TIMEOUT_READ
+} RAPISTREAMFLAG;
+
+struct IRAPIStreamVtbl
+{
+  HRESULT (__stdcall * SetRapiStat)( IRAPIStream * This, RAPISTREAMFLAG Flag, DWORD dwValue) ;
+  HRESULT (__stdcall * GetRapiStat)( IRAPIStream * This, RAPISTREAMFLAG Flag, DWORD *pdwValue) ;
+};
+
+// RAPI extension on Windows CE (e.g., MyFunctionFOO) called via CeRapiInvoke should be declared as:
+// EXTERN_C RAPIEXT MyFunctionFOO;
+typedef  HRESULT (STDAPICALLTYPE RAPIEXT)(
+                DWORD                  cbInput,                        // [IN]
+                BYTE                   *pInput,                        // [IN]
+                DWORD                  *pcbOutput,                     // [OUT]
+                BYTE                   **ppOutput,                     // [OUT]
+                IRAPIStream    *pIRAPIStream           // [IN]
+                );
+
+typedef struct _RAPIINIT
+{
+    DWORD cbSize;
+    HANDLE heRapiInit;
+    HRESULT hrRapiInit;
+} RAPIINIT;
+
+STDAPI CeRapiInit();
+STDAPI CeRapiInitEx(RAPIINIT*);
+STDAPI_(BOOL) CeCreateProcess(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES,
+                             BOOL, DWORD, LPVOID, LPWSTR, LPSTARTUPINFO, LPPROCESS_INFORMATION);
+STDAPI CeRapiUninit();
+
+STDAPI_(BOOL) CeWriteFile(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
+STDAPI_(HANDLE) CeCreateFile(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); 
+STDAPI_(BOOL) CeCreateDirectory(LPCWSTR, LPSECURITY_ATTRIBUTES); 
+STDAPI_(DWORD) CeGetLastError(void);
+STDAPI_(BOOL) CeGetFileTime(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME); 
+STDAPI_(BOOL) CeCloseHandle(HANDLE); 
+
+#endif /* _RAPI_H */
diff --git a/winsup/cygwin/include/wchar.h b/winsup/cygwin/include/wchar.h
new file mode 100644 (file)
index 0000000..8c7c94d
--- /dev/null
@@ -0,0 +1,27 @@
+/* wchar.h
+
+   Copyright 1998 Cygnus Solutions
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _WCHAR_H
+#define _WCHAR_H
+
+#include <sys/cdefs.h>
+
+/* Get wchar_t from <stddef.h>.  */
+#define __need_wchar_t
+#include <stddef.h>
+
+__BEGIN_DECLS
+
+int wcscmp (wchar_t *__s1, wchar_t *__s2);
+int wcslen (wchar_t *__s1);
+
+__END_DECLS
+
+#endif /* _WCHAR_H */
diff --git a/winsup/cygwin/libc/getopt.c b/winsup/cygwin/libc/getopt.c
new file mode 100644 (file)
index 0000000..a5883f0
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 1987, 1993, 1994, 1996
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "getopt.h"
+
+int      opterr = 1;   /* if error message should be printed */
+int      optind = 1;   /* index into parent argv vector */
+int      optopt;       /* character checked for validity */
+int      optreset;     /* reset getopt */
+char     *optarg;      /* argument associated with option */
+
+static char * __progname (char *);
+int getopt_internal (int, char * const *, const char *);
+
+static char * __progname(nargv0)
+    char * nargv0;
+{
+    char * tmp = strrchr(nargv0, '/');
+    if (tmp) tmp++; else tmp = nargv0;
+    return(tmp);
+}
+
+#define        BADCH   (int)'?'
+#define        BADARG  (int)':'
+#define        EMSG    ""
+
+/*
+ * getopt --
+ *     Parse argc/argv argument vector.
+ */
+int
+getopt_internal(nargc, nargv, ostr)
+       int nargc;
+       char * const *nargv;
+       const char *ostr;
+{
+       static const char *place = EMSG;        /* option letter processing */
+       char *oli;                              /* option letter list index */
+
+       if (optreset || !*place) {              /* update scanning pointer */
+               optreset = 0;
+               if (optind >= nargc || *(place = nargv[optind]) != '-') {
+                       place = EMSG;
+                       return (-1);
+               }
+               if (place[1] && *++place == '-') {      /* found "--" */
+                       /* ++optind; */
+                       place = EMSG;
+                       return (-2);
+               }
+       }                                       /* option letter okay? */
+       if ((optopt = (int)*place++) == (int)':' ||
+           !(oli = strchr(ostr, optopt))) {
+               /*
+                * if the user didn't specify '-' as an option,
+                * assume it means -1.
+                */
+               if (optopt == (int)'-')
+                       return (-1);
+               if (!*place)
+                       ++optind;
+               if (opterr && *ostr != ':')
+                       (void)fprintf(stderr,
+                           "%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
+               return (BADCH);
+       }
+       if (*++oli != ':') {                    /* don't need argument */
+               optarg = NULL;
+               if (!*place)
+                       ++optind;
+       } else {                                /* need an argument */
+               if (*place)                     /* no white space */
+                       optarg = (char *)place;
+               else if (nargc <= ++optind) {   /* no arg */
+                       place = EMSG;
+                       if ((opterr) && (*ostr != ':'))
+                               (void)fprintf(stderr,
+                                   "%s: option requires an argument -- %c\n",
+                                   __progname(nargv[0]), optopt);
+                       return (BADARG);
+               } else                          /* white space */
+                       optarg = nargv[optind];
+               place = EMSG;
+               ++optind;
+       }
+       return (optopt);                        /* dump back option letter */
+}
+
+/*
+ * getopt --
+ *     Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, ostr)
+       int nargc;
+       char * const *nargv;
+       const char *ostr;
+{
+       int retval;
+
+       if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
+               retval = -1;
+               ++optind;
+       }
+       return(retval);
+}
+
+/*
+ * getopt_long --
+ *     Parse argc/argv argument vector.
+ */
+int
+getopt_long(nargc, nargv, options, long_options, index)
+     int nargc;
+     char ** nargv;
+     char * options;
+     struct option * long_options;
+     int * index;
+{
+       int retval;
+
+       if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
+               char *current_argv = nargv[optind++] + 2, *has_equal;
+               int i, current_argv_len, match = -1;
+
+               if (*current_argv == '\0') {
+                       return(-1);
+               }
+               if ((has_equal = strchr(current_argv, '='))) {
+                       current_argv_len = has_equal - current_argv;
+                       has_equal++;
+               } else
+                       current_argv_len = strlen(current_argv);
+
+               for (i = 0; long_options[i].name; i++) {
+                       if (strncmp(current_argv, long_options[i].name, current_argv_len))
+                               continue;
+
+                       if (strlen(long_options[i].name) == current_argv_len) {
+                               match = i;
+                               break;
+                       }
+                       if (match == -1)
+                               match = i;
+               }
+               if (match != -1) {
+                       if (long_options[match].has_arg) {
+                               if (has_equal)
+                                       optarg = has_equal;
+                               else
+                                       optarg = nargv[optind++];
+                       }
+                       if ((long_options[match].has_arg == 1) && (optarg == NULL)) {
+                               /* Missing option, leading : indecates no error */
+                               if ((opterr) && (*options != ':'))
+                                       (void)fprintf(stderr,
+                                     "%s: option requires an argument -- %s\n",
+                                     __progname(nargv[0]), current_argv);
+                               return (BADARG);
+                       }
+               } else { /* No matching argument */
+                       if ((opterr) && (*options != ':'))
+                               (void)fprintf(stderr,
+                                   "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
+                       return (BADCH);
+               }
+               if (long_options[match].flag) {
+                       *long_options[match].flag = long_options[match].val;
+                       retval = 0;
+               } else
+                       retval = long_options[match].val;
+               if (index)
+                       *index = match;
+       }
+       return(retval);
+}
+/*****************************************************************/
+
+
+
+
+
+
+#include <stdio.h>
+#include "getopt.h"
+
+/* Stuff for getopt */
+static struct option long_options[] = {
+       { (char *)"simple", 0, NULL, 's' },
+       { (char *)"t", 0, NULL, 't' },
+       { (char *)"u", 1, NULL, 'u' },
+       { (char *)"v", 0, NULL, 'v' },
+       /* Do not reorder the following */
+       { (char *)"yy", 0, NULL, 'Y' },
+       {  (char *)"y", 0, NULL, 'y' },
+       { (char *)"zz", 0, NULL, 'z' },
+       { (char *)"zzz", 0, NULL, 'Z' },
+       { NULL, 0, NULL, 0 }
+};
+extern char * optarg;
+extern int optreset;
+extern int optind;
+
+int test_getopt_long(args, expected_result)
+    char ** args, * expected_result;
+{
+       char actual_result[256];
+       int count, pass, i;
+
+       pass = 0;
+       optind = 1;
+       optreset = 1;
+       for (count = 0; args[count]; count++);
+       while ((i = getopt_long(count, args, (char *)"ab:", long_options, NULL)) != EOF) {
+               switch(i) {
+               case 'u':
+                       if (strcmp(optarg, "bogus")) {
+                               printf("--u option does not have bogus optarg.\n");
+                               return(1);
+                       }
+               case 'Y':
+               case 's':
+               case 't':
+               case 'v':
+               case 'y':
+               case 'z':
+                       actual_result[pass++] = i;
+                       break;
+               default:
+                       actual_result[pass++] = '?';
+                       break;
+               }
+       }
+
+       actual_result[pass] = '\0';
+       return(strcmp(actual_result, expected_result));
+       
+}
+
+#if 0
+int usage(value)
+       int value;
+{
+       printf("test_getopt [-d]\n");
+       exit(value);
+}
+#endif
+
+#if 0
+
+/*
+ * Static arglists for individual tests
+ * This is ugly and maybe I should just use a variable arglist
+ */
+const char *argv1[] = { "Test simple", "--s", NULL };
+const char *argv2[] = { "Test multiple", "--s", "--t", NULL };
+const char *argv3[] = { "Test optarg with space", "--u", "bogus", NULL };
+const char *argv4[] = { "Test optarg with equal", "--u=bogus", NULL };
+const char *argv5[] = { "Test complex", "--s", "--t", "--u", "bogus", "--v", NULL };
+const char *argv6[] = { "Test exact", "--y", NULL };
+const char *argv7[] = { "Test abbr", "--z", NULL };
+const char *argv8[] = { "Test simple termination", "--z", "foo", "--z", NULL };
+const char *argv9[] = { "Test -- termination", "--z", "--", "--z", NULL };
+
+int debug = 0;
+int main(argc, argv)
+    int argc;
+    char ** argv;
+{
+       int i;
+
+       /* Of course if getopt() has a bug this won't work */
+       while ((i = getopt(argc, argv, "d")) != EOF) {
+               switch(i) {
+               case 'd':
+                       debug++;
+                       break;
+               default:
+                       usage(1);
+                       break;
+               }
+       }
+
+       /* Test getopt_long() */
+       {
+               if (test_getopt_long(argv1, "s")) {
+                       printf("Test simple failed.\n");
+                       exit(1);
+               }
+       }
+
+       /* Test multiple arguments */
+       {
+               if (test_getopt_long(argv2, "st")) {
+                       printf("Test multiple failed.\n");
+                       exit(1);
+               }
+       }
+
+       /* Test optarg with space */
+       {
+               if (test_getopt_long(argv3, "u")) {
+                       printf("Test optarg with space failed.\n");
+                       exit(1);
+               }
+       }
+
+       /* Test optarg with equal */
+       {
+               if (test_getopt_long(argv4, "u")) {
+                       printf("Test optarg with equal failed.\n");
+                       exit(1);
+               }
+       }
+
+       /* Test complex */
+       {
+               if (test_getopt_long(argv5, "stuv")) {
+                       printf("Test complex failed.\n");
+                       exit(1);
+               }
+       }
+
+       /* Test that exact matches override abbr matches */
+       {
+               if (test_getopt_long(argv6, "y")) {
+                       printf("Test exact failed.\n");
+                       exit(1);
+               }
+       }
+
+       /* Test that abbr matches are first match. */
+       {
+               if (test_getopt_long(argv7, "z")) {
+                       printf("Test abbr failed.\n");
+                       exit(1);
+               }
+       }
+
+       /* Test that option termination succeeds */
+       {
+               if (test_getopt_long(argv8, "z")) {
+                       printf("Test simple termination failed.\n");
+                       exit(1);
+               }
+       }
+
+       /* Test that "--" termination succeeds */
+       {
+               if (test_getopt_long(argv9, "z")) {
+                       printf("Test -- termination failed.\n");
+                       exit(1);
+               }
+       }
+       exit(0);
+}
+#endif
diff --git a/winsup/cygwin/libccrt0.cc b/winsup/cygwin/libccrt0.cc
new file mode 100644 (file)
index 0000000..6f7d534
--- /dev/null
@@ -0,0 +1,95 @@
+/* libccrt0.cc: crt0 for libc [newlib calls this one]
+
+   Copyright 1996, 1998, 1999, 2000 Cygnus Solutions.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#undef MALLOC_DEBUG
+
+#include "winsup.h"
+#include <reent.h>
+#include <stdlib.h>
+
+typedef int (*MainFunc) (int argc, char *argc[], char **env);
+
+extern "C"
+{
+  char **environ;
+  void cygwin_crt0 (MainFunc);
+  int cygwin_attach_dll (HMODULE, MainFunc);
+  int cygwin_attach_noncygwin_dll (HMODULE, MainFunc);
+  int main (int, char **, char **);
+  struct _reent *_impure_ptr;
+  int _fmode;
+};
+
+static per_process this_proc;
+
+/* Set up pointers to various pieces so the dll can then use them,
+   and then jump to the dll.  */
+
+static void
+cygwin_crt0_common (MainFunc f)
+{
+  /* This is used to record what the initial sp was.  The value is needed
+     when copying the parent's stack to the child during a fork.  */
+  int onstack;
+
+  /* The version numbers are the main source of compatibility checking.
+     As a backup to them, we use the size of the per_process struct.  */
+  this_proc.magic_biscuit = sizeof (per_process);
+
+  /* cygwin.dll version number in effect at the time the app was created.  */
+  this_proc.dll_major = CYGWIN_VERSION_DLL_MAJOR;
+  this_proc.dll_minor = CYGWIN_VERSION_DLL_MINOR;
+  this_proc.api_major = CYGWIN_VERSION_API_MAJOR;
+  this_proc.api_minor = CYGWIN_VERSION_API_MINOR;
+
+  this_proc.ctors = &__CTOR_LIST__;
+  this_proc.dtors = &__DTOR_LIST__;
+  this_proc.envptr = &environ;
+  this_proc.impure_ptr_ptr = &_impure_ptr;
+  this_proc.main = f;
+  this_proc.fmode_ptr = &_fmode;
+  this_proc.initial_sp = (char *) &onstack;
+
+  /* Remember whatever the user linked his application with - or
+     point to entries in the dll.  */
+  this_proc.malloc = &malloc;
+  this_proc.free = &free;
+  this_proc.realloc = &realloc;
+  this_proc.calloc = &calloc;
+
+  /* Setup the module handle so fork can get the path name. */
+  this_proc.hmodule = GetModuleHandle (0);
+
+  /* variables for fork */
+  this_proc.data_start = &_data_start__;
+  this_proc.data_end = &_data_end__;
+  this_proc.bss_start = &_bss_start__;
+  this_proc.bss_end = &_bss_end__;
+}
+
+/* for main module */
+void
+cygwin_crt0 (MainFunc f)
+{
+  cygwin_crt0_common (f);
+
+ /* Jump into the dll. */
+  dll_crt0 (&this_proc);
+}
+
+/* for a loaded dll */
+int
+cygwin_attach_dll (HMODULE h, MainFunc f)
+{
+  cygwin_crt0_common (f);
+
+  /* jump into the dll. */
+  return dll_dllcrt0 (h, &this_proc);
+}
diff --git a/winsup/cygwin/libcmain.cc b/winsup/cygwin/libcmain.cc
new file mode 100644 (file)
index 0000000..a8ae341
--- /dev/null
@@ -0,0 +1,34 @@
+/* libcmain.cc
+
+   Copyright 1996, 1997, 1998 Cygnus Solutions.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <windows.h>
+
+/* Allow apps which don't have a main work, as long as they define WinMain */
+extern "C" int main ()
+{
+  HMODULE x = GetModuleHandleA(0);
+  char *s = GetCommandLineA ();
+  STARTUPINFO si;
+
+  /* GetCommandLineA returns the entire command line including the
+     program name, but WinMain is defined to accept the command
+     line without the program name.  */
+  while (*s != ' ' && *s != '\0')
+    ++s;
+  while (*s == ' ')
+    ++s;
+
+  GetStartupInfo (&si);
+
+  WinMain (x, 0, s,
+          ((si.dwFlags & STARTF_USESHOWWINDOW) != 0
+           ? si.wShowWindow
+           : SW_SHOWNORMAL));
+}
diff --git a/winsup/cygwin/localtime.c b/winsup/cygwin/localtime.c
new file mode 100644 (file)
index 0000000..5784f3c
--- /dev/null
@@ -0,0 +1,2250 @@
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+/* Temporarily merged private.h and tzfile.h for ease of management - DJ */
+
+/* CYGNUS LOCAL */
+#define lint
+#include <windows.h>
+#include <sys/strace.h>
+
+extern DWORD strace_active;
+
+#define USG_COMPAT
+
+/* END CYGNUS LOCAL */
+
+#ifndef lint
+#ifndef NOID
+static char    elsieid[] = "@(#)localtime.c    7.66";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
+** POSIX-style TZ environment variable handling from Guy Harris
+** (guy@auspex.com).
+*/
+
+/*LINTLIBRARY*/
+
+#ifndef PRIVATE_H
+
+#define PRIVATE_H
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** ID
+*/
+
+#ifndef lint
+#ifndef NOID
+static char    privatehid[] = "@(#)private.h   7.48";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Defaults for preprocessor symbols.
+** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
+*/
+
+#ifndef HAVE_ADJTIME
+#define HAVE_ADJTIME           1
+#endif /* !defined HAVE_ADJTIME */
+
+#ifndef HAVE_GETTEXT
+#define HAVE_GETTEXT           0
+#endif /* !defined HAVE_GETTEXT */
+
+#ifndef HAVE_SETTIMEOFDAY
+#define HAVE_SETTIMEOFDAY      3
+#endif /* !defined HAVE_SETTIMEOFDAY */
+
+#ifndef HAVE_STRERROR
+#define HAVE_STRERROR          0
+#endif /* !defined HAVE_STRERROR */
+
+#ifndef HAVE_SYMLINK
+#define HAVE_SYMLINK           1
+#endif /* !defined HAVE_SYMLINK */
+
+#ifndef HAVE_UNISTD_H
+#define HAVE_UNISTD_H          1
+#endif /* !defined HAVE_UNISTD_H */
+
+#ifndef HAVE_UTMPX_H
+#define HAVE_UTMPX_H           0
+#endif /* !defined HAVE_UTMPX_H */
+
+#ifndef LOCALE_HOME
+#define LOCALE_HOME            "/usr/lib/locale"
+#endif /* !defined LOCALE_HOME */
+
+/*
+** Nested includes
+*/
+
+#include "sys/types.h" /* for time_t */
+#include "stdio.h"
+#include "errno.h"
+#include "limits.h"    /* for CHAR_BIT */
+#include "time.h"
+#include "stdlib.h"
+
+#if HAVE_GETTEXT - 0
+#include "libintl.h"
+#endif /* HAVE_GETTEXT - 0 */
+
+#if HAVE_UNISTD_H - 0
+#include "unistd.h"    /* for F_OK and R_OK */
+#endif /* HAVE_UNISTD_H - 0 */
+
+#if !(HAVE_UNISTD_H - 0)
+#ifndef F_OK
+#define F_OK   0
+#endif /* !defined F_OK */
+#ifndef R_OK
+#define R_OK   4
+#endif /* !defined R_OK */
+#endif /* !(HAVE_UNISTD_H - 0) */
+
+/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX.  */
+#define is_digit(c) ((unsigned)(c) - '0' <= 9)
+
+/*
+** Workarounds for compilers/systems.
+*/
+
+/*
+** SunOS 4.1.1 cc lacks const.
+*/
+
+#ifndef const
+#ifndef __STDC__
+#define const
+#endif /* !defined __STDC__ */
+#endif /* !defined const */
+
+/*
+** SunOS 4.1.1 cc lacks prototypes.
+*/
+
+#ifndef P
+#ifdef __STDC__
+#define P(x)   x
+#endif /* defined __STDC__ */
+#ifndef __STDC__
+#define P(x)   ()
+#endif /* !defined __STDC__ */
+#endif /* !defined P */
+
+/*
+** SunOS 4.1.1 headers lack EXIT_SUCCESS.
+*/
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS   0
+#endif /* !defined EXIT_SUCCESS */
+
+/*
+** SunOS 4.1.1 headers lack EXIT_FAILURE.
+*/
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE   1
+#endif /* !defined EXIT_FAILURE */
+
+/*
+** SunOS 4.1.1 headers lack FILENAME_MAX.
+*/
+
+#ifndef FILENAME_MAX
+
+#ifndef MAXPATHLEN
+#ifdef unix
+#include "sys/param.h"
+#endif /* defined unix */
+#endif /* !defined MAXPATHLEN */
+
+#ifdef MAXPATHLEN
+#define FILENAME_MAX   MAXPATHLEN
+#endif /* defined MAXPATHLEN */
+#ifndef MAXPATHLEN
+#define FILENAME_MAX   1024            /* Pure guesswork */
+#endif /* !defined MAXPATHLEN */
+
+#endif /* !defined FILENAME_MAX */
+
+/*
+** SunOS 4.1.1 libraries lack remove.
+*/
+
+#ifndef remove
+extern int     unlink P((const char * filename));
+#define remove unlink
+#endif /* !defined remove */
+
+/*
+** Some ancient errno.h implementations don't declare errno.
+** But some newer errno.h implementations define it as a macro.
+** Fix the former without affecting the latter.
+*/
+#ifndef errno
+extern int errno;
+#endif /* !defined errno */
+
+/*
+** Private function declarations.
+*/
+char * icalloc P((int nelem, int elsize));
+char * icatalloc P((char * old, const char * new));
+char * icpyalloc P((const char * string));
+char * imalloc P((int n));
+void * irealloc P((void * pointer, int size));
+void   icfree P((char * pointer));
+void   ifree P((char * pointer));
+char * scheck P((const char *string, const char *format));
+
+
+/*
+** Finally, some convenience items.
+*/
+
+#ifndef TRUE
+#define TRUE   1
+#endif /* !defined TRUE */
+
+#ifndef FALSE
+#define FALSE  0
+#endif /* !defined FALSE */
+
+#ifndef TYPE_BIT
+#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
+#endif /* !defined TYPE_BIT */
+
+#ifndef TYPE_SIGNED
+#define TYPE_SIGNED(type) (((type) -1) < 0)
+#endif /* !defined TYPE_SIGNED */
+
+#ifndef INT_STRLEN_MAXIMUM
+/*
+** 302 / 1000 is log10(2.0) rounded up.
+** Subtract one for the sign bit if the type is signed;
+** add one for integer division truncation;
+** add one more for a minus sign if the type is signed.
+*/
+#define INT_STRLEN_MAXIMUM(type) \
+    ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
+#endif /* !defined INT_STRLEN_MAXIMUM */
+
+/*
+** INITIALIZE(x)
+*/
+
+#ifndef GNUC_or_lint
+#ifdef lint
+#define GNUC_or_lint
+#endif /* defined lint */
+#ifndef lint
+#ifdef __GNUC__
+#define GNUC_or_lint
+#endif /* defined __GNUC__ */
+#endif /* !defined lint */
+#endif /* !defined GNUC_or_lint */
+
+#ifndef INITIALIZE
+#ifdef GNUC_or_lint
+#define INITIALIZE(x)  ((x) = 0)
+#endif /* defined GNUC_or_lint */
+#ifndef GNUC_or_lint
+#define INITIALIZE(x)
+#endif /* !defined GNUC_or_lint */
+#endif /* !defined INITIALIZE */
+
+/*
+** For the benefit of GNU folk...
+** `_(MSGID)' uses the current locale's message library string for MSGID.
+** The default is to use gettext if available, and use MSGID otherwise.
+*/
+
+#ifndef _
+#if HAVE_GETTEXT - 0
+#define _(msgid) gettext(msgid)
+#else /* !(HAVE_GETTEXT - 0) */
+#define _(msgid) msgid
+#endif /* !(HAVE_GETTEXT - 0) */
+#endif /* !defined _ */
+
+#ifndef TZ_DOMAIN
+#define TZ_DOMAIN "tz"
+#endif /* !defined TZ_DOMAIN */
+
+/*
+** UNIX was a registered trademark of UNIX System Laboratories in 1993.
+*/
+
+#endif /* !defined PRIVATE_H */
+
+#ifndef TZFILE_H
+
+#define TZFILE_H
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** ID
+*/
+
+#ifndef lint
+#ifndef NOID
+static char    tzfilehid[] = "@(#)tzfile.h     7.14";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Information about time zone files.
+*/
+
+#ifndef TZDIR
+#define TZDIR  "/usr/local/etc/zoneinfo" /* Time zone object file directory */
+#endif /* !defined TZDIR */
+
+#ifndef TZDEFAULT
+#define TZDEFAULT      "localtime"
+#endif /* !defined TZDEFAULT */
+
+#ifndef TZDEFRULES
+#define TZDEFRULES     "posixrules"
+#endif /* !defined TZDEFRULES */
+
+/*
+** Each file begins with. . .
+*/
+
+#define        TZ_MAGIC        "TZif"
+
+struct tzhead {
+       char    tzh_magic[4];           /* TZ_MAGIC */
+       char    tzh_reserved[16];       /* reserved for future use */
+       char    tzh_ttisgmtcnt[4];      /* coded number of trans. time flags */
+       char    tzh_ttisstdcnt[4];      /* coded number of trans. time flags */
+       char    tzh_leapcnt[4];         /* coded number of leap seconds */
+       char    tzh_timecnt[4];         /* coded number of transition times */
+       char    tzh_typecnt[4];         /* coded number of local time types */
+       char    tzh_charcnt[4];         /* coded number of abbr. chars */
+};
+
+/*
+** . . .followed by. . .
+**
+**     tzh_timecnt (char [4])s         coded transition times a la time(2)
+**     tzh_timecnt (unsigned char)s    types of local time starting at above
+**     tzh_typecnt repetitions of
+**             one (char [4])          coded UTC offset in seconds
+**             one (unsigned char)     used to set tm_isdst
+**             one (unsigned char)     that's an abbreviation list index
+**     tzh_charcnt (char)s             '\0'-terminated zone abbreviations
+**     tzh_leapcnt repetitions of
+**             one (char [4])          coded leap second transition times
+**             one (char [4])          total correction after above
+**     tzh_ttisstdcnt (char)s          indexed by type; if TRUE, transition
+**                                     time is standard time, if FALSE,
+**                                     transition time is wall clock time
+**                                     if absent, transition times are
+**                                     assumed to be wall clock time
+**     tzh_ttisgmtcnt (char)s          indexed by type; if TRUE, transition
+**                                     time is UTC, if FALSE,
+**                                     transition time is local time
+**                                     if absent, transition times are
+**                                     assumed to be local time
+*/
+
+/*
+** In the current implementation, "tzset()" refuses to deal with files that
+** exceed any of the limits below.
+*/
+
+#ifndef TZ_MAX_TIMES
+/*
+** The TZ_MAX_TIMES value below is enough to handle a bit more than a
+** year's worth of solar time (corrected daily to the nearest second) or
+** 138 years of Pacific Presidential Election time
+** (where there are three time zone transitions every fourth year).
+*/
+#define TZ_MAX_TIMES   370
+#endif /* !defined TZ_MAX_TIMES */
+
+#ifndef TZ_MAX_TYPES
+#ifndef NOSOLAR
+#define TZ_MAX_TYPES   256 /* Limited by what (unsigned char)'s can hold */
+#endif /* !defined NOSOLAR */
+#ifdef NOSOLAR
+/*
+** Must be at least 14 for Europe/Riga as of Jan 12 1995,
+** as noted by Earl Chew <earl@hpato.aus.hp.com>.
+*/
+#define TZ_MAX_TYPES   20      /* Maximum number of local time types */
+#endif /* !defined NOSOLAR */
+#endif /* !defined TZ_MAX_TYPES */
+
+#ifndef TZ_MAX_CHARS
+#define TZ_MAX_CHARS   50      /* Maximum number of abbreviation characters */
+                               /* (limited by what unsigned chars can hold) */
+#endif /* !defined TZ_MAX_CHARS */
+
+#ifndef TZ_MAX_LEAPS
+#define TZ_MAX_LEAPS   50      /* Maximum number of leap second corrections */
+#endif /* !defined TZ_MAX_LEAPS */
+
+#define SECSPERMIN     60
+#define MINSPERHOUR    60
+#define HOURSPERDAY    24
+#define DAYSPERWEEK    7
+#define DAYSPERNYEAR   365
+#define DAYSPERLYEAR   366
+#define SECSPERHOUR    (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY     ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR    12
+
+#define TM_SUNDAY      0
+#define TM_MONDAY      1
+#define TM_TUESDAY     2
+#define TM_WEDNESDAY   3
+#define TM_THURSDAY    4
+#define TM_FRIDAY      5
+#define TM_SATURDAY    6
+
+#define TM_JANUARY     0
+#define TM_FEBRUARY    1
+#define TM_MARCH       2
+#define TM_APRIL       3
+#define TM_MAY         4
+#define TM_JUNE                5
+#define TM_JULY                6
+#define TM_AUGUST      7
+#define TM_SEPTEMBER   8
+#define TM_OCTOBER     9
+#define TM_NOVEMBER    10
+#define TM_DECEMBER    11
+
+#define TM_YEAR_BASE   1900
+
+#define EPOCH_YEAR     1970
+#define EPOCH_WDAY     TM_THURSDAY
+
+/*
+** Accurate only for the past couple of centuries;
+** that will probably do.
+*/
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+
+#ifndef USG
+
+/*
+** Use of the underscored variants may cause problems if you move your code to
+** certain System-V-based systems; for maximum portability, use the
+** underscore-free variants.  The underscored variants are provided for
+** backward compatibility only; they may disappear from future versions of
+** this file.
+*/
+
+#define SECS_PER_MIN   SECSPERMIN
+#define MINS_PER_HOUR  MINSPERHOUR
+#define HOURS_PER_DAY  HOURSPERDAY
+#define DAYS_PER_WEEK  DAYSPERWEEK
+#define DAYS_PER_NYEAR DAYSPERNYEAR
+#define DAYS_PER_LYEAR DAYSPERLYEAR
+#define SECS_PER_HOUR  SECSPERHOUR
+#define SECS_PER_DAY   SECSPERDAY
+#define MONS_PER_YEAR  MONSPERYEAR
+
+#endif /* !defined USG */
+
+#endif /* !defined TZFILE_H */
+
+#include "fcntl.h"
+
+/*
+** SunOS 4.1.1 headers lack O_BINARY.
+*/
+
+#ifdef O_BINARY
+#define OPEN_MODE      (O_RDONLY | O_BINARY)
+#endif /* defined O_BINARY */
+#ifndef O_BINARY
+#define OPEN_MODE      O_RDONLY
+#endif /* !defined O_BINARY */
+
+#ifndef WILDABBR
+/*
+** Someone might make incorrect use of a time zone abbreviation:
+**     1.      They might reference tzname[0] before calling tzset (explicitly
+**             or implicitly).
+**     2.      They might reference tzname[1] before calling tzset (explicitly
+**             or implicitly).
+**     3.      They might reference tzname[1] after setting to a time zone
+**             in which Daylight Saving Time is never observed.
+**     4.      They might reference tzname[0] after setting to a time zone
+**             in which Standard Time is never observed.
+**     5.      They might reference tm.TM_ZONE after calling offtime.
+** What's best to do in the above cases is open to debate;
+** for now, we just set things up so that in any of the five cases
+** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
+** string "tzname[0] used before set", and similarly for the other cases.
+** And another:  initialize tzname[0] to "ERA", with an explanation in the
+** manual page of what this "time zone abbreviation" means (doing this so
+** that tzname[0] has the "normal" length of three characters).
+*/
+#define WILDABBR       "   "
+#endif /* !defined WILDABBR */
+
+static char            wildabbr[] = WILDABBR;
+
+static const char      gmt[] = "GMT";
+
+struct ttinfo {                                /* time type information */
+       long            tt_gmtoff;      /* UTC offset in seconds */
+       int             tt_isdst;       /* used to set tm_isdst */
+       int             tt_abbrind;     /* abbreviation list index */
+       int             tt_ttisstd;     /* TRUE if transition is std time */
+       int             tt_ttisgmt;     /* TRUE if transition is UTC */
+};
+
+struct lsinfo {                                /* leap second information */
+       time_t          ls_trans;       /* transition time */
+       long            ls_corr;        /* correction to apply */
+};
+
+#define BIGGEST(a, b)  (((a) > (b)) ? (a) : (b))
+
+#ifdef TZNAME_MAX
+#define MY_TZNAME_MAX  TZNAME_MAX
+#endif /* defined TZNAME_MAX */
+#ifndef TZNAME_MAX
+#define MY_TZNAME_MAX  255
+#endif /* !defined TZNAME_MAX */
+
+struct state {
+       int             leapcnt;
+       int             timecnt;
+       int             typecnt;
+       int             charcnt;
+       time_t          ats[TZ_MAX_TIMES];
+       unsigned char   types[TZ_MAX_TIMES];
+       struct ttinfo   ttis[TZ_MAX_TYPES];
+       char            chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
+                               (2 * (MY_TZNAME_MAX + 1)))];
+       struct lsinfo   lsis[TZ_MAX_LEAPS];
+};
+
+struct rule {
+       int             r_type;         /* type of rule--see below */
+       int             r_day;          /* day number of rule */
+       int             r_week;         /* week number of rule */
+       int             r_mon;          /* month number of rule */
+       long            r_time;         /* transition time of rule */
+};
+
+#define JULIAN_DAY             0       /* Jn - Julian day */
+#define DAY_OF_YEAR            1       /* n - day of year */
+#define MONTH_NTH_DAY_OF_WEEK  2       /* Mm.n.d - month, week, day of week */
+
+/*
+** Prototypes for static functions.
+*/
+
+static long            detzcode P((const char * codep));
+static const char *    getzname P((const char * strp));
+static const char *    getnum P((const char * strp, int * nump, int min,
+                               int max));
+static const char *    getsecs P((const char * strp, long * secsp));
+static const char *    getoffset P((const char * strp, long * offsetp));
+static const char *    getrule P((const char * strp, struct rule * rulep));
+static void            gmtload P((struct state * sp));
+static void            gmtsub P((const time_t * timep, long offset,
+                               struct tm * tmp));
+static void            localsub P((const time_t * timep, long offset,
+                               struct tm * tmp));
+static int             increment_overflow P((int * number, int delta));
+static int             normalize_overflow P((int * tensptr, int * unitsptr,
+                               int base));
+static void            settzname P((void));
+static time_t          time1 P((struct tm * tmp,
+                               void(*funcp) P((const time_t *,
+                               long, struct tm *)),
+                               long offset));
+static time_t          time2 P((struct tm *tmp,
+                               void(*funcp) P((const time_t *,
+                               long, struct tm*)),
+                               long offset, int * okayp));
+static time_t          time2sub P((struct tm *tmp,
+                               void(*funcp) P((const time_t *,
+                               long, struct tm*)),
+                               long offset, int * okayp, int do_norm_secs));
+static void            timesub P((const time_t * timep, long offset,
+                               const struct state * sp, struct tm * tmp));
+static int             tmcomp P((const struct tm * atmp,
+                               const struct tm * btmp));
+static time_t          transtime P((time_t janfirst, int year,
+                               const struct rule * rulep, long offset));
+static int             tzload P((const char * name, struct state * sp));
+static int             tzparse P((const char * name, struct state * sp,
+                               int lastditch));
+
+#ifdef ALL_STATE
+static struct state *  lclptr;
+static struct state *  gmtptr;
+#endif /* defined ALL_STATE */
+
+#ifndef ALL_STATE
+static struct state    lclmem;
+static struct state    gmtmem;
+#define lclptr         (&lclmem)
+#define gmtptr         (&gmtmem)
+#endif /* State Farm */
+
+#ifndef TZ_STRLEN_MAX
+#define TZ_STRLEN_MAX 255
+#endif /* !defined TZ_STRLEN_MAX */
+
+static char            lcl_TZname[TZ_STRLEN_MAX + 1];
+static int             lcl_is_set;
+static int             gmt_is_set;
+
+#define tzname _tzname
+#undef _tzname
+
+char * tzname[2] = {
+       wildabbr,
+       wildabbr
+};
+
+/*
+** Section 4.12.3 of X3.159-1989 requires that
+**     Except for the strftime function, these functions [asctime,
+**     ctime, gmtime, localtime] return values in one of two static
+**     objects: a broken-down time structure and an array of char.
+** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
+*/
+
+static struct tm       tm;
+
+
+/* These variables are initialized by tzset.  The macro versions are
+   defined in time.h, and indirect through the __imp_ pointers.  */
+
+#define timezone _timezone
+#define daylight _daylight
+#undef _timezone
+#undef _daylight
+
+#ifdef USG_COMPAT
+time_t                 timezone = 0;
+int                    daylight = 0;
+#endif /* defined USG_COMPAT */
+
+#ifdef ALTZONE
+time_t                 altzone = 0;
+#endif /* defined ALTZONE */
+
+static long
+detzcode(codep)
+const char * const     codep;
+{
+       register long   result;
+       register int    i;
+
+       result = (codep[0] & 0x80) ? ~0L : 0L;
+       for (i = 0; i < 4; ++i)
+               result = (result << 8) | (codep[i] & 0xff);
+       return result;
+}
+
+static void
+settzname P((void))
+{
+       register struct state * const   sp = lclptr;
+       register int                    i;
+
+       tzname[0] = wildabbr;
+       tzname[1] = wildabbr;
+#ifdef USG_COMPAT
+       daylight = 0;
+       timezone = 0;
+#endif /* defined USG_COMPAT */
+#ifdef ALTZONE
+       altzone = 0;
+#endif /* defined ALTZONE */
+#ifdef ALL_STATE
+       if (sp == NULL) {
+               tzname[0] = tzname[1] = gmt;
+               return;
+       }
+#endif /* defined ALL_STATE */
+       for (i = 0; i < sp->typecnt; ++i) {
+               register const struct ttinfo * const    ttisp = &sp->ttis[i];
+
+               tzname[ttisp->tt_isdst] =
+                       &sp->chars[ttisp->tt_abbrind];
+#ifdef USG_COMPAT
+               if (ttisp->tt_isdst)
+                       daylight = 1;
+               if (i == 0 || !ttisp->tt_isdst)
+                       timezone = -(ttisp->tt_gmtoff);
+#endif /* defined USG_COMPAT */
+#ifdef ALTZONE
+               if (i == 0 || ttisp->tt_isdst)
+                       altzone = -(ttisp->tt_gmtoff);
+#endif /* defined ALTZONE */
+       }
+       /*
+       ** And to get the latest zone names into tzname. . .
+       */
+       for (i = 0; i < sp->timecnt; ++i) {
+               register const struct ttinfo * const    ttisp =
+                                                       &sp->ttis[
+                                                               sp->types[i]];
+
+               tzname[ttisp->tt_isdst] =
+                       &sp->chars[ttisp->tt_abbrind];
+       }
+}
+
+#include "tz_posixrules.h"
+
+static int
+tzload(name, sp)
+register const char *          name;
+register struct state * const  sp;
+{
+       register const char *   p;
+       register int            i;
+       register int            fid;
+
+       if (name == NULL && (name = TZDEFAULT) == NULL)
+               return -1;
+       {
+               register int    doaccess;
+               /*
+               ** Section 4.9.1 of the C standard says that
+               ** "FILENAME_MAX expands to an integral constant expression
+               ** that is the size needed for an array of char large enough
+               ** to hold the longest file name string that the implementation
+               ** guarantees can be opened."
+               */
+               char            fullname[FILENAME_MAX + 1];
+
+               if (name[0] == ':')
+                       ++name;
+               doaccess = name[0] == '/';
+               if (!doaccess) {
+                       if ((p = TZDIR) == NULL)
+                               return -1;
+                       if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
+                               return -1;
+                       (void) strcpy(fullname, p);
+                       (void) strcat(fullname, "/");
+                       (void) strcat(fullname, name);
+                       /*
+                       ** Set doaccess if '.' (as in "../") shows up in name.
+                       */
+                       if (strchr(name, '.') != NULL)
+                               doaccess = TRUE;
+                       name = fullname;
+               }
+#if 0
+               if (doaccess && access(name, R_OK) != 0)
+                       return -1;
+#endif
+               if ((fid = open(name, OPEN_MODE)) == -1)
+                 {
+                   const char *base = strrchr(name, '/');
+                   if (base)
+                     base++;
+                   else
+                     base = name;
+                   if (strcmp(base, "posixrules"))
+                     return -1;
+
+                   /* We've got a built-in copy of posixrules just in case */
+                   fid = -2;
+                 }
+       }
+       {
+               struct tzhead * tzhp;
+               union {
+                 struct tzhead tzhead;
+                 char          buf[sizeof *sp + sizeof *tzhp];
+               } u;
+               int             ttisstdcnt;
+               int             ttisgmtcnt;
+
+               if (fid == -2)
+                 {
+                   memcpy(u.buf, _posixrules_data, sizeof(_posixrules_data));
+                   i = sizeof(_posixrules_data);
+                 }
+               else
+                 {
+                   i = read(fid, u.buf, sizeof u.buf);
+                   if (close(fid) != 0)
+                       return -1;
+                 }
+               ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
+               ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
+               sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
+               sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
+               sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
+               sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
+               p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
+               if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
+                       sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
+                       sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
+                       sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
+                       (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
+                       (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
+                               return -1;
+               if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */
+                       sp->timecnt +                   /* types */
+                       sp->typecnt * (4 + 2) +         /* ttinfos */
+                       sp->charcnt +                   /* chars */
+                       sp->leapcnt * (4 + 4) +         /* lsinfos */
+                       ttisstdcnt +                    /* ttisstds */
+                       ttisgmtcnt)                     /* ttisgmts */
+                               return -1;
+               for (i = 0; i < sp->timecnt; ++i) {
+                       sp->ats[i] = detzcode(p);
+                       p += 4;
+               }
+               for (i = 0; i < sp->timecnt; ++i) {
+                       sp->types[i] = (unsigned char) *p++;
+                       if (sp->types[i] >= sp->typecnt)
+                               return -1;
+               }
+               for (i = 0; i < sp->typecnt; ++i) {
+                       register struct ttinfo *        ttisp;
+
+                       ttisp = &sp->ttis[i];
+                       ttisp->tt_gmtoff = detzcode(p);
+                       p += 4;
+                       ttisp->tt_isdst = (unsigned char) *p++;
+                       if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
+                               return -1;
+                       ttisp->tt_abbrind = (unsigned char) *p++;
+                       if (ttisp->tt_abbrind < 0 ||
+                               ttisp->tt_abbrind > sp->charcnt)
+                                       return -1;
+               }
+               for (i = 0; i < sp->charcnt; ++i)
+                       sp->chars[i] = *p++;
+               sp->chars[i] = '\0';    /* ensure '\0' at end */
+               for (i = 0; i < sp->leapcnt; ++i) {
+                       register struct lsinfo *        lsisp;
+
+                       lsisp = &sp->lsis[i];
+                       lsisp->ls_trans = detzcode(p);
+                       p += 4;
+                       lsisp->ls_corr = detzcode(p);
+                       p += 4;
+               }
+               for (i = 0; i < sp->typecnt; ++i) {
+                       register struct ttinfo *        ttisp;
+
+                       ttisp = &sp->ttis[i];
+                       if (ttisstdcnt == 0)
+                               ttisp->tt_ttisstd = FALSE;
+                       else {
+                               ttisp->tt_ttisstd = *p++;
+                               if (ttisp->tt_ttisstd != TRUE &&
+                                       ttisp->tt_ttisstd != FALSE)
+                                               return -1;
+                       }
+               }
+               for (i = 0; i < sp->typecnt; ++i) {
+                       register struct ttinfo *        ttisp;
+
+                       ttisp = &sp->ttis[i];
+                       if (ttisgmtcnt == 0)
+                               ttisp->tt_ttisgmt = FALSE;
+                       else {
+                               ttisp->tt_ttisgmt = *p++;
+                               if (ttisp->tt_ttisgmt != TRUE &&
+                                       ttisp->tt_ttisgmt != FALSE)
+                                               return -1;
+                       }
+               }
+       }
+       return 0;
+}
+
+static const int       mon_lengths[2][MONSPERYEAR] = {
+       { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+       { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static const int       year_lengths[2] = {
+       DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+/*
+** Given a pointer into a time zone string, scan until a character that is not
+** a valid character in a zone name is found.  Return a pointer to that
+** character.
+*/
+
+static const char *
+getzname(strp)
+register const char *  strp;
+{
+       register char   c;
+
+       while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
+               c != '+')
+                       ++strp;
+       return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a number from that string.
+** Check that the number is within a specified range; if it is not, return
+** NULL.
+** Otherwise, return a pointer to the first character not part of the number.
+*/
+
+static const char *
+getnum(strp, nump, min, max)
+register const char *  strp;
+int * const            nump;
+const int              min;
+const int              max;
+{
+       register char   c;
+       register int    num;
+
+       if (strp == NULL || !is_digit(c = *strp))
+               return NULL;
+       num = 0;
+       do {
+               num = num * 10 + (c - '0');
+               if (num > max)
+                       return NULL;    /* illegal value */
+               c = *++strp;
+       } while (is_digit(c));
+       if (num < min)
+               return NULL;            /* illegal value */
+       *nump = num;
+       return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a number of seconds,
+** in hh[:mm[:ss]] form, from the string.
+** If any error occurs, return NULL.
+** Otherwise, return a pointer to the first character not part of the number
+** of seconds.
+*/
+
+static const char *
+getsecs(strp, secsp)
+register const char *  strp;
+long * const           secsp;
+{
+       int     num;
+
+       /*
+       ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
+       ** "M10.4.6/26", which does not conform to Posix,
+       ** but which specifies the equivalent of
+       ** ``02:00 on the first Sunday on or after 23 Oct''.
+       */
+       strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
+       if (strp == NULL)
+               return NULL;
+       *secsp = num * (long) SECSPERHOUR;
+       if (*strp == ':') {
+               ++strp;
+               strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
+               if (strp == NULL)
+                       return NULL;
+               *secsp += num * SECSPERMIN;
+               if (*strp == ':') {
+                       ++strp;
+                       /* `SECSPERMIN' allows for leap seconds.  */
+                       strp = getnum(strp, &num, 0, SECSPERMIN);
+                       if (strp == NULL)
+                               return NULL;
+                       *secsp += num;
+               }
+       }
+       return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract an offset, in
+** [+-]hh[:mm[:ss]] form, from the string.
+** If any error occurs, return NULL.
+** Otherwise, return a pointer to the first character not part of the time.
+*/
+
+static const char *
+getoffset(strp, offsetp)
+register const char *  strp;
+long * const           offsetp;
+{
+       register int    neg = 0;
+
+       if (*strp == '-') {
+               neg = 1;
+               ++strp;
+       } else if (*strp == '+')
+               ++strp;
+       strp = getsecs(strp, offsetp);
+       if (strp == NULL)
+               return NULL;            /* illegal time */
+       if (neg)
+               *offsetp = -*offsetp;
+       return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a rule in the form
+** date[/time].  See POSIX section 8 for the format of "date" and "time".
+** If a valid rule is not found, return NULL.
+** Otherwise, return a pointer to the first character not part of the rule.
+*/
+
+static const char *
+getrule(strp, rulep)
+const char *                   strp;
+register struct rule * const   rulep;
+{
+       if (*strp == 'J') {
+               /*
+               ** Julian day.
+               */
+               rulep->r_type = JULIAN_DAY;
+               ++strp;
+               strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
+       } else if (*strp == 'M') {
+               /*
+               ** Month, week, day.
+               */
+               rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
+               ++strp;
+               strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
+               if (strp == NULL)
+                       return NULL;
+               if (*strp++ != '.')
+                       return NULL;
+               strp = getnum(strp, &rulep->r_week, 1, 5);
+               if (strp == NULL)
+                       return NULL;
+               if (*strp++ != '.')
+                       return NULL;
+               strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
+       } else if (is_digit(*strp)) {
+               /*
+               ** Day of year.
+               */
+               rulep->r_type = DAY_OF_YEAR;
+               strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
+       } else  return NULL;            /* invalid format */
+       if (strp == NULL)
+               return NULL;
+       if (*strp == '/') {
+               /*
+               ** Time specified.
+               */
+               ++strp;
+               strp = getsecs(strp, &rulep->r_time);
+       } else  rulep->r_time = 2 * SECSPERHOUR;        /* default = 2:00:00 */
+       return strp;
+}
+
+/*
+** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
+** year, a rule, and the offset from UTC at the time that rule takes effect,
+** calculate the Epoch-relative time that rule takes effect.
+*/
+
+static time_t
+transtime(janfirst, year, rulep, offset)
+const time_t                           janfirst;
+const int                              year;
+register const struct rule * const     rulep;
+const long                             offset;
+{
+       register int    leapyear;
+       register time_t value;
+       register int    i;
+       int             d, m1, yy0, yy1, yy2, dow;
+
+       INITIALIZE(value);
+       leapyear = isleap(year);
+       switch (rulep->r_type) {
+
+       case JULIAN_DAY:
+               /*
+               ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
+               ** years.
+               ** In non-leap years, or if the day number is 59 or less, just
+               ** add SECSPERDAY times the day number-1 to the time of
+               ** January 1, midnight, to get the day.
+               */
+               value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
+               if (leapyear && rulep->r_day >= 60)
+                       value += SECSPERDAY;
+               break;
+
+       case DAY_OF_YEAR:
+               /*
+               ** n - day of year.
+               ** Just add SECSPERDAY times the day number to the time of
+               ** January 1, midnight, to get the day.
+               */
+               value = janfirst + rulep->r_day * SECSPERDAY;
+               break;
+
+       case MONTH_NTH_DAY_OF_WEEK:
+               /*
+               ** Mm.n.d - nth "dth day" of month m.
+               */
+               value = janfirst;
+               for (i = 0; i < rulep->r_mon - 1; ++i)
+                       value += mon_lengths[leapyear][i] * SECSPERDAY;
+
+               /*
+               ** Use Zeller's Congruence to get day-of-week of first day of
+               ** month.
+               */
+               m1 = (rulep->r_mon + 9) % 12 + 1;
+               yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
+               yy1 = yy0 / 100;
+               yy2 = yy0 % 100;
+               dow = ((26 * m1 - 2) / 10 +
+                       1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
+               if (dow < 0)
+                       dow += DAYSPERWEEK;
+
+               /*
+               ** "dow" is the day-of-week of the first day of the month.  Get
+               ** the day-of-month (zero-origin) of the first "dow" day of the
+               ** month.
+               */
+               d = rulep->r_day - dow;
+               if (d < 0)
+                       d += DAYSPERWEEK;
+               for (i = 1; i < rulep->r_week; ++i) {
+                       if (d + DAYSPERWEEK >=
+                               mon_lengths[leapyear][rulep->r_mon - 1])
+                                       break;
+                       d += DAYSPERWEEK;
+               }
+
+               /*
+               ** "d" is the day-of-month (zero-origin) of the day we want.
+               */
+               value += d * SECSPERDAY;
+               break;
+       }
+
+       /*
+       ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
+       ** question.  To get the Epoch-relative time of the specified local
+       ** time on that day, add the transition time and the current offset
+       ** from UTC.
+       */
+       return value + rulep->r_time + offset;
+}
+
+/*
+** Given a POSIX section 8-style TZ string, fill in the rule tables as
+** appropriate.
+*/
+
+static int
+tzparse(name, sp, lastditch)
+const char *                   name;
+register struct state * const  sp;
+const int                      lastditch;
+{
+       const char *                    stdname;
+       const char *                    dstname;
+       size_t                          stdlen;
+       size_t                          dstlen;
+       long                            stdoffset;
+       long                            dstoffset;
+       register time_t *               atp;
+       register unsigned char *        typep;
+       register char *                 cp;
+       register int                    load_result;
+
+       INITIALIZE(dstname);
+       stdname = name;
+       if (lastditch) {
+               stdlen = strlen(name);  /* length of standard zone name */
+               name += stdlen;
+               if (stdlen >= sizeof sp->chars)
+                       stdlen = (sizeof sp->chars) - 1;
+               stdoffset = 0;
+       } else {
+               name = getzname(name);
+               stdlen = name - stdname;
+               if (stdlen < 3)
+                       return -1;
+               if (*name == '\0')
+                       return -1;
+               name = getoffset(name, &stdoffset);
+               if (name == NULL)
+                       return -1;
+       }
+       load_result = tzload(TZDEFRULES, sp);
+       if (load_result != 0)
+               sp->leapcnt = 0;                /* so, we're off a little */
+       if (*name != '\0') {
+               dstname = name;
+               name = getzname(name);
+               dstlen = name - dstname;        /* length of DST zone name */
+               if (dstlen < 3)
+                       return -1;
+               if (*name != '\0' && *name != ',' && *name != ';') {
+                       name = getoffset(name, &dstoffset);
+                       if (name == NULL)
+                               return -1;
+               } else  dstoffset = stdoffset - SECSPERHOUR;
+               if (*name == ',' || *name == ';') {
+                       struct rule     start;
+                       struct rule     end;
+                       register int    year;
+                       register time_t janfirst;
+                       time_t          starttime;
+                       time_t          endtime;
+
+                       ++name;
+                       if ((name = getrule(name, &start)) == NULL)
+                               return -1;
+                       if (*name++ != ',')
+                               return -1;
+                       if ((name = getrule(name, &end)) == NULL)
+                               return -1;
+                       if (*name != '\0')
+                               return -1;
+                       sp->typecnt = 2;        /* standard time and DST */
+                       /*
+                       ** Two transitions per year, from EPOCH_YEAR to 2037.
+                       */
+                       sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
+                       if (sp->timecnt > TZ_MAX_TIMES)
+                               return -1;
+                       sp->ttis[0].tt_gmtoff = -dstoffset;
+                       sp->ttis[0].tt_isdst = 1;
+                       sp->ttis[0].tt_abbrind = stdlen + 1;
+                       sp->ttis[1].tt_gmtoff = -stdoffset;
+                       sp->ttis[1].tt_isdst = 0;
+                       sp->ttis[1].tt_abbrind = 0;
+                       atp = sp->ats;
+                       typep = sp->types;
+                       janfirst = 0;
+                       for (year = EPOCH_YEAR; year <= 2037; ++year) {
+                               starttime = transtime(janfirst, year, &start,
+                                       stdoffset);
+                               endtime = transtime(janfirst, year, &end,
+                                       dstoffset);
+                               if (starttime > endtime) {
+                                       *atp++ = endtime;
+                                       *typep++ = 1;   /* DST ends */
+                                       *atp++ = starttime;
+                                       *typep++ = 0;   /* DST begins */
+                               } else {
+                                       *atp++ = starttime;
+                                       *typep++ = 0;   /* DST begins */
+                                       *atp++ = endtime;
+                                       *typep++ = 1;   /* DST ends */
+                               }
+                               janfirst += year_lengths[isleap(year)] *
+                                       SECSPERDAY;
+                       }
+               } else {
+                       register long   theirstdoffset;
+                       register long   theirdstoffset;
+                       register long   theiroffset;
+                       register int    isdst;
+                       register int    i;
+                       register int    j;
+
+                       if (*name != '\0')
+                               return -1;
+                       if (load_result != 0)
+                               return -1;
+                       /*
+                       ** Initial values of theirstdoffset and theirdstoffset.
+                       */
+                       theirstdoffset = 0;
+                       for (i = 0; i < sp->timecnt; ++i) {
+                               j = sp->types[i];
+                               if (!sp->ttis[j].tt_isdst) {
+                                       theirstdoffset =
+                                               -sp->ttis[j].tt_gmtoff;
+                                       break;
+                               }
+                       }
+                       theirdstoffset = 0;
+                       for (i = 0; i < sp->timecnt; ++i) {
+                               j = sp->types[i];
+                               if (sp->ttis[j].tt_isdst) {
+                                       theirdstoffset =
+                                               -sp->ttis[j].tt_gmtoff;
+                                       break;
+                               }
+                       }
+                       /*
+                       ** Initially we're assumed to be in standard time.
+                       */
+                       isdst = FALSE;
+                       theiroffset = theirstdoffset;
+                       /*
+                       ** Now juggle transition times and types
+                       ** tracking offsets as you do.
+                       */
+                       for (i = 0; i < sp->timecnt; ++i) {
+                               j = sp->types[i];
+                               sp->types[i] = sp->ttis[j].tt_isdst;
+                               if (sp->ttis[j].tt_ttisgmt) {
+                                       /* No adjustment to transition time */
+                               } else {
+                                       /*
+                                       ** If summer time is in effect, and the
+                                       ** transition time was not specified as
+                                       ** standard time, add the summer time
+                                       ** offset to the transition time;
+                                       ** otherwise, add the standard time
+                                       ** offset to the transition time.
+                                       */
+                                       /*
+                                       ** Transitions from DST to DDST
+                                       ** will effectively disappear since
+                                       ** POSIX provides for only one DST
+                                       ** offset.
+                                       */
+                                       if (isdst && !sp->ttis[j].tt_ttisstd) {
+                                               sp->ats[i] += dstoffset -
+                                                       theirdstoffset;
+                                       } else {
+                                               sp->ats[i] += stdoffset -
+                                                       theirstdoffset;
+                                       }
+                               }
+                               theiroffset = -sp->ttis[j].tt_gmtoff;
+                               if (sp->ttis[j].tt_isdst)
+                                       theirdstoffset = theiroffset;
+                               else    theirstdoffset = theiroffset;
+                       }
+                       /*
+                       ** Finally, fill in ttis.
+                       ** ttisstd and ttisgmt need not be handled.
+                       */
+                       sp->ttis[0].tt_gmtoff = -stdoffset;
+                       sp->ttis[0].tt_isdst = FALSE;
+                       sp->ttis[0].tt_abbrind = 0;
+                       sp->ttis[1].tt_gmtoff = -dstoffset;
+                       sp->ttis[1].tt_isdst = TRUE;
+                       sp->ttis[1].tt_abbrind = stdlen + 1;
+                       sp->typecnt = 2;
+               }
+       } else {
+               dstlen = 0;
+               sp->typecnt = 1;                /* only standard time */
+               sp->timecnt = 0;
+               sp->ttis[0].tt_gmtoff = -stdoffset;
+               sp->ttis[0].tt_isdst = 0;
+               sp->ttis[0].tt_abbrind = 0;
+       }
+       sp->charcnt = stdlen + 1;
+       if (dstlen != 0)
+               sp->charcnt += dstlen + 1;
+       if ((size_t) sp->charcnt > sizeof sp->chars)
+               return -1;
+       cp = sp->chars;
+       (void) strncpy(cp, stdname, stdlen);
+       cp += stdlen;
+       *cp++ = '\0';
+       if (dstlen != 0) {
+               (void) strncpy(cp, dstname, dstlen);
+               *(cp + dstlen) = '\0';
+       }
+       return 0;
+}
+
+static void
+gmtload(sp)
+struct state * const   sp;
+{
+       if (tzload(gmt, sp) != 0)
+               (void) tzparse(gmt, sp, TRUE);
+}
+
+#ifndef STD_INSPIRED
+/*
+** A non-static declaration of tzsetwall in a system header file
+** may cause a warning about this upcoming static declaration...
+*/
+static
+#endif /* !defined STD_INSPIRED */
+void
+tzsetwall P((void))
+{
+       if (lcl_is_set < 0)
+               return;
+       lcl_is_set = -1;
+
+#ifdef ALL_STATE
+       if (lclptr == NULL) {
+               lclptr = (struct state *) malloc(sizeof *lclptr);
+               if (lclptr == NULL) {
+                       settzname();    /* all we can do */
+                       return;
+               }
+       }
+#endif /* defined ALL_STATE */
+#ifdef _WIN32
+#define is_upper(c) ((unsigned)(c) - 'A' <= 26)
+       {
+           TIME_ZONE_INFORMATION tz;
+           char buf[BUFSIZ];
+           char *cp, *dst;
+           wchar_t *src;
+           div_t d;
+           GetTimeZoneInformation(&tz);
+           dst = cp = buf;
+           for (src = tz.StandardName; *src; src++)
+             if (is_upper(*src)) *dst++ = *src;
+           if (cp == dst)
+             {
+               /* In Asian Windows, tz.StandardName may not contain
+                  the timezone name. */
+               strcpy(cp, wildabbr);
+               cp += strlen(wildabbr);
+             }
+           else
+             cp = dst;
+           d = div(tz.Bias+tz.StandardBias, 60);
+           sprintf(cp, "%d", d.quot);
+           if (d.rem)
+               sprintf(cp=strchr(cp, 0), ":%d", abs(d.rem));
+           if(tz.StandardDate.wMonth) {
+               cp = strchr(cp, 0);
+               dst = cp;
+               for (src = tz.DaylightName; *src; src++)
+                 if (is_upper(*src)) *dst++ = *src;
+               if (cp == dst)
+                 {
+                   /* In Asian Windows, tz.StandardName may not contain
+                      the daylight name. */
+                   strcpy(buf, wildabbr);
+                   cp += strlen(wildabbr);
+                 }
+               else
+                 cp = dst;
+               d = div(tz.Bias+tz.DaylightBias, 60);
+               sprintf(cp, "%d", d.quot);
+               if (d.rem)
+                   sprintf(cp=strchr(cp, 0), ":%d", abs(d.rem));
+               cp = strchr(cp, 0);
+               sprintf(cp=strchr(cp, 0), ",M%d.%d.%d/%d",
+                   tz.DaylightDate.wMonth,
+                   tz.DaylightDate.wDay,
+                   tz.DaylightDate.wDayOfWeek,
+                   tz.DaylightDate.wHour);
+               if (tz.DaylightDate.wMinute || tz.DaylightDate.wSecond)
+                   sprintf(cp=strchr(cp, 0), ":%d", tz.DaylightDate.wMinute);
+               if (tz.DaylightDate.wSecond)
+                   sprintf(cp=strchr(cp, 0), ":%d", tz.DaylightDate.wSecond);
+               cp = strchr(cp, 0);
+               sprintf(cp=strchr(cp, 0), ",M%d.%d.%d/%d",
+                   tz.StandardDate.wMonth,
+                   tz.StandardDate.wDay,
+                   tz.StandardDate.wDayOfWeek,
+                   tz.StandardDate.wHour);
+               if (tz.StandardDate.wMinute || tz.StandardDate.wSecond)
+                   sprintf(cp=strchr(cp, 0), ":%d", tz.StandardDate.wMinute);
+               if (tz.StandardDate.wSecond)
+                   sprintf(cp=strchr(cp, 0), ":%d", tz.StandardDate.wSecond);
+           }
+           /* printf("TZ deduced as `%s'\n", buf); */
+           if (tzparse(buf, lclptr, FALSE) == 0) {
+               settzname();
+               setenv("TZ", buf, 1);
+               return;
+           }
+       }
+#endif
+       if (tzload((char *) NULL, lclptr) != 0)
+               gmtload(lclptr);
+       settzname();
+}
+
+void
+tzset P((void))
+{
+       const char *    name = getenv("TZ");
+
+       if (name == NULL) {
+               tzsetwall();
+               return;
+       }
+
+       if (lcl_is_set > 0  &&  strcmp(lcl_TZname, name) == 0)
+               return;
+       lcl_is_set = (strlen(name) < sizeof(lcl_TZname));
+       if (lcl_is_set)
+               (void) strcpy(lcl_TZname, name);
+
+#ifdef ALL_STATE
+       if (lclptr == NULL) {
+               lclptr = (struct state *) malloc(sizeof *lclptr);
+               if (lclptr == NULL) {
+                       settzname();    /* all we can do */
+                       return;
+               }
+       }
+#endif /* defined ALL_STATE */
+       if (*name == '\0') {
+               /*
+               ** User wants it fast rather than right.
+               */
+               lclptr->leapcnt = 0;            /* so, we're off a little */
+               lclptr->timecnt = 0;
+               lclptr->ttis[0].tt_gmtoff = 0;
+               lclptr->ttis[0].tt_abbrind = 0;
+               (void) strcpy(lclptr->chars, gmt);
+       } else if (tzload(name, lclptr) != 0) {
+               if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
+                       (void) gmtload(lclptr);
+       }
+       settzname();
+}
+
+/*
+** The easy way to behave "as if no library function calls" localtime
+** is to not call it--so we drop its guts into "localsub", which can be
+** freely called.  (And no, the PANS doesn't require the above behavior--
+** but it *is* desirable.)
+**
+** The unused offset argument is for the benefit of mktime variants.
+*/
+
+/*ARGSUSED*/
+static void
+localsub(timep, offset, tmp)
+const time_t * const   timep;
+const long             offset;
+struct tm * const      tmp;
+{
+       register struct state *         sp;
+       register const struct ttinfo *  ttisp;
+       register int                    i;
+       const time_t                    t = *timep;
+
+       sp = lclptr;
+#ifdef ALL_STATE
+       if (sp == NULL) {
+               gmtsub(timep, offset, tmp);
+               return;
+       }
+#endif /* defined ALL_STATE */
+       if (sp->timecnt == 0 || t < sp->ats[0]) {
+               i = 0;
+               while (sp->ttis[i].tt_isdst)
+                       if (++i >= sp->typecnt) {
+                               i = 0;
+                               break;
+                       }
+       } else {
+               for (i = 1; i < sp->timecnt; ++i)
+                       if (t < sp->ats[i])
+                               break;
+               i = sp->types[i - 1];
+       }
+       ttisp = &sp->ttis[i];
+       /*
+       ** To get (wrong) behavior that's compatible with System V Release 2.0
+       ** you'd replace the statement below with
+       **      t += ttisp->tt_gmtoff;
+       **      timesub(&t, 0L, sp, tmp);
+       */
+       timesub(&t, ttisp->tt_gmtoff, sp, tmp);
+       tmp->tm_isdst = ttisp->tt_isdst;
+       tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
+#ifdef TM_ZONE
+       tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
+#endif /* defined TM_ZONE */
+}
+
+struct tm *
+localtime(timep)
+const time_t * const   timep;
+{
+       tzset();
+       localsub(timep, 0L, &tm);
+       return &tm;
+}
+
+/*
+ * Re-entrant version of localtime
+ */
+struct tm *
+localtime_r(timep, tm)
+const time_t * const   timep;
+struct tm *            tm;
+{
+       localsub(timep, 0L, tm);
+       return tm;
+}
+
+/*
+** gmtsub is to gmtime as localsub is to localtime.
+*/
+
+static void
+gmtsub(timep, offset, tmp)
+const time_t * const   timep;
+const long             offset;
+struct tm * const      tmp;
+{
+       if (!gmt_is_set) {
+               gmt_is_set = TRUE;
+#ifdef ALL_STATE
+               gmtptr = (struct state *) malloc(sizeof *gmtptr);
+               if (gmtptr != NULL)
+#endif /* defined ALL_STATE */
+                       gmtload(gmtptr);
+       }
+       timesub(timep, offset, gmtptr, tmp);
+#ifdef TM_ZONE
+       /*
+       ** Could get fancy here and deliver something such as
+       ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
+       ** but this is no time for a treasure hunt.
+       */
+       if (offset != 0)
+               tmp->TM_ZONE = wildabbr;
+       else {
+#ifdef ALL_STATE
+               if (gmtptr == NULL)
+                       tmp->TM_ZONE = gmt;
+               else    tmp->TM_ZONE = gmtptr->chars;
+#endif /* defined ALL_STATE */
+#ifndef ALL_STATE
+               tmp->TM_ZONE = gmtptr->chars;
+#endif /* State Farm */
+       }
+#endif /* defined TM_ZONE */
+}
+
+struct tm *
+gmtime(timep)
+const time_t * const   timep;
+{
+       gmtsub(timep, 0L, &tm);
+       return &tm;
+}
+
+/*
+ * Re-entrant version of gmtime
+ */
+struct tm *
+gmtime_r(timep, tm)
+const time_t * const   timep;
+struct tm *            tm;
+{
+       gmtsub(timep, 0L, tm);
+       return tm;
+}
+
+#ifdef STD_INSPIRED
+
+struct tm *
+offtime(timep, offset)
+const time_t * const   timep;
+const long             offset;
+{
+       gmtsub(timep, offset, &tm);
+       return &tm;
+}
+
+#endif /* defined STD_INSPIRED */
+
+static void
+timesub(timep, offset, sp, tmp)
+const time_t * const                   timep;
+const long                             offset;
+register const struct state * const    sp;
+register struct tm * const             tmp;
+{
+       register const struct lsinfo *  lp;
+       register long                   days;
+       register long                   rem;
+       register int                    y;
+       register int                    yleap;
+       register const int *            ip;
+       register long                   corr;
+       register int                    hit;
+       register int                    i;
+
+       corr = 0;
+       hit = 0;
+#ifdef ALL_STATE
+       i = (sp == NULL) ? 0 : sp->leapcnt;
+#endif /* defined ALL_STATE */
+#ifndef ALL_STATE
+       i = sp->leapcnt;
+#endif /* State Farm */
+       while (--i >= 0) {
+               lp = &sp->lsis[i];
+               if (*timep >= lp->ls_trans) {
+                       if (*timep == lp->ls_trans) {
+                               hit = ((i == 0 && lp->ls_corr > 0) ||
+                                       lp->ls_corr > sp->lsis[i - 1].ls_corr);
+                               if (hit)
+                                       while (i > 0 &&
+                                               sp->lsis[i].ls_trans ==
+                                               sp->lsis[i - 1].ls_trans + 1 &&
+                                               sp->lsis[i].ls_corr ==
+                                               sp->lsis[i - 1].ls_corr + 1) {
+                                                       ++hit;
+                                                       --i;
+                                       }
+                       }
+                       corr = lp->ls_corr;
+                       break;
+               }
+       }
+       days = *timep / SECSPERDAY;
+       rem = *timep % SECSPERDAY;
+#ifdef mc68k
+       if (*timep == 0x80000000) {
+               /*
+               ** A 3B1 muffs the division on the most negative number.
+               */
+               days = -24855;
+               rem = -11648;
+       }
+#endif /* defined mc68k */
+       rem += (offset - corr);
+       while (rem < 0) {
+               rem += SECSPERDAY;
+               --days;
+       }
+       while (rem >= SECSPERDAY) {
+               rem -= SECSPERDAY;
+               ++days;
+       }
+       tmp->tm_hour = (int) (rem / SECSPERHOUR);
+       rem = rem % SECSPERHOUR;
+       tmp->tm_min = (int) (rem / SECSPERMIN);
+       /*
+       ** A positive leap second requires a special
+       ** representation.  This uses "... ??:59:60" et seq.
+       */
+       tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
+       tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
+       if (tmp->tm_wday < 0)
+               tmp->tm_wday += DAYSPERWEEK;
+       y = EPOCH_YEAR;
+#define LEAPS_THRU_END_OF(y)   ((y) / 4 - (y) / 100 + (y) / 400)
+       while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
+               register int    newy;
+
+               newy = y + days / DAYSPERNYEAR;
+               if (days < 0)
+                       --newy;
+               days -= (newy - y) * DAYSPERNYEAR +
+                       LEAPS_THRU_END_OF(newy - 1) -
+                       LEAPS_THRU_END_OF(y - 1);
+               y = newy;
+       }
+       tmp->tm_year = y - TM_YEAR_BASE;
+       tmp->tm_yday = (int) days;
+       ip = mon_lengths[yleap];
+       for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
+               days = days - (long) ip[tmp->tm_mon];
+       tmp->tm_mday = (int) (days + 1);
+       tmp->tm_isdst = 0;
+#ifdef TM_GMTOFF
+       tmp->TM_GMTOFF = offset;
+#endif /* defined TM_GMTOFF */
+}
+
+char *
+ctime(timep)
+const time_t * const   timep;
+{
+/*
+** Section 4.12.3.2 of X3.159-1989 requires that
+**     The ctime function converts the calendar time pointed to by timer
+**     to local time in the form of a string.  It is equivalent to
+**             asctime(localtime(timer))
+*/
+       return asctime(localtime(timep));
+}
+
+char *
+ctime_r(timep, buf)
+const time_t * const   timep;
+char *                 buf;
+{
+       struct tm       tm;
+
+       return asctime_r(localtime_r(timep, &tm), buf);
+}
+
+/*
+** Adapted from code provided by Robert Elz, who writes:
+**     The "best" way to do mktime I think is based on an idea of Bob
+**     Kridle's (so its said...) from a long time ago.
+**     [kridle@xinet.com as of 1996-01-16.]
+**     It does a binary search of the time_t space.  Since time_t's are
+**     just 32 bits, its a max of 32 iterations (even at 64 bits it
+**     would still be very reasonable).
+*/
+
+#ifndef WRONG
+#define WRONG  (-1)
+#endif /* !defined WRONG */
+
+/*
+** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
+*/
+
+static int
+increment_overflow(number, delta)
+int *  number;
+int    delta;
+{
+       int     number0;
+
+       number0 = *number;
+       *number += delta;
+       return (*number < number0) != (delta < 0);
+}
+
+static int
+normalize_overflow(tensptr, unitsptr, base)
+int * const    tensptr;
+int * const    unitsptr;
+const int      base;
+{
+       register int    tensdelta;
+
+       tensdelta = (*unitsptr >= 0) ?
+               (*unitsptr / base) :
+               (-1 - (-1 - *unitsptr) / base);
+       *unitsptr -= tensdelta * base;
+       return increment_overflow(tensptr, tensdelta);
+}
+
+static int
+tmcomp(atmp, btmp)
+register const struct tm * const atmp;
+register const struct tm * const btmp;
+{
+       register int    result;
+
+       if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
+               (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+               (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+               (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+               (result = (atmp->tm_min - btmp->tm_min)) == 0)
+                       result = atmp->tm_sec - btmp->tm_sec;
+       return result;
+}
+
+static time_t
+time2sub(tmp, funcp, offset, okayp, do_norm_secs)
+struct tm * const      tmp;
+void (* const          funcp) P((const time_t*, long, struct tm*));
+const long             offset;
+int * const            okayp;
+const int              do_norm_secs;
+{
+       register const struct state *   sp;
+       register int                    dir;
+       register int                    bits;
+       register int                    i, j ;
+       register int                    saved_seconds;
+       time_t                          newt;
+       time_t                          t;
+       struct tm                       yourtm, mytm;
+
+       *okayp = FALSE;
+       yourtm = *tmp;
+       if (do_norm_secs) {
+               if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
+                       SECSPERMIN))
+                               return WRONG;
+       }
+       if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
+               return WRONG;
+       if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
+               return WRONG;
+       if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
+               return WRONG;
+       /*
+       ** Turn yourtm.tm_year into an actual year number for now.
+       ** It is converted back to an offset from TM_YEAR_BASE later.
+       */
+       if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
+               return WRONG;
+       while (yourtm.tm_mday <= 0) {
+               if (increment_overflow(&yourtm.tm_year, -1))
+                       return WRONG;
+               i = yourtm.tm_year + (1 < yourtm.tm_mon);
+               yourtm.tm_mday += year_lengths[isleap(i)];
+       }
+       while (yourtm.tm_mday > DAYSPERLYEAR) {
+               i = yourtm.tm_year + (1 < yourtm.tm_mon);
+               yourtm.tm_mday -= year_lengths[isleap(i)];
+               if (increment_overflow(&yourtm.tm_year, 1))
+                       return WRONG;
+       }
+       for ( ; ; ) {
+               i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
+               if (yourtm.tm_mday <= i)
+                       break;
+               yourtm.tm_mday -= i;
+               if (++yourtm.tm_mon >= MONSPERYEAR) {
+                       yourtm.tm_mon = 0;
+                       if (increment_overflow(&yourtm.tm_year, 1))
+                               return WRONG;
+               }
+       }
+       if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
+               return WRONG;
+       if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
+               /*
+               ** We can't set tm_sec to 0, because that might push the
+               ** time below the minimum representable time.
+               ** Set tm_sec to 59 instead.
+               ** This assumes that the minimum representable time is
+               ** not in the same minute that a leap second was deleted from,
+               ** which is a safer assumption than using 58 would be.
+               */
+               if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
+                       return WRONG;
+               saved_seconds = yourtm.tm_sec;
+               yourtm.tm_sec = SECSPERMIN - 1;
+       } else {
+               saved_seconds = yourtm.tm_sec;
+               yourtm.tm_sec = 0;
+       }
+       /*
+       ** Divide the search space in half
+       ** (this works whether time_t is signed or unsigned).
+       */
+       bits = TYPE_BIT(time_t) - 1;
+       /*
+       ** If time_t is signed, then 0 is just above the median,
+       ** assuming two's complement arithmetic.
+       ** If time_t is unsigned, then (1 << bits) is just above the median.
+       */
+       t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
+       for ( ; ; ) {
+               (*funcp)(&t, offset, &mytm);
+               dir = tmcomp(&mytm, &yourtm);
+               if (dir != 0) {
+                       if (bits-- < 0)
+                               return WRONG;
+                       if (bits < 0)
+                               --t; /* may be needed if new t is minimal */
+                       else if (dir > 0)
+                               t -= ((time_t) 1) << bits;
+                       else    t += ((time_t) 1) << bits;
+                       continue;
+               }
+               if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
+                       break;
+               /*
+               ** Right time, wrong type.
+               ** Hunt for right time, right type.
+               ** It's okay to guess wrong since the guess
+               ** gets checked.
+               */
+               /*
+               ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
+               */
+               sp = (const struct state *)
+                       (((void *) funcp == (void *) localsub) ?
+                       lclptr : gmtptr);
+#ifdef ALL_STATE
+               if (sp == NULL)
+                       return WRONG;
+#endif /* defined ALL_STATE */
+               for (i = sp->typecnt - 1; i >= 0; --i) {
+                       if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
+                               continue;
+                       for (j = sp->typecnt - 1; j >= 0; --j) {
+                               if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
+                                       continue;
+                               newt = t + sp->ttis[j].tt_gmtoff -
+                                       sp->ttis[i].tt_gmtoff;
+                               (*funcp)(&newt, offset, &mytm);
+                               if (tmcomp(&mytm, &yourtm) != 0)
+                                       continue;
+                               if (mytm.tm_isdst != yourtm.tm_isdst)
+                                       continue;
+                               /*
+                               ** We have a match.
+                               */
+                               t = newt;
+                               goto label;
+                       }
+               }
+               return WRONG;
+       }
+label:
+       newt = t + saved_seconds;
+       if ((newt < t) != (saved_seconds < 0))
+               return WRONG;
+       t = newt;
+       (*funcp)(&t, offset, tmp);
+       *okayp = TRUE;
+       return t;
+}
+
+static time_t
+time2(tmp, funcp, offset, okayp)
+struct tm * const      tmp;
+void (* const          funcp) P((const time_t*, long, struct tm*));
+const long             offset;
+int * const            okayp;
+{
+       time_t  t;
+
+       /*
+       ** First try without normalization of seconds
+       ** (in case tm_sec contains a value associated with a leap second).
+       ** If that fails, try with normalization of seconds.
+       */
+       t = time2sub(tmp, funcp, offset, okayp, FALSE);
+       return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
+}
+
+static time_t
+time1(tmp, funcp, offset)
+struct tm * const      tmp;
+void (* const          funcp) P((const time_t *, long, struct tm *));
+const long             offset;
+{
+       register time_t                 t;
+       register const struct state *   sp;
+       register int                    samei, otheri;
+       int                             okay;
+
+       if (tmp->tm_isdst > 1)
+               tmp->tm_isdst = 1;
+       t = time2(tmp, funcp, offset, &okay);
+#ifdef PCTS
+       /*
+       ** PCTS code courtesy Grant Sullivan (grant@osf.org).
+       */
+       if (okay)
+               return t;
+       if (tmp->tm_isdst < 0)
+               tmp->tm_isdst = 0;      /* reset to std and try again */
+#endif /* defined PCTS */
+#ifndef PCTS
+       if (okay || tmp->tm_isdst < 0)
+               return t;
+#endif /* !defined PCTS */
+       /*
+       ** We're supposed to assume that somebody took a time of one type
+       ** and did some math on it that yielded a "struct tm" that's bad.
+       ** We try to divine the type they started from and adjust to the
+       ** type they need.
+       */
+       /*
+       ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
+       */
+       sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
+               lclptr : gmtptr);
+#ifdef ALL_STATE
+       if (sp == NULL)
+               return WRONG;
+#endif /* defined ALL_STATE */
+       for (samei = sp->typecnt - 1; samei >= 0; --samei) {
+               if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
+                       continue;
+               for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
+                       if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
+                               continue;
+                       tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
+                                       sp->ttis[samei].tt_gmtoff;
+                       tmp->tm_isdst = !tmp->tm_isdst;
+                       t = time2(tmp, funcp, offset, &okay);
+                       if (okay)
+                               return t;
+                       tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
+                                       sp->ttis[samei].tt_gmtoff;
+                       tmp->tm_isdst = !tmp->tm_isdst;
+               }
+       }
+       return WRONG;
+}
+
+time_t
+mktime(tmp)
+struct tm * const      tmp;
+{
+       tzset();
+       return time1(tmp, localsub, 0L);
+}
+
+#ifdef STD_INSPIRED
+
+time_t
+timelocal(tmp)
+struct tm * const      tmp;
+{
+       tmp->tm_isdst = -1;     /* in case it wasn't initialized */
+       return mktime(tmp);
+}
+
+time_t
+timegm(tmp)
+struct tm * const      tmp;
+{
+       tmp->tm_isdst = 0;
+       return time1(tmp, gmtsub, 0L);
+}
+
+time_t
+timeoff(tmp, offset)
+struct tm * const      tmp;
+const long             offset;
+{
+       tmp->tm_isdst = 0;
+       return time1(tmp, gmtsub, offset);
+}
+
+#endif /* defined STD_INSPIRED */
+
+#ifdef CMUCS
+
+/*
+** The following is supplied for compatibility with
+** previous versions of the CMUCS runtime library.
+*/
+
+long
+gtime(tmp)
+struct tm * const      tmp;
+{
+       const time_t    t = mktime(tmp);
+
+       if (t == WRONG)
+               return -1;
+       return t;
+}
+
+#endif /* defined CMUCS */
+
+/*
+** XXX--is the below the right way to conditionalize??
+*/
+
+#ifdef STD_INSPIRED
+
+/*
+** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
+** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
+** is not the case if we are accounting for leap seconds.
+** So, we provide the following conversion routines for use
+** when exchanging timestamps with POSIX conforming systems.
+*/
+
+static long
+leapcorr(timep)
+time_t *       timep;
+{
+       register struct state *         sp;
+       register struct lsinfo *        lp;
+       register int                    i;
+
+       sp = lclptr;
+       i = sp->leapcnt;
+       while (--i >= 0) {
+               lp = &sp->lsis[i];
+               if (*timep >= lp->ls_trans)
+                       return lp->ls_corr;
+       }
+       return 0;
+}
+
+time_t
+time2posix(t)
+time_t t;
+{
+       tzset();
+       return t - leapcorr(&t);
+}
+
+time_t
+posix2time(t)
+time_t t;
+{
+       time_t  x;
+       time_t  y;
+
+       tzset();
+       /*
+       ** For a positive leap second hit, the result
+       ** is not unique.  For a negative leap second
+       ** hit, the corresponding time doesn't exist,
+       ** so we return an adjacent second.
+       */
+       x = t + leapcorr(&t);
+       y = x - leapcorr(&x);
+       if (y < t) {
+               do {
+                       x++;
+                       y = x - leapcorr(&x);
+               } while (y < t);
+               if (t != y)
+                       return x - 1;
+       } else if (y > t) {
+               do {
+                       --x;
+                       y = x - leapcorr(&x);
+               } while (y > t);
+               if (t != y)
+                       return x + 1;
+       }
+       return x;
+}
+
+#endif /* defined STD_INSPIRED */
diff --git a/winsup/cygwin/regexp/regerror.c b/winsup/cygwin/regexp/regerror.c
new file mode 100644 (file)
index 0000000..ab6954e
--- /dev/null
@@ -0,0 +1,24 @@
+#if 0
+#ifndef lint
+static char *rcsid = "$Id$";
+#endif /* not lint */
+#endif
+
+#include "regexp.h"
+#include <stdio.h>
+
+void
+regerror(s)
+const char *s;
+{
+#ifdef ERRAVAIL
+       error("regexp: %s", s);
+#else
+/*
+       fprintf(stderr, "regexp(3): %s\n", s);
+       exit(1);
+*/
+       return;   /* let std. egrep handle errors */
+#endif
+       /* NOTREACHED */
+}
diff --git a/winsup/cygwin/regexp/regexp.3 b/winsup/cygwin/regexp/regexp.3
new file mode 100644 (file)
index 0000000..d1a3a00
--- /dev/null
@@ -0,0 +1,321 @@
+.\" Copyright (c) 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"    This product includes software developed by the University of
+.\"    California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)regexp.3   8.1 (Berkeley) 6/4/93
+.\"
+.Dd June 4, 1993
+.Dt REGEXP 3
+.Os
+.Sh NAME
+.Nm regcomp ,
+.Nm regexec ,
+.Nm regsub ,
+.Nm regerror
+.Nd regular expression handlers
+.Sh SYNOPSIS
+.Fd #include <regexp.h>
+.Ft regexp *
+.Fn regcomp "const char *exp"
+.Ft int
+.Fn regexec "const regexp *prog" "const char *string"
+.Ft void
+.Fn regsub "const regexp *prog" "const char *source" "char *dest"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is made obsolete by
+.Xr regex 3 .
+It is available from the compatibility library, libcompat.
+.Ef
+.Pp
+The
+.Fn regcomp ,
+.Fn regexec ,
+.Fn regsub ,
+and
+.Fn regerror
+functions
+implement
+.Xr egrep 1 Ns -style
+regular expressions and supporting facilities.
+.Pp
+The
+.Fn regcomp
+function
+compiles a regular expression into a structure of type
+.Xr regexp ,
+and returns a pointer to it.
+The space has been allocated using
+.Xr malloc 3
+and may be released by
+.Xr free .
+.Pp
+The
+.Fn regexec
+function
+matches a
+.Dv NUL Ns -terminated
+.Fa string
+against the compiled regular expression
+in
+.Fa prog .
+It returns 1 for success and 0 for failure, and adjusts the contents of
+.Fa prog Ns 's
+.Em startp
+and
+.Em endp
+(see below) accordingly.
+.Pp
+The members of a
+.Xr regexp
+structure include at least the following (not necessarily in order):
+.Bd -literal -offset indent
+char *startp[NSUBEXP];
+char *endp[NSUBEXP];
+.Ed
+.Pp
+where
+.Dv NSUBEXP
+is defined (as 10) in the header file.
+Once a successful
+.Fn regexec
+has been done using the
+.Fn regexp ,
+each
+.Em startp Ns - Em endp
+pair describes one substring
+within the
+.Fa string ,
+with the
+.Em startp
+pointing to the first character of the substring and
+the
+.Em endp
+pointing to the first character following the substring.
+The 0th substring is the substring of
+.Fa string
+that matched the whole
+regular expression.
+The others are those substrings that matched parenthesized expressions
+within the regular expression, with parenthesized expressions numbered
+in left-to-right order of their opening parentheses.
+.Pp
+The
+.Fn regsub
+function
+copies
+.Fa source
+to
+.Fa dest ,
+making substitutions according to the
+most recent
+.Fn regexec
+performed using
+.Fa prog .
+Each instance of `&' in
+.Fa source
+is replaced by the substring
+indicated by
+.Em startp Ns Bq
+and
+.Em endp Ns Bq .
+Each instance of
+.Sq \e Ns Em n ,
+where
+.Em n
+is a digit, is replaced by
+the substring indicated by
+.Em startp Ns Bq Em n
+and
+.Em endp Ns Bq Em n .
+To get a literal `&' or
+.Sq \e Ns Em n
+into
+.Fa dest ,
+prefix it with `\e';
+to get a literal `\e' preceding `&' or
+.Sq \e Ns Em n ,
+prefix it with
+another `\e'.
+.Pp
+The
+.Fn regerror
+function
+is called whenever an error is detected in
+.Fn regcomp ,
+.Fn regexec ,
+or
+.Fn regsub .
+The default
+.Fn regerror
+writes the string
+.Fa msg ,
+with a suitable indicator of origin,
+on the standard
+error output
+and invokes
+.Xr exit 2 .
+The
+.Fn regerror
+function
+can be replaced by the user if other actions are desirable.
+.Sh REGULAR EXPRESSION SYNTAX
+A regular expression is zero or more
+.Em branches ,
+separated by `|'.
+It matches anything that matches one of the branches.
+.Pp
+A branch is zero or more
+.Em pieces ,
+concatenated.
+It matches a match for the first, followed by a match for the second, etc.
+.Pp
+A piece is an
+.Em atom
+possibly followed by `*', `+', or `?'.
+An atom followed by `*' matches a sequence of 0 or more matches of the atom.
+An atom followed by `+' matches a sequence of 1 or more matches of the atom.
+An atom followed by `?' matches a match of the atom, or the null string.
+.Pp
+An atom is a regular expression in parentheses (matching a match for the
+regular expression), a
+.Em range
+(see below), `.'
+(matching any single character), `^' (matching the null string at the
+beginning of the input string), `$' (matching the null string at the
+end of the input string), a `\e' followed by a single character (matching
+that character), or a single character with no other significance
+(matching that character).
+.Pp
+A
+.Em range
+is a sequence of characters enclosed in `[]'.
+It normally matches any single character from the sequence.
+If the sequence begins with `^',
+it matches any single character
+.Em not
+from the rest of the sequence.
+If two characters in the sequence are separated by `\-', this is shorthand
+for the full list of
+.Tn ASCII
+characters between them
+(e.g. `[0-9]' matches any decimal digit).
+To include a literal `]' in the sequence, make it the first character
+(following a possible `^').
+To include a literal `\-', make it the first or last character.
+.Sh AMBIGUITY
+If a regular expression could match two different parts of the input string,
+it will match the one which begins earliest.
+If both begin in the same place but match different lengths, or match
+the same length in different ways, life gets messier, as follows.
+.Pp
+In general, the possibilities in a list of branches are considered in
+left-to-right order, the possibilities for `*', `+', and `?' are
+considered longest-first, nested constructs are considered from the
+outermost in, and concatenated constructs are considered leftmost-first.
+The match that will be chosen is the one that uses the earliest
+possibility in the first choice that has to be made.
+If there is more than one choice, the next will be made in the same manner
+(earliest possibility) subject to the decision on the first choice.
+And so forth.
+.Pp
+For example,
+.Sq Li (ab|a)b*c
+could match
+`abc' in one of two ways.
+The first choice is between `ab' and `a'; since `ab' is earlier, and does
+lead to a successful overall match, it is chosen.
+Since the `b' is already spoken for,
+the `b*' must match its last possibility\(emthe empty string\(emsince
+it must respect the earlier choice.
+.Pp
+In the particular case where no `|'s are present and there is only one
+`*', `+', or `?', the net effect is that the longest possible
+match will be chosen.
+So
+.Sq Li ab* ,
+presented with `xabbbby', will match `abbbb'.
+Note that if
+.Sq Li ab* ,
+is tried against `xabyabbbz', it
+will match `ab' just after `x', due to the begins-earliest rule.
+(In effect, the decision on where to start the match is the first choice
+to be made, hence subsequent choices must respect it even if this leads them
+to less-preferred alternatives.)
+.Sh RETURN VALUES
+The
+.Fn regcomp
+function
+returns
+.Dv NULL
+for a failure
+.Pf ( Fn regerror
+permitting),
+where failures are syntax errors, exceeding implementation limits,
+or applying `+' or `*' to a possibly-null operand.
+.Sh SEE ALSO
+.Xr ed 1 ,
+.Xr ex 1 ,
+.Xr expr 1 ,
+.Xr egrep 1 ,
+.Xr fgrep 1 ,
+.Xr grep 1 ,
+.Xr regex 3
+.Sh HISTORY
+Both code and manual page for
+.Fn regcomp ,
+.Fn regexec ,
+.Fn regsub ,
+and
+.Fn regerror
+were written at the University of Toronto
+and appeared in
+.Bx 4.3 tahoe .
+They are intended to be compatible with the Bell V8
+.Xr regexp 3 ,
+but are not derived from Bell code.
+.Sh BUGS
+Empty branches and empty regular expressions are not portable to V8.
+.Pp
+The restriction against
+applying `*' or `+' to a possibly-null operand is an artifact of the
+simplistic implementation.
+.Pp
+Does not support
+.Xr egrep Ns 's
+newline-separated branches;
+neither does the V8
+.Xr regexp 3 ,
+though.
+.Pp
+Due to emphasis on
+compactness and simplicity,
+it's not strikingly fast.
+It does give special attention to handling simple cases quickly.
diff --git a/winsup/cygwin/regexp/regexp.c b/winsup/cygwin/regexp/regexp.c
new file mode 100644 (file)
index 0000000..2f84865
--- /dev/null
@@ -0,0 +1,1326 @@
+/*
+ * regcomp and regexec -- regsub and regerror are elsewhere
+ *
+ *     Copyright (c) 1986 by University of Toronto.
+ *     Written by Henry Spencer.  Not derived from licensed software.
+ *
+ *     Permission is granted to anyone to use this software for any
+ *     purpose on any computer system, and to redistribute it freely,
+ *     subject to the following restrictions:
+ *
+ *     1. The author is not responsible for the consequences of use of
+ *             this software, no matter how awful, even if they arise
+ *             from defects in it.
+ *
+ *     2. The origin of this software must not be misrepresented, either
+ *             by explicit claim or by omission.
+ *
+ *     3. Altered versions must be plainly marked as such, and must not
+ *             be misrepresented as being the original software.
+ *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to |
+ *** to assist in implementing egrep.
+ *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
+ *** as in BSD grep and ex.
+ *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
+ *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
+ *** THIS IS AN ALTERED VERSION.  It was altered by James A. Woods,
+ *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
+ *** THIS IS AN ALTERED VERSION.  It was altered by Geoffrey Noer,
+ *** noer@cygnus.com, on 6 Oct 1997, to change the prototype format
+ *** for inclusion in the Cygwin32 library.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions.  Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+
+#if 0
+#ifndef lint
+static char *rcsid = "$Id$";
+#endif /* not lint */
+#endif
+
+#include "regexp.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "regmagic.h"
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases.  They are:
+ *
+ * regstart    char that must begin a match; '\0' if none obvious
+ * reganch     is the match anchored (at beginning-of-line only)?
+ * regmust     string (pointer into program) that match must include, or NULL
+ * regmlen     length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot.  Regmust permits fast rejection
+ * of lines that cannot possibly match.  The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup).  Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ */
+
+/*
+ * Structure for regexp "program".  This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology).  Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives.  (Here we
+ * have one of the subtle syntax dependencies:  an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.)  The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM.  In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure:  the tail of the branch connects
+ * to the thing following the set of BRANCHes.)  The opcodes are:
+ */
+
+/* definition  number  opnd?   meaning */
+#define        END     0       /* no   End of program. */
+#define        BOL     1       /* no   Match "" at beginning of line. */
+#define        EOL     2       /* no   Match "" at end of line. */
+#define        ANY     3       /* no   Match any one character. */
+#define        ANYOF   4       /* str  Match any character in this string. */
+#define        ANYBUT  5       /* str  Match any character not in this string. */
+#define        BRANCH  6       /* node Match this alternative, or the next... */
+#define        BACK    7       /* no   Match "", "next" ptr points backward. */
+#define        EXACTLY 8       /* str  Match this string. */
+#define        NOTHING 9       /* no   Match empty string. */
+#define        STAR    10      /* node Match this (simple) thing 0 or more times. */
+#define        PLUS    11      /* node Match this (simple) thing 1 or more times. */
+#define        WORDA   12      /* no   Match "" at wordchar, where prev is nonword */
+#define        WORDZ   13      /* no   Match "" at nonwordchar, where prev is word */
+#define        OPEN    20      /* no   Mark this point in input as start of #n. */
+                       /*      OPEN+1 is number 1, etc. */
+#define        CLOSE   30      /* no   Analogous to OPEN. */
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH      The set of branches constituting a single choice are hooked
+ *             together with their "next" pointers, since precedence prevents
+ *             anything being concatenated to any individual branch.  The
+ *             "next" pointer of the last BRANCH in a choice points to the
+ *             thing following the whole choice.  This is also where the
+ *             final "next" pointer of each individual branch points; each
+ *             branch starts with the operand node of a BRANCH node.
+ *
+ * BACK                Normal "next" pointers all implicitly point forward; BACK
+ *             exists to make loop structures possible.
+ *
+ * STAR,PLUS   '?', and complex '*' and '+', are implemented as circular
+ *             BRANCH structures using BACK.  Simple cases (one character
+ *             per match) are implemented with STAR and PLUS for speed
+ *             and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE  ...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first.  The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node.  (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define        OP(p)   (*(p))
+#define        NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define        OPERAND(p)      ((p) + 3)
+
+/*
+ * See regmagic.h for one further detail of program structure.
+ */
+
+
+/*
+ * Utility definitions.
+ */
+#ifndef CHARBITS
+#define        UCHARAT(p)      ((int)*(unsigned char *)(p))
+#else
+#define        UCHARAT(p)      ((int)*(p)&CHARBITS)
+#endif
+
+#define        FAIL(m) { regerror(m); return(NULL); }
+#define        ISMULT(c)       ((c) == '*' || (c) == '+' || (c) == '?')
+
+/*
+ * Flags to be passed up and down.
+ */
+#define        HASWIDTH        01      /* Known never to match null string. */
+#define        SIMPLE          02      /* Simple enough to be STAR/PLUS operand. */
+#define        SPSTART         04      /* Starts with * or +. */
+#define        WORST           0       /* Worst case. */
+
+/*
+ * Global work variables for regcomp().
+ */
+static char *regparse;         /* Input-scan pointer. */
+static int regnpar;            /* () count. */
+static char regdummy;
+static char *regcode;          /* Code-emit pointer; &regdummy = don't. */
+static long regsize;           /* Code size. */
+
+/*
+ * Forward declarations for regcomp()'s friends.
+ */
+#ifndef STATIC
+#define        STATIC  static
+#endif
+STATIC char *reg (int, int *);
+STATIC char *regbranch (int *);
+STATIC char *regpiece (int *);
+STATIC char *regatom (int *);
+STATIC char *regnode (char);
+STATIC char *regnext (char *);
+STATIC void regc (char);
+STATIC void reginsert (char, char *);
+STATIC void regtail (char *, char *);
+STATIC void regoptail (char *, char *);
+#ifdef STRCSPN
+STATIC int strcspn (char *, char *);
+#endif
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code.  So we cheat:  we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it.  (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+regexp *
+regcomp(exp)
+const char *exp;
+{
+       register regexp *r;
+       register char *scan;
+       register char *longest;
+       register int len;
+       int flags;
+
+       if (exp == NULL)
+               FAIL("NULL argument");
+
+       /* First pass: determine size, legality. */
+#ifdef notdef
+       if (exp[0] == '.' && exp[1] == '*') exp += 2;  /* aid grep */
+#endif
+       regparse = (char *)exp;
+       regnpar = 1;
+       regsize = 0L;
+       regcode = &regdummy;
+       regc(MAGIC);
+       if (reg(0, &flags) == NULL)
+               return(NULL);
+
+       /* Small enough for pointer-storage convention? */
+       if (regsize >= 32767L)          /* Probably could be 65535L. */
+               FAIL("regexp too big");
+
+       /* Allocate space. */
+       r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
+       if (r == NULL)
+               FAIL("out of space");
+
+       /* Second pass: emit code. */
+       regparse = (char *)exp;
+       regnpar = 1;
+       regcode = r->program;
+       regc(MAGIC);
+       if (reg(0, &flags) == NULL)
+               return(NULL);
+
+       /* Dig out information for optimizations. */
+       r->regstart = '\0';     /* Worst-case defaults. */
+       r->reganch = 0;
+       r->regmust = NULL;
+       r->regmlen = 0;
+       scan = r->program+1;                    /* First BRANCH. */
+       if (OP(regnext(scan)) == END) {         /* Only one top-level choice. */
+               scan = OPERAND(scan);
+
+               /* Starting-point info. */
+               if (OP(scan) == EXACTLY)
+                       r->regstart = *OPERAND(scan);
+               else if (OP(scan) == BOL)
+                       r->reganch++;
+
+               /*
+                * If there's something expensive in the r.e., find the
+                * longest literal string that must appear and make it the
+                * regmust.  Resolve ties in favor of later strings, since
+                * the regstart check works with the beginning of the r.e.
+                * and avoiding duplication strengthens checking.  Not a
+                * strong reason, but sufficient in the absence of others.
+                */
+               if (flags&SPSTART) {
+                       longest = NULL;
+                       len = 0;
+                       for (; scan != NULL; scan = regnext(scan))
+                               if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+                                       longest = OPERAND(scan);
+                                       len = strlen(OPERAND(scan));
+                               }
+                       r->regmust = longest;
+                       r->regmlen = len;
+               }
+       }
+
+       return(r);
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char *
+reg(paren, flagp)
+int paren;                     /* Parenthesized? */
+int *flagp;
+{
+       register char *ret;
+       register char *br;
+       register char *ender;
+       register int parno = 0;
+       int flags;
+
+       *flagp = HASWIDTH;      /* Tentatively. */
+
+       /* Make an OPEN node, if parenthesized. */
+       if (paren) {
+               if (regnpar >= NSUBEXP)
+                       FAIL("too many ()");
+               parno = regnpar;
+               regnpar++;
+               ret = regnode(OPEN+parno);
+       } else
+               ret = NULL;
+
+       /* Pick up the branches, linking them together. */
+       br = regbranch(&flags);
+       if (br == NULL)
+               return(NULL);
+       if (ret != NULL)
+               regtail(ret, br);       /* OPEN -> first. */
+       else
+               ret = br;
+       if (!(flags&HASWIDTH))
+               *flagp &= ~HASWIDTH;
+       *flagp |= flags&SPSTART;
+       while (*regparse == '|' || *regparse == '\n') {
+               regparse++;
+               br = regbranch(&flags);
+               if (br == NULL)
+                       return(NULL);
+               regtail(ret, br);       /* BRANCH -> BRANCH. */
+               if (!(flags&HASWIDTH))
+                       *flagp &= ~HASWIDTH;
+               *flagp |= flags&SPSTART;
+       }
+
+       /* Make a closing node, and hook it on the end. */
+       ender = regnode((paren) ? CLOSE+parno : END);   
+       regtail(ret, ender);
+
+       /* Hook the tails of the branches to the closing node. */
+       for (br = ret; br != NULL; br = regnext(br))
+               regoptail(br, ender);
+
+       /* Check for proper termination. */
+       if (paren && *regparse++ != ')') {
+               FAIL("unmatched ()");
+       } else if (!paren && *regparse != '\0') {
+               if (*regparse == ')') {
+                       FAIL("unmatched ()");
+               } else
+                       FAIL("junk on end");    /* "Can't happen". */
+               /* NOTREACHED */
+       }
+
+       return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char *
+regbranch(flagp)
+int *flagp;
+{
+       register char *ret;
+       register char *chain;
+       register char *latest;
+       int flags;
+
+       *flagp = WORST;         /* Tentatively. */
+
+       ret = regnode(BRANCH);
+       chain = NULL;
+       while (*regparse != '\0' && *regparse != ')' &&
+              *regparse != '\n' && *regparse != '|') {
+               latest = regpiece(&flags);
+               if (latest == NULL)
+                       return(NULL);
+               *flagp |= flags&HASWIDTH;
+               if (chain == NULL)      /* First piece. */
+                       *flagp |= flags&SPSTART;
+               else
+                       regtail(chain, latest);
+               chain = latest;
+       }
+       if (chain == NULL)      /* Loop ran zero times. */
+               (void) regnode(NOTHING);
+
+       return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized:  they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char *
+regpiece(flagp)
+int *flagp;
+{
+       register char *ret;
+       register char op;
+       register char *next;
+       int flags;
+
+       ret = regatom(&flags);
+       if (ret == NULL)
+               return(NULL);
+
+       op = *regparse;
+       if (!ISMULT(op)) {
+               *flagp = flags;
+               return(ret);
+       }
+
+       if (!(flags&HASWIDTH) && op != '?')
+               FAIL("*+ operand could be empty");
+       *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
+
+       if (op == '*' && (flags&SIMPLE))
+               reginsert(STAR, ret);
+       else if (op == '*') {
+               /* Emit x* as (x&|), where & means "self". */
+               reginsert(BRANCH, ret);                 /* Either x */
+               regoptail(ret, regnode(BACK));          /* and loop */
+               regoptail(ret, ret);                    /* back */
+               regtail(ret, regnode(BRANCH));          /* or */
+               regtail(ret, regnode(NOTHING));         /* null. */
+       } else if (op == '+' && (flags&SIMPLE))
+               reginsert(PLUS, ret);
+       else if (op == '+') {
+               /* Emit x+ as x(&|), where & means "self". */
+               next = regnode(BRANCH);                 /* Either */
+               regtail(ret, next);
+               regtail(regnode(BACK), ret);            /* loop back */
+               regtail(next, regnode(BRANCH));         /* or */
+               regtail(ret, regnode(NOTHING));         /* null. */
+       } else if (op == '?') {
+               /* Emit x? as (x|) */
+               reginsert(BRANCH, ret);                 /* Either x */
+               regtail(ret, regnode(BRANCH));          /* or */
+               next = regnode(NOTHING);                /* null. */
+               regtail(ret, next);
+               regoptail(ret, next);
+       }
+       regparse++;
+       if (ISMULT(*regparse))
+               FAIL("nested *?+");
+
+       return(ret);
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization:  gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run.  Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char *
+regatom(flagp)
+int *flagp;
+{
+       register char *ret;
+       int flags;
+
+       *flagp = WORST;         /* Tentatively. */
+
+       switch (*regparse++) {
+       /* FIXME: these chars only have meaning at beg/end of pat? */
+       case '^':
+               ret = regnode(BOL);
+               break;
+       case '$':
+               ret = regnode(EOL);
+               break;
+       case '.':
+               ret = regnode(ANY);
+               *flagp |= HASWIDTH|SIMPLE;
+               break;
+       case '[': {
+                       register int class;
+                       register int classend;
+
+                       if (*regparse == '^') { /* Complement of range. */
+                               ret = regnode(ANYBUT);
+                               regparse++;
+                       } else
+                               ret = regnode(ANYOF);
+                       if (*regparse == ']' || *regparse == '-')
+                               regc(*regparse++);
+                       while (*regparse != '\0' && *regparse != ']') {
+                               if (*regparse == '-') {
+                                       regparse++;
+                                       if (*regparse == ']' || *regparse == '\0')
+                                               regc('-');
+                                       else {
+                                               class = UCHARAT(regparse-2)+1;
+                                               classend = UCHARAT(regparse);
+                                               if (class > classend+1)
+                                                       FAIL("invalid [] range");
+                                               for (; class <= classend; class++)
+                                                       regc(class);
+                                               regparse++;
+                                       }
+                               } else
+                                       regc(*regparse++);
+                       }
+                       regc('\0');
+                       if (*regparse != ']')
+                               FAIL("unmatched []");
+                       regparse++;
+                       *flagp |= HASWIDTH|SIMPLE;
+               }
+               break;
+       case '(':
+               ret = reg(1, &flags);
+               if (ret == NULL)
+                       return(NULL);
+               *flagp |= flags&(HASWIDTH|SPSTART);
+               break;
+       case '\0':
+       case '|':
+       case '\n':
+       case ')':
+               FAIL("internal urp");   /* Supposed to be caught earlier. */
+               break;
+       case '?':
+       case '+':
+       case '*':
+               FAIL("?+* follows nothing");
+               break;
+       case '\\':
+               switch (*regparse++) {
+               case '\0':
+                       FAIL("trailing \\");
+                       break;
+               case '<':
+                       ret = regnode(WORDA);
+                       break;
+               case '>':
+                       ret = regnode(WORDZ);
+                       break;
+               /* FIXME: Someday handle \1, \2, ... */
+               default:
+                       /* Handle general quoted chars in exact-match routine */
+                       goto de_fault;
+               }
+               break;
+       de_fault:
+       default:
+               /*
+                * Encode a string of characters to be matched exactly.
+                *
+                * This is a bit tricky due to quoted chars and due to
+                * '*', '+', and '?' taking the SINGLE char previous
+                * as their operand.
+                *
+                * On entry, the char at regparse[-1] is going to go
+                * into the string, no matter what it is.  (It could be
+                * following a \ if we are entered from the '\' case.)
+                * 
+                * Basic idea is to pick up a good char in  ch  and
+                * examine the next char.  If it's *+? then we twiddle.
+                * If it's \ then we frozzle.  If it's other magic char
+                * we push  ch  and terminate the string.  If none of the
+                * above, we push  ch  on the string and go around again.
+                *
+                *  regprev  is used to remember where "the current char"
+                * starts in the string, if due to a *+? we need to back
+                * up and put the current char in a separate, 1-char, string.
+                * When  regprev  is NULL,  ch  is the only char in the
+                * string; this is used in *+? handling, and in setting
+                * flags |= SIMPLE at the end.
+                */
+               {
+                       char *regprev;
+                       register char ch = 0;
+
+                       regparse--;                     /* Look at cur char */
+                       ret = regnode(EXACTLY);
+                       for ( regprev = 0 ; ; ) {
+                               ch = *regparse++;       /* Get current char */
+                               switch (*regparse) {    /* look at next one */
+
+                               default:
+                                       regc(ch);       /* Add cur to string */
+                                       break;
+
+                               case '.': case '[': case '(':
+                               case ')': case '|': case '\n':
+                               case '$': case '^':
+                               case '\0':
+                               /* FIXME, $ and ^ should not always be magic */
+                               magic:
+                                       regc(ch);       /* dump cur char */
+                                       goto done;      /* and we are done */
+
+                               case '?': case '+': case '*':
+                                       if (!regprev)   /* If just ch in str, */
+                                               goto magic;     /* use it */
+                                       /* End mult-char string one early */
+                                       regparse = regprev; /* Back up parse */
+                                       goto done;
+
+                               case '\\':
+                                       regc(ch);       /* Cur char OK */
+                                       switch (regparse[1]){ /* Look after \ */
+                                       case '\0':
+                                       case '<':
+                                       case '>':
+                                       /* FIXME: Someday handle \1, \2, ... */
+                                               goto done; /* Not quoted */
+                                       default:
+                                               /* Backup point is \, scan                                                       * point is after it. */
+                                               regprev = regparse;
+                                               regparse++; 
+                                               continue;       /* NOT break; */
+                                       }
+                               }
+                               regprev = regparse;     /* Set backup point */
+                       }
+               done:
+                       regc('\0');
+                       *flagp |= HASWIDTH;
+                       if (!regprev)           /* One char? */
+                               *flagp |= SIMPLE;
+               }
+               break;
+       }
+
+       return(ret);
+}
+
+/*
+ - regnode - emit a node
+ */
+static char *                  /* Location. */
+regnode(op)
+char op;
+{
+       register char *ret;
+       register char *ptr;
+
+       ret = regcode;
+       if (ret == &regdummy) {
+               regsize += 3;
+               return(ret);
+       }
+
+       ptr = ret;
+       *ptr++ = op;
+       *ptr++ = '\0';          /* Null "next" pointer. */
+       *ptr++ = '\0';
+       regcode = ptr;
+
+       return(ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void
+regc(b)
+char b;
+{
+       if (regcode != &regdummy)
+               *regcode++ = b;
+       else
+               regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void
+reginsert(op, opnd)
+char op;
+char *opnd;
+{
+       register char *src;
+       register char *dst;
+       register char *place;
+
+       if (regcode == &regdummy) {
+               regsize += 3;
+               return;
+       }
+
+       src = regcode;
+       regcode += 3;
+       dst = regcode;
+       while (src > opnd)
+               *--dst = *--src;
+
+       place = opnd;           /* Op node, where operand used to be. */
+       *place++ = op;
+       *place++ = '\0';
+       *place++ = '\0';
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void
+regtail(p, val)
+char *p;
+char *val;
+{
+       register char *scan;
+       register char *temp;
+       register int offset;
+
+       if (p == &regdummy)
+               return;
+
+       /* Find last node. */
+       scan = p;
+       for (;;) {
+               temp = regnext(scan);
+               if (temp == NULL)
+                       break;
+               scan = temp;
+       }
+
+       if (OP(scan) == BACK)
+               offset = scan - val;
+       else
+               offset = val - scan;
+       *(scan+1) = (offset>>8)&0377;
+       *(scan+2) = offset&0377;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void
+regoptail(p, val)
+char *p;
+char *val;
+{
+       /* "Operandless" and "op != BRANCH" are synonymous in practice. */
+       if (p == NULL || p == &regdummy || OP(p) != BRANCH)
+               return;
+       regtail(OPERAND(p), val);
+}
+
+/*
+ * regexec and friends
+ */
+
+/*
+ * Global work variables for regexec().
+ */
+static char *reginput;         /* String-input pointer. */
+static char *regbol;           /* Beginning of input, for ^ check. */
+static char **regstartp;       /* Pointer to startp array. */
+static char **regendp;         /* Ditto for endp. */
+
+/*
+ * Forwards.
+ */
+STATIC int regtry (const regexp *, const char *);
+STATIC int regmatch (char *);
+STATIC int regrepeat (char *);
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump __P((regexp *));
+STATIC char *regprop __P((char *));
+#endif
+
+/*
+ - regexec - match a regexp against a string
+ */
+int
+regexec(prog, string)
+register const regexp *prog;
+register const char *string;
+{
+       register char *s;
+
+       /* Be paranoid... */
+       if (prog == NULL || string == NULL) {
+               regerror("NULL parameter");
+               return(0);
+       }
+
+       /* Check validity of program. */
+       if (UCHARAT(prog->program) != MAGIC) {
+               regerror("corrupted program");
+               return(0);
+       }
+
+       /* If there is a "must appear" string, look for it. */
+       if (prog->regmust != NULL) {
+               s = (char *)string;
+               while ((s = strchr(s, prog->regmust[0])) != NULL) {
+                       if (strncmp(s, prog->regmust, prog->regmlen) == 0)
+                               break;  /* Found it. */
+                       s++;
+               }
+               if (s == NULL)  /* Not present. */
+                       return(0);
+       }
+
+       /* Mark beginning of line for ^ . */
+       regbol = (char *)string;
+
+       /* Simplest case:  anchored match need be tried only once. */
+       if (prog->reganch)
+               return(regtry(prog, string));
+
+       /* Messy cases:  unanchored match. */
+       s = (char *)string;
+       if (prog->regstart != '\0')
+               /* We know what char it must start with. */
+               while ((s = strchr(s, prog->regstart)) != NULL) {
+                       if (regtry(prog, s))
+                               return(1);
+                       s++;
+               }
+       else
+               /* We don't -- general case. */
+               do {
+                       if (regtry(prog, s))
+                               return(1);
+               } while (*s++ != '\0');
+
+       /* Failure. */
+       return(0);
+}
+
+/*
+ - regtry - try match at specific point
+ */
+static int                     /* 0 failure, 1 success */
+regtry(prog, string)
+const regexp *prog;
+const char *string;
+{
+       register int i;
+       register char **sp;
+       register char **ep;
+
+       reginput = (char *)string;                              /* XXX */
+       regstartp = (char **)prog->startp;                      /* XXX */
+       regendp = (char **)prog->endp;                          /* XXX */
+
+       sp = (char **)prog->startp;                             /* XXX */
+       ep = (char **)prog->endp;                               /* XXX */
+       for (i = NSUBEXP; i > 0; i--) {
+               *sp++ = NULL;
+               *ep++ = NULL;
+       }
+       if (regmatch((char *)prog->program + 1)) {              /* XXX */
+               ((regexp *)prog)->startp[0] = (char *)string;   /* XXX */
+               ((regexp *)prog)->endp[0] = reginput;           /* XXX */
+               return(1);
+       } else
+               return(0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple:  check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly.  In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+static int                     /* 0 failure, 1 success */
+regmatch(prog)
+char *prog;
+{
+       register char *scan;    /* Current node. */
+       char *next;             /* Next node. */
+
+       scan = prog;
+#ifdef DEBUG
+       if (scan != NULL && regnarrate)
+               fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+       while (scan != NULL) {
+#ifdef DEBUG
+               if (regnarrate)
+                       fprintf(stderr, "%s...\n", regprop(scan));
+#endif
+               next = regnext(scan);
+
+               switch (OP(scan)) {
+               case BOL:
+                       if (reginput != regbol)
+                               return(0);
+                       break;
+               case EOL:
+                       if (*reginput != '\0')
+                               return(0);
+                       break;
+               case WORDA:
+                       /* Must be looking at a letter, digit, or _ */
+                       if ((!isalnum(*reginput)) && *reginput != '_')
+                               return(0);
+                       /* Prev must be BOL or nonword */
+                       if (reginput > regbol &&
+                           (isalnum(reginput[-1]) || reginput[-1] == '_'))
+                               return(0);
+                       break;
+               case WORDZ:
+                       /* Must be looking at non letter, digit, or _ */
+                       if (isalnum(*reginput) || *reginput == '_')
+                               return(0);
+                       /* We don't care what the previous char was */
+                       break;
+               case ANY:
+                       if (*reginput == '\0')
+                               return(0);
+                       reginput++;
+                       break;
+               case EXACTLY: {
+                               register int len;
+                               register char *opnd;
+
+                               opnd = OPERAND(scan);
+                               /* Inline the first character, for speed. */
+                               if (*opnd != *reginput)
+                                       return(0);
+                               len = strlen(opnd);
+                               if (len > 1 && strncmp(opnd, reginput, len) != 0)
+                                       return(0);
+                               reginput += len;
+                       }
+                       break;
+               case ANYOF:
+                       if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
+                               return(0);
+                       reginput++;
+                       break;
+               case ANYBUT:
+                       if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
+                               return(0);
+                       reginput++;
+                       break;
+               case NOTHING:
+                       break;
+               case BACK:
+                       break;
+               case OPEN+1:
+               case OPEN+2:
+               case OPEN+3:
+               case OPEN+4:
+               case OPEN+5:
+               case OPEN+6:
+               case OPEN+7:
+               case OPEN+8:
+               case OPEN+9: {
+                               register int no;
+                               register char *save;
+
+                               no = OP(scan) - OPEN;
+                               save = reginput;
+
+                               if (regmatch(next)) {
+                                       /*
+                                        * Don't set startp if some later
+                                        * invocation of the same parentheses
+                                        * already has.
+                                        */
+                                       if (regstartp[no] == NULL)
+                                               regstartp[no] = save;
+                                       return(1);
+                               } else
+                                       return(0);
+                       }
+                       break;
+               case CLOSE+1:
+               case CLOSE+2:
+               case CLOSE+3:
+               case CLOSE+4:
+               case CLOSE+5:
+               case CLOSE+6:
+               case CLOSE+7:
+               case CLOSE+8:
+               case CLOSE+9: {
+                               register int no;
+                               register char *save;
+
+                               no = OP(scan) - CLOSE;
+                               save = reginput;
+
+                               if (regmatch(next)) {
+                                       /*
+                                        * Don't set endp if some later
+                                        * invocation of the same parentheses
+                                        * already has.
+                                        */
+                                       if (regendp[no] == NULL)
+                                               regendp[no] = save;
+                                       return(1);
+                               } else
+                                       return(0);
+                       }
+                       break;
+               case BRANCH: {
+                               register char *save;
+
+                               if (OP(next) != BRANCH)         /* No choice. */
+                                       next = OPERAND(scan);   /* Avoid recursion. */
+                               else {
+                                       do {
+                                               save = reginput;
+                                               if (regmatch(OPERAND(scan)))
+                                                       return(1);
+                                               reginput = save;
+                                               scan = regnext(scan);
+                                       } while (scan != NULL && OP(scan) == BRANCH);
+                                       return(0);
+                                       /* NOTREACHED */
+                               }
+                       }
+                       break;
+               case STAR:
+               case PLUS: {
+                               register char nextch;
+                               register int no;
+                               register char *save;
+                               register int min;
+
+                               /*
+                                * Lookahead to avoid useless match attempts
+                                * when we know what character comes next.
+                                */
+                               nextch = '\0';
+                               if (OP(next) == EXACTLY)
+                                       nextch = *OPERAND(next);
+                               min = (OP(scan) == STAR) ? 0 : 1;
+                               save = reginput;
+                               no = regrepeat(OPERAND(scan));
+                               while (no >= min) {
+                                       /* If it could work, try it. */
+                                       if (nextch == '\0' || *reginput == nextch)
+                                               if (regmatch(next))
+                                                       return(1);
+                                       /* Couldn't or didn't -- back up. */
+                                       no--;
+                                       reginput = save + no;
+                               }
+                               return(0);
+                       }
+                       break;
+               case END:
+                       return(1);      /* Success! */
+                       break;
+               default:
+                       regerror("memory corruption");
+                       return(0);
+                       break;
+               }
+
+               scan = next;
+       }
+
+       /*
+        * We get here only if there's trouble -- normally "case END" is
+        * the terminating point.
+        */
+       regerror("corrupted pointers");
+       return(0);
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int
+regrepeat(p)
+char *p;
+{
+       register int count = 0;
+       register char *scan;
+       register char *opnd;
+
+       scan = reginput;
+       opnd = OPERAND(p);
+       switch (OP(p)) {
+       case ANY:
+               count = strlen(scan);
+               scan += count;
+               break;
+       case EXACTLY:
+               while (*opnd == *scan) {
+                       count++;
+                       scan++;
+               }
+               break;
+       case ANYOF:
+               while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
+                       count++;
+                       scan++;
+               }
+               break;
+       case ANYBUT:
+               while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
+                       count++;
+                       scan++;
+               }
+               break;
+       default:                /* Oh dear.  Called inappropriately. */
+               regerror("internal foulup");
+               count = 0;      /* Best compromise. */
+               break;
+       }
+       reginput = scan;
+
+       return(count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static char *
+regnext(p)
+register char *p;
+{
+       register int offset;
+
+       if (p == &regdummy)
+               return(NULL);
+
+       offset = NEXT(p);
+       if (offset == 0)
+               return(NULL);
+
+       if (OP(p) == BACK)
+               return(p-offset);
+       else
+               return(p+offset);
+}
+
+#ifdef DEBUG
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+void
+regdump(r)
+regexp *r;
+{
+       register char *s;
+       register char op = EXACTLY;     /* Arbitrary non-END op. */
+       register char *next;
+       extern char *strchr();
+
+
+       s = r->program + 1;
+       while (op != END) {     /* While that wasn't END last time... */
+               op = OP(s);
+               printf("%2d%s", s-r->program, regprop(s));      /* Where, what. */
+               next = regnext(s);
+               if (next == NULL)               /* Next ptr. */
+                       printf("(0)");
+               else 
+                       printf("(%d)", (s-r->program)+(next-s));
+               s += 3;
+               if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
+                       /* Literal string, where present. */
+                       while (*s != '\0') {
+                               putchar(*s);
+                               s++;
+                       }
+                       s++;
+               }
+               putchar('\n');
+       }
+
+       /* Header fields of interest. */
+       if (r->regstart != '\0')
+               printf("start `%c' ", r->regstart);
+       if (r->reganch)
+               printf("anchored ");
+       if (r->regmust != NULL)
+               printf("must have \"%s\"", r->regmust);
+       printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+static char *
+regprop(op)
+char *op;
+{
+       register char *p;
+       static char buf[50];
+
+       (void) strcpy(buf, ":");
+
+       switch (OP(op)) {
+       case BOL:
+               p = "BOL";
+               break;
+       case EOL:
+               p = "EOL";
+               break;
+       case ANY:
+               p = "ANY";
+               break;
+       case ANYOF:
+               p = "ANYOF";
+               break;
+       case ANYBUT:
+               p = "ANYBUT";
+               break;
+       case BRANCH:
+               p = "BRANCH";
+               break;
+       case EXACTLY:
+               p = "EXACTLY";
+               break;
+       case NOTHING:
+               p = "NOTHING";
+               break;
+       case BACK:
+               p = "BACK";
+               break;
+       case END:
+               p = "END";
+               break;
+       case OPEN+1:
+       case OPEN+2:
+       case OPEN+3:
+       case OPEN+4:
+       case OPEN+5:
+       case OPEN+6:
+       case OPEN+7:
+       case OPEN+8:
+       case OPEN+9:
+               sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
+               p = NULL;
+               break;
+       case CLOSE+1:
+       case CLOSE+2:
+       case CLOSE+3:
+       case CLOSE+4:
+       case CLOSE+5:
+       case CLOSE+6:
+       case CLOSE+7:
+       case CLOSE+8:
+       case CLOSE+9:
+               sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
+               p = NULL;
+               break;
+       case STAR:
+               p = "STAR";
+               break;
+       case PLUS:
+               p = "PLUS";
+               break;
+       case WORDA:
+               p = "WORDA";
+               break;
+       case WORDZ:
+               p = "WORDZ";
+               break;
+       default:
+               regerror("corrupted opcode");
+               break;
+       }
+       if (p != NULL)
+               (void) strcat(buf, p);
+       return(buf);
+}
+#endif
+
+/*
+ * The following is provided for those people who do not have strcspn() in
+ * their C libraries.  They should get off their butts and do something
+ * about it; at least one public-domain implementation of those (highly
+ * useful) string routines has been published on Usenet.
+ */
+#ifdef STRCSPN
+/*
+ * strcspn - find length of initial segment of s1 consisting entirely
+ * of characters not from s2
+ */
+
+static int
+strcspn(s1, s2)
+char *s1;
+char *s2;
+{
+       register char *scan1;
+       register char *scan2;
+       register int count;
+
+       count = 0;
+       for (scan1 = s1; *scan1 != '\0'; scan1++) {
+               for (scan2 = s2; *scan2 != '\0';)       /* ++ moved down. */
+                       if (*scan1 == *scan2++)
+                               return(count);
+               count++;
+       }
+       return(count);
+}
+#endif
diff --git a/winsup/cygwin/regexp/regsub.c b/winsup/cygwin/regexp/regsub.c
new file mode 100644 (file)
index 0000000..3983cc5
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * regsub
+ *
+ *     Copyright (c) 1986 by University of Toronto.
+ *     Written by Henry Spencer.  Not derived from licensed software.
+ *
+ *     Permission is granted to anyone to use this software for any
+ *     purpose on any computer system, and to redistribute it freely,
+ *     subject to the following restrictions:
+ *
+ *     1. The author is not responsible for the consequences of use of
+ *             this software, no matter how awful, even if they arise
+ *             from defects in it.
+ *
+ *     2. The origin of this software must not be misrepresented, either
+ *             by explicit claim or by omission.
+ *
+ *     3. Altered versions must be plainly marked as such, and must not
+ *             be misrepresented as being the original software.
+ */
+
+#if 0
+#ifndef lint
+static char *rcsid = "$Id$";
+#endif /* not lint */
+#endif
+
+#include "regexp.h"
+#include <stdio.h>
+#include <string.h>
+#include "regmagic.h"
+
+#ifndef CHARBITS
+#define        UCHARAT(p)      ((int)*(unsigned char *)(p))
+#else
+#define        UCHARAT(p)      ((int)*(p)&CHARBITS)
+#endif
+
+/*
+ - regsub - perform substitutions after a regexp match
+ */
+void
+regsub(prog, source, dest)
+const regexp *prog;
+const char *source;
+char *dest;
+{
+       register char *src;
+       register char *dst;
+       register char c;
+       register int no;
+       register int len;
+
+       if (prog == NULL || source == NULL || dest == NULL) {
+               regerror("NULL parm to regsub");
+               return;
+       }
+       if (UCHARAT(prog->program) != MAGIC) {
+               regerror("damaged regexp fed to regsub");
+               return;
+       }
+
+       src = (char *)source;
+       dst = dest;
+       while ((c = *src++) != '\0') {
+               if (c == '&')
+                       no = 0;
+               else if (c == '\\' && '0' <= *src && *src <= '9')
+                       no = *src++ - '0';
+               else
+                       no = -1;
+               if (no < 0) {   /* Ordinary character. */
+                       if (c == '\\' && (*src == '\\' || *src == '&'))
+                               c = *src++;
+                       *dst++ = c;
+               } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
+                       len = prog->endp[no] - prog->startp[no];
+                       (void) strncpy(dst, prog->startp[no], len);
+                       dst += len;
+                       if (len != 0 && *(dst-1) == '\0') {     /* strncpy hit NUL. */
+                               regerror("damaged match string");
+                               return;
+                       }
+               }
+       }
+       *dst++ = '\0';
+}
diff --git a/winsup/cygwin/shared.h b/winsup/cygwin/shared.h
new file mode 100644 (file)
index 0000000..036ca88
--- /dev/null
@@ -0,0 +1,552 @@
+/* shared.h: shared info for cygwin
+
+   Copyright 1998, 1999, 2000 Cygnus Solutions.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+/******** Functions declarations for use in methods below ********/
+
+/* Printf type functions */
+extern "C" void __api_fatal (const char *, ...) __attribute__ ((noreturn));
+extern "C" int __small_sprintf (char *dst, const char *fmt, ...);
+extern "C" int __small_vsprintf (char *dst, const char *fmt, va_list ap);
+extern "C" int __small_sprintf (char *dst, const char *fmt, ...);
+
+/******** Deletion Queue Class ********/
+
+/* First pass at a file deletion queue structure.
+
+   We can't keep this list in the per-process info, since
+   one process may open a file, and outlive a process which
+   wanted to unlink the file - and the data would go away.
+
+   Perhaps the FILE_FLAG_DELETE_ON_CLOSE would be ok,
+   but brief experimentation didn't get too far.
+*/
+
+#define MAX_DELQUEUES_PENDING 100
+
+class delqueue_list
+{
+  char name[MAX_DELQUEUES_PENDING][MAX_PATH];
+  char inuse[MAX_DELQUEUES_PENDING];
+  int empty;
+
+public:
+  void init ();
+  void queue_file (const char *dosname);
+  void process_queue ();
+};
+
+/******** Process Table ********/
+
+/* Signal constants (have to define them here, unfortunately) */
+
+enum
+{
+  __SIGFLUSH       = -2,
+  __SIGSTRACE      = -1,
+  __SIGCHILDSTOPPED =  0,
+  __SIGOFFSET      =  3
+};
+
+class pinfo
+{
+ public:
+
+  /* If hProcess is set, it's because it came from a
+     CreateProcess call.  This means it's process relative
+     to the thing which created the process.  That's ok because
+     we only use this handle from the parent. */
+  HANDLE hProcess;
+
+  HANDLE parent_alive;
+
+  /* dwProcessId contains the processid used for sending signals.  It
+   * will be reset in a child process when it is capable of receiving
+   * signals.
+   */
+  DWORD dwProcessId;
+
+  /* User information.
+     The information is derived from the GetUserName system call,
+     with the name looked up in /etc/passwd and assigned a default value
+     if not found.  This data resides in the shared data area (allowing
+     tasks to store whatever they want here) so it's for informational
+     purposes only. */
+  uid_t uid;       /* User ID */
+  gid_t gid;       /* Group ID */
+  pid_t pgid;      /* Process group ID */
+  pid_t sid;       /* Session ID */
+  int ctty;        /* Control tty */
+  mode_t umask;
+  char username[MAX_USER_NAME]; /* user's name */
+
+  /* Extendend user information.
+     The information is derived from the internal_getlogin call
+     when on a NT system. */
+  PSID psid;        /* user's SID */
+  char sidbuf[40];  /* buffer for user's SID */
+  char logsrv[256]; /* Logon server, may be fully qualified DNS name */
+  char domain[MAX_COMPUTERNAME_LENGTH+1]; /* Logon domain of the user */
+
+  /* Non-zero if process was stopped by a signal. */
+  char stopsig;
+
+  struct sigaction& getsig (int);
+  void copysigs (pinfo *);
+  sigset_t& getsigmask ();
+  void setsigmask (sigset_t);
+  LONG* getsigtodo (int);
+  HANDLE getthread2signal ();
+  void setthread2signal (void *);
+
+  /* Resources used by process. */
+  long start_time;
+  struct rusage rusage_self;
+  struct rusage rusage_children;
+
+private:
+  struct sigaction sigs[NSIG];
+  sigset_t sig_mask;           /* one set for everything to ignore. */
+  LONG _sigtodo[NSIG + __SIGOFFSET];
+#ifdef _MT_SAFE
+  ThreadItem* thread2signal;  // NULL means means thread any other means a pthread
+#endif
+
+public:
+
+  /* Pointer to mmap'ed areas for this process.  Set up by fork. */
+  void *mmap_ptr;
+
+  /* Used to spawn a child for fork(), among other things. */
+  char progname[MAX_PATH];
+
+  #define PINFO_ZERO ((((pinfo *) NULL)->progname + 1) - ((char *) NULL))
+
+  /* Anything below this point is not zeroed automatically by allocate_pid */
+
+  /* The pid stays the same, while the hProcess moves due to execs. */
+  pid_t pid;
+  /* Parent process id.  */
+  pid_t ppid;
+
+  /* Various flags indicating the state of the process.  See PID_
+     constants below. */
+  DWORD process_state;
+
+  void record_death (int lock = 1);
+};
+
+#define ISSTATE(p, f)  (!!((p)->process_state & f))
+#define NOTSTATE(p, f) (!((p)->process_state & f))
+
+/* Flags associated with process_state */
+enum
+{
+  PID_NOT_IN_USE       = 0x0000, // Free entry.
+  PID_IN_USE          = 0x0001, // Entry in use.
+  PID_ZOMBIE          = 0x0002, // Child exited: no parent wait.
+  PID_STOPPED         = 0x0004, // Waiting for SIGCONT.
+  PID_TTYIN           = 0x0008, // Waiting for terminal input.
+  PID_TTYOU           = 0x0010, // Waiting for terminal output.
+  PID_ORPHANED        = 0x0020, // Member of an orphaned process group.
+  PID_ACTIVE          = 0x0040, // Pid accepts signals.
+  PID_CYGPARENT               = 0x0080, // Set if parent was a cygwin app.
+  PID_SPLIT_HEAP       = 0x0100, // Set if the heap has been split,
+                                //  which means we can't fork again.
+  PID_CLEAR           = 0x0200, // Flag that pid should be cleared from parent's
+                                //  wait list
+  PID_SOCKETS_USED     = 0x0400, // Set if process uses Winsock.
+  PID_INITIALIZING     = 0x0800, // Set until ready to receive signals.
+  PID_USETTY          = 0x1000, // Setting this enables or disables cygwin's
+                                //  tty support.  This is inherited by
+                                //  all execed or forked processes.
+  PID_REPARENT        = 0x2000  // child has execed
+};
+
+#define PSIZE 128
+
+class pinfo_list
+{
+ public:
+  int next_pid;
+  pinfo vec[PSIZE];
+  char lock_info[MAX_PATH + 1];
+  pinfo * operator[] (pid_t x);
+  int size (void) { return PSIZE; }
+  pinfo *allocate_pid (void);
+  void init (void);
+};
+
+void __stdcall pinfo_init (PBYTE);
+pinfo *__stdcall procinfo (int n);
+
+enum
+{
+  PROC_MAGIC = 0xaf04f000,
+  PROC_FORK = PROC_MAGIC + 1,
+  PROC_EXEC = PROC_MAGIC + 2,
+  PROC_SPAWN = PROC_MAGIC + 3,
+  PROC_FORK1 = PROC_MAGIC + 4  // Newer versions provide stack
+                               // location information
+};
+
+#define PROC_MAGIC_MASK 0xff00f000
+#define PROC_MAGIC_GENERIC 0xaf00f000
+#define PROC_MAGIC_VER_MASK 0x0ff0000
+
+#define EXEC_MAGIC_SIZE sizeof(child_info)
+class child_info
+{
+public:
+  DWORD zero[1];       // must be zeroed
+  DWORD cb;            // size of this record
+  DWORD type;          // type of record
+  int cygpid;          // cygwin pid of child process
+  HANDLE subproc_ready;        // used for synchronization with parent
+  HANDLE shared_h;
+  HANDLE console_h;
+  HANDLE parent_alive; // handle of thread used to track children
+};
+
+class child_info_fork: public child_info
+{
+public:
+  HANDLE forker_finished;// for synchronization with child
+  DWORD stacksize;     // size of parent stack
+  void *heaptop;
+  void *heapbase;
+  void *heapptr;
+  jmp_buf jmp;         // where child will jump to
+  void *stacktop;      // location of top of parent stack
+  void *stackbottom;   // location of bottom of parent stack
+};
+
+void __stdcall init_child_info (DWORD, child_info *, int, HANDLE);
+
+extern child_info_fork *child_proc_info;
+
+/* Process info for this process */
+extern pinfo *myself;
+
+/* non-NULL if this process is a child of a cygwin process */
+extern HANDLE parent_alive;
+
+/******** Registry Access ********/
+
+class reg_key
+{
+private:
+
+  HKEY key;
+
+public:
+
+  reg_key (HKEY toplev, REGSAM access, ...);
+  reg_key (REGSAM access, ...);
+  reg_key (REGSAM access = KEY_ALL_ACCESS);
+
+  void *operator new (size_t, void *p) {return p;}
+  void build_reg (HKEY key, REGSAM access, va_list av);
+
+  int error () {return key == (HKEY) INVALID_HANDLE_VALUE;}
+
+  int kill (const char *child);
+
+  HKEY get_key ();
+  int get_int (const char *,int def);
+  int get_string (const char *, char *buf, size_t len, const char *def);
+  int set_string (const char *,const char *);
+  int set_int (const char *, int val);
+  int setone_string (const char *src, const char *name);
+
+  ~reg_key ();
+};
+
+/******** Mount Table ********/
+
+/* Mount table entry */
+
+class mount_item
+{
+public:
+  /* FIXME: Nasty static allocation.  Need to have a heap in the shared
+     area [with the user being able to configure at runtime the max size].  */
+
+  /* Win32-style mounted partition source ("C:\foo\bar").
+     native_path[0] == 0 for unused entries.  */
+  char native_path[MAX_PATH];
+  int native_pathlen;
+
+  /* POSIX-style mount point ("/foo/bar") */
+  char posix_path[MAX_PATH];
+  int posix_pathlen;
+
+  unsigned flags;
+
+  void init (const char *dev, const char *path, unsigned flags);
+
+  struct mntent *getmntent ();
+};
+
+/* Warning: Decreasing this value will cause cygwin.dll to ignore existing
+   higher numbered registry entries.  Don't change this number willy-nilly.
+   What we need is to have a more dynamic allocation scheme, but the current
+   scheme should be satisfactory for a long while yet.  */
+#define MAX_MOUNTS 30
+
+class mount_info
+{
+  int posix_sorted[MAX_MOUNTS];
+  int native_sorted[MAX_MOUNTS];
+public:
+  int nmounts;
+  mount_item mount[MAX_MOUNTS];
+
+  /* Strings used by getmntent(). */
+  char mnt_type[20];
+  char mnt_opts[20];
+  char mnt_fsname[MAX_PATH];
+  char mnt_dir[MAX_PATH];
+
+  /* cygdrive_prefix is used as the root of the path automatically
+     prepended to a path when the path has no associated mount.
+     cygdrive_flags are the default flags for the cygdrives. */
+  char cygdrive[MAX_PATH];
+  size_t cygdrive_len;
+  unsigned cygdrive_flags;
+
+  /* Increment when setting up a reg_key if mounts area had to be
+     created so we know when we need to import old mount tables. */
+  int had_to_create_mount_areas;
+
+  void init ();
+  int add_item (const char *dev, const char *path, unsigned flags);
+  int del_item (const char *path, unsigned flags);
+
+  void from_registry ();
+  void from_v1_registry ();
+  int add_reg_mount (const char * native_path, const char * posix_path,
+                     unsigned mountflags);
+  int del_reg_mount (const char * posix_path, unsigned mountflags);
+
+  unsigned set_flags_from_win32_path (const char *path);
+  int conv_to_win32_path (const char *src_path, char *win32_path,
+                         char *full_win32_path, DWORD &devn, int &unit,
+                         unsigned *flags = NULL);
+  int conv_to_posix_path (const char *src_path, char *posix_path,
+                         int keep_rel_p);
+  struct mntent *getmntent (int x);
+
+  int write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsigned flags);
+
+  void import_v1_mounts ();
+
+private:
+
+  void sort ();
+  void read_mounts (reg_key& r);
+  void read_v1_mounts (reg_key r, unsigned which);
+  void mount_slash ();
+  void to_registry ();
+
+  int cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p);
+  void cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p);
+  void slash_drive_to_win32_path (const char *path, char *buf, int trailing_slash_p);
+  void read_cygdrive_info_from_registry ();
+};
+
+/******** TTY Support ********/
+
+/* tty tables */
+
+#define INP_BUFFER_SIZE 256
+#define OUT_BUFFER_SIZE 256
+#define NTTYS          128
+#define TTY_CONSOLE    0x40000000
+#define tty_attached(p)        ((p)->ctty >= 0 && (p)->ctty != TTY_CONSOLE)
+
+/* Input/Output/ioctl events */
+
+#define OUTPUT_DONE_EVENT      "cygtty%d.output.done"
+#define IOCTL_REQUEST_EVENT    "cygtty%d.ioctl.request"
+#define IOCTL_DONE_EVENT       "cygtty%d.ioctl.done"
+#define RESTART_OUTPUT_EVENT   "cygtty%d.output.restart"
+#define OUTPUT_MUTEX           "cygtty%d.output.mutex"
+#define TTY_SLAVE_ALIVE                "cygtty%x.slave_alive"
+#define TTY_MASTER_ALIVE       "cygtty%x.master_alive"
+
+#include <sys/termios.h>
+
+enum
+{
+  TTY_INITIALIZED = 1,         /* Set if tty is initialized */
+  TTY_RSTCONS = 2              /* Set if console needs to be set to "non-cooked" */
+};
+
+#define TTYISSETF(x)   __ISSETF (tc, x, TTY)
+#define TTYSETF(x)     __SETF (tc, x, TTY)
+#define TTYCLEARF(x)   __CLEARF (tc, x, TTY)
+#define TTYCONDSETF(n, x) __CONDSETF(n, tc, x, TTY)
+
+#ifndef MIN_CTRL_C_SLOP
+#define MIN_CTRL_C_SLOP 50
+#endif
+
+class tty_min
+{
+  pid_t sid;   /* Session ID of tty */
+public:
+  DWORD status;
+  pid_t pgid;
+  int OutputStopped;
+  int ntty;
+  DWORD last_ctrl_c;   // tick count of last ctrl-c
+
+  tty_min (int t = -1, pid_t s = -1) : sid (s), ntty (t) {}
+  void setntty (int n) {ntty = n;}
+  pid_t getpgid () {return pgid;}
+  void setpgid (int pid) {pgid = pid;}
+  int getsid () {return sid;}
+  void setsid (pid_t tsid) {sid = tsid;}
+  struct termios ti;
+  struct winsize winsize;
+
+  /* ioctl requests buffer */
+  int cmd;
+  union
+  {
+    struct termios termios;
+    struct winsize winsize;
+    int value;
+    pid_t pid;
+  } arg;
+  /* XXX_retval variables holds master's completion codes. Error are stored as
+   * -ERRNO
+   */
+  int ioctl_retval;
+
+  int write_retval;
+};
+
+class fhandler_pty_master;
+
+class tty: public tty_min
+{
+  HANDLE get_event (const char *fmt, BOOL inherit);
+public:
+  HWND  hwnd;  /* Console window handle tty belongs to */
+
+  DWORD master_pid;    /* Win32 PID of tty master process */
+
+  HANDLE from_master, to_slave;
+  HANDLE from_slave, to_master;
+
+  int read_retval;
+  BOOL was_opened;     /* True if opened at least once. */
+
+  void init ();
+  HANDLE create_inuse (const char *);
+  BOOL common_init (fhandler_pty_master *);
+  BOOL alive (const char *fmt);
+  BOOL slave_alive ();
+  BOOL master_alive ();
+  HWND gethwnd () {return hwnd;}
+  void sethwnd (HWND wnd) {hwnd = wnd;}
+  int make_pipes (fhandler_pty_master *ptym);
+  HANDLE open_output_mutex (BOOL inherit = FALSE)
+  {
+    char buf[80];
+    __small_sprintf (buf, OUTPUT_MUTEX, ntty);
+    return OpenMutex (MUTEX_ALL_ACCESS, inherit, buf);
+  }
+  BOOL exists ()
+  {
+    HANDLE h = open_output_mutex ();
+    if (h)
+      {
+       CloseHandle (h);
+       return 1;
+      }
+    return slave_alive ();
+  }
+};
+
+class tty_list
+{
+  tty ttys[NTTYS];
+
+public:
+  tty * operator [](int n) {return ttys + n;}
+  int allocate_tty (int n); /* n non zero if allocate a tty, pty otherwise */
+  int connect_tty (int);
+  void terminate ();
+  void init ();
+  tty_min *get_tty (int n);
+};
+
+void __stdcall tty_init ();
+void __stdcall tty_terminate ();
+int __stdcall attach_tty (int);
+void __stdcall create_tty_master (int);
+extern "C" int ttyslot (void);
+
+/******** Shared Info ********/
+/* Data accessible to all tasks */
+
+class shared_info
+{
+  DWORD inited;
+
+public:
+  pinfo_list p;
+
+  /* FIXME: Doesn't work if more than one user on system. */
+  mount_info mount;
+
+  int heap_chunk_in_mb;
+  unsigned heap_chunk_size (void);
+
+  tty_list tty;
+  delqueue_list delqueue;
+  void initialize (void);
+};
+
+/* Various types of security attributes for use in Create* functions. */
+extern SECURITY_ATTRIBUTES sec_none, sec_none_nih, sec_all, sec_all_nih;
+extern SECURITY_ATTRIBUTES *__stdcall sec_user (PVOID sa_buf, PSID sid2 = NULL, BOOL inherit = TRUE);
+extern SECURITY_ATTRIBUTES *__stdcall sec_user_nih (PVOID sa_buf, PSID sid2 = NULL);
+
+extern shared_info *cygwin_shared;
+extern HANDLE cygwin_shared_h;
+extern HANDLE console_shared_h;
+extern int __stdcall set_console_state_for_spawn ();
+
+void __stdcall shared_init (void);
+void __stdcall shared_terminate (void);
+
+/* This is for programs that want to access the shared data. */
+extern "C" class shared_info *cygwin_getshared (void);
+
+char *__stdcall shared_name (const char *, int);
+void *__stdcall open_shared (const char *name, HANDLE &shared_h, DWORD size, void *addr);
+
+struct cygwin_version_info
+{
+  unsigned short api_major;
+  unsigned short api_minor;
+  unsigned short dll_major;
+  unsigned short dll_minor;
+  unsigned short shared_data;
+  unsigned short mount_registry;
+  const char *dll_build_date;
+  const char shared_id[sizeof (CYGWIN_VERSION_DLL_IDENTIFIER) + 64];
+};
+
+extern cygwin_version_info cygwin_version;
+extern const char *cygwin_version_strings;
diff --git a/winsup/cygwin/test.c b/winsup/cygwin/test.c
new file mode 100644 (file)
index 0000000..cd63a3e
--- /dev/null
@@ -0,0 +1,165 @@
+/* test.c: misc Cygwin testing code
+
+   Copyright 1996, 1998 Cygnus Solutions.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <stdio.h>
+#include <windows.h>
+
+char a[] ="This is static data";
+
+void
+test1()
+{
+  int depth = 0;
+  while (depth < 5) 
+    {
+      int  r;
+      printf ("about to fork %d\n", depth);
+
+      r = fork ();
+
+      if (r == 0)
+       {
+         int res;
+         depth++;
+         printf ("************Depth is %d\n", depth);
+         sleep (1);
+       }
+      else 
+       {
+         printf ("This is the parent, quitting %d\n", depth);
+         sleep (1);
+         exit (1);
+       }
+      printf ("done loop, depth %d\n", depth);
+    }
+}
+
+#define N 10
+int v[N];
+startup ()
+{
+  int i;
+  for (i = 0; i < N; i++)
+    {
+      int r;
+      fflush (stdout);
+      r = fork ();
+      if (r) 
+       {
+         v[i] = r;
+         printf ("started %d, were'id %d\n", v[i], GetCurrentProcessId ());
+         fflush (stdout);
+       }
+      else
+       {
+         /* running the child, sleep a bit and exit. */
+         printf ("the fork said 0, were %d\n", GetCurrentProcessId ());
+         fflush (stdout);
+  sleep (2);
+         printf ("Running, and exiting %d\n", i);
+         fflush (stdout);
+         _exit (i + 0x30);
+       }
+    }
+}
+
+test2()
+{
+  int i;
+  startup ();
+  sleep (1);
+  /* Wait for them one by one */
+  for (i = 0; i < N; i++) 
+    {
+      int res;
+      
+      waitpid (v[i], &res, 0);
+      printf ("Process %d gave res %x\n", v[i], res);
+      if (res != (0x30 + i) << 8)
+       printf ("***** BAD *** Process %d gave res %x\n", v[i], res);
+    }
+}
+
+test3()
+{
+  int i;
+  startup ();
+  /* Wait for them all at the same time */
+  for (i = 0; i < N; i++) 
+    {
+      int res;
+      wait (&res);
+      printf ("Got res %x\n", res);
+    }
+}
+
+test5()
+{
+  char *c = strdup ("HI STEVE");
+  printf ("c is %s\n", c);
+  free (c);
+}
+
+int count;
+
+main (int ac, char **av)
+{
+  int r;
+  int done;
+  int test;
+  fprintf (stderr,"TO STDERR\n");
+  if (ac < 2) {
+               printf ("usage: test <n>\n");
+               exit (2);
+             }
+  test = atoi (av[1]);
+
+  printf ("%d %d Hi steve, about to start fork test %d %d.\n",getpid (), count++, test,
+        GetCurrentProcessId ());
+fflush (stdout);
+  switch (test) 
+    {
+    case 1:
+      test1();
+      break;
+    case 2:
+      test2();
+      break;
+    case 3:
+      test3();
+      break;
+    case 4:
+SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), FOREGROUND_RED);
+break;
+    case 5:
+      test5();
+break;
+    }
+
+}
+
+free ()
+{
+  printf ("MY FREE!\n");
+}
+
+char b[100000];
+int i;
+
+malloc (x)
+{
+char *r = b + i;
+i += x;
+return r;
+}
+
+realloc ()
+{
+}
diff --git a/winsup/cygwin/testsuite/README b/winsup/cygwin/testsuite/README
new file mode 100644 (file)
index 0000000..92ede0d
--- /dev/null
@@ -0,0 +1,42 @@
+1999-12-23  DJ Delorie  <dj@cygnus.com>
+
+Here are some notes about adding and using this testsuite.
+
+First, all the programs are linked with new-libcygwin.a, which is just
+like libcygwin.a, except that it wants new-cygwin1.dll, not
+cygwin1.dll.  The testsuite adds the winsup build directory to the
+PATH so that new-cygwin1.dll can be found by windows during testing.
+
+Because we'll probably run into complaints about using two DLLs, we
+run cygrun.exe for each test.  All this does is run the test with
+CreateProcess() so that we don't attempt to do the special code for
+when a cygwin program calls another cygwin program, as this might be a
+"multiple cygwins" problem.
+
+Any test that needs to test command line args or redirection needs to
+run such a child program itself, as the testsuite will not do any
+arguments or redirection for it.  Same for fork, signals, etc.
+
+The testsuite/winsup.api subdirectory is for testing the API to
+cygwin1.dll ONLY.  Create other subdirs under testsuite/ for other
+classes of testing.
+
+Tests in winsup.api/*.c or winsup.api/*/*.c (only one subdirectory
+level is allowed) either compile, run, and exit(0) or they fail.
+Either abort or exit with a non-zero code to indicate failure.  Don't
+print anything to the screen if you can avoid it (except for failure
+reasons, of course).  One .c file per test, no compile options are
+allowed (we're testing the api, not the compiler).
+
+Tests whose filename begin with "xf-" will be *expected* to fail, and
+will "fail" if they compile, run, and return zero.  Note that the
+*only* purpose for adding this feature is to test the testing
+framework itself.  All real tests should NOT be named xf-*, and should
+pass for real (compile, run, return 0) if the dll is working
+correctly.  Do not use xf-* to "silence" a failure that you know isn't
+going to get fixed for a while; let it just keep failing.  There are
+five "sample" tests that demonstrate how the framework works and what
+happens to each condition.
+
+"make check" will only work if you run it *on* an NT machine.
+Cross-checking is not supported.
diff --git a/winsup/cygwin/testsuite/config/default.exp b/winsup/cygwin/testsuite/config/default.exp
new file mode 100644 (file)
index 0000000..ec8ce14
--- /dev/null
@@ -0,0 +1,6 @@
+proc winsup_version {} {
+    clone_output "\n[exec grep ^%%% ../new-cygwin1.dll]\n"
+}
+
+proc winsup_exit {} {
+}
diff --git a/winsup/cygwin/testsuite/winsup.api/devzero.c b/winsup/cygwin/testsuite/winsup.api/devzero.c
new file mode 100644 (file)
index 0000000..85a2615
--- /dev/null
@@ -0,0 +1,113 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+main()
+{
+  int fd, r, w, l;
+  char buf[1024];
+  char *v;
+
+  fd = open("/dev/zero", O_RDONLY);
+  if (fd < 0)
+    {
+      fprintf(stderr, "Unable to open /dev/zero for reading\n");
+      perror("The error was");
+      exit(1);
+    }
+
+  l = read(fd, buf, 1024);
+  if (l != 1024)
+    {
+      fprintf(stderr, "Asked to read 1024 bytes, got %d\n", l);
+      exit(1);
+    }
+
+  for (r=0; r<1024; r++)
+    if (buf[r] != 0)
+      {
+       fprintf(stderr, "/dev/zero returned a byte of %02x at offset %d\n",
+               buf[r], r);
+       exit(1);
+      }
+
+  l = lseek(fd, 4096, 0);
+  if (l != 0)
+    {
+      fprintf(stderr, "l == %d\n", l);
+      exit(1);
+    }
+
+  l = close(fd);
+  if (l != 0)
+    {
+      fprintf(stderr, "close: returned %d\n", l);
+      perror("The error was");
+      exit(1);
+    }
+
+  fd = open("/dev/zero", O_WRONLY);
+  if (fd < 0)
+    {
+      fprintf(stderr, "Unable to open /dev/zero for writing\n");
+      perror("The error was");
+      exit(1);
+    }
+
+  l = write(fd, buf, 1024);
+  if (l != 1024)
+    {
+      fprintf(stderr, "Asked to write 1024 bytes, got %d\n", l);
+      exit(1);
+    }
+
+  l = close(fd);
+  if (l != 0)
+    {
+      fprintf(stderr, "close: returned %d\n", l);
+      perror("The error was");
+      exit(1);
+    }
+
+  fd = open("/dev/zero", O_RDWR);
+  v = (char *)mmap(0, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+  if (v == (char *)-1)
+    {
+      fprintf(stderr, "mmap r/w /dev/zero failed\n");
+      perror("The error was");
+      exit(1);
+    }
+
+  for (r=0; r<65536; r++)
+    if (v[r] != 0)
+      {
+       fprintf(stderr, "mmap'd r/w /dev/zero has byte %d at offset %d\n",
+               v[r], r);
+       exit(1);
+      }
+  munmap(v, 65536);
+  close(fd);
+
+  fd = open("/dev/zero", O_RDONLY);
+  v = (char *)mmap(0, 65536, PROT_READ, MAP_SHARED, fd, 0);
+  if (v == (char *)-1)
+    {
+      fprintf(stderr, "mmap /dev/zero r/o failed\n");
+      perror("The error was");
+      exit(1);
+    }
+
+  for (r=0; r<65536; r++)
+    if (v[r] != 0)
+      {
+       fprintf(stderr, "mmap'd r/o /dev/zero has byte %d at offset %d\n",
+               v[r], r);
+       exit(1);
+      }
+  munmap(v, 65536);
+  close(fd);
+
+  exit(0);
+}
diff --git a/winsup/cygwin/testsuite/winsup.api/samples/sample-pass.c b/winsup/cygwin/testsuite/winsup.api/samples/sample-pass.c
new file mode 100644 (file)
index 0000000..893a0b6
--- /dev/null
@@ -0,0 +1,4 @@
+main()
+{
+  return 0;
+}
diff --git a/winsup/cygwin/testsuite/winsup.api/samples/xf-sample-fail.c b/winsup/cygwin/testsuite/winsup.api/samples/xf-sample-fail.c
new file mode 100644 (file)
index 0000000..d8beb90
--- /dev/null
@@ -0,0 +1,4 @@
+main()
+{
+  return 1;
+}
diff --git a/winsup/cygwin/testsuite/winsup.api/samples/xf-sample-miscompile.c b/winsup/cygwin/testsuite/winsup.api/samples/xf-sample-miscompile.c
new file mode 100644 (file)
index 0000000..bc0d21d
--- /dev/null
@@ -0,0 +1 @@
+foo bar grill
diff --git a/winsup/cygwin/testsuite/winsup.api/winsup.exp b/winsup/cygwin/testsuite/winsup.api/winsup.exp
new file mode 100644 (file)
index 0000000..5c85cc0
--- /dev/null
@@ -0,0 +1,43 @@
+source "site.exp"
+
+if { ! [isnative] } {
+    verbose "skipping winsup.api because it's not native"
+    return
+}
+
+set rv ""
+
+proc ws_spawn {cmd args} {
+    global rv
+    verbose "running $cmd\n"
+    catch [eval "exec $cmd"] rv
+    verbose send "catchCode = $rv\n"
+}
+
+foreach src [glob -nocomplain $srcdir/$subdir/*.c $srcdir/$subdir/*/*.c] {
+    regsub "^$srcdir/$subdir/" $src "" testcase
+    regsub ".c$" $testcase "" base
+    regsub ".*/" $base "" basename
+    regsub "/" $base "-" base
+
+    if { [regexp "^xf-" $basename] } {
+       setup_xfail "*-*-*"
+    } else {
+       clear_xfail
+    }
+
+    ws_spawn "$CC $src $rootme/new-libcygwin.a -o $base.exe"
+    if { $rv != "" } {
+       verbose -log "$rv"
+       fail "$testcase (compile)"
+    } else {
+        ws_spawn "../cygrun ./$base.exe"
+        if { $rv != "" } {
+           verbose -log "$testcase: $rv"
+           fail "$testcase (execute)"
+       } else {
+           pass "$testcase"
+           file delete "$base.exe"
+       }
+    }
+}
diff --git a/winsup/doc/sites.texinfo b/winsup/doc/sites.texinfo
new file mode 100644 (file)
index 0000000..adba7ad
--- /dev/null
@@ -0,0 +1,83 @@
+@chapter Cygwin Resources on the Internet
+
+@section FTP Sites
+
+@itemize @bullet
+@item North America:
+@itemize @bullet
+@item Alberta: @file{ftp://ftp.reversion.ca/pub/mirrors/cygwin/}
+@item Arizona: @file{ftp://ftp.ninemoons.com/pub/cygwin/}
+@item California: @file{ftp://ftp.yggdrasil.com/mirrors/site/sourceware.cygnus.com/pub/cygwin/}
+@item California (secondary): @file{ftp://sourceware.cygnus.com/pub/cygwin/}
+@item Kansas: @file{ftp://ftp.the-b.org/pub/cygwin/}
+@item Tennessee: @file{ftp://ftp.sunsite.utk.edu/pub/cygwin/}
+@end itemize
+
+@item Central America:
+@itemize @bullet
+@item Costa Rica: @file{ftp://sunsite.ulatina.ac.cr/cygwin/}
+@end itemize
+
+@item South America:
+@itemize @bullet
+@item Brazil: @file{ftp://ftp.unicamp.br/pub/gnu/=EXTRA=/cygnus/cygwin/}
+@end itemize
+
+@item Africa:
+@itemize @bullet
+@item South Africa: @file{ftp://ftp.sun.ac.za/sites/sourceware.cygnus.com/pub/cygwin/}
+@end itemize
+
+@item Asia:
+@itemize @bullet
+@item Japan: @file{ftp://ring.aist.go.jp/archives/pc/gnu-win32/}
+@item Japan: @file{ftp://ring.etl.go.jp/archives/pc/gnu-win32/}
+@item Japan: @file{ftp://ring.asahi-net.or.jp/archives/pc/gnu-win32/}
+@item Japan: @file{ftp://ring.crl.go.jp/archives/pc/gnu-win32/}
+@item Japan: @file{ftp://ring.astem.or.jp/archives/pc/gnu-win32/}
+@item Japan: @file{ftp://ring.jah.ne.jp/archives/pc/gnu-win32/}
+@item Japan: @file{ftp://ring.saitama-u.ac.jp/archives/pc/gnu-win32/}
+@item Japan: @file{ftp://ring.nacsis.ac.jp/archives/pc/gnu-win32/}
+@item Japan: @file{ftp://ring.exp.fujixerox.co.jp/archives/pc/gnu-win32/}
+@item Japan: @file{ftp://ring.so-net.ne.jp/archives/pc/gnu-win32/}
+@item Japan: @file{ftp://ring.ip-kyoto.ad.jp/archives/pc/gnu-win32/}
+@item Japan: @file{ftp://sysg.kek.jp/cygnus/cygwin/}
+@item Japan: @file{ftp://ftp.u-aizu.ac.jp/pub/gnu/gnu-win32/}
+@item Taiwan: @file{ftp://ftp1.sinica.edu.tw/pub3/CYGNUS/cygwin/}
+@end itemize
+
+@item Australasia:
+@itemize @bullet
+@item Australia: @file{ftp://mirror.aarnet.edu.au/pub/cygwin/}
+@end itemize
+
+@item Europe:
+@itemize @bullet
+@item Austria: @file{ftp://gd.tuwien.ac.at/gnu/cygwin/}
+@item Czech Republic: @file{ftp://sunsite.ms.mff.cuni.cz/MIRRORS/sourceware.cygnus.com/pub/cygwin/}
+@item Denmark: @file{ftp://sunsite.auc.dk/pub/cygwin/}
+@item Finland: @file{ftp://ftp.funet.fi/mirrors/sourceware.cygnus.com/pub/cygwin/}
+@item Germany: @file{ftp://ftp.franken.de/pub/win32/develop/gnuwin32/cygwin32/mirrors/cygnus/}
+@item Greece: @file{ftp://ftp.ntua.gr/pub/pc/cygwin/}
+@item Hungary: @file{ftp://ftp.szrmkk.hu/pub/gnu-win32/ftp.cygnus.com/}
+@item Italy: @file{ftp://ftp.unina.it/pub/Unix/cygnus/cygwin/}
+@item Poland: @file{ftp://sunsite.icm.edu.pl/pub/cygnus/cygwin/}
+@item Slovenia: @file{ftp://sunsite.fri.uni-lj.si/pub/gnu-win32/}
+@item Spain: @file{ftp://ftp.rediris.es/mirror/cygwin}
+@item Sweden: @file{ftp://ftp.sunet.se/pub/lang/cygwin/}
+@item Switzerland: @file{ftp://sunsite.cnlab-switch.ch/mirror/cygwin/}
+@item UK: @file{ftp://sunsite.org.uk/Mirrors/sourceware.cygnus.com/pub/cygwin/}
+@item UK: @file{ftp://ftp.ccp14.dl.ac.uk/ccp14/ftp-mirror/programming/cygnus-gnu-win32/pub/gnu-win32/}
+@end itemize
+@end itemize
+
+@section The Cygwin Project WWW Site
+
+The main WWW page for the Cygwin project is
+@file{http://sourceware.cygnus.com/cygwin/}.
+
+A page containing tool-specific information is
+@file{http://www.cygnus.com/pubs/gnupro/}.
+
+Links to additional documentation are accessible from the main
+web page.
diff --git a/winsup/mingw/dirent.c b/winsup/mingw/dirent.c
new file mode 100644 (file)
index 0000000..00041d7
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * dirent.c
+ *
+ * Derived from DIRLIB.C by Matt J. Weinstein 
+ * This note appears in the DIRLIB.H
+ * DIRLIB.H by M. J. Weinstein   Released to public domain 1-Jan-89
+ *
+ * Updated by Jeremy Bettis <jeremy@hksys.com>
+ * Significantly revised and rewinddir, seekdir and telldir added by Colin
+ * Peters <colin@fu.is.saga-u.ac.jp>
+ *
+ * $Revision$
+ * $Author$
+ * $Date$
+ *
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <io.h>
+#include <direct.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+
+#define SUFFIX "*"
+#define        SLASH   "\\"
+
+/*
+ * opendir
+ *
+ * Returns a pointer to a DIR structure appropriately filled in to begin
+ * searching a directory.
+ */
+DIR *
+opendir (const char *szPath)
+{
+  DIR *nd;
+  struct _stat statDir;
+
+  errno = 0;
+
+  if (!szPath)
+    {
+      errno = EFAULT;
+      return (DIR *) 0;
+    }
+
+  if (szPath[0] == '\0')
+    {
+      errno = ENOTDIR;
+      return (DIR *) 0;
+    }
+
+  /* Attempt to determine if the given path really is a directory. */
+  if (_stat (szPath, &statDir))
+    {
+      /* Error, stat should have set an error value. */
+      return (DIR *) 0;
+    }
+
+  if (!S_ISDIR (statDir.st_mode))
+    {
+      /* Error, stat reports not a directory. */
+      errno = ENOTDIR;
+      return (DIR *) 0;
+    }
+
+  /* Allocate enough space to store DIR structure and the complete
+   * directory path given. */
+  nd = (DIR *) malloc (sizeof (DIR) + strlen (szPath) + strlen (SLASH) +
+                      strlen (SUFFIX));
+
+  if (!nd)
+    {
+      /* Error, out of memory. */
+      errno = ENOMEM;
+      return (DIR *) 0;
+    }
+
+  /* Create the search expression. */
+  strcpy (nd->dd_name, szPath);
+
+  /* Add on a slash if the path does not end with one. */
+  if (nd->dd_name[0] != '\0' &&
+      nd->dd_name[strlen (nd->dd_name) - 1] != '/' &&
+      nd->dd_name[strlen (nd->dd_name) - 1] != '\\')
+    {
+      strcat (nd->dd_name, SLASH);
+    }
+
+  /* Add on the search pattern */
+  strcat (nd->dd_name, SUFFIX);
+
+  /* Initialize handle to -1 so that a premature closedir doesn't try
+   * to call _findclose on it. */
+  nd->dd_handle = -1;
+
+  /* Initialize the status. */
+  nd->dd_stat = 0;
+
+  /* Initialize the dirent structure. ino and reclen are invalid under
+   * Win32, and name simply points at the appropriate part of the
+   * findfirst_t structure. */
+  nd->dd_dir.d_ino = 0;
+  nd->dd_dir.d_reclen = 0;
+  nd->dd_dir.d_namlen = 0;
+  nd->dd_dir.d_name = nd->dd_dta.name;
+
+  return nd;
+}
+
+
+/*
+ * readdir
+ *
+ * Return a pointer to a dirent structure filled with the information on the
+ * next entry in the directory.
+ */
+struct dirent *
+readdir (DIR * dirp)
+{
+  errno = 0;
+
+  /* Check for valid DIR struct. */
+  if (!dirp)
+    {
+      errno = EFAULT;
+      return (struct dirent *) 0;
+    }
+
+  if (dirp->dd_dir.d_name != dirp->dd_dta.name)
+    {
+      /* The structure does not seem to be set up correctly. */
+      errno = EINVAL;
+      return (struct dirent *) 0;
+    }
+
+  if (dirp->dd_stat < 0)
+    {
+      /* We have already returned all files in the directory
+       * (or the structure has an invalid dd_stat). */
+      return (struct dirent *) 0;
+    }
+  else if (dirp->dd_stat == 0)
+    {
+      /* We haven't started the search yet. */
+      /* Start the search */
+      dirp->dd_handle = _findfirst (dirp->dd_name, &(dirp->dd_dta));
+
+      if (dirp->dd_handle == -1)
+       {
+         /* Whoops! Seems there are no files in that
+          * directory. */
+         dirp->dd_stat = -1;
+       }
+      else
+       {
+         dirp->dd_stat = 1;
+       }
+    }
+  else
+    {
+      /* Get the next search entry. */
+      if (_findnext (dirp->dd_handle, &(dirp->dd_dta)))
+       {
+         /* We are off the end or otherwise error. */
+         _findclose (dirp->dd_handle);
+         dirp->dd_handle = -1;
+         dirp->dd_stat = -1;
+       }
+      else
+       {
+         /* Update the status to indicate the correct
+          * number. */
+         dirp->dd_stat++;
+       }
+    }
+
+  if (dirp->dd_stat > 0)
+    {
+      /* Successfully got an entry. Everything about the file is
+       * already appropriately filled in except the length of the
+       * file name. */
+      dirp->dd_dir.d_namlen = strlen (dirp->dd_dir.d_name);
+      return &dirp->dd_dir;
+    }
+
+  return (struct dirent *) 0;
+}
+
+
+/*
+ * closedir
+ *
+ * Frees up resources allocated by opendir.
+ */
+int
+closedir (DIR * dirp)
+{
+  int rc;
+
+  errno = 0;
+  rc = 0;
+
+  if (!dirp)
+    {
+      errno = EFAULT;
+      return -1;
+    }
+
+  if (dirp->dd_handle != -1)
+    {
+      rc = _findclose (dirp->dd_handle);
+    }
+
+  /* Delete the dir structure. */
+  free (dirp);
+
+  return rc;
+}
+
+/*
+ * rewinddir
+ *
+ * Return to the beginning of the directory "stream". We simply call findclose
+ * and then reset things like an opendir.
+ */
+void
+rewinddir (DIR * dirp)
+{
+  errno = 0;
+
+  if (!dirp)
+    {
+      errno = EFAULT;
+      return;
+    }
+
+  if (dirp->dd_handle != -1)
+    {
+      _findclose (dirp->dd_handle);
+    }
+
+  dirp->dd_handle = -1;
+  dirp->dd_stat = 0;
+}
+
+/*
+ * telldir
+ *
+ * Returns the "position" in the "directory stream" which can be used with
+ * seekdir to go back to an old entry. We simply return the value in stat.
+ */
+long
+telldir (DIR * dirp)
+{
+  errno = 0;
+
+  if (!dirp)
+    {
+      errno = EFAULT;
+      return -1;
+    }
+  return dirp->dd_stat;
+}
+
+/*
+ * seekdir
+ *
+ * Seek to an entry previously returned by telldir. We rewind the directory
+ * and call readdir repeatedly until either dd_stat is the position number
+ * or -1 (off the end). This is not perfect, in that the directory may
+ * have changed while we weren't looking. But that is probably the case with
+ * any such system.
+ */
+void
+seekdir (DIR * dirp, long lPos)
+{
+  errno = 0;
+
+  if (!dirp)
+    {
+      errno = EFAULT;
+      return;
+    }
+
+  if (lPos < -1)
+    {
+      /* Seeking to an invalid position. */
+      errno = EINVAL;
+      return;
+    }
+  else if (lPos == -1)
+    {
+      /* Seek past end. */
+      if (dirp->dd_handle != -1)
+       {
+         _findclose (dirp->dd_handle);
+       }
+      dirp->dd_handle = -1;
+      dirp->dd_stat = -1;
+    }
+  else
+    {
+      /* Rewind and read forward to the appropriate index. */
+      rewinddir (dirp);
+
+      while ((dirp->dd_stat < lPos) && readdir (dirp))
+       ;
+    }
+}
diff --git a/winsup/mingw/profile/ChangeLog b/winsup/mingw/profile/ChangeLog
new file mode 100644 (file)
index 0000000..d6e94e8
--- /dev/null
@@ -0,0 +1,25 @@
+Thu Nov 18 00:20:00 1999  Mumit Khan  <khan@xraylith.wisc.edu>
+
+       * profil.c (profile_on): Set the profiler thread priority to
+       be time critical. Thanks to Pascal Obry <pascal_obry@csi.com>.
+
+Sun Nov  7 04:17:27 1999  Mumit Khan  <khan@xraylith.wisc.edu>
+
+       * Makefile.in (install): Fix target.
+
+Thu Nov  4 14:06:21 1999  Mumit Khan  <khan@xraylith.wisc.edu>
+
+       * Makefile.in: New file.
+       * configure.in: New file.
+       * configure: Generate.
+
+       * gcrt0.c (u_char, u_short, u_int, u_long): typedef for Mingw.
+       * gmon.h (u_char, u_short, u_int, u_long): Likewise.
+       * gmon.c (unistd.h): Include conditionally.
+       (sys/param.h): Likewise.
+       * mcount.c (sys/param.h): Likewise.
+       * profil.c (profile_on): thread id is DWORD, not int.
+
+       * Imported profiling sources from winsup-19991026 snapshot.
+
+
diff --git a/winsup/utils/cygwin.cc b/winsup/utils/cygwin.cc
new file mode 100644 (file)
index 0000000..1fba787
--- /dev/null
@@ -0,0 +1,126 @@
+/* cygwin.cc: general system debugging tool.
+
+   Copyright 1996, 1998 Cygnus Solutions.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+/* This program is intended to be a general tool for debugging cygwin.
+   Possibilities include
+   - dumping various internal data structures
+   - poking various values into system tables
+   - turning on strace'ing for arbitrary tasks
+   */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <windows.h>
+#include "winsup.h"
+
+static char *prog_name;
+
+static void
+usage (FILE *stream, int status)
+{
+  fprintf (stream, "\
+Usage: %s \\\n\
+       [-s|--strace pid mask]\\\n\
+       [-H|--help] [-V|--version]\n\
+",
+          prog_name);
+  exit (status);
+}
+
+static struct option long_options[] =
+{
+  { "version", no_argument, NULL, 'V' },
+  { "help", no_argument, NULL, 'H' },
+  { "strace", required_argument, NULL, 's' },
+  { 0, no_argument, 0, 0 }
+};
+
+struct strace_args
+{
+  int pid;
+  int mask;
+  char *fn;
+};
+
+/* Turn on strace'ing for the indicated pid.  */
+
+static void
+set_strace (strace_args *args)
+{
+  shared_info *s = cygwin_getshared ();
+
+  pinfo *p = s->p[args->pid];
+
+  if (!p)
+    {
+      fprintf (stderr, "%s: process %d not found\n", prog_name, args->pid);
+      exit (1);
+    }
+
+  p->strace_mask = args->mask;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int c;
+  int seen_flag_p = 0;
+  int show_version_p = 0;
+  int set_strace_p = 0;
+  strace_args strace_args;
+
+  prog_name = strrchr (argv[0], '/');
+  if (prog_name == NULL)
+    prog_name = strrchr (argv[0], '\\');
+  if (prog_name == NULL)
+    prog_name = argv[0];
+
+  while ((c = getopt_long (argc, argv, "HVs:", long_options, (int *) 0))
+        != EOF)
+    {
+      seen_flag_p = 1;
+
+      switch (c)
+       {
+       case 'H':
+         usage (stdout, 0);
+         break;
+       case 'V':
+         show_version_p = 1;
+         break;
+       case 's':
+         if (optind + 1 > argc)
+           usage (stderr, 1);
+         strace_args.pid = atoi (optarg);
+         if (optind < argc)
+           strace_args.mask = atoi (argv[optind++]);
+         if (optind < argc)
+           strace_args.fn = argv[optind++];
+         set_strace_p = 1;
+         break;
+       default:
+         usage (stderr, 1);
+         break;
+       }
+    }
+
+  if (show_version_p)
+    printf ("CYGWIN version ???\n");
+
+  if (!seen_flag_p || optind != argc)
+    usage (stderr, 1);
+
+  if (set_strace_p)
+    set_strace (&strace_args);
+
+  return 0;
+}
diff --git a/winsup/w32api/README b/winsup/w32api/README
new file mode 100644 (file)
index 0000000..9868968
--- /dev/null
@@ -0,0 +1,91 @@
+        Free headers and libraries for the Win32 API
+
+        Written by Anders Norlander
+        Send bug reports and questions to anorland@hem2.passagen.se
+        URL: http://www.acc.umu.se/~anorland/gnu-win32/
+
+* License
+
+  You are free to use, modify and copy this package. No restrictions
+  are imposed on programs or object files compiled with this library.
+  
+  You may not restrict the the usage of this library.
+
+  You may distribute this library as part of another package or as a
+  modified package if and only if you do *not* restrict the usage of
+  the portions consisting of this (optionally modified) library.
+
+  If distributed as part of another package, please notify the author
+  of what you are going to do.  If distributed as a modified package,
+  this file *must* be included.
+
+  This library is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+* What is it?
+
+  This is a free set of headers and import libraries for the Win32
+  API.  The library differs from the GNU Windows32 library in that I
+  have tried to use a file structure that mirrors Microsoft's.  I
+  don't like having *all* definitions in one single header as in the
+  GNU Windows32 library, I want a clean separation between different
+  parts of the API.
+
+  Daniel Guerrero Miralles contributed the DirectX 6.1 import
+  libraries and DirectX GUID definitions.
+
+  See the files NOTES and TODO for what needs to be done.
+
+* Size does matter
+
+  Since the WIN32 API is severely bloated (as most MS products seem to
+  be) the headers are designed to be as compact as possible, while
+  still being readable, in order to minimize parsing time.
+
+  The convention is to omit parameter names for function prototypes,
+  no excessive white space. Struct/union members are indented with tab
+  characters to make them readable. Comment only when necessary.
+
+  If you are contributing a patch please follow the above mentioned
+  convention. Make sure your editor does not convert tabs to spaces.
+
+* What do I need to use it?
+
+  The library is intended for use with egcs 1.1 or later but it is
+  possible to use with some other tools as well (although it is not
+  very useful). LCC-Win32, MSVC and Borland C++ 5.01 or higher may
+  work as well. The import libraries are for GNU tools only.
+
+  The library requires egcs 1.1 or later, since the `#pragma pack'
+  feature is used. Mumit Khan provides egcs patches and binaries for
+  win32 at `http://www.xraylith.wisc.edu/~khan/software/gnu-win32/'.
+
+  If you are going to use C++ COM objects, you will need a version of
+  egcs that recognizes the `comobject' attribute and then define
+  HAVE_COMOBJECT when compiling your program. Antonio Mendes de
+  Oliveira Neto has a prebuilt version at
+  `http://li.facens.br/EGCS-WIN32/english/index.html'. Note that this
+  is very experimental. If you want to use COM objects in C++ but with
+  C interfaces you must define CINTERFACE.
+
+  Objective-C programs cannot use COM functionality because of
+  conflicts between the interface define and the Objective-C
+  @interface directive.  There is also a conflict between the windows
+  Obj-C BOOL types. To avoid this conflict you should use WINBOOL in
+  all places where you would use BOOL in a C/C++ windows program. If
+  you include any windows headers *after* `windows.h' you must use the
+  method outlined below:
+
+  /* non-windows includes */
+  #include <objc/objc.h>
+  ...
+  /* windows specific headers */
+  #include <windows.h>
+  #define BOOL WINBOOL
+  #include <commctrl.h>
+  ...
+  #undef BOOL
+  ...
+  /* include other headers */
+
diff --git a/winsup/w32api/include/excpt.h b/winsup/w32api/include/excpt.h
new file mode 100644 (file)
index 0000000..39621a8
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _EXCPT_H
+#define _EXCPT_H
+
+/* FIXME: This will make some code compile. The programs will most
+   likely crash when an exception is raised, but at least they will
+   compile. */
+#ifdef __GNUC__
+#define __try
+#define __except(x) if (0) /* don't execute handler */
+#define __finally
+
+#define _try __try
+#define _except __except
+#define _finally __finally
+#endif
+
+#endif
This page took 0.166339 seconds and 5 git commands to generate.