Check-in [91eaf123c4]

Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:More formatting fixes
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 91eaf123c45aab17be3eb43a3231df1e6a2556b7b366ca074b9e5ea293902c93
User & Date: dkf 2019-02-19 10:40:39
Context
2019-02-20
13:29
CFV for 527 by KBK check-in: b1a11fd5c7 user: dkf tags: trunk
2019-02-19
10:40
More formatting fixes check-in: 91eaf123c4 user: dkf tags: trunk
10:21
Formatting fix check-in: acc664dc37 user: dkf tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to tip/430.md.

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
...
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327

328
329
330
331
332
333
334
335

336
337
338
339
340
341
342
343
344
345
346
...
347
348
349
350
351
352
353
354
# Specification

There shall be new ensemble **zipfs** added to tcl. That ensemble will
contain several commands including:

 * **zipfs canonical** _filename_

      > Returns the a string representing where _filename_ would be located
      > within zipfs.

 * **zipfs exists** _filename_

      > Returns true if a file exists in zipfs. Unlike _file exists_
      > this command is safe to run in a safe interp, because it confers
      > no access to the local file system.

 * **zipfs mount** ?_archive_? ?_mountpoint_?

     > Mounts the ZIP file _archive_ at the location given by _mountpoint_,
     > which will default to **zipfs:/_archive_** if absent. With no arguments
     > this command describes all current mounts, returning a list of pairs.

 * **zipfs root**

     > Return the root mount point for Zipfs file systems. On windows this returns **zipfs:/**.
     > On all other platforms this returns **//zipfs:/**


 * **zipfs tcl_library**

     > Search the current executable, the tcl dynamic library, and the local file system
     > for a zipfs file system containing Tcl's init.tcl file. Returns null if none was found.

 * **zipfs unmount** _archive_

     > Unmounts the ZIP file _archive_, which must have been previously mounted.

Outside of a save interpreter, the following additional commands will be available:

 * **zipfs lmkimg** _outfile_ _inlist_ ?strip? ?_password_? ?infile?

     > Generate a zip archive (_outfile_) from a list of files (_inlist_),
     > as a self extracting executable appended to a bare executable (_infile_).
     >
     > If _strip_ is given, that string will be removed from the front of all files
     > before generating their names within the archive.
     >
     > If _password_ is given, the file will be encrypted with that passphrase

 * **zipfs lmkzip** _outfile_ _inlist_ ?strip? ?_password_?

     > Generate a zip archive (_outfile_) from a list of files (_inlist_).

 * **zipfs mkzip** _outfile_ _indir_ ?strip? ?_password_?

     > Generate a zip archive (_outfile_) from the contents of a directory (_indir_)

 * **zipfs mkimg** _outfile_ _indir_ ?strip? ?_password_? ?infile?

     > Generate a zip archive (_outfile_) from the contents of a directory (_indir_),
     > as a self extracting executable appended to a bare executable (_infile_).


## VFS Mount Point

On virtually all platforms tcl supports (Unix, Windows) ZipFs will mount all archives
under *//zipfs:/*. Some operating systems (past or future) may have a special meaning
for this style path. To that end, it may be changed to address the needs of the
specific environment. Which root is being used for
................................................................................
## Generating Task Executables Tclsh/Wish

If tclsh/wish detect that the executable has a zip archive attached, the executable will be
mounted as **ZIPFS\_ROOT**_/app_. If **ZIPFS\_ROOT**_/app/main.tcl_ exists, that file is marked
set the shell's startup script. If **ZIPFS\_ROOT**_/app/tcl\_library/_ exists, it will be
searched for init.tcl.

The way to produce an executable will be as follows (Assuming the source for the application
is at ~/myapp/src:

From Tcl:

    > zipfs mkimg ~/bin/myapp.exe ~/myapp/src ~/myapp/src ~/bin/tclsh87.exe

From Unix:

    > cd ~/myapp/src
    > zip -r ~/myapp.zip .
    > cd ..
    > cp ~/bin/tclsh87.exe myapp.exe
    > cat myapp.zip >> myapp.exe

## First argument handling for Tclsh/Wish

If the first argument to Tclsh or Wish is detected to be a zipfile, that file will be
mounted as **ZIPFS\_ROOT*_/app_. If **ZIPFS\_ROOT**_/app/main.tcl_ exists, that file is marked
set the shell's startup script. If **ZIPFS\_ROOT**_/app/tcl\_library_ exists, it will be
searched for init.tcl.

## New Tclsh features for TEA

To assist in packaging extensions, **tclsh** will take on a new command _install_. If
_install_ is the first argument, set subsequent arguments are passed to a new file
in library **install.tcl**.

**tclsh install** with no arguments is designed to return immediately with a normal return code,
thus making it easy to test if a tclsh is tip430 Savvy but running in autoconf:

    > AS_IF([$TCLSH_PROG install],[
    >  ZIP_PROG=${TCLSH_PROG}
    >  ZIP_PROG_OPTIONS="install mkzip"
    >  ZIP_PROG_VFSSEARCH="."
    >  AC_MSG_RESULT([Can use Native Tclsh for Zip encoding])
    > ])

This tip only defines 2 function for install:

 * **tclsh install mkzip**.

    > This command is a passthrough to the **zipfs mkzip** command, and allows
    > tclsh to operate as zip encoder from make.

 * **tclsh install mkimg**.

    > This command is a passthrough to the **zipfs mkimg** command, and allows
    > tclsh to operate as zip encoder from make.

 * **tclsh install copyDir** _source_ _destination_

    > This command will recursively copy the file structure of _source_
    > to _destination_

 * **tclsh install installDir** _source_ _destination_

    > This command will recursively copy the file structure of _source_
    > to _destination_, deleting _destination_ if it already exists, and
    > marking all files copies as read-only.

 * **tclsh install pkgindex_path** _path_ ?_path_...?

    > Index all of the paths specified and generate a script that can
    > be sourced to feed all of the __package ifneeded__ statements
    > to an interpreter in one shot. Useful for indexing VFS file systems
    >
    > example:

        tclsh install copyDir ~/myapp/src myapp.vfs
        tclsh install pkgindex_path myapp.vfs > myapp.vfs/pkgIndex.tcl

## Package loading

Calls to **tcl_findLibrary** will now search through loaded packages to see if
................................................................................
# Implementation

This work is largely adapted Richard Hipp's work on Tcl As One Big Executable \(TOBE\).
The concept has been modernized, somewhat, as well as heavily influenced by improvements
made to it through the FreeWrap and Androwish projects. That implementation consists of one C file
\(_tclZipvfs.c_\).  I have also prepared a set of kit-like behaviors for the
core to express when tclAppInit.c is not compiled with a **TCL\_LOCAL\_MAIN\_HOOK**
defined. Those behaviors reside in the *TclZipfs_AppHook\(\)* function.

This work is checked in as the "_core\_zip\_vfs_" branch on both Tcl and Tk.


## Modifications to auto.tcl

*auto.tcl* now has rules for scanning DLLs for zip file systems.
................................................................................
## Modifications to Tk

Tk will scan tclConfig.sh, and if it detects a non-blank value for **TCL_ZIP_FILE**, it
will make a call to *TclZipfs_AppHook\(\)* if no **TK\_LOCAL\_MAIN\_HOOK** was defined.

# C API

* **int TclZipfs_AppHook\(int \*argc, char \*\*\*argv\);**

1. If the current executable has an attached zip file system, mount that to **ZIPFS\_ROOT**/app.
2. If the file **ZIPFS\_ROOT**_/app/main.tcl_ exists, register that file as the process startup script.
3. If the file **ZIPFS\_ROOT**_/app/tcl\_library/init.tcl_ exists, register **ZIPFS\_ROOT**_/app/tcl\_library/init.tcl_ as **tcl\_library**
4. If the file **ZIPFS\_ROOT**_/app/tk\_library/init.tcl_ exists, register **ZIPFS\_ROOT**_/app/tk\_library/init.tcl* as **tk\_library**
5. If **tcl\_library** was not set, the function will then scan the local environment for a
zipfs file system attached to either the tcl dynamic library or an archive named
*libtcl\_MAJOR\_MINOR\_PATCHLEVEL.zip*. That file can either be in the present working directory
or in the standard system install location for Tcl.

