]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Added support for OS/2. Ticket #1817 (CVS 3198)
authordrh <drh@noemail.net>
Sat, 3 Jun 2006 18:02:15 +0000 (18:02 +0000)
committerdrh <drh@noemail.net>
Sat, 3 Jun 2006 18:02:15 +0000 (18:02 +0000)
FossilOrigin-Name: 373246c2d1edaec1ce248ff875db48ce51d896f9

Makefile.in
aclocal.m4
configure
configure.ac
main.mk
manifest
manifest.uuid
src/os.h
src/os_os2.c [new file with mode: 0644]
src/os_os2.h [new file with mode: 0644]

index 2c584c3c2a0462d4fcf7c340e8978532b8a22c39..81ea22e95e3533ba3bb02b00d1d59c2fb4235e12 100644 (file)
@@ -125,7 +125,7 @@ TCC += -DSQLITE_OMIT_CURSOR
 LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btree.lo build.lo \
          callback.lo complete.lo date.lo \
          delete.lo expr.lo func.lo hash.lo insert.lo \
-         main.lo opcodes.lo os.lo os_unix.lo os_win.lo \
+         main.lo opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \
          pager.lo parse.lo pragma.lo prepare.lo printf.lo random.lo \
          select.lo table.lo tokenize.lo trigger.lo update.lo \
          util.lo vacuum.lo \
@@ -156,6 +156,7 @@ SRC = \
   $(TOP)/src/os.c \
   $(TOP)/src/os_unix.c \
   $(TOP)/src/os_win.c \
+  $(TOP)/src/os_os2.c \
   $(TOP)/src/pager.c \
   $(TOP)/src/pager.h \
   $(TOP)/src/parse.y \
@@ -193,6 +194,7 @@ TESTSRC = \
   $(TOP)/src/os.c \
   $(TOP)/src/os_unix.c \
   $(TOP)/src/os_win.c \
+  $(TOP)/src/os_os2.c \
   $(TOP)/src/pager.c \
   $(TOP)/src/pragma.c \
   $(TOP)/src/printf.c \
@@ -257,7 +259,7 @@ libtclsqlite3.la:   tclsqlite.lo libsqlite3.la
 
 sqlite3$(TEXE):        $(TOP)/src/shell.c libsqlite3.la sqlite3.h
        $(LTLINK) $(READLINE_FLAGS) $(LIBPTHREAD) \
-               -o sqlite3 $(TOP)/src/shell.c libsqlite3.la \
+               -o $@ $(TOP)/src/shell.c libsqlite3.la \
                $(LIBREADLINE) $(TLIBS)
 
 # This target creates a directory named "tsrc" and fills it with
@@ -352,6 +354,9 @@ os_unix.lo: $(TOP)/src/os_unix.c $(HDR)
 os_win.lo:     $(TOP)/src/os_win.c $(HDR)
        $(LTCOMPILE) -c $(TOP)/src/os_win.c
 
+os_os2.lo:     $(TOP)/src/os_os2.c $(HDR)
+       $(LTCOMPILE) -c $(TOP)/src/os_os2.c
+
 parse.lo:      parse.c $(HDR)
        $(LTCOMPILE) -c parse.c
 
index 852eb3134b70592c91e41ffc9aa938637dab27b2..b50b61e56a5e6ed87a0dd3deac3a185169d2d089 100644 (file)
@@ -151,7 +151,7 @@ ltmain="$ac_aux_dir/ltmain.sh"
 ofile="$default_ofile"
 with_gnu_ld="$lt_cv_prog_gnu_ld"
 
-AC_CHECK_TOOL(AR, ar, false)
+AC_CHECK_TOOL(AR, ar, AC_CHECK_TOOL(AR, emxomfar, false))
 AC_CHECK_TOOL(RANLIB, ranlib, :)
 AC_CHECK_TOOL(STRIP, strip, :)
 
index 39ee1c5b812fdf2b4d9b9e72acec2cc155364b11..90b92b0540a2c009fa6e77ef81bd3c59cb718e9a 100755 (executable)
--- a/configure
+++ b/configure
@@ -463,7 +463,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP CPP CXX CXXFLAGS ac_ct_CXX CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AWK program_prefix VERSION RELEASE VERSION_NUMBER BUILD_CC BUILD_CFLAGS BUILD_LIBS TARGET_CC TARGET_CFLAGS TARGET_LINK TARGET_LFLAGS TARGET_RANLIB TARGET_AR THREADSAFE TARGET_THREAD_LIB XTHREADCONNECT THREADSOVERRIDELOCKS ALLOWRELEASE TEMP_STORE BUILD_EXEEXT OS_UNIX OS_WIN TARGET_EXEEXT TCL_VERSION TCL_BIN_DIR TCL_SRC_DIR TCL_LIBS TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC HAVE_TCL TARGET_READLINE_LIBS TARGET_READLINE_INC TARGET_HAVE_READLINE TARGET_DEBUG TARGET_LIBS LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP CPP CXX CXXFLAGS ac_ct_CXX CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AWK program_prefix VERSION RELEASE VERSION_NUMBER BUILD_CC BUILD_CFLAGS BUILD_LIBS TARGET_CC TARGET_CFLAGS TARGET_LINK TARGET_LFLAGS TARGET_RANLIB TARGET_AR THREADSAFE TARGET_THREAD_LIB XTHREADCONNECT THREADSOVERRIDELOCKS ALLOWRELEASE TEMP_STORE BUILD_EXEEXT OS_UNIX OS_WIN OS_OS2 TARGET_EXEEXT TCL_VERSION TCL_BIN_DIR TCL_SRC_DIR TCL_LIBS TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC HAVE_TCL TARGET_READLINE_LIBS TARGET_READLINE_INC TARGET_HAVE_READLINE TARGET_DEBUG TARGET_LIBS LIBOBJS LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -1502,7 +1502,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
 # The following RCS revision string applies to configure.in
-# $Revision: 1.39 $
+# $Revision: 1.40 $
 
 #########
 # Programs needed
@@ -19695,13 +19695,26 @@ else
   TARGET_EXEEXT=$config_TARGET_EXEEXT
 fi
 if test "$TARGET_EXEEXT" = ".exe"; then
-  OS_UNIX=0
-  OS_WIN=1
-  tclsubdir=win
-  TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1"
+  if test $OS2_SHELL ; then
+    OS_UNIX=0
+    OS_WIN=0
+    OS_OS2=1
+    TARGET_CFLAGS="$TARGET_CFLAGS -DOS_OS2=1"
+    if test "$ac_compiler_gnu" == "yes" ; then
+      TARGET_CFLAGS="$TARGET_CFLAGS -Zomf -Zexe -Zmap"
+      BUILD_CFLAGS="$BUILD_CFLAGS -Zomf -Zexe"
+    fi
+  else
+    OS_UNIX=0
+    OS_WIN=1
+    OS_OS2=0
+    tclsubdir=win
+    TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1"
+  fi
 else
   OS_UNIX=1
   OS_WIN=0
