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);
}