Updated 2013-12-15 21:33:49 by AMG
diff --git a/Android.mk b/Android.mk
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,224 @@
+LOCAL_PATH := $(call my-dir)
+
+###########################
+#
+# Tcl shared library
+#
+###########################
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := tcl
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/generic $(LOCAL_PATH)/unix
+
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
+
+LOCAL_SRC_FILES := \
+        libtommath/bncore.c \
+        libtommath/bn_reverse.c \
+        libtommath/bn_fast_s_mp_mul_digs.c \
+        libtommath/bn_fast_s_mp_sqr.c \
+        libtommath/bn_mp_add.c \
+        libtommath/bn_mp_add_d.c \
+        libtommath/bn_mp_and.c \
+        libtommath/bn_mp_clamp.c \
+        libtommath/bn_mp_clear.c \
+        libtommath/bn_mp_clear_multi.c \
+        libtommath/bn_mp_cmp.c \
+        libtommath/bn_mp_cmp_d.c \
+        libtommath/bn_mp_cmp_mag.c \
+        libtommath/bn_mp_copy.c \
+        libtommath/bn_mp_cnt_lsb.c \
+        libtommath/bn_mp_count_bits.c \
+        libtommath/bn_mp_div.c \
+        libtommath/bn_mp_div_d.c \
+        libtommath/bn_mp_div_2.c \
+        libtommath/bn_mp_div_2d.c \
+        libtommath/bn_mp_div_3.c \
+        libtommath/bn_mp_exch.c \
+        libtommath/bn_mp_expt_d.c \
+        libtommath/bn_mp_grow.c \
+        libtommath/bn_mp_init.c \
+        libtommath/bn_mp_init_copy.c \
+        libtommath/bn_mp_init_multi.c \
+        libtommath/bn_mp_init_set.c \
+        libtommath/bn_mp_init_set_int.c \
+        libtommath/bn_mp_init_size.c \
+        libtommath/bn_mp_karatsuba_mul.c \
+        libtommath/bn_mp_karatsuba_sqr.c \
+        libtommath/bn_mp_lshd.c \
+        libtommath/bn_mp_mod.c \
+        libtommath/bn_mp_mod_2d.c \
+        libtommath/bn_mp_mul.c \
+        libtommath/bn_mp_mul_2.c \
+        libtommath/bn_mp_mul_2d.c \
+        libtommath/bn_mp_mul_d.c \
+        libtommath/bn_mp_neg.c \
+        libtommath/bn_mp_or.c \
+        libtommath/bn_mp_radix_size.c \
+        libtommath/bn_mp_radix_smap.c \
+        libtommath/bn_mp_read_radix.c \
+        libtommath/bn_mp_rshd.c \
+        libtommath/bn_mp_set.c \
+        libtommath/bn_mp_set_int.c \
+        libtommath/bn_mp_shrink.c \
+        libtommath/bn_mp_sqr.c \
+        libtommath/bn_mp_sqrt.c \
+        libtommath/bn_mp_sub.c \
+        libtommath/bn_mp_sub_d.c \
+        libtommath/bn_mp_to_unsigned_bin.c \
+        libtommath/bn_mp_to_unsigned_bin_n.c \
+        libtommath/bn_mp_toom_mul.c \
+        libtommath/bn_mp_toom_sqr.c \
+        libtommath/bn_mp_toradix_n.c \
+        libtommath/bn_mp_unsigned_bin_size.c \
+        libtommath/bn_mp_xor.c \
+        libtommath/bn_mp_zero.c \
+        libtommath/bn_s_mp_add.c \
+        libtommath/bn_s_mp_mul_digs.c \
+        libtommath/bn_s_mp_sqr.c \
+        libtommath/bn_s_mp_sub.c \
+        generic/regcomp.c \
+        generic/regexec.c \
+        generic/regfree.c \
+        generic/regerror.c \
+        generic/tclAlloc.c \
+        generic/tclAssembly.c \
+        generic/tclAsync.c \
+        generic/tclBasic.c \
+        generic/tclBinary.c \
+        generic/tclCkalloc.c \
+        generic/tclClock.c \
+        generic/tclCmdAH.c \
+        generic/tclCmdIL.c \
+        generic/tclCmdMZ.c \
+        generic/tclCompCmds.c \
+        generic/tclCompCmdsGR.c \
+        generic/tclCompCmdsSZ.c \
+        generic/tclCompExpr.c \
+        generic/tclCompile.c \
+        generic/tclConfig.c \
+        generic/tclDate.c \
+        generic/tclDictObj.c \
+        generic/tclEncoding.c \
+        generic/tclEnsemble.c \
+        generic/tclEnv.c \
+        generic/tclEvent.c \
+        generic/tclExecute.c \
+        generic/tclFCmd.c \
+        generic/tclFileName.c \
+        generic/tclGet.c \
+        generic/tclHash.c \
+        generic/tclHistory.c \
+        generic/tclIndexObj.c \
+        generic/tclInterp.c \
+        generic/tclIO.c \
+        generic/tclIOCmd.c \
+        generic/tclIOGT.c \
+        generic/tclIOSock.c \
+        generic/tclIOUtil.c \
+        generic/tclIORChan.c \
+        generic/tclIORTrans.c \
+        generic/tclLink.c \
+        generic/tclListObj.c \
+        generic/tclLiteral.c \
+        generic/tclLoad.c \
+        generic/tclMain.c \
+        generic/tclNamesp.c \
+        generic/tclNotify.c \
+        generic/tclObj.c \
+        generic/tclOptimize.c \
+        generic/tclParse.c \
+        generic/tclPathObj.c \
+        generic/tclPipe.c \
+        generic/tclPkg.c \
+        generic/tclPkgConfig.c \
+        generic/tclPosixStr.c \
+        generic/tclPreserve.c \
+        generic/tclProc.c \
+        generic/tclRegexp.c \
+        generic/tclResolve.c \
+        generic/tclResult.c \
+        generic/tclScan.c \
+        generic/tclStubInit.c \
+        generic/tclStringObj.c \
+        generic/tclStrToD.c \
+        generic/tclTest.c \
+        generic/tclTestObj.c \
+        generic/tclTestProcBodyObj.c \
+        generic/tclThread.c \
+        generic/tclThreadAlloc.c \
+        generic/tclThreadJoin.c \
+        generic/tclThreadStorage.c \
+        generic/tclTimer.c \
+        generic/tclTrace.c \
+        generic/tclUtil.c \
+        generic/tclVar.c \
+        generic/tclZlib.c \
+        generic/tclOO.c \
+        generic/tclOOBasic.c \
+        generic/tclOOCall.c \
+        generic/tclOODefineCmds.c \
+        generic/tclOOInfo.c \
+        generic/tclOOMethod.c \
+        generic/tclOOStubInit.c \
+        generic/tclStubLib.c \
+        generic/tclTomMathStubLib.c \
+        generic/tclOOStubLib.c \
+        generic/zipfs.c \
+        unix/tclAppInit.c \
+        unix/tclLoadDl.c \
+        unix/tclUnixChan.c \
+        unix/tclUnixCompat.c \
+        unix/tclUnixEvent.c \
+        unix/tclUnixFCmd.c \
+        unix/tclUnixFile.c \
+        unix/tclUnixInit.c \
+        unix/tclUnixNotfy.c \
+        unix/tclUnixPipe.c \
+        unix/tclUnixSock.c \
+        unix/tclUnixTest.c \
+        unix/tclUnixThrd.c \
+        unix/tclUnixTime.c
+
+LOCAL_CFLAGS += \
+        -DHAVE_SYS_SELECT_H=1 \
+        -DHAVE_LIMITS_H=1 \
+        -DHAVE_UNISTD_H=1 \
+        -DHAVE_SYS_PARAM_H=1 \
+        -DPEEK_XCLOSEIM=1 \
+        -D_LARGEFILE64_SOURCE=1 \
+        -DTCL_WIDE_INT_TYPE="long long" \
+        -DTCL_SHLIB_EXT="\".so\"" \
+        -DHAVE_GETCWD=1 \
+        -DHAVE_OPENDIR=1 \
+        -DHAVE_STRSTR=1 \
+        -DHAVE_STRTOL=1 \
+        -DHAVE_STRTOLL=1 \
+        -DHAVE_STRTOULL=1 \
+        -DHAVE_TMPNAM=1 \
+        -DHAVE_WAITPID=1 \
+        -DUSE_TERMIOS=1 \
+        -DUSE_INTERP_ERRORLINE=1 \
+        -DHAVE_SYS_TIME_H=1 \
+        -DTIME_WITH_SYS_TIME=1 \
+        -DHAVE_TM_ZONE=1 \
+        -DHAVE_GMTIME_R=1 \
+        -DHAVE_LOCALTIME_R=1 \
+        -DHAVE_TM_GMTOFF=1 \
+        -DHAVE_TIMEZONE_VAR=1 \
+        -DHAVE_ST_BLKSIZE=1 \
+        -DSTDC_HEADERS=1 \
+        -DHAVE_SYS_IOCTL_H=1 \
+        -DVOID=void \
+        -DNO_UNION_WAIT=1 \
+        -DHAVE_LIBZ=1 \
+        -DZIPFS_IN_TCL=1 \
+        -DTCL_PACKAGE_PATH="\"/assets \"" \
+        -DTCL_LIBRARY="\"/assets/tcl8.4\"" \
+        -Dmain=tclsh
+
+LOCAL_LDLIBS := -ldl -lz
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/generic/tclInt.decls b/generic/tclInt.decls
--- a/generic/tclInt.decls
+++ b/generic/tclInt.decls
@@ -1006,6 +1006,18 @@ declare 249 {
 declare 250 {
     void TclSetSlaveCancelFlags(Tcl_Interp *interp, int flags, int force)
 }
+
+declare 251 {
+    int Tclzipfs_Init(Tcl_Interp *interp)
+}
+declare 252 {
+    int Tclzipfs_Mount(Tcl_Interp *interp, const char *zipname,
+        const char *mntpt, const char *passwd)
+}
+declare 253 {
+    int Tclzipfs_Unmount(Tcl_Interp *interp, const char *zipname)
+}
+
 
 ##############################################################################
 
diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h
--- a/generic/tclIntDecls.h
+++ b/generic/tclIntDecls.h
@@ -610,6 +610,15 @@ EXTERN char *                TclDoubleDigits(double dv
 /* 250 */
 EXTERN void                TclSetSlaveCancelFlags(Tcl_Interp *interp, int flags,
                                 int force);
+/* 251 */
+EXTERN int                Tclzipfs_Init(Tcl_Interp *interp);
+/* 252 */
+EXTERN int                Tclzipfs_Mount(Tcl_Interp *interp,
+                                const char *zipname, const char *mntpt,
+                                const char *passwd);
+/* 253 */
+EXTERN int                Tclzipfs_Unmount(Tcl_Interp *interp,
+                                const char *zipname);
 
 typedef struct TclIntStubs {
     int magic;
@@ -866,6 +875,9 @@ typedef struct TclIntStubs {
     int (*tclCopyChannel) (Tcl_Interp *interp, Tcl_Channel inChan, Tcl_Channel outChan, Tcl_WideInt toRead, Tcl_Obj *cmdPtr); /* 248 */
     char * (*tclDoubleDigits) (double dv, int ndigits, int flags, int *decpt, int *signum, char **endPtr); /* 249 */
     void (*tclSetSlaveCancelFlags) (Tcl_Interp *interp, int flags, int force); /* 250 */
+    int (*tclzipfs_Init) (Tcl_Interp *interp); /* 251 */
+    int (*tclzipfs_Mount) (Tcl_Interp *interp, const char *zipname, const char *mntpt, const char *passwd); /* 252 */
+    int (*tclzipfs_Unmount) (Tcl_Interp *interp, const char *zipname); /* 253 */
 } TclIntStubs;
 
 #ifdef __cplusplus
@@ -1297,6 +1309,12 @@ extern const TclIntStubs *tclIntStubsPtr
         (tclIntStubsPtr->tclDoubleDigits) /* 249 */
 #define TclSetSlaveCancelFlags \
         (tclIntStubsPtr->tclSetSlaveCancelFlags) /* 250 */
+#define Tclzipfs_Init \
+        (tclIntStubsPtr->tclzipfs_Init) /* 251 */
+#define Tclzipfs_Mount \
+        (tclIntStubsPtr->tclzipfs_Mount) /* 252 */
+#define Tclzipfs_Unmount \
+        (tclIntStubsPtr->tclzipfs_Unmount) /* 253 */
 
 #endif /* defined(USE_TCL_STUBS) */
 
diff --git a/generic/tclMain.c b/generic/tclMain.c
--- a/generic/tclMain.c
+++ b/generic/tclMain.c
@@ -34,6 +34,10 @@
 
 #include "tclInt.h"
 
+#ifdef ZIPFS_IN_TCL
+#include "zipfs.h"
+#endif
+
 /*
  * The default prompt used when the user has not overridden it.
  */
@@ -308,10 +312,15 @@ Tcl_MainEx(
 {
     Tcl_Obj *path, *resultPtr, *argvPtr, *appName;
     const char *encodingName = NULL;
-    int code, exitCode = 0;
+    int code, length, exitCode = 0;
     Tcl_MainLoopProc *mainLoopProc;
     Tcl_Channel chan;
     InteractiveState is;
+    CONST char *zipFile = NULL;
+    int autoRun = 1;
+#ifdef ZIPFS_IN_TCL
+    int zipOk = TCL_ERROR;
+#endif
 
     TclpSetInitialEncodings();
     TclpFindExecutable((const char *)argv[0]);
@@ -329,6 +338,19 @@ Tcl_MainEx(
      */
 
     if (NULL == Tcl_GetStartupScript(NULL)) {
+        if (argc > 1) {
+            length = strlen(argv[1]);
+            if ((length >= 2) && (strncmp(argv[1], "-zip", length) == 0)) {
+                argc--;
+                argv++;
+                if ((argc > 1) && (argv[1][0] != '-')) {
+                    zipFile = argv[1];
+                    autoRun = 0;
+                    argc--;
+                    argv++;
+                }
+            } 
+        }
         /*
          * Check whether first 3 args (argv[1] - argv[3]) look like
          *  -encoding ENCODING FILENAME
@@ -377,6 +399,48 @@ Tcl_MainEx(
     Tcl_SetVar2Ex(interp, "tcl_interactive", NULL,
             Tcl_NewIntObj(!path && is.tty), TCL_GLOBAL_ONLY);
 
+
+#ifdef ZIPFS_IN_TCL
+    zipOk = Tclzipfs_Init(interp);
+    if (zipOk == TCL_OK) {
+        int relax = 0;
+
+        if (zipFile == NULL) {
+            relax = 1;
+#ifdef ANDROID
+            zipFile = getenv("PACKAGE_CODE_PATH");
+            if (zipFile == NULL) {
+                zipFile = Tcl_GetNameOfExecutable();
+            }
+#else
+            zipFile = Tcl_GetNameOfExecutable();
+#endif
+        }
+        if (zipFile != NULL) {
+            zipOk = Tclzipfs_Mount(interp, zipFile, "", NULL);
+            if (!relax && (zipOk != TCL_OK)) {
+                exitCode = 1;
+                goto done;
+            }
+        } else {
+            zipOk = TCL_ERROR;
+        }
+        Tcl_ResetResult(interp);
+    }
+    if (zipOk == TCL_OK) {
+        char *tcl_lib = "/assets/tcl" TCL_VERSION;
+        char *tcl_pkg = "/assets";
+
+        Tcl_SetVar2(interp, "env", "TCL_LIBRARY", tcl_lib, TCL_GLOBAL_ONLY);
+        Tcl_SetVar(interp, "tcl_libPath", tcl_lib, TCL_GLOBAL_ONLY);
+        Tcl_SetVar(interp, "tcl_library", tcl_lib, TCL_GLOBAL_ONLY);
+        Tcl_SetVar(interp, "tcl_pkgPath", tcl_pkg, TCL_GLOBAL_ONLY);
+        Tcl_SetVar(interp, "auto_path", tcl_lib,
+                   TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT);
+
+    }
+#endif
+    
     /*
      * Invoke application-specific initialization.
      */
@@ -390,6 +454,9 @@ Tcl_MainEx(
             Tcl_WriteObj(chan, Tcl_GetObjResult(interp));
             Tcl_WriteChars(chan, "\n", 1);
         }
+        if (zipFile != NULL) {
+            Tcl_DeleteInterp(interp);
+        }
     }
     if (Tcl_InterpDeleted(interp)) {
         goto done;
@@ -406,6 +473,77 @@ Tcl_MainEx(
         Tcl_CreateExitHandler(FreeMainInterp, interp);
     }
 
+#ifdef ZIPFS_IN_TCL
+    /*
+     * Setup auto loading info to point to mounted ZIP file.
+     */
+
+    if (zipOk == TCL_OK) {
+        char *tcl_lib = "/assets/tcl" TCL_VERSION;
+        char *tcl_pkg = "/assets";
+
+        Tcl_SetVar(interp, "tcl_libPath", tcl_lib, TCL_GLOBAL_ONLY);
+        Tcl_SetVar(interp, "tcl_library", tcl_lib, TCL_GLOBAL_ONLY);
+        Tcl_SetVar(interp, "tcl_pkgPath", tcl_pkg, TCL_GLOBAL_ONLY);
+
+        /*
+         * We need to re-init encoding (after initializing Tcl),
+         * otherwise "encoding system" will return "identity"
+         */
+
+        TclpSetInitialEncodings();
+    }
+
+    /*
+     * Set embedded application startup file, if any.
+     */
+
+    if ((zipOk == TCL_OK) && autoRun) {
+        char *filename;
+        Tcl_Channel chan;
+
+        filename = "/assets/app/main.tcl";
+        chan = Tcl_OpenFileChannel(NULL, filename, "r", 0);
+        if (chan != (Tcl_Channel) NULL) {
+            CONST char *arg;
+
+            Tcl_Close(NULL, chan);
+
+            /*
+             * Push back script file to argv, if any.
+             */
+            if ((arg = Tcl_GetStartupScript(NULL)) != NULL) {
+                Tcl_Obj *v, *no;
+
+                no = Tcl_NewStringObj("argv", 4);
+                v = Tcl_ObjGetVar2(interp, no, NULL, TCL_GLOBAL_ONLY);
+                if (v != NULL) {
+                    Tcl_Obj **objv, *n, *nv;
+                    int objc, i;
+
+                    objc = 0;
+                    Tcl_ListObjGetElements(NULL, v, &objc, &objv);
+                    n = Tcl_NewStringObj(arg, -1);
+                    nv = Tcl_NewListObj(1, &n);
+                    for (i = 0; i < objc; i++) {
+                        Tcl_ListObjAppendElement(NULL, nv, objv[i]);
+                    }
+                    Tcl_IncrRefCount(nv);
+                    if (Tcl_ObjSetVar2(interp, no, NULL, nv, TCL_GLOBAL_ONLY)
+                        != NULL) {
+                        Tcl_GlobalEval(interp, "incr argc");
+                    } 
+                    Tcl_DecrRefCount(nv);
+                }
+                Tcl_DecrRefCount(no);
+            }
+            Tcl_SetStartupScript(filename, NULL);
+            Tcl_SetVar(interp, "argv0", filename, TCL_GLOBAL_ONLY);
+            Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
+        }
+    }
+#endif
+
     /*
      * Invoke the script specified on the command line, if any. Must fetch it
      * again, as the appInitProc might have reset it.
diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c
--- a/generic/tclStubInit.c
+++ b/generic/tclStubInit.c
@@ -553,6 +553,9 @@ static const TclIntStubs tclIntStubs = {
     TclCopyChannel, /* 248 */
     TclDoubleDigits, /* 249 */
     TclSetSlaveCancelFlags, /* 250 */
+    Tclzipfs_Init, /* 251 */
+    Tclzipfs_Mount, /* 252 */
+    Tclzipfs_Unmount, /* 253 */
 };
 
 static const TclIntPlatStubs tclIntPlatStubs = {
diff --git a/unix/Makefile.in b/unix/Makefile.in
--- a/unix/Makefile.in
+++ b/unix/Makefile.in
@@ -308,7 +308,7 @@ GENERIC_OBJS = regcomp.o regexec.o regfr
         tclStrToD.o tclThread.o \
         tclThreadAlloc.o tclThreadJoin.o tclThreadStorage.o tclStubInit.o \
         tclTimer.o tclTrace.o tclUtf.o tclUtil.o tclVar.o tclZlib.o \
-        tclTomMathInterface.o
+        tclTomMathInterface.o zipfs.o
 
 OO_OBJS = tclOO.o tclOOBasic.o tclOOCall.o tclOODefineCmds.o tclOOInfo.o \
         tclOOMethod.o tclOOStubInit.o
@@ -382,7 +382,8 @@ GENERIC_HDRS = \
         $(GENERIC_DIR)/tclPatch.h \
         $(GENERIC_DIR)/tclPlatDecls.h \
         $(GENERIC_DIR)/tclPort.h \
-        $(GENERIC_DIR)/tclRegexp.h
+        $(GENERIC_DIR)/tclRegexp.h \
+        $(GENERIC_DIR)/zipfs.h
 
 GENERIC_SRCS = \
         $(GENERIC_DIR)/regcomp.c \
@@ -462,7 +463,8 @@ GENERIC_SRCS = \
         $(GENERIC_DIR)/tclUtil.c \
         $(GENERIC_DIR)/tclVar.c \
         $(GENERIC_DIR)/tclAssembly.c \
-        $(GENERIC_DIR)/tclZlib.c
+        $(GENERIC_DIR)/tclZlib.c \
+        $(GENERIC_DIR)/zipfs.c
 
 OO_SRCS = \
         $(GENERIC_DIR)/tclOO.c \
@@ -1315,6 +1317,9 @@ tclUtf.o: $(GENERIC_DIR)/tclUtf.c $(GENE
 tclVar.o: $(GENERIC_DIR)/tclVar.c
         $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclVar.c
 
+zipfs.o: $(GENERIC_DIR)/zipfs.c
+        $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/zipfs.c
+
 tclZlib.o: $(GENERIC_DIR)/tclZlib.c
         $(CC) -c $(CC_SWITCHES) $(ZLIB_INCLUDE) $(GENERIC_DIR)/tclZlib.c
 
diff --git a/unix/tclLoadDl.c b/unix/tclLoadDl.c
--- a/unix/tclLoadDl.c
+++ b/unix/tclLoadDl.c
@@ -114,6 +114,24 @@ TclpDlopen(
          */
         handle = dlopen(native, dlopenflags);
 #ifdef ANDROID
+        /*
+         * If not an absolute or relative path, try to load
+         * from $INTERNAL_STORAGE/../lib (the place where the
+         * system has installed bundled .so files from the .APK)
+         */
+        if ((handle == NULL) && (strchr(native, '/') == NULL)) {
+            char *storage = getenv("INTERNAL_STORAGE");
+            Tcl_DString ds2;
+
+            if ((storage != NULL) && (storage[0] != '\0')) {
+                Tcl_DStringInit(&ds2);
+                Tcl_DStringAppend(&ds2, storage, -1);
+                Tcl_DStringAppend(&ds2, "/../lib/", -1);
+                Tcl_DStringAppend(&ds2, native, -1);
+                handle = dlopen(Tcl_DStringValue(&ds2), RTLD_NOW | RTLD_GLOBAL);
+                Tcl_DStringFree(&ds2);
+            }
+        }
 #endif
         Tcl_DStringFree(&ds);
     }