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