Index: Makefile.linux-gcc
===================================================================
--- Makefile.linux-gcc	2009-09-03 13:32:06.000000000 -0700
+++ Makefile.linux-gcc	2009-07-01 12:08:39.000000000 -0700
@@ -14,7 +14,7 @@
 #### The toplevel directory of the source tree.  This is the directory
 #    that contains this "Makefile.in" and the "configure.in" script.
 #
-TOP = ../sqlite
+TOP = ..
 
 #### C Compiler and options for use in building executables that
 #    will run on the platform that is doing the build.
@@ -33,13 +33,13 @@
 #    appropriately:
 #
 #THREADSAFE = -DTHREADSAFE=1
-THREADSAFE = -DTHREADSAFE=0
+THREADSAFE = -DTHREADSAFE=1
 
 #### Specify any extra linker options needed to make the library
 #    thread safe
 #
 #THREADLIB = -lpthread
-THREADLIB = 
+THREADLIB = -lpthread
 
 #### Specify any extra libraries needed to access required functions.
 #
@@ -57,8 +57,29 @@
 #OPTS = -DSQLITE_DEBUG=2
 #OPTS = -DSQLITE_DEBUG=1
 #OPTS = 
-OPTS = -DNDEBUG=1
-OPTS += -DHAVE_FDATASYNC=1
+
+# These flags match those for SQLITE_CFLAGS in config.mk.  
+
+OPTS += -DNDEBUG
+OPTS += -DSQLITE_CORE
+OPTS += -DSQLITE_ENABLE_FTS1 -DSQLITE_ENABLE_BROKEN_FTS1
+OPTS += -DSQLITE_ENABLE_FTS2 -DSQLITE_ENABLE_BROKEN_FTS2
+OPTS += -DSQLITE_DEFAULT_FILE_PERMISSIONS=0600
+OPTS += -DHAVE_USLEEP=1
+
+# Additional SQLite tests.
+OPTS += -DSQLITE_MEMDEBUG=1
+
+# Don't include these ones, they break the SQLite tests.
+#  -DSQLITE_OMIT_ATTACH=1 \
+#  -DSQLITE_OMIT_LOAD_EXTENSION=1 \
+#  -DSQLITE_OMIT_VACUUM=1 \
+#  -DSQLITE_TRANSACTION_DEFAULT_IMMEDIATE=1 \
+
+SHELL_ICU = $(TOP)/src/shell_icu_linux.c -licuuc
+
+# TODO(shess) I can't see why I need this setting.
+OPTS += -DOS_UNIX=1
 
 #### The suffix to add to executable files.  ".exe" for windows.
 #    Nothing for unix.
@@ -91,16 +112,16 @@
 
 #### Extra compiler options needed for programs that use the TCL library.
 #
-#TCL_FLAGS =
+TCL_FLAGS = -I/usr/include/tcl8.4
 #TCL_FLAGS = -DSTATIC_BUILD=1
-TCL_FLAGS = -I/home/drh/tcltk/8.4linux
+#TCL_FLAGS = -I/home/drh/tcltk/8.4linux
 #TCL_FLAGS = -I/home/drh/tcltk/8.4win -DSTATIC_BUILD=1
 #TCL_FLAGS = -I/home/drh/tcltk/8.3hpux
 
 #### Linker options needed to link against the TCL library.
 #
-#LIBTCL = -ltcl -lm -ldl
-LIBTCL = /home/drh/tcltk/8.4linux/libtcl8.4g.a -lm -ldl
+LIBTCL = -ltcl8.4 -lm -ldl
+#LIBTCL = /home/drh/tcltk/8.4linux/libtcl8.4g.a -lm -ldl
 #LIBTCL = /home/drh/tcltk/8.4win/libtcl84s.a -lmsvcrt
 #LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc
 
Index: ext/fts1/fts1.c
===================================================================
--- ext/fts1/fts1.c	2009-09-04 13:37:41.000000000 -0700
+++ ext/fts1/fts1.c	2009-09-14 18:16:55.000000000 -0700
@@ -1225,10 +1225,6 @@
     break;
   }
   return rc;