+  OS_OS2=0
   tclsubdir=unix
   TARGET_CFLAGS="$TARGET_CFLAGS -DOS_UNIX=1"
 fi
@@ -21378,6 +21391,7 @@ s,@TEMP_STORE@,$TEMP_STORE,;t t
 s,@BUILD_EXEEXT@,$BUILD_EXEEXT,;t t
 s,@OS_UNIX@,$OS_UNIX,;t t
 s,@OS_WIN@,$OS_WIN,;t t
+s,@OS_OS2@,$OS_OS2,;t t
 s,@TARGET_EXEEXT@,$TARGET_EXEEXT,;t t
 s,@TCL_VERSION@,$TCL_VERSION,;t t
 s,@TCL_BIN_DIR@,$TCL_BIN_DIR,;t t
index 47deadc2a9b9a777105e211f73286b4da2650f25..85af8960d5b72af8e62dc4785eb2bd6b0c0307c1 100644 (file)
@@ -116,7 +116,7 @@ AC_INIT(src/sqlite.h.in)
 dnl Put the RCS revision string after AC_INIT so that it will also
 dnl show in in configure.
 # The following RCS revision string applies to configure.in
-# $Revision: 1.25 $
+# $Revision: 1.26 $
 
 #########
 # Programs needed
@@ -407,13 +407,26 @@ else
   TARGET_EXEEXT=$config_TARGET_EXEEXT
 fi
 if test "$TARGET_EXEEXT" = ".exe"; then
-  OS_UNIX=0
-  OS_WIN=1
-  tclsubdir=win
-  TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1"
+  if test $OS2_SHELL ; then
+    OS_UNIX=0
+    OS_WIN=0
+    OS_OS2=1
+    TARGET_CFLAGS="$TARGET_CFLAGS -DOS_OS2=1"
+    if test "$ac_compiler_gnu" == "yes" ; then
+      TARGET_CFLAGS="$TARGET_CFLAGS -Zomf -Zexe -Zmap"
+      BUILD_CFLAGS="$BUILD_CFLAGS -Zomf -Zexe"
+    fi
+  else
+    OS_UNIX=0
+    OS_WIN=1
+    OS_OS2=0
+    tclsubdir=win
+    TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1"
+  fi
 else
   OS_UNIX=1
   OS_WIN=0
+  OS_OS2=0
   tclsubdir=unix
   TARGET_CFLAGS="$TARGET_CFLAGS -DOS_UNIX=1"
 fi
@@ -421,6 +434,7 @@ fi
 AC_SUBST(BUILD_EXEEXT)
 AC_SUBST(OS_UNIX)
 AC_SUBST(OS_WIN)
+AC_SUBST(OS_OS2)
 AC_SUBST(TARGET_EXEEXT)
 
 ##########
diff --git a/main.mk b/main.mk
index 504676531ca13354836604a561a30a8393bf1875..580835f2897df3ba864ae6769a962ee9266f35c3 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -58,7 +58,7 @@ TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src
 LIBOBJ+= alter.o analyze.o attach.o auth.o btree.o build.o \
          callback.o complete.o date.o delete.o \
          expr.o func.o hash.o insert.o \
-         main.o opcodes.o os.o os_unix.o os_win.o \
+         main.o opcodes.o os.o os_os2.o os_unix.o os_win.o \
          pager.o parse.o pragma.o prepare.o printf.o random.o \
          select.o table.o tclsqlite.o tokenize.o trigger.o \
          update.o util.o vacuum.o \
@@ -87,6 +87,7 @@ SRC = \
   $(TOP)/src/legacy.c \
   $(TOP)/src/main.c \
   $(TOP)/src/os.c \
+  $(TOP)/src/os_os2.c \
   $(TOP)/src/os_unix.c \
   $(TOP)/src/os_win.c \
   $(TOP)/src/pager.c \
@@ -124,6 +125,7 @@ TESTSRC = \
   $(TOP)/src/date.c \
   $(TOP)/src/func.c \
   $(TOP)/src/os.c \
+  $(TOP)/src/os_os2.c \
   $(TOP)/src/os_unix.c \
   $(TOP)/src/os_win.c \
   $(TOP)/src/pager.c \
@@ -270,6 +272,9 @@ opcodes.h:  parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk
 os.o:  $(TOP)/src/os.c $(HDR)
        $(TCCX) -c $(TOP)/src/os.c
 
+os_os2.o:      $(TOP)/src/os_os2.c $(HDR)
+       $(TCCX) -c $(TOP)/src/os_os2.c
+
 os_unix.o:     $(TOP)/src/os_unix.c $(HDR)
        $(TCCX) -c $(TOP)/src/os_unix.c
 
index 5d59ed4b7e698d3b24085f5303fcde6827de7047..2800f241dc52b457b606c12f4d555982a0b2240d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,10 +1,10 @@
-C Do\snot\srecord\sblank\slines\sin\sthe\scommand-line\sediting\shistory\sof\sthe\sshell.\s(CVS\s3197)
-D 2006-06-03T17:37:26
-F Makefile.in 5d8dff443383918b700e495de42ec65bc1c8865b
+C Added\ssupport\sfor\sOS/2.\s\sTicket\s#1817\s(CVS\s3198)
+D 2006-06-03T18:02:16
+F Makefile.in 87b6d483513ab8a4e763775bc5b434d6b5c34963
 F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
 F VERSION 2bc3eace6a71bc4f2575679b944378b275e9412c
-F aclocal.m4 7daea4c35e88de30d5a3f6f7a2ab99720e803bbd
+F aclocal.m4 a8df0ae21d1ac797fa7d7eaa1703412bc61b973f
 F addopcodes.awk 701697fae48376375ec8532c3d04e910cfeef352
 F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
 F art/SQLite.eps 9b43cc99cfd2be687d386faea6862ea68d6a72b2
@@ -12,14 +12,14 @@ F art/SQLite.gif 1bbb94484963f1382e27e1c5e86dd0c1061eba2b
 F art/SQLiteLogo3.tiff b9e6bf022ae939bc986cddb8ab99583ca1b02cb3
 F config.guess 2103e94b15dc57112d7b9ee152c6fac5288895b4
 F config.sub 9bf686ec001ae7bc53f5b3563c90c62d4c6d48be
-F configure d454f3ef3a1cf42e91e97d06c27179d56a77c005 x
-F configure.ac f6c5246585d14bc1ee1773ae5b71ae6cafa7494a
+F configure 6be7b37dd811c43f59c119aa5a713f688a2184c4 x
+F configure.ac 83eaf11869cd893db6126c0ce77381a9cd264bad
 F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
 F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
 F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826