* **int TclZipfs_Mount\(Tcl\_Interp \*interp, const char \*zipname, const char \*mntpt, const char \*passwd\);**


    > Mounts a zip file _zipname_ to the mount point _mntpt_. If _passwd_ is
    > non-null, that string is used as the password to decrypt the contents.
    > _mntpnt_ will always be relative to **zipfs:**

* **int TclZipfs_Unmount\(Tcl\_Interp \*interp, const char \*zipname\);**

    > Unmount the file system created by a prior call to **TclZipfs_Mount\(\)**


# Creating a wrapped executable

With this tip, producing a wrapped executable is now a matter of:

    mkdir myvfs.vfs
    cd myvfs.vfs
    echo "puts {hello world}" > main.tcl
    zip -r ../hello.zip .
    cd ..
    cp tclsh8.7 hello
................................................................................
    cat hello.zip >> hello
    ./hello
    > hello world

# Copyright

This document has been placed in the public domain.







|
|



|
|
|



|
|
|



|
|
<



|
|



|





|
|
|
|
|
|
|



|



|



|
|
<







 







|
|



|



|
|
|
|
|




|

|








|

|
|
|
|
|
|



|

|
|

|

|
|

|

|
|

|

|
|




|
|
|
|
|







 







|







 







|





|
<
<
<