-
- err:
-  sqlite3_finalize(s);
-  return rc;
 }
 
 /* Like sql_step_statement(), but convert SQLITE_DONE to SQLITE_OK.
Index: ext/icu/icu.c
===================================================================
--- ext/icu/icu.c	2009-09-03 13:32:06.000000000 -0700
+++ ext/icu/icu.c	2009-07-01 12:08:37.000000000 -0700
@@ -38,6 +38,11 @@
 
 #include <assert.h>
 
+// TODO(evanm): this is cut'n'pasted from fts2.c.  Why is it necessary?
+#if !defined(SQLITE_CORE)
+# define SQLITE_CORE 1
+#endif
+
 #ifndef SQLITE_CORE
   #include "sqlite3ext.h"
   SQLITE_EXTENSION_INIT1
Index: main.mk
===================================================================
--- main.mk	2009-09-10 12:18:17.000000000 -0700
+++ main.mk	2009-09-15 11:45:21.000000000 -0700
@@ -69,6 +69,16 @@
          walker.o where.o utf.o vtab.o
 
 
+LIBOBJ += fts1.o \
+	  fts1_hash.o \
+	  fts1_tokenizer1.o \
+	  fts1_porter.o
+LIBOBJ += fts2.o \
+	  fts2_hash.o \
+	  fts2_icu.o \
+	  fts2_porter.o \
+          fts2_tokenizer.o \
+	  fts2_tokenizer1.o
 
 # All of the source code files.
 #
@@ -243,6 +253,25 @@
   $(TOP)/src/test_thread.c \
   $(TOP)/src/test_wsd.c
 
+TESTSRC += \
+  $(TOP)/ext/fts1/fts1.c \
+  $(TOP)/ext/fts1/fts1.h \
+  $(TOP)/ext/fts1/fts1_hash.c \
+  $(TOP)/ext/fts1/fts1_hash.h \
+  $(TOP)/ext/fts1/fts1_porter.c \
+  $(TOP)/ext/fts1/fts1_tokenizer.h \
+  $(TOP)/ext/fts1/fts1_tokenizer1.c
+TESTSRC += \
+  $(TOP)/ext/fts2/fts2.c \
+  $(TOP)/ext/fts2/fts2.h \
+  $(TOP)/ext/fts2/fts2_hash.c \
+  $(TOP)/ext/fts2/fts2_hash.h \
+  $(TOP)/ext/fts2/fts2_icu.c \
+  $(TOP)/ext/fts2/fts2_porter.c \
+  $(TOP)/ext/fts2/fts2_tokenizer.h \
+  $(TOP)/ext/fts2/fts2_tokenizer.c \
+  $(TOP)/ext/fts2/fts2_tokenizer1.c
+
 #TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
 #TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c
 
@@ -314,8 +343,8 @@
 
 sqlite3$(EXE):	$(TOP)/src/shell.c libsqlite3.a sqlite3.h
 	$(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE)                  \
-		$(TOP)/src/shell.c                                  \
-		libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
+		$(TOP)/src/shell.c $(SHELL_ICU)                     \
+		libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB) -ldl
 
 objects: $(LIBOBJ_ORIG)
 
@@ -447,6 +476,20 @@
 	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c
 
 
+
+
+fts1.o:	$(TOP)/ext/fts1/fts1.c $(HDR) $(EXTHDR)
+	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts1/fts1.c
+
+fts1_hash.o:	$(TOP)/ext/fts1/fts1_hash.c $(HDR) $(EXTHDR)
+	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts1/fts1_hash.c
+
+fts1_tokenizer1.o:	$(TOP)/ext/fts1/fts1_tokenizer1.c $(HDR) $(EXTHDR)
+	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts1/fts1_tokenizer1.c
+
+fts1_porter.o:	$(TOP)/ext/fts1/fts1_porter.c $(HDR) $(EXTHDR)
+	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts1/fts1_porter.c
+
 # Rules for building test programs and for running tests
 #
 tclsqlite3:	$(TOP)/src/tclsqlite.c libsqlite3.a
@@ -484,6 +527,15 @@
 test:	testfixture$(EXE) sqlite3$(EXE)
 	./testfixture$(EXE) $(TOP)/test/veryquick.test
 
+ftstest:	testfixture$(EXE) sqlite3$(EXE)
+	./testfixture$(EXE) $(TOP)/test/fts.test
+
+fts1test:	testfixture$(EXE) sqlite3$(EXE)
+	./testfixture$(EXE) $(TOP)/test/fts1.test
+
+fts2test:	testfixture$(EXE) sqlite3$(EXE)
+	./testfixture$(EXE) $(TOP)/test/fts2.test
+
 sqlite3_analyzer$(EXE):	$(TOP)/src/tclsqlite.c sqlite3.c $(TESTSRC) \
 			$(TOP)/tool/spaceanal.tcl
 	sed \
Index: src/expr.c
===================================================================
--- src/expr.c	2009-09-08 12:16:11.000000000 -0700
+++ src/expr.c	2009-09-23 16:58:47.000000000 -0700
@@ -804,7 +804,9 @@
       }else{
         int nSize = exprStructSize(p);
         memcpy(zAlloc, p, nSize);
-        memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
+        if( EXPR_FULLSIZE>nSize ){
+          memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
+        }
       }
 
       /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
Index: src/func.c
===================================================================
--- src/func.c	2009-09-04 13:37:42.000000000 -0700
+++ src/func.c	2009-09-14 18:18:18.000000000 -0700
@@ -1020,7 +1020,7 @@
       }
     }
     if( zCharSet ){
-      sqlite3_free(azChar);
+      sqlite3_free((void*)azChar);
     }
   }
   sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
Index: src/os.h
===================================================================
--- src/os.h	2009-09-04 13:37:42.000000000 -0700
+++ src/os.h	2009-09-14 18:18:24.000000000 -0700
@@ -29,6 +29,10 @@
 ** will defined to either 1 or 0.  One of the four will be 1.  The other 
 ** three will be 0.
 */
+#ifdef OS_SYMBIAN
+# define SQLITE_OS_SYMBIAN 1
+# define SQLITE_OS_OTHER 1
+#endif
 #if defined(SQLITE_OS_OTHER)
 # if SQLITE_OS_OTHER==1
 #   undef SQLITE_OS_UNIX