-F main.mk 33144e8ccfa885a4b0c1c03e85131bd6c541f30c
+F main.mk e3dd76266d1b62f1835b238bb0565900ab99fe14
 F mkdll.sh 919df5efde876194e3102c6ebc60657d38949909
 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d
 F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5
@@ -51,8 +51,10 @@ F src/legacy.c fa15d505dd4e45044177ee4d1c6aeaf8c836d390
 F src/main.c 928d93cfd5d72be3a619ee908182c9432151a99e
 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
 F src/os.c 59f05de8c5777c34876607114a2fbe55ae578235
-F src/os.h 93035a0e3b9dd05cdd0aaef32ea28ca28e02fe78
+F src/os.h 46fad85c707ad8643622bab9d894a642940850aa
 F src/os_common.h 108cd719c96a2b714b64e02aeabbd40684274e6a
+F src/os_os2.c 123cb394c069bc8c6a305830ffa2bc5f72e5b83a
+F src/os_os2.h e5f17dd69333632bbc3112881ea407c37d245eb3
 F src/os_test.c 49833426101f99aee4bb5f6a44b7c4b2029fda1c
 F src/os_test.h 903c93554c23d88f34f667f1979e4a1cee792af3
 F src/os_unix.c 17d91581a0ab478a06cb6f257b707a4c4a93e5a7
@@ -356,7 +358,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 4bf03c3bbc1303ed9b4059917e8d6a613b1510f3
-R b3aa39403a9b5a900b82638a005965c6
+P 0eabda82cd0d476a7e05ba4b027b819318aef9c3
+R 6acf85d509c19fb60080d44405f8852c
 U drh
-Z eb8ea770aee12d212e5ceb58cc64d4fe
+Z b6f82a7c0122f6042d20b908e87d0aa6
index 9f28723c8727c571907d7f6b049ca60cff55d4f5..a1dee26ce06be84084a0ff92e1b73c0b9359c276 100644 (file)
@@ -1 +1 @@
-0eabda82cd0d476a7e05ba4b027b819318aef9c3
\ No newline at end of file
+373246c2d1edaec1ce248ff875db48ce51d896f9
\ No newline at end of file
index b294346b050933674cf5ca50c8f8d05dbe7f76ef..8f7c650efc30c1157c07fa08576680d662de335f 100644 (file)
--- a/src/os.h
+++ b/src/os.h
 #   if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
 #     define OS_WIN 1
 #     define OS_UNIX 0
+#     define OS_OS2 0
+#   elif defined(_EMX_) || defined(_OS2) || defined(OS2) || defined(OS_OS2)
+#     define OS_WIN 0
+#     define OS_UNIX 0
+#     define OS_OS2 1
 #   else
 #     define OS_WIN 0
 #     define OS_UNIX 1
+#     define OS_OS2 0
 #  endif
 # else
 #  define OS_UNIX 0
+#  define OS_OS2 0
 # endif
 #else
 # ifndef OS_WIN
 #if OS_WIN
 # include <windows.h>
 # define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
+#elif OS_OS2
+# define INCL_DOSDATETIME
+# define INCL_DOSFILEMGR
+# define INCL_DOSERRORS
+# define INCL_DOSMISC
+# define INCL_DOSPROCESS
+# include <os2.h>
+# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP)
 #else
 # define SQLITE_TEMPNAME_SIZE 200
 #endif
@@ -72,7 +87,7 @@
 #endif
 
 /*
-** Define the interfaces for Unix and for Windows.
+** Define the interfaces for Unix, Windows, and OS/2.
 */
 #if OS_UNIX
 #define sqlite3OsOpenReadWrite      sqlite3UnixOpenReadWrite
 #define sqlite3OsFree               sqlite3GenericFree
 #define sqlite3OsAllocationSize     sqlite3GenericAllocationSize
 #endif