<
>





|

|
>



|







 







<
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
...
307
308
309
310
311
312
313
314
315
316
317
318
319
320



321

322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
...
343
344
345
346
347
348
349

# Specification

There shall be new ensemble **zipfs** added to tcl. That ensemble will
contain several commands including:

 * **zipfs canonical** _filename_

    Returns the a string representing where _filename_ would be located
    within zipfs.

 * **zipfs exists** _filename_

    Returns true if a file exists in zipfs. Unlike _file exists_
    this command is safe to run in a safe interp, because it confers
    no access to the local file system.

 * **zipfs mount** ?_archive_? ?_mountpoint_?

    Mounts the ZIP file _archive_ at the location given by _mountpoint_,
    which will default to **zipfs:/_archive_** if absent. With no arguments
    this command describes all current mounts, returning a list of pairs.

 * **zipfs root**

    Return the root mount point for Zipfs file systems. On windows this returns **zipfs:/**.
    On all other platforms this returns **//zipfs:/**


 * **zipfs tcl_library**

    Search the current executable, the tcl dynamic library, and the local file system
    for a zipfs file system containing Tcl's init.tcl file. Returns null if none was found.

 * **zipfs unmount** _archive_

    Unmounts the ZIP file _archive_, which must have been previously mounted.

Outside of a save interpreter, the following additional commands will be available:

 * **zipfs lmkimg** _outfile_ _inlist_ ?strip? ?_password_? ?infile?

    Generate a zip archive (_outfile_) from a list of files (_inlist_),
    as a self extracting executable appended to a bare executable (_infile_).

    If _strip_ is given, that string will be removed from the front of all files
    before generating their names within the archive.

    If _password_ is given, the file will be encrypted with that passphrase

 * **zipfs lmkzip** _outfile_ _inlist_ ?strip? ?_password_?

    Generate a zip archive (_outfile_) from a list of files (_inlist_).

 * **zipfs mkzip** _outfile_ _indir_ ?strip? ?_password_?

    Generate a zip archive (_outfile_) from the contents of a directory (_indir_)

 * **zipfs mkimg** _outfile_ _indir_ ?strip? ?_password_? ?infile?

    Generate a zip archive (_outfile_) from the contents of a directory (_indir_),
    as a self extracting executable appended to a bare executable (_infile_).


## VFS Mount Point

On virtually all platforms tcl supports (Unix, Windows) ZipFs will mount all archives
under *//zipfs:/*. Some operating systems (past or future) may have a special meaning
for this style path. To that end, it may be changed to address the needs of the
specific environment. Which root is being used for
................................................................................
## Generating Task Executables Tclsh/Wish

If tclsh/wish detect that the executable has a zip archive attached, the executable will be
mounted as **ZIPFS\_ROOT**_/app_. If **ZIPFS\_ROOT**_/app/main.tcl_ exists, that file is marked
set the shell's startup script. If **ZIPFS\_ROOT**_/app/tcl\_library/_ exists, it will be
searched for init.tcl.

The way to produce an executable will be as follows (assuming the source for the application
is at `~/myapp/src`):

From Tcl:

    zipfs mkimg ~/bin/myapp.exe ~/myapp/src ~/myapp/src ~/bin/tclsh87.exe

From Unix:

    cd ~/myapp/src
    zip -r ~/myapp.zip .
    cd ..
    cp ~/bin/tclsh87.exe myapp.exe
    cat myapp.zip >> myapp.exe

## First argument handling for Tclsh/Wish

If the first argument to Tclsh or Wish is detected to be a zipfile, that file will be
mounted as **ZIPFS\_ROOT**_/app_. If **ZIPFS\_ROOT**_/app/main.tcl_ exists, that file is marked
set the shell's startup script. If **ZIPFS\_ROOT**_/app/tcl\_library_ exists, it will be
searched for _init.tcl_.

## New Tclsh features for TEA

To assist in packaging extensions, **tclsh** will take on a new command _install_. If
_install_ is the first argument, set subsequent arguments are passed to a new file
in library **install.tcl**.

**tclsh install** with no arguments is designed to return immediately with a normal return code,
thus making it easy to test if a tclsh is tip430 savvy but running in autoconf:

    AS_IF([$TCLSH_PROG install],[
        ZIP_PROG=${TCLSH_PROG}
        ZIP_PROG_OPTIONS="install mkzip"
        ZIP_PROG_VFSSEARCH="."
        AC_MSG_RESULT([Can use Native Tclsh for Zip encoding])
    ])

This tip only defines 2 function for install:

 * **tclsh install mkzip** ...

    This command is a passthrough to the **zipfs mkzip** command, and allows
    tclsh to operate as zip encoder from make.

 * **tclsh install mkimg** ....

    This command is a passthrough to the **zipfs mkimg** command, and allows
    tclsh to operate as zip encoder from make.

 * **tclsh install copyDir** _source destination_

    This command will recursively copy the file structure of _source_
    to _destination_

 * **tclsh install installDir** _source destination_

    This command will recursively copy the file structure of _source_
    to _destination_, deleting _destination_ if it already exists, and
    > marking all files copies as read-only.

 * **tclsh install pkgindex_path** _path_ ?_path_...?

    Index all of the paths specified and generate a script that can
    be sourced to feed all of the __package ifneeded__ statements
    to an interpreter in one shot. Useful for indexing VFS file systems

    example:

        tclsh install copyDir ~/myapp/src myapp.vfs
        tclsh install pkgindex_path myapp.vfs > myapp.vfs/pkgIndex.tcl

## Package loading

Calls to **tcl_findLibrary** will now search through loaded packages to see if
................................................................................
# Implementation

This work is largely adapted Richard Hipp's work on Tcl As One Big Executable \(TOBE\).
The concept has been modernized, somewhat, as well as heavily influenced by improvements
made to it through the FreeWrap and Androwish projects. That implementation consists of one C file
\(_tclZipvfs.c_\).  I have also prepared a set of kit-like behaviors for the
core to express when tclAppInit.c is not compiled with a **TCL\_LOCAL\_MAIN\_HOOK**
defined. Those behaviors reside in the **TclZipfs_AppHook**\(\) function.

This work is checked in as the "_core\_zip\_vfs_" branch on both Tcl and Tk.


## Modifications to auto.tcl

*auto.tcl* now has rules for scanning DLLs for zip file systems.
................................................................................
## Modifications to Tk

Tk will scan tclConfig.sh, and if it detects a non-blank value for **TCL_ZIP_FILE**, it
will make a call to *TclZipfs_AppHook\(\)* if no **TK\_LOCAL\_MAIN\_HOOK** was defined.

# C API

int **TclZipfs\_AppHook**\(int _\*argc,_ char _\*\*\*argv_\);

1. If the current executable has an attached zip file system, mount that to **ZIPFS\_ROOT**/app.
2. If the file **ZIPFS\_ROOT**_/app/main.tcl_ exists, register that file as the process startup script.
3. If the file **ZIPFS\_ROOT**_/app/tcl\_library/init.tcl_ exists, register **ZIPFS\_ROOT**_/app/tcl\_library/init.tcl_ as **tcl\_library**
4. If the file **ZIPFS\_ROOT**_/app/tk\_library/init.tcl_ exists, register **ZIPFS\_ROOT**_/app/tk\_library/init.tcl* as **tk\_library**
5. If **tcl\_library** was not set, the function will then scan the local environment for a zipfs file system attached to either the tcl dynamic library or an archive named `libtcl\_MAJOR\_MINOR\_PATCHLEVEL.zip` (where `MAJOR`, `MINOR` and `PATCHLEVEL` depend on the exact version of Tcl). That file can either be in the present working directory or in the standard system install location for Tcl.





int **TclZipfs\_Mount**\(Tcl\_Interp _\*interp,_ const char _\*zipname,_ const char _\*mntpt,_ const char _\*passwd_\);

 > Mounts a zip file _zipname_ to the mount point _mntpt_. If _passwd_ is
 > non-null, that string is used as the password to decrypt the contents.
 > _mntpnt_ will always be relative to **zipfs:**

int **TclZipfs\_Unmount**\(Tcl\_Interp _\*interp,_ const char _\*zipname_\);

 > Unmount the file system created (from _zipname_) by a prior call to
 > **TclZipfs_Mount**\(\).

# Creating a wrapped executable

With this TIP, producing a wrapped executable is now a matter of:

    mkdir myvfs.vfs
    cd myvfs.vfs
    echo "puts {hello world}" > main.tcl
    zip -r ../hello.zip .
    cd ..
    cp tclsh8.7 hello
................................................................................
    cat hello.zip >> hello
    ./hello
    > hello world

# Copyright

This document has been placed in the public domain.