Index: src/os_unix.c
===================================================================
--- src/os_unix.c	2009-09-10 12:14:55.000000000 -0700
+++ src/os_unix.c	2009-09-15 16:50:43.000000000 -0700
@@ -3215,6 +3215,7 @@
 ********************** End sqlite3_file Methods *******************************
 ******************************************************************************/
 
+
 /*
 ** This division contains definitions of sqlite3_io_methods objects that
 ** implement various file locking strategies.  It also contains definitions
@@ -3496,9 +3497,16 @@
 */
 
 /*
+** Initializes a unixFile structure with zeros.
+*/
+void initUnixFile(sqlite3_file* file) {
+  memset(file, 0, sizeof(unixFile));
+}
+
+/*
 ** Initialize the contents of the unixFile structure pointed to by pId.
 */
-static int fillInUnixFile(
+int fillInUnixFile(
   sqlite3_vfs *pVfs,      /* Pointer to vfs object */
   int h,                  /* Open file descriptor of file being opened */
   int dirfd,              /* Directory file descriptor */
Index: src/os_win.c
===================================================================
--- src/os_win.c	2009-09-10 15:08:39.000000000 -0700
+++ src/os_win.c	2009-09-14 18:26:16.000000000 -0700
@@ -1890,4 +1890,11 @@
   return SQLITE_OK;
 }
 
+void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle) {
+  winFile* winSQLite3File = (winFile*)file;
+  memset(file, 0, sizeof(*file));
+  winSQLite3File->pMethod = &winIoMethod;
+  winSQLite3File->h = handle;
+}
+
 #endif /* SQLITE_OS_WIN */
Index: src/pcache.c
===================================================================
--- src/pcache.c	2009-09-04 13:37:42.000000000 -0700
+++ src/pcache.c	2009-09-15 16:41:55.000000000 -0700
@@ -542,14 +542,12 @@
   return nPage;
 }
 
-#ifdef SQLITE_TEST
 /*
 ** Get the suggested cache-size value.
 */
 int sqlite3PcacheGetCachesize(PCache *pCache){
   return pCache->nMax;
 }
-#endif
 
 /*
 ** Set the suggested cache-size value.
Index: src/pcache.h
===================================================================
--- src/pcache.h	2009-09-04 13:37:42.000000000 -0700
+++ src/pcache.h	2009-09-15 16:41:52.000000000 -0700
@@ -139,9 +139,7 @@
 ** of the suggested cache-sizes.
 */
 void sqlite3PcacheSetCachesize(PCache *, int);
-#ifdef SQLITE_TEST
 int sqlite3PcacheGetCachesize(PCache *);
-#endif
 
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
 /* Try to return memory used by the pcache module to the main memory heap */
Index: src/shell.c
===================================================================
--- src/shell.c	2009-09-04 13:37:43.000000000 -0700
+++ src/shell.c	2009-09-15 11:32:08.000000000 -0700
@@ -3007,6 +3007,18 @@
   int i;
   int rc = 0;
 
+  /* Begin evanm patch. */
+#ifdef SQLITE_GEARS_DISABLE_SHELL_ICU
+  /* Gears doesn't use this. */
+#else
+  extern int sqlite_shell_init_icu();
+  if( !sqlite_shell_init_icu() ){
+    fprintf(stderr, "%s: warning: couldn't find icudt38.dll; "
+                    "queries against ICU FTS tables will fail.\n", argv[0]);
+  }
+#endif
+  /* End evanm patch. */
+
   Argv0 = argv[0];
   main_init(&data);
   stdin_is_interactive = isatty(0);
Index: src/sqlite3ext.h
===================================================================
--- src/sqlite3ext.h	2009-09-03 13:32:06.000000000 -0700
+++ src/sqlite3ext.h	2009-09-15 11:34:43.000000000 -0700
@@ -372,9 +372,15 @@
 #define sqlite3_next_stmt              sqlite3_api->next_stmt
 #define sqlite3_sql                    sqlite3_api->sql
 #define sqlite3_status                 sqlite3_api->status
-#endif /* SQLITE_CORE */
 
 #define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api = 0;
 #define SQLITE_EXTENSION_INIT2(v)  sqlite3_api = v;
 
+#else
+
+#define SQLITE_EXTENSION_INIT1
+#define SQLITE_EXTENSION_INIT2(v)
+
+#endif /* SQLITE_CORE */
+
 #endif /* _SQLITE3EXT_H_ */
Index: src/test_autoext.c
===================================================================
--- src/test_autoext.c	2009-09-03 13:32:06.000000000 -0700
+++ src/test_autoext.c	2009-09-15 18:14:35.000000000 -0700
@@ -17,7 +17,9 @@
 #include "sqlite3ext.h"
 
 #ifndef SQLITE_OMIT_LOAD_EXTENSION
+#ifndef SQLITE_CORE
 static SQLITE_EXTENSION_INIT1