+#if OS_OS2
+#define sqlite3OsOpenReadWrite      sqlite3Os2OpenReadWrite
+#define sqlite3OsOpenExclusive      sqlite3Os2OpenExclusive
+#define sqlite3OsOpenReadOnly       sqlite3Os2OpenReadOnly
+#define sqlite3OsDelete             sqlite3Os2Delete
+#define sqlite3OsFileExists         sqlite3Os2FileExists
+#define sqlite3OsFullPathname       sqlite3Os2FullPathname
+#define sqlite3OsIsDirWritable      sqlite3Os2IsDirWritable
+#define sqlite3OsSyncDirectory      sqlite3Os2SyncDirectory
+#define sqlite3OsTempFileName       sqlite3Os2TempFileName
+#define sqlite3OsRandomSeed         sqlite3Os2RandomSeed
+#define sqlite3OsSleep              sqlite3Os2Sleep
+#define sqlite3OsCurrentTime        sqlite3Os2CurrentTime
+#define sqlite3OsEnterMutex         sqlite3Os2EnterMutex
+#define sqlite3OsLeaveMutex         sqlite3Os2LeaveMutex
+#define sqlite3OsInMutex            sqlite3Os2InMutex
+#define sqlite3OsThreadSpecificData sqlite3Os2ThreadSpecificData
+#define sqlite3OsMalloc             sqlite3GenericMalloc
+#define sqlite3OsRealloc            sqlite3GenericRealloc
+#define sqlite3OsFree               sqlite3GenericFree
+#define sqlite3OsAllocationSize     sqlite3GenericAllocationSize
+#endif
+
 
 /*
 ** If using an alternative OS interface, then we must have an "os_other.h"
diff --git a/src/os_os2.c b/src/os_os2.c
new file mode 100644 (file)
index 0000000..ee68d58
--- /dev/null
@@ -0,0 +1,965 @@
+/*
+** 2006 Feb 14
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains code that is specific to OS/2.
+*/
+#include "sqliteInt.h"
+#include "os.h"
+
+#if OS_OS2
+
+/*
+** Macros used to determine whether or not to use threads.
+*/
+#if defined(THREADSAFE) && THREADSAFE
+# define SQLITE_OS2_THREADS 1
+#endif
+
+/*
+** Include code that is common to all os_*.c files
+*/
+#include "os_common.h"
+
+/*
+** The os2File structure is subclass of OsFile specific for the OS/2
+** protability layer.
+*/
+typedef struct os2File os2File;
+struct os2File {
+  IoMethod const *pMethod;  /* Always the first entry */
+  HFILE h;                  /* Handle for accessing the file */
+  int delOnClose;           /* True if file is to be deleted on close */
+  char* pathToDel;          /* Name of file to delete on close */
+  unsigned char locktype;   /* Type of lock currently held on this file */
+};
+
+/*
+** Do not include any of the File I/O interface procedures if the
+** SQLITE_OMIT_DISKIO macro is defined (indicating that there database
+** will be in-memory only)
+*/
+#ifndef SQLITE_OMIT_DISKIO
+
+/*
+** Delete the named file
+*/
+int sqlite3Os2Delete( const char *zFilename ){
+  DosDelete( (PSZ)zFilename );
+  TRACE2( "DELETE \"%s\"\n", zFilename );
+  return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the named file exists.
+*/
+int sqlite3Os2FileExists( const char *zFilename ){
+  FILESTATUS3 fsts3ConfigInfo;
+  memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo));
+  return DosQueryPathInfo( (PSZ)zFilename, FIL_STANDARD,
+        &fsts3ConfigInfo, sizeof(FILESTATUS3) ) == NO_ERROR;
+}
+
+/* Forward declaration */
+int allocateOs2File( os2File *pInit, OsFile **pld );
+
+/*
+** Attempt to open a file for both reading and writing.  If that
+** fails, try opening it read-only.  If the file does not exist,
+** try to create it.
+**
+** On success, a handle for the open file is written to *id
+** and *pReadonly is set to 0 if the file was opened for reading and
+** writing or 1 if the file was opened read-only.  The function returns
+** SQLITE_OK.
+**
+** On failure, the function returns SQLITE_CANTOPEN and leaves
+** *id and *pReadonly unchanged.
+*/
+int sqlite3Os2OpenReadWrite(
+  const char *zFilename,
+  OsFile **pld,
+  int *pReadonly
+){
+  os2File  f;
+  HFILE    hf;
+  ULONG    ulAction;
+  APIRET   rc;
+
+  assert( *pld == 0 );
+  rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L,
+            FILE_ARCHIVED | FILE_NORMAL,
+                OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
+                OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM |
+                    OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL );
+  if( rc != NO_ERROR ){
+    rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L,
+            FILE_ARCHIVED | FILE_NORMAL,
+                OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
+                OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM |
+                        OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL );
+    if( rc != NO_ERROR ){
+        return SQLITE_CANTOPEN;
+    }
+    *pReadonly = 1;
+  }
+  else{
+    *pReadonly = 0;
+  }
+  f.h = hf;
+  f.locktype = NO_LOCK;
+  f.delOnClose = 0;
+  f.pathToDel = NULL;
+  OpenCounter(+1);
+  TRACE3( "OPEN R/W %d \"%s\"\n", hf, zFilename );
+  return allocateOs2File( &f, pld );
+}
+
+
+/*
+** Attempt to open a new file for exclusive access by this process.
+** The file will be opened for both reading and writing.  To avoid
+** a potential security problem, we do not allow the file to have
+** previously existed.  Nor do we allow the file to be a symbolic
+** link.
+**
+** If delFlag is true, then make arrangements to automatically delete
+** the file when it is closed.
+**
+** On success, write the file handle into *id and return SQLITE_OK.
+**
+** On failure, return SQLITE_CANTOPEN.
+*/
+int sqlite3Os2OpenExclusive( const char *zFilename, OsFile **pld, int delFlag ){
+  os2File  f;
+  HFILE    hf;
+  ULONG    ulAction;
+  APIRET   rc;
+
+  assert( *pld == 0 );
+  rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, FILE_NORMAL,
+            OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS,
+            OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM |
+                OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL );
+  if( rc != NO_ERROR ){
+    return SQLITE_CANTOPEN;
+  }
+
+  f.h = hf;
+  f.locktype = NO_LOCK;
+  f.delOnClose = delFlag ? 1 : 0;
+  f.pathToDel = delFlag ? sqlite3OsFullPathname( zFilename ) : NULL;
+  OpenCounter( +1 );
+  if( delFlag ) DosForceDelete( sqlite3OsFullPathname( zFilename ) );
+  TRACE3( "OPEN EX %d \"%s\"\n", hf, sqlite3OsFullPathname ( zFilename ) );
+  return allocateOs2File( &f, pld );
+}
+
+/*
+** Attempt to open a new file for read-only access.
+**
+** On success, write the file handle into *id and return SQLITE_OK.
+**
+** On failure, return SQLITE_CANTOPEN.
+*/
+int sqlite3Os2OpenReadOnly( const char *zFilename, OsFile **pld ){
+  os2File  f;
+  HFILE    hf;
+  ULONG    ulAction;
+  APIRET   rc;
+
+  assert( *pld == 0 );
+  rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L,
+            FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
+            OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM |
+                OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL );
+  if( rc != NO_ERROR ){
+    return SQLITE_CANTOPEN;
+  }
+  f.h = hf;
+  f.locktype = NO_LOCK;
+  f.delOnClose = 0;
+  f.pathToDel = NULL;
+  OpenCounter( +1 );
+  TRACE3( "OPEN RO %d \"%s\"\n", hf, zFilename );
+  return allocateOs2File( &f, pld );
+}
+
+/*
+** Attempt to open a file descriptor for the directory that contains a
+** file.  This file descriptor can be used to fsync() the directory
+** in order to make sure the creation of a new file is actually written
+** to disk.
+**
+** This routine is only meaningful for Unix.  It is a no-op under
+** OS/2 since OS/2 does not support hard links.
+**
+** On success, a handle for a previously open file is at *id is
+** updated with the new directory file descriptor and SQLITE_OK is
+** returned.
+**
+** On failure, the function returns SQLITE_CANTOPEN and leaves
+** *id unchanged.
+*/
+int os2OpenDirectory(
+  OsFile *id,
+  const char *zDirname
+){
+  return SQLITE_OK;
+}
+
+/*
+** If the following global variable points to a string which is the
+** name of a directory, then that directory will be used to store
+** temporary files.
+*/
+char *sqlite3_temp_directory = 0;
+
+/*
+** Create a temporary file name in zBuf.  zBuf must be big enough to
+** hold at least SQLITE_TEMPNAME_SIZE characters.
+*/
+int sqlite3Os2TempFileName( char *zBuf ){
+  static const unsigned char zChars[] =
+    "abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "0123456789";
+  int i, j;
+  PSZ zTempPath = 0;
+  if( DosScanEnv( "TEMP", &zTempPath ) ){
+    if( DosScanEnv( "TMP", &zTempPath ) ){
+      if( DosScanEnv( "TMPDIR", &zTempPath ) ){
+           ULONG ulDriveNum = 0, ulDriveMap = 0;
+           DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap );
+           sprintf( zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) );
+      }
+    }
+  }
+  for(;;){
+      sprintf( zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath );
+      j = strlen( zBuf );
+      sqlite3Randomness( 15, &zBuf[j] );
+      for( i = 0; i < 15; i++, j++ ){
+        zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
+      }
+      zBuf[j] = 0;
+      if( !sqlite3OsFileExists( zBuf ) ) break;
+  }
+  TRACE2( "TEMP FILENAME: %s\n", zBuf );
+  return SQLITE_OK;
+}
+
+/*
+** Close a file.
+*/
+int os2Close( OsFile **pld ){
+  os2File *pFile;
+  if( pld && (pFile = (os2File*)*pld)!=0 ){
+    TRACE2( "CLOSE %d\n", pFile->h );
+    DosClose( pFile->h );
+    pFile->locktype = NO_LOCK;
+    if( pFile->delOnClose != 0 ){
+        DosForceDelete( pFile->pathToDel );
+    }
+    *pld = 0;
+    OpenCounter( -1 );
+  }
+
+  return SQLITE_OK;
+}
+
+/*
+** Read data from a file into a buffer.  Return SQLITE_OK if all
+** bytes were read successfully and SQLITE_IOERR if anything goes
+** wrong.
+*/
+int os2Read( OsFile *id, void *pBuf, int amt ){
+  ULONG got;
+  assert( id!=0 );
+  SimulateIOError( SQLITE_IOERR );
+  TRACE3( "READ %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype );
+  DosRead( ((os2File*)id)->h, pBuf, amt, &got );
+  return (got == (ULONG)amt) ? SQLITE_OK : SQLITE_IOERR;
+}
+
+/*
+** Write data from a buffer into a file.  Return SQLITE_OK on success
+** or some other error code on failure.
+*/
+int os2Write( OsFile *id, const void *pBuf, int amt ){
+  APIRET rc=NO_ERROR;
+  ULONG wrote;
+  assert( id!=0 );
+  SimulateIOError( SQLITE_IOERR );
+  SimulateDiskfullError;
+  TRACE3( "WRITE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype );
+  while( amt > 0 &&
+      (rc = DosWrite( ((os2File*)id)->h, (PVOID)pBuf, amt, &wrote )) && wrote > 0 ){
+      amt -= wrote;
+      pBuf = &((char*)pBuf)[wrote];
+  }
+
+  return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK;
+}
+
+/*
+** Move the read/write pointer in a file.
+*/
+int os2Seek( OsFile *id, i64 offset ){
+  APIRET rc;
+  ULONG filePointer = 0L;
+  assert( id!=0 );
+  rc = DosSetFilePtr( ((os2File*)id)->h, offset, FILE_BEGIN, &filePointer );
+  TRACE3( "SEEK %d %lld\n", ((os2File*)id)->h, offset );
+  return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
+}
+
+/*
+** Make sure all writes to a particular file are committed to disk.
+*/
+int os2Sync( OsFile *id, int dataOnly ){
+  assert( id!=0 );
+  TRACE3( "SYNC %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype );
+  return DosResetBuffer( ((os2File*)id)->h ) ? SQLITE_IOERR : SQLITE_OK;
+}
+
+/*
+** Sync the directory zDirname. This is a no-op on operating systems other
+** than UNIX.
+*/
+int sqlite3Os2SyncDirectory( const char *zDirname ){
+  SimulateIOError( SQLITE_IOERR );
+  return SQLITE_OK;
+}
+
+/*
+** Truncate an open file to a specified size
+*/
+int os2Truncate( OsFile *id, i64 nByte ){
+  APIRET rc;
+  ULONG upperBits = nByte>>32;
+  assert( id!=0 );
+  TRACE3( "TRUNCATE %d %lld\n", ((os2File*)id)->h, nByte );
+  SimulateIOError( SQLITE_IOERR );
+  rc = DosSetFilePtr( ((os2File*)id)->h, nByte, FILE_BEGIN, &upperBits );
+  if( rc != NO_ERROR ){
+    return SQLITE_IOERR;
+  }
+  rc = DosSetFilePtr( ((os2File*)id)->h, 0L, FILE_END, &upperBits );
+  return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
+}
+
+/*
+** Determine the current size of a file in bytes
+*/
+int os2FileSize( OsFile *id, i64 *pSize ){
+  APIRET rc;
+  FILESTATUS3 fsts3FileInfo;
+  memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo));
+  assert( id!=0 );
+  SimulateIOError( SQLITE_IOERR );
+  rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) );
+  if( rc == NO_ERROR ){
+    *pSize = fsts3FileInfo.cbFile;
+    return SQLITE_OK;
+  }
+  else{
+    return SQLITE_IOERR;
+  }
+}
+
+/*
+** Acquire a reader lock.
+*/
+static int getReadLock( os2File *id ){
+  FILELOCK  LockArea,
+            UnlockArea;
+  memset(&LockArea, 0, sizeof(LockArea));
+  memset(&UnlockArea, 0, sizeof(UnlockArea));
+  LockArea.lOffset = SHARED_FIRST;
+  LockArea.lRange = SHARED_SIZE;
+  UnlockArea.lOffset = 0L;
+  UnlockArea.lRange = 0L;
+  return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L );
+}
+
+/*
+** Undo a readlock
+*/
+static int unlockReadLock( os2File *id ){
+  FILELOCK  LockArea,
+            UnlockArea;
+  memset(&LockArea, 0, sizeof(LockArea));
+  memset(&UnlockArea, 0, sizeof(UnlockArea));
+  LockArea.lOffset = 0L;
+  LockArea.lRange = 0L;
+  UnlockArea.lOffset = SHARED_FIRST;
+  UnlockArea.lRange = SHARED_SIZE;
+  return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L );
+}
+
+#ifndef SQLITE_OMIT_PAGER_PRAGMAS
+/*
+** Check that a given pathname is a directory and is writable
+**
+*/
+int sqlite3Os2IsDirWritable( char *zDirname ){
+  FILESTATUS3 fsts3ConfigInfo;
+  APIRET rc = NO_ERROR;
+  memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo));
+  if( zDirname==0 ) return 0;
+  if( strlen(zDirname)>CCHMAXPATH ) return 0;
+  rc = DosQueryPathInfo( (PSZ)zDirname, FIL_STANDARD, &fsts3ConfigInfo, sizeof(FILESTATUS3) );
+  if( rc != NO_ERROR ) return 0;
+  if( (fsts3ConfigInfo.attrFile & FILE_DIRECTORY) != FILE_DIRECTORY ) return 0;
+
+  return 1;
+}
+#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
+
+/*
+** Lock the file with the lock specified by parameter locktype - one
+** of the following:
+**
+**     (1) SHARED_LOCK
+**     (2) RESERVED_LOCK
+**     (3) PENDING_LOCK
+**     (4) EXCLUSIVE_LOCK
+**
+** Sometimes when requesting one lock state, additional lock states
+** are inserted in between.  The locking might fail on one of the later
+** transitions leaving the lock state different from what it started but
+** still short of its goal.  The following chart shows the allowed
+** transitions and the inserted intermediate states:
+**
+**    UNLOCKED -> SHARED
+**    SHARED -> RESERVED
+**    SHARED -> (PENDING) -> EXCLUSIVE
+**    RESERVED -> (PENDING) -> EXCLUSIVE
+**    PENDING -> EXCLUSIVE
+**
+** This routine will only increase a lock.  The os2Unlock() routine
+** erases all locks at once and returns us immediately to locking level 0.
+** It is not possible to lower the locking level one step at a time.  You
+** must go straight to locking level 0.
+*/
+int os2Lock( OsFile *id, int locktype ){
+  APIRET rc = SQLITE_OK;    /* Return code from subroutines */
+  APIRET res = 1;           /* Result of a windows lock call */
+  int newLocktype;       /* Set id->locktype to this value before exiting */
+  int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
+  FILELOCK  LockArea,
+            UnlockArea;
+  os2File *pFile = (os2File*)id;
+  memset(&LockArea, 0, sizeof(LockArea));
+  memset(&UnlockArea, 0, sizeof(UnlockArea));
+  assert( pFile!=0 );
+  TRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype );
+
+  /* If there is already a lock of this type or more restrictive on the
+  ** OsFile, do nothing. Don't use the end_lock: exit path, as
+  ** sqlite3OsEnterMutex() hasn't been called yet.
+  */
+  if( pFile->locktype>=locktype ){
+    return SQLITE_OK;
+  }
+
+  /* Make sure the locking sequence is correct
+  */
+  assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
+  assert( locktype!=PENDING_LOCK );
+  assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
+
+  /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
+  ** a SHARED lock.  If we are acquiring a SHARED lock, the acquisition of
+  ** the PENDING_LOCK byte is temporary.
+  */
+  newLocktype = pFile->locktype;
+  if( pFile->locktype==NO_LOCK
+   || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
+  ){
+    int cnt = 3;
+
+    LockArea.lOffset = PENDING_BYTE;
+    LockArea.lRange = 1L;
+    UnlockArea.lOffset = 0L;
+    UnlockArea.lRange = 0L;
+
+    while( cnt-->0 && (res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L) )!=NO_ERROR ){
+      /* Try 3 times to get the pending lock.  The pending lock might be
+      ** held by another reader process who will release it momentarily.
+      */
+      TRACE2( "could not get a PENDING lock. cnt=%d\n", cnt );
+      DosSleep(1);
+    }
+    gotPendingLock = res;
+  }
+
+  /* Acquire a shared lock
+  */
+  if( locktype==SHARED_LOCK && res ){
+    assert( pFile->locktype==NO_LOCK );
+    res = getReadLock(pFile);
+    if( res == NO_ERROR ){
+      newLocktype = SHARED_LOCK;
+    }
+  }
+
+  /* Acquire a RESERVED lock
+  */
+  if( locktype==RESERVED_LOCK && res ){
+    assert( pFile->locktype==SHARED_LOCK );
+    LockArea.lOffset = RESERVED_BYTE;
+    LockArea.lRange = 1L;
+    UnlockArea.lOffset = 0L;
+    UnlockArea.lRange = 0L;
+    res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
+    if( res == NO_ERROR ){
+      newLocktype = RESERVED_LOCK;
+    }
+  }
+
+  /* Acquire a PENDING lock
+  */
+  if( locktype==EXCLUSIVE_LOCK && res ){
+    newLocktype = PENDING_LOCK;
+    gotPendingLock = 0;
+  }
+
+  /* Acquire an EXCLUSIVE lock
+  */
+  if( locktype==EXCLUSIVE_LOCK && res ){
+    assert( pFile->locktype>=SHARED_LOCK );
+    res = unlockReadLock(pFile);
+    TRACE2( "unreadlock = %d\n", res );
+    LockArea.lOffset = SHARED_FIRST;
+    LockArea.lRange = SHARED_SIZE;
+    UnlockArea.lOffset = 0L;
+    UnlockArea.lRange = 0L;
+    res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
+    if( res == NO_ERROR ){
+      newLocktype = EXCLUSIVE_LOCK;
+    }else{
+      TRACE2( "error-code = %d\n", res );
+    }
+  }
+
+  /* If we are holding a PENDING lock that ought to be released, then
+  ** release it now.
+  */
+  if( gotPendingLock && locktype==SHARED_LOCK ){
+    LockArea.lOffset = 0L;
+    LockArea.lRange = 0L;
+    UnlockArea.lOffset = PENDING_BYTE;
+    UnlockArea.lRange = 1L;
+    DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
+  }
+
+  /* Update the state of the lock has held in the file descriptor then
+  ** return the appropriate result code.
+  */
+  if( res == NO_ERROR ){
+    rc = SQLITE_OK;
+  }else{
+    TRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
+           locktype, newLocktype );
+    rc = SQLITE_BUSY;
+  }
+  pFile->locktype = newLocktype;
+  return rc;
+}
+
+/*
+** This routine checks if there is a RESERVED lock held on the specified
+** file by this or any other process. If such a lock is held, return
+** non-zero, otherwise zero.
+*/
+int os2CheckReservedLock( OsFile *id ){
+  APIRET rc;
+  os2File *pFile = (os2File*)id;
+  assert( pFile!=0 );
+  if( pFile->locktype>=RESERVED_LOCK ){
+    rc = 1;
+    TRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, rc );
+  }else{
+    FILELOCK  LockArea,
+              UnlockArea;
+    memset(&LockArea, 0, sizeof(LockArea));
+    memset(&UnlockArea, 0, sizeof(UnlockArea));
+    LockArea.lOffset = RESERVED_BYTE;
+    LockArea.lRange = 1L;
+    UnlockArea.lOffset = 0L;
+    UnlockArea.lRange = 0L;
+    rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
+    if( rc == NO_ERROR ){
+      LockArea.lOffset = 0L;
+      LockArea.lRange = 0L;
+      UnlockArea.lOffset = RESERVED_BYTE;
+      UnlockArea.lRange = 1L;
+      rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
+    }
+    TRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, rc );
+  }
+  return rc;
+}
+
+/*
+** Lower the locking level on file descriptor id to locktype.  locktype
+** must be either NO_LOCK or SHARED_LOCK.
+**
+** If the locking level of the file descriptor is already at or below
+** the requested locking level, this routine is a no-op.
+**
+** It is not possible for this routine to fail if the second argument
+** is NO_LOCK.  If the second argument is SHARED_LOCK then this routine
+** might return SQLITE_IOERR;
+*/
+int os2Unlock( OsFile *id, int locktype ){
+  int type;
+  APIRET rc = SQLITE_OK;
+  os2File *pFile = (os2File*)id;
+  FILELOCK  LockArea,
+            UnlockArea;
+  memset(&LockArea, 0, sizeof(LockArea));
+  memset(&UnlockArea, 0, sizeof(UnlockArea));
+  assert( pFile!=0 );
+  assert( locktype<=SHARED_LOCK );
+  TRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype );
+  type = pFile->locktype;
+  if( type>=EXCLUSIVE_LOCK ){
+    LockArea.lOffset = 0L;
+    LockArea.lRange = 0L;
+    UnlockArea.lOffset = SHARED_FIRST;
+    UnlockArea.lRange = SHARED_SIZE;
+    DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
+    if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){
+      /* This should never happen.  We should always be able to
+      ** reacquire the read lock */
+      rc = SQLITE_IOERR;
+    }
+  }
+  if( type>=RESERVED_LOCK ){
+    LockArea.lOffset = 0L;
+    LockArea.lRange = 0L;
+    UnlockArea.lOffset = RESERVED_BYTE;
+    UnlockArea.lRange = 1L;
+    DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
+  }
+  if( locktype==NO_LOCK && type>=SHARED_LOCK ){
+    unlockReadLock(pFile);
+  }
+  if( type>=PENDING_LOCK ){
+    LockArea.lOffset = 0L;
+    LockArea.lRange = 0L;
+    UnlockArea.lOffset = PENDING_BYTE;
+    UnlockArea.lRange = 1L;
+    DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
+  }
+  pFile->locktype = locktype;
+  return rc;
+}
+
+/*
+** Turn a relative pathname into a full pathname.  Return a pointer
+** to the full pathname stored in space obtained from sqliteMalloc().
+** The calling function is responsible for freeing this space once it
+** is no longer needed.
+*/
+char *sqlite3Os2FullPathname( const char *zRelative ){
+  char *zFull = 0;
+  if( strchr(zRelative, ':') ){
+    sqlite3SetString( &zFull, zRelative, (char*)0 );
+  }else{
+    char zBuff[SQLITE_TEMPNAME_SIZE - 2] = {0};
+    char zDrive[1] = {0};
+    ULONG cbzFullLen = SQLITE_TEMPNAME_SIZE;
+    ULONG ulDriveNum = 0;
+    ULONG ulDriveMap = 0;
+    DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap );
+    DosQueryCurrentDir( 0L, zBuff, &cbzFullLen );
+    zFull = sqliteMalloc( cbzFullLen );
+    sprintf( zDrive, "%c", (char)('A' + ulDriveNum - 1) );
+    sqlite3SetString( &zFull, zDrive, ":\\", zBuff, "\\", zRelative, (char*)0 );
+  }
+  return zFull;
+}
+
+/*
+** The fullSync option is meaningless on os2, or correct me if I'm wrong.  This is a no-op.
+** From os_unix.c: Change the value of the fullsync flag in the given file descriptor.
+** From os_unix.c: ((unixFile*)id)->fullSync = v;
+*/
+static void os2SetFullSync( OsFile *id, int v ){
+  return;
+}
+
+/*
+** Return the underlying file handle for an OsFile
+*/
+static int os2FileHandle( OsFile *id ){
+  return (int)((os2File*)id)->h;
+}
+
+/*
+** Return an integer that indices the type of lock currently held
+** by this handle.  (Used for testing and analysis only.)
+*/
+static int os2LockState( OsFile *id ){
+  return ((os2File*)id)->locktype;
+}
+
+/*
+** This vector defines all the methods that can operate on an OsFile
+** for os2.
+*/
+static const IoMethod sqlite3Os2IoMethod = {
+  os2Close,
+  os2OpenDirectory,
+  os2Read,
+  os2Write,
+  os2Seek,
+  os2Truncate,
+  os2Sync,
+  os2SetFullSync,
+  os2FileHandle,
+  os2FileSize,
+  os2Lock,
+  os2Unlock,
+  os2LockState,
+  os2CheckReservedLock,
+};
+
+/*
+** Allocate memory for an OsFile.  Initialize the new OsFile
+** to the value given in pInit and return a pointer to the new
+** OsFile.  If we run out of memory, close the file and return NULL.
+*/
+int allocateOs2File( os2File *pInit, OsFile **pld ){
+  os2File *pNew;
+  pNew = sqliteMalloc( sizeof(*pNew) );
+  if( pNew==0 ){
+    DosClose( pInit->h );
+    *pld = 0;
+    return SQLITE_NOMEM;
+  }else{
+    *pNew = *pInit;
+    pNew->pMethod = &sqlite3Os2IoMethod;
+    pNew->locktype = NO_LOCK;
+    *pld = (OsFile*)pNew;
+    OpenCounter(+1);
+    return SQLITE_OK;
+  }
+}
+
+#endif /* SQLITE_OMIT_DISKIO */
+/***************************************************************************
+** Everything above deals with file I/O.  Everything that follows deals
+** with other miscellanous aspects of the operating system interface
+****************************************************************************/
+
+/*
+** Get information to seed the random number generator.  The seed
+** is written into the buffer zBuf[256].  The calling function must
+** supply a sufficiently large buffer.
+*/
+int sqlite3Os2RandomSeed( char *zBuf ){
+  /* We have to initialize zBuf to prevent valgrind from reporting
+  ** errors.  The reports issued by valgrind are incorrect - we would
+  ** prefer that the randomness be increased by making use of the
+  ** uninitialized space in zBuf - but valgrind errors tend to worry
+  ** some users.  Rather than argue, it seems easier just to initialize
+  ** the whole array and silence valgrind, even if that means less randomness
+  ** in the random seed.
+  **
+  ** When testing, initializing zBuf[] to zero is all we do.  That means
+  ** that we always use the same random number sequence.* This makes the
+  ** tests repeatable.
+  */
+  memset( zBuf, 0, 256 );
+  DosGetDateTime( (PDATETIME)zBuf );
+  return SQLITE_OK;
+}
+
+/*
+** Sleep for a little while.  Return the amount of time slept.
+*/
+int sqlite3Os2Sleep( int ms ){
+  DosSleep( ms );
+  return ms;
+}
+
+/*
+** Static variables used for thread synchronization
+*/
+static int inMutex = 0;
+#ifdef SQLITE_OS2_THREADS
+static ULONG mutexOwner;
+#endif
+
+/*
+** The following pair of routines implement mutual exclusion for
+** multi-threaded processes.  Only a single thread is allowed to
+** executed code that is surrounded by EnterMutex() and LeaveMutex().
+**
+** SQLite uses only a single Mutex.  There is not much critical
+** code and what little there is executes quickly and without blocking.
+*/
+void sqlite3Os2EnterMutex(){
+  PTIB ptib;
+#ifdef SQLITE_OS2_THREADS
+  DosEnterCritSec();
+  DosGetInfoBlocks( &ptib, NULL );
+  mutexOwner = ptib->tib_ptib2->tib2_ultid;
+#endif
+  assert( !inMutex );
+  inMutex = 1;
+}
+void sqlite3Os2LeaveMutex(){
+  PTIB ptib;
+  assert( inMutex );
+  inMutex = 0;
+#ifdef SQLITE_OS2_THREADS
+  DosGetInfoBlocks( &ptib, NULL );
+  assert( mutexOwner == ptib->tib_ptib2->tib2_ultid );
+  DosExitCritSec();
+#endif
+}
+
+/*
+** Return TRUE if the mutex is currently held.
+**
+** If the thisThreadOnly parameter is true, return true if and only if the
+** calling thread holds the mutex.  If the parameter is false, return
+** true if any thread holds the mutex.
+*/
+int sqlite3Os2InMutex( int thisThreadOnly ){
+#ifdef SQLITE_OS2_THREADS
+  PTIB ptib;
+  DosGetInfoBlocks( &ptib, NULL );
+  return inMutex>0 && (thisThreadOnly==0 || mutexOwner==ptib->tib_ptib2->tib2_ultid);
+#else
+  return inMutex>0;
+#endif
+}
+
+/*
+** The following variable, if set to a non-zero value, becomes the result
+** returned from sqlite3OsCurrentTime().  This is used for testing.
+*/
+#ifdef SQLITE_TEST
+int sqlite3_current_time = 0;
+#endif
+
+/*
+** Find the current time (in Universal Coordinated Time).  Write the
+** current time and date as a Julian Day number into *prNow and
+** return 0.  Return 1 if the time and date cannot be found.
+*/
+int sqlite3Os2CurrentTime( double *prNow ){
+  double now;
+  USHORT second, minute, hour,
+         day, month, year;
+  DATETIME dt;
+  DosGetDateTime( &dt );
+  second = (USHORT)dt.seconds;
+  minute = (USHORT)dt.minutes + dt.timezone;
+  hour = (USHORT)dt.hours;
+  day = (USHORT)dt.day;
+  month = (USHORT)dt.month;
+  year = (USHORT)dt.year;
+
+  /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html
+     http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */
+  /* Calculate the Julian days */
+  now = day - 32076 +
+    1461*(year + 4800 + (month - 14)/12)/4 +
+    367*(month - 2 - (month - 14)/12*12)/12 -
+    3*((year + 4900 + (month - 14)/12)/100)/4;
+
+  /* Add the fractional hours, mins and seconds */
+  now += (hour + 12.0)/24.0;
+  now += minute/1440.0;
+  now += second/86400.0;
+  *prNow = now;
+#ifdef SQLITE_TEST
+  if( sqlite3_current_time ){
+    *prNow = sqlite3_current_time/86400.0 + 2440587.5;
+  }
+#endif
+  return 0;
+}
+
+/*
+** Remember the number of thread-specific-data blocks allocated.
+** Use this to verify that we are not leaking thread-specific-data.
+** Ticket #1601
+*/
+#ifdef SQLITE_TEST
+int sqlite3_tsd_count = 0;
+# define TSD_COUNTER_INCR InterlockedIncrement( &sqlite3_tsd_count )
+# define TSD_COUNTER_DECR InterlockedDecrement( &sqlite3_tsd_count )
+#else
+# define TSD_COUNTER_INCR  /* no-op */
+# define TSD_COUNTER_DECR  /* no-op */
+#endif
+
+/*
+** If called with allocateFlag>1, then return a pointer to thread
+** specific data for the current thread.  Allocate and zero the
+** thread-specific data if it does not already exist necessary.
+**
+** If called with allocateFlag==0, then check the current thread
+** specific data.  Return it if it exists.  If it does not exist,
+** then return NULL.
+**
+** If called with allocateFlag<0, check to see if the thread specific
+** data is allocated and is all zero.  If it is then deallocate it.
+** Return a pointer to the thread specific data or NULL if it is
+** unallocated or gets deallocated.
+*/
+ThreadData *sqlite3Os2ThreadSpecificData( int allocateFlag ){
+  static ThreadData **s_ppTsd = NULL;
+  static const ThreadData zeroData = {0, 0, 0};
+  ThreadData *pTsd;
+
+  if( !s_ppTsd ){
+    sqlite3OsEnterMutex();
+    if( !s_ppTsd ){
+      PULONG pul;
+      APIRET rc = DosAllocThreadLocalMemory(1, &pul);
+      if( rc != NO_ERROR ){
+        sqlite3OsLeaveMutex();
+        return 0;
+      }
+      s_ppTsd = (ThreadData **)pul;
+    }
+    sqlite3OsLeaveMutex();
+  }
+  pTsd = *s_ppTsd;
+  if( allocateFlag>0 ){
+    if( !pTsd ){
+      pTsd = sqlite3OsMalloc( sizeof(zeroData) );
+      if( pTsd ){
+        *pTsd = zeroData;
+        *s_ppTsd = pTsd;
+        TSD_COUNTER_INCR;
+      }
+    }
+  }else if( pTsd!=0 && allocateFlag<0
+              && memcmp( pTsd, &zeroData, sizeof(ThreadData) )==0 ){
+    sqlite3OsFree(pTsd);
+    *s_ppTsd = NULL;
+    TSD_COUNTER_DECR;
+    pTsd = 0;
+  }
+  return pTsd;
+}
+#endif /* OS_OS2 */
diff --git a/src/os_os2.h b/src/os_os2.h
new file mode 100644 (file)
index 0000000..b738185
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+** 2004 May 22
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This header file defined OS-specific features for OS/2.
+*/
+#ifndef _SQLITE_OS_OS2_H_
+#define _SQLITE_OS_OS2_H_
+
+/*
+** standard include files.
+*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/*
+** Macros used to determine whether or not to use threads.  The
+** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for
+** Posix threads and SQLITE_W32_THREADS is defined if we are
+** synchronizing using Win32 threads.
+*/
+/* this mutex implementation only available with EMX */
+#if defined(THREADSAFE) && THREADSAFE
+# include <sys/builtin.h>
+# include <sys/smutex.h>
+# define SQLITE_OS2_THREADS 1
+#endif
+
+/*
+** The OsFile structure is a operating-system independing representation
+** of an open file handle.  It is defined differently for each architecture.
+**
+** This is the definition for Unix.
+**
+** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK,
+** PENDING_LOCK or EXCLUSIVE_LOCK.
+*/
+typedef struct OsFile OsFile;
+struct OsFile {
+     int h;        /* The file descriptor (LHANDLE) */
+     int locked;              /* True if this user holds the lock */
+     int delOnClose;          /* True if file is to be deleted on close */
+     char *pathToDel;         /* Name of file to delete on close */
+     unsigned char locktype;   /* The type of lock held on this fd */
+     unsigned char isOpen;   /* True if needs to be closed */
+     unsigned char fullSync;
+};
+
+/*
+** Maximum number of characters in a temporary file name
+*/
+#define SQLITE_TEMPNAME_SIZE 200
+
+/*
+** Minimum interval supported by sqlite3OsSleep().
+*/
+#define SQLITE_MIN_SLEEP_MS 1
+
+#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS
+# define SQLITE_DEFAULT_FILE_PERMISSIONS 0600
+#endif
+
+#endif /* _SQLITE_OS_OS2_H_ */