+#endif
 
 /*
 ** The sqr() SQL function returns the square of its input value.
Index: src/quick.test
===================================================================
--- test/quick.test	2009-09-04 13:37:44.000000000 -0700
+++ test/quick.test	2009-09-15 11:34:54.000000000 -0700
@@ -58,6 +58,9 @@
   crash7.test
   delete3.test
   fts3.test
+  fts.test
+  fts1.test
+  fts2.test
   fuzz.test
   fuzz3.test
   fuzz_malloc.test
Index: src/os_symbian.cc
===================================================================
--- src/os_symbian.cc	1969-12-31 16:00:00.000000000 -0800
+++ src/os_symbian.cc	2009-07-01 12:08:37.000000000 -0700
@@ -0,0 +1,579 @@
+// Copyright 2008, Google Inc.
+//
+// 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. Neither the name of Google Inc. 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 AUTHOR ``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 AUTHOR 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.
+
+// This file contains code that is specific to Symbian.
+// Differently from the rest of SQLite, it is implemented in C++ as this is
+// the native language of the OS and all interfaces we need to use are C++.
+//
+// This file follows the Gears code style guidelines.
+
+#ifdef OS_SYMBIAN
+#include <coemain.h>
+#include <e32math.h>
+#include <f32file.h>
+#include <utf.h>
+
+extern "C" {
+#include "sqliteInt.h"
+#include "os_common.h"
+}
+
+const TInt kFileLockAttempts = 3;
+
+// The global file system session.
+RFs g_fs_session;
+
+static TInt UTF8ToUTF16(const char *in, TDes *out16) {
+  assert(in);
+  TPtrC8 in_des(reinterpret_cast<const unsigned char*>(in));
+  return CnvUtfConverter::ConvertToUnicodeFromUtf8(*out16, in_des);
+}
+
+static TInt UTF16ToUTF8(const TDesC16& in16, TDes8 *out8) {
+  return CnvUtfConverter::ConvertFromUnicodeToUtf8(*out8, in16);
+}
+
+// The SymbianFile structure is a subclass of sqlite3_file* specific to the
+// Symbian portability layer.
+struct SymbianFile {
+  const sqlite3_io_methods *methods;
+  RFile handle;              // The file handle
+  TUint8 lock_type;          // Type of lock currently held on this file
+  TUint16 shared_lock_byte;  // Randomly chosen byte used as a shared lock
+};
+
+static SymbianFile* ConvertToSymbianFile(sqlite3_file* const id) {
+  assert(id);
+  return reinterpret_cast<SymbianFile*>(id);
+}
+
+static int SymbianClose(sqlite3_file *id) {
+  SymbianFile *file_id = ConvertToSymbianFile(id);
+  file_id->handle.Close();
+  OpenCounter(-1);
+  return SQLITE_OK;
+}
+
+static int SymbianRead(sqlite3_file *id,
+                       void *buffer,
+                       int amount,
+                       sqlite3_int64 offset) {
+  assert(buffer);
+  assert(amount >=0);
+  assert(offset >=0);
+
+  SymbianFile* file_id = ConvertToSymbianFile(id);
+  TPtr8 dest(static_cast<unsigned char*>(buffer), amount);
+
+  if (KErrNone == file_id->handle.Read(offset, dest, amount)) {
+    if (dest.Length() == amount) {
+      return SQLITE_OK;
+    } else {
+      return SQLITE_IOERR_SHORT_READ;
+    }
+  } else {
+    return SQLITE_IOERR;
+  }
+}
+
+static int SymbianWrite(sqlite3_file *id,
+                        const void *buffer,
+                        int amount,
+                        sqlite3_int64 offset) {
+  assert(buffer);
+  assert(amount >=0);
+  assert(offset >=0);
+
+  SymbianFile *file_id = ConvertToSymbianFile(id);
+  TPtrC8 src(static_cast<const unsigned char*>(buffer), amount);
+  if (file_id->handle.Write(offset, src) != KErrNone) {
+    return SQLITE_IOERR_WRITE;
+  }
+
+  return SQLITE_OK;
+}
+
+static int SymbianTruncate(sqlite3_file *id, sqlite3_int64 bytes) {
+  assert(bytes >=0);
+
+  SymbianFile *file_id = ConvertToSymbianFile(id);
+  if (file_id->handle.SetSize(bytes) != KErrNone) {
+    return SQLITE_IOERR;
+  }
+  return SQLITE_OK;
+}
+
+static int SymbianSync(sqlite3_file *id, int /*flags*/) {
+  SymbianFile *file_id = ConvertToSymbianFile(id);
+  if (file_id->handle.Flush() != KErrNone) {
+    return SQLITE_IOERR;
+  } else {
+    return SQLITE_OK;
+  }
+}
+
+static int SymbianFileSize(sqlite3_file *id, sqlite3_int64 *size) {
+  assert(size);
+
+  SymbianFile *file_id = ConvertToSymbianFile(id);
+  TInt size_tmp;
+  if (file_id->handle.Size(size_tmp) != KErrNone) {
+    return SQLITE_IOERR;
+  }
+  *size = size_tmp;
+  return SQLITE_OK;
+}
+
+// File lock/unlock functions; see os_win.c for a description
+// of the algorithm used.
+static int GetReadLock(SymbianFile *file) {
+  file->shared_lock_byte = Math::Random() % (SHARED_SIZE - 1);
+  return file->handle.Lock(SHARED_FIRST + file->shared_lock_byte, 1);
+}
+
+static int UnlockReadLock(SymbianFile *file) {
+  return file->handle.UnLock(SHARED_FIRST + file->shared_lock_byte, 1);
+}
+
+static int SymbianLock(sqlite3_file *id, int lock_type) {
+  SymbianFile *file = ConvertToSymbianFile(id);
+  if (file->lock_type >= lock_type) {
+    return SQLITE_OK;
+  }
+
+  // Make sure the locking sequence is correct
+  assert(file->lock_type != NO_LOCK || lock_type == SHARED_LOCK);
+  assert(lock_type != PENDING_LOCK);
+  assert(lock_type != RESERVED_LOCK || file->lock_type == 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.
+  int new_lock_type = file->lock_type;
+  int got_pending_lock = 0;
+  int res = KErrNone;
+  if (file->lock_type == NO_LOCK ||
+         (lock_type == EXCLUSIVE_LOCK && file->lock_type == RESERVED_LOCK)) {
+    int count = kFileLockAttempts;
+    while (count-- > 0 &&
+        (res = file->handle.Lock(PENDING_BYTE, 1)) != KErrNone ) {
+      // Try 3 times to get the pending lock.  The pending lock might be
+      // held by another reader process who will release it momentarily.
+      OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
+      User::After(1000);
+    }
+    got_pending_lock = (res == KErrNone? 1 : 0);
+  }
+
+  // Acquire a shared lock
+  if (lock_type == SHARED_LOCK && res == KErrNone) {
+    assert(file->lock_type == NO_LOCK);
+    res = GetReadLock(file);
+    if (res == KErrNone) {
+      new_lock_type = SHARED_LOCK;
+    }
+  }
+
+  // Acquire a RESERVED lock
+  if (lock_type == RESERVED_LOCK && res == KErrNone) {
+    assert(file->lock_type == SHARED_LOCK);
+    res = file->handle.Lock(RESERVED_BYTE, 1);
+    if (res == KErrNone) {
+      new_lock_type = RESERVED_LOCK;
+    }
+  }
+
+  // Acquire a PENDING lock
+  if (lock_type == EXCLUSIVE_LOCK && res == KErrNone) {
+    new_lock_type = PENDING_LOCK;
+    got_pending_lock = 0;
+  }
+
+  // Acquire an EXCLUSIVE lock
+  if (lock_type == EXCLUSIVE_LOCK && res == KErrNone) {
+    assert(file->lock_type >= SHARED_LOCK);
+    res = UnlockReadLock(file);
+    OSTRACE2("unreadlock = %d\n", res);
+    res = file->handle.Lock(SHARED_FIRST, SHARED_SIZE);
+    if (res == KErrNone) {
+      new_lock_type = EXCLUSIVE_LOCK;
+    } else {
+      OSTRACE2("error-code = %d\n", GetLastError());
+      GetReadLock(file);
+    }
+  }
+
+  // If we are holding a PENDING lock that ought to be released, then
+  // release it now.
+  if (got_pending_lock && lock_type == SHARED_LOCK) {
+    file->handle.UnLock(PENDING_BYTE, 1);
+  }
+
+  // Update the state of the lock held in the file descriptor, then
+  // return the appropriate result code.
+  file->lock_type = new_lock_type;
+  if (res == KErrNone) {
+    return SQLITE_OK;
+  } else {
+    OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", file->handle,
+           lock_type, new_lock_type);
+    return SQLITE_BUSY;
+  }
+}
+
+static int SymbianUnlock(sqlite3_file *id, int lock_type) {
+  int type;
+  int rc = SQLITE_OK;
+  SymbianFile *file = ConvertToSymbianFile(id);
+  assert(lock_type <= SHARED_LOCK);
+  OSTRACE5("UNLOCK %d to %d was %d(%d)\n", file->handle, lock_type,
+          file->lock_type, file->shared_lock_byte);
+  type = file->lock_type;
+  if (type >= EXCLUSIVE_LOCK) {
+    file->handle.UnLock(SHARED_FIRST, SHARED_SIZE);
+    if (lock_type == SHARED_LOCK && GetReadLock(file) != KErrNone) {
+      // This should never happen.  We should always be able to
+      // reacquire the read lock
+      rc = SQLITE_IOERR_UNLOCK;
+    }
+  }
+  if (type >= RESERVED_LOCK) {
+    file->handle.UnLock(RESERVED_BYTE, 1);
+  }
+  if (lock_type == NO_LOCK && type >= SHARED_LOCK) {
+    UnlockReadLock(file);
+  }
+  if (type >= PENDING_LOCK) {
+    file->handle.UnLock(PENDING_BYTE, 1);
+  }
+  file->lock_type = lock_type;
+  return rc;
+}
+
+static int SymbianCheckReservedLock(sqlite3_file *id, int *result) {
+  int rc;
+  SymbianFile *file = ConvertToSymbianFile(id);
+  if (file->lock_type >= RESERVED_LOCK) {
+    rc = 1;
+    OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
+  } else {
+    rc = file->handle.Lock(RESERVED_BYTE, 1);
+    if (rc == KErrNone) {
+      file->handle.UnLock(RESERVED_BYTE, 1);
+    }
+    rc = !rc;
+    OSTRACE3("TEST WR-LOCK %d %d (remote)\n", file->handle, rc);
+  }
+  *result = rc;
+  return SQLITE_OK;
+}
+
+static int SymbianFileControl(sqlite3_file */*id*/,
+                              int /*op*/,
+                              void */*arg*/) {
+  return SQLITE_OK;
+}
+
+static int SymbianSectorSize(sqlite3_file */*id*/) {
+  return SQLITE_DEFAULT_SECTOR_SIZE;
+}
+
+static int SymbianDeviceCharacteristics(sqlite3_file */*id*/) {
+  return 0;
+}
+
+/*
+** This vector defines all the methods that can operate on a
+** sqlite3_file for Symbian.
+*/
+static const sqlite3_io_methods SymbianIoMethod = {
+  1,    // iVersion
+  SymbianClose,
+  SymbianRead,
+  SymbianWrite,
+  SymbianTruncate,
+  SymbianSync,
+  SymbianFileSize,
+  SymbianLock,
+  SymbianUnlock,
+  SymbianCheckReservedLock,
+  SymbianFileControl,
+  SymbianSectorSize,
+  SymbianDeviceCharacteristics
+};
+
+// ============================================================================
+// vfs methods begin here
+// ============================================================================
+static int SymbianOpen(sqlite3_vfs */*vfs*/,
+                       const char *name,
+                       sqlite3_file *id,
+                       int flags,
+                       int *out_flags) {
+  TUint desired_access;
+  TUint share_mode;
+  TInt err = KErrNone;
+  TFileName name_utf16;
+  SymbianFile *file = ConvertToSymbianFile(id);
+
+  if (out_flags) {
+    *out_flags = flags;
+  }
+
+  // if the name is NULL we have to open a temporary file.
+  if (!name) {
+    TPath private_path;
+    TFileName file_name;
+    if (g_fs_session.PrivatePath(private_path) != KErrNone) {
+      return SQLITE_CANTOPEN;
+    }
+    if (file->handle.Temp(g_fs_session,
+                          private_path,
+                          file_name,
+                          EFileWrite) !=
+        KErrNone) {
+      return SQLITE_CANTOPEN;
+    }
+    file->methods = &SymbianIoMethod;
+    file->lock_type = NO_LOCK;
+    file->shared_lock_byte = 0;
+    OpenCounter(+1);
+    return SQLITE_OK;
+  }
+
+  if (UTF8ToUTF16(name, &name_utf16) != KErrNone)
+    return SQLITE_CANTOPEN;
+
+  if (flags & SQLITE_OPEN_READWRITE) {
+    desired_access = EFileWrite;
+  } else {
+    desired_access = EFileRead;
+  }
+  if (flags & SQLITE_OPEN_MAIN_DB) {
+    share_mode = EFileShareReadersOrWriters;
+  } else {
+    share_mode = 0;
+  }
+
+  if (flags & SQLITE_OPEN_CREATE) {
+    err = file->handle.Create(g_fs_session,
+                              name_utf16,
+                              desired_access | share_mode);
+    if (err != KErrNone && err != KErrAlreadyExists) {
+      return SQLITE_CANTOPEN;
+    }
+  }
+
+  if (err != KErrNone) {
+    err = file->handle.Open(g_fs_session,
+                            name_utf16,
+                            desired_access | share_mode);
+    if (err != KErrNone && flags & SQLITE_OPEN_READWRITE) {
+      if (out_flags) {
+        *out_flags = (flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE;
+      }
+      desired_access = EFileRead;
+      err = file->handle.Open(g_fs_session,
+                              name_utf16,
+                              desired_access | share_mode);
+    }
+    if (err != KErrNone) {
+      return SQLITE_CANTOPEN;
+    }
+  }
+  file->methods = &SymbianIoMethod;
+  file->lock_type = NO_LOCK;
+  file->shared_lock_byte = 0;
+  OpenCounter(+1);
+  return SQLITE_OK;
+}
+
+static int SymbianDelete(sqlite3_vfs */*vfs*/,
+                         const char *file_name,
+                         int /*sync_dir*/) {
+  assert(file_name);
+  TFileName file_name_utf16;
+
+  if (UTF8ToUTF16(file_name, &file_name_utf16) != KErrNone) {
+    return SQLITE_ERROR;
+  }
+
+  TInt result = g_fs_session.Delete(file_name_utf16);
+  return (result == KErrNone || result == KErrPathNotFound)?
+         SQLITE_OK : SQLITE_IOERR_DELETE;
+}
+
+static int SymbianAccess(sqlite3_vfs */*vfs*/,
+                         const char *file_name,
+                         int flags,
+                         int *result) {
+  assert(file_name);
+  TEntry entry;
+  TFileName file_name_utf16;
+
+  if (UTF8ToUTF16(file_name, &file_name_utf16) != KErrNone) {
+    return SQLITE_ERROR;
+  }
+
+  if (g_fs_session.Entry(file_name_utf16, entry) != KErrNone) {
+    *result = 0;
+    return SQLITE_OK;
+  }
+
+  switch (flags) {
+    case SQLITE_ACCESS_READ:
+    case SQLITE_ACCESS_EXISTS:
+      *result = !entry.IsDir();
+      break;
+    case SQLITE_ACCESS_READWRITE:
+      *result = !entry.IsDir() && !entry.IsReadOnly();
+      break;
+    default:
+      return SQLITE_ERROR;
+  }
+
+  return SQLITE_OK;
+}
+
+static int SymbianFullPathname(sqlite3_vfs */*vfs*/,
+                               const char *relative,
+                               int full_len,
+                               char *full) {
+  assert(relative);
+  assert(full);
+
+  TParse parse;
+  TPath relative_utf16;
+  TPath base_path;
+  TPtr8 full_utf8(reinterpret_cast<unsigned char*>(full), full_len);
+
+  g_fs_session.PrivatePath(base_path);
+
+  if (UTF8ToUTF16(relative, &relative_utf16) != KErrNone) {
+    return SQLITE_ERROR;
+  }
+
+  if (parse.Set(relative_utf16, &base_path, NULL) != KErrNone) {
+    return SQLITE_ERROR;
+  }
+
+  TDesC full_utf16(parse.FullName());
+  if (UTF16ToUTF8(relative_utf16, &full_utf8) != KErrNone) {
+    return SQLITE_ERROR;
+  }
+
+  full_utf8.PtrZ();
+  return SQLITE_OK;
+}
+
+static int SymbianRandomness(sqlite3_vfs */*vfs*/, int buf_len, char *buffer) {
+  assert(buffer);
+  TInt64 seed = User::TickCount();
+  for (TInt i = 0; i < buf_len; i++) {
+    buffer[i] = Math::Rand(seed) % 255;
+  }
+  return SQLITE_OK;
+}
+
+static int SymbianSleep(sqlite3_vfs */*vfs*/, int microsec) {
+  User::After(microsec);
+  return SQLITE_OK;
+}
+
+int SymbianCurrentTime(sqlite3_vfs */*vfs*/, double *now) {
+  _LIT(kEpoch, "19700101:000000.000000");
+  assert(now);
+  TTime time;
+  TTime epoch_time(kEpoch);
+  TTimeIntervalSeconds interval;
+
+  time.HomeTime();
+  // calculate seconds elapsed since 1-1-1970
+  time.SecondsFrom(epoch_time, interval);
+
+  // Julian date @ 1-1-1970 = 2440587.5
+  // seconds per day = 86400.0
+  *now = interval.Int()/86400.0 + 2440587.5;
+  return SQLITE_OK;
+}
+
+static int SymbianGetLastError(sqlite3_vfs */*vfs*/,
+                               int /*buf_len*/,
+                               char */*buf*/) {
+  assert(buf[0] == '\0');
+  return 0;
+}
+
+// Interfaces for opening a shared library, finding entry points
+// within the shared library, and closing the shared library.
+// TODO(marcogelmi): implement.
+#define SymbianDlOpen  0
+#define SymbianDlError 0
+#define SymbianDlSym   0
+#define SymbianDlClose 0
+
+// Initialize and deinitialize the operating system interface.
+int sqlite3_os_init(void) {
+  static sqlite3_vfs symbian_vfs = {
+    1,                     // iVersion
+    sizeof(SymbianFile),   // szOsFile
+    KMaxPath,              // mxPathname
+    0,                     // pNext
+    "symbian",             // name
+    0,                     // pAppData
+
+    SymbianOpen,           // xOpen
+    SymbianDelete,         // xDelete
+    SymbianAccess,         // xAccess
+    SymbianFullPathname,   // xFullPathname
+    SymbianDlOpen,         // xDlOpen
+    SymbianDlError,        // xDlError
+    SymbianDlSym,          // xDlSym
+    SymbianDlClose,        // xDlClose
+    SymbianRandomness,     // xRandomness
+    SymbianSleep,          // xSleep
+    SymbianCurrentTime,    // xCurrentTime
+    SymbianGetLastError    // xGetLastError
+  };
+
+  if (g_fs_session.Connect() != KErrNone) {
+    return SQLITE_ERROR;
+  }
+
+  if (g_fs_session.ShareAuto() != KErrNone) {
+    g_fs_session.Close();
+    return SQLITE_ERROR;
+  }
+
+  sqlite3_vfs_register(&symbian_vfs, 1);
+  return SQLITE_OK;
+}
+
+int sqlite3_os_end(void) {
+  g_fs_session.Close();
+  return SQLITE_OK;
+}
+
+#endif /* OS_SYMBIAN*/
Index: src/shell_icu_linux.c
===================================================================
--- src/shell_icu_linux.c	1969-12-31 16:00:00.000000000 -0800
+++ src/shell_icu_linux.c	2009-09-17 13:48:49.000000000 -0700
@@ -0,0 +1,26 @@
+/* Copyright 2007 Google Inc. All Rights Reserved.
+**/
+
+#include <limits.h>
+#include <unistd.h>
+#include "unicode/udata.h"
+
+/*
+** This function attempts to load the ICU data tables from a data file.
+** Returns 0 on failure, nonzero on success.
+** This a hack job of icu_utils.cc:Initialize().  It's Chrome-specific code.
+*/
+int sqlite_shell_init_icu() {
+  char bin_dir[PATH_MAX + 1];
+  int bin_dir_size = readlink("/proc/self/exe", bin_dir, PATH_MAX);
+  if (bin_dir_size < 0 || bin_dir_size > PATH_MAX)
+    return 0;
+  bin_dir[bin_dir_size] = 0;;
+
+  u_setDataDirectory(bin_dir);
+  // Only look for the packaged data file;
+  // the default behavior is to look for individual files.
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setFileAccess(UDATA_ONLY_PACKAGES, &err);
+  return err == U_ZERO_ERROR;
+}
Index: src/shell_icu_win.c
===================================================================
--- src/shell_icu_win.c	1969-12-31 16:00:00.000000000 -0800
+++ src/shell_icu_win.c	2009-09-09 12:29:11.000000000 -0700
@@ -0,0 +1,34 @@
+/* Copyright 2007 Google Inc. All Rights Reserved.
+**/
+
+#include <windows.h>
+#include "unicode/udata.h"
+
+/*
+** This function attempts to load the ICU data tables from a DLL.
+** Returns 0 on failure, nonzero on success.
+** This a hack job of icu_utils.cc:Initialize().  It's Chrome-specific code.
+*/
+
+#define ICU_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat"
+int sqlite_shell_init_icu() {
+  HMODULE module;
+  FARPROC addr;
+  UErrorCode err;
+
+  wchar_t dll_name[12];
+  wsprintf(dll_name, L"icudt%2S.dll", U_ICU_VERSION_SHORT);
+  dll_name[11] = L'\0';
+  module = LoadLibrary(dll_name);
+  if (!module)
+    return 0;
+
+  addr = GetProcAddress(module, ICU_DATA_SYMBOL);
+  if (!addr)
+    return 0;
+
+  err = U_ZERO_ERROR;
+  udata_setCommonData(addr, &err);
+
+  return 1;
+}
Index: test/fts.test
===================================================================
--- test/fts.test	1969-12-31 16:00:00.000000000 -0800
+++ test/fts.test	2009-07-01 12:08:39.000000000 -0700
@@ -0,0 +1,61 @@
+#
+#    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 runs the fts tests.
+#
+# $Id$
+
+proc lshift {lvar} {
+  upvar $lvar l
+  set ret [lindex $l 0]
+  set l [lrange $l 1 end]
+  return $ret
+}
+while {[set arg [lshift argv]] != ""} {
+  switch -- $arg {
+    -sharedpagercache {
+      sqlite3_enable_shared_cache 1
+    }
+    default {
+      set argv [linsert $argv 0 $arg]
+      break
+    }
+  }
+}
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+rename finish_test really_finish_test
+proc finish_test {} {}
+set ISQUICK 1
+
+set EXCLUDE {
+  fts.test
+  fts1.test
+  fts2.test
+}
+
+if {[sqlite3 -has-codec]} {
+  # lappend EXCLUDE \
+  #  conflict.test
+}
+
+foreach testfile [lsort -dictionary [glob $testdir/fts*.test]] {
+  set tail [file tail $testfile]
+  puts "test: $tail"
+  if {[lsearch -exact $EXCLUDE $tail]>=0} continue
+  source $testfile
+  catch {db close}
+  if {$sqlite_open_file_count>0} {
+    puts "$tail did not close all files: $sqlite_open_file_count"
+    incr nErr
+    lappend ::failList $tail
+  }
+}
+source $testdir/misuse.test
+
+set sqlite_open_file_count 0
+really_finish_test
Index: test/fts1.test
===================================================================
--- test/fts1.test	1969-12-31 16:00:00.000000000 -0800
+++ test/fts1.test	2009-07-01 12:08:39.000000000 -0700
@@ -0,0 +1,61 @@
+#
+#    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 runs the fts tests.
+#
+# $Id$
+
+proc lshift {lvar} {
+  upvar $lvar l
+  set ret [lindex $l 0]
+  set l [lrange $l 1 end]
+  return $ret
+}
+while {[set arg [lshift argv]] != ""} {
+  switch -- $arg {
+    -sharedpagercache {
+      sqlite3_enable_shared_cache 1
+    }
+    default {
+      set argv [linsert $argv 0 $arg]
+      break
+    }
+  }
+}
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+rename finish_test really_finish_test
+proc finish_test {} {}
+set ISQUICK 1
+
+set EXCLUDE {
+  fts.test
+  fts1.test
+  fts2.test
+}
+
+if {[sqlite3 -has-codec]} {
+  # lappend EXCLUDE \
+  #  conflict.test
+}
+
+foreach testfile [lsort -dictionary [glob $testdir/fts1*.test]] {
+  set tail [file tail $testfile]
+  puts "test: $tail"
+  if {[lsearch -exact $EXCLUDE $tail]>=0} continue
+  source $testfile
+  catch {db close}
+  if {$sqlite_open_file_count>0} {
+    puts "$tail did not close all files: $sqlite_open_file_count"
+    incr nErr
+    lappend ::failList $tail
+  }
+}
+source $testdir/misuse.test
+
+set sqlite_open_file_count 0
+really_finish_test