aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/codeql.yml4
-rw-r--r--CONTRIBUTING.md65
-rw-r--r--DEVELOPING93
-rw-r--r--Makefile.in2
-rw-r--r--README.namespaces7
-rw-r--r--Tcl_shipped.html811
-rw-r--r--auto.def8
-rw-r--r--autosetup/README.autosetup2
-rwxr-xr-xautosetup/autosetup10
-rwxr-xr-xautosetup/autosetup-config.guess121
-rwxr-xr-xautosetup/autosetup-config.sub953
-rwxr-xr-xautosetup/autosetup-find-tclsh2
-rw-r--r--autosetup/cc.tcl126
-rw-r--r--autosetup/jimsh0.c732
-rw-r--r--autosetup/system.tcl170
-rw-r--r--initjimsh.tcl10
-rw-r--r--jim-aio.c250
-rw-r--r--jim-file.c12
-rw-r--r--jim-json.c12
-rw-r--r--jim-namespace.c2
-rw-r--r--jim-package.c18
-rw-r--r--jim-readline.c2
-rw-r--r--jim-win32compat.h11
-rw-r--r--jim.c222
-rw-r--r--jim.h8
-rw-r--r--jim_tcl.txt312
-rw-r--r--jimiocompat.c6
-rw-r--r--jimiocompat.h23
-rw-r--r--jimsh.c8
-rw-r--r--jsmn/jsmn.c82
-rw-r--r--jsmn/jsmn.h3
-rw-r--r--linenoise.c186
-rwxr-xr-xmake-bootstrap-jim10
-rwxr-xr-xmake-index8
-rwxr-xr-xmake-release.sh2
-rw-r--r--regtest.tcl18
-rw-r--r--tclcompat.tcl5
-rw-r--r--tcltest.tcl5
-rw-r--r--tests/breakcont.test (renamed from tests/breakcontinue.test)0
-rw-r--r--tests/event.test23
-rw-r--r--tests/expr.test7
-rw-r--r--tests/forget-test.tcl3
-rw-r--r--tests/io.test26
-rw-r--r--tests/jimsh.test30
-rw-r--r--tests/json.test26
-rw-r--r--tests/lsort.test129
-rw-r--r--tests/package.test12
-rw-r--r--tests/try.test9
48 files changed, 3069 insertions, 1517 deletions
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 8164922..f55e344 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -27,7 +27,7 @@ jobs:
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners
# Consider using larger runners for possible analysis time improvements.
- runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-20.04' }}
+ runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
actions: read
@@ -114,7 +114,7 @@ jobs:
- name: Upload CodeQL results as an artifact
if: success() || failure()
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: codeql-results
path: ${{ steps.step1.outputs.sarif-output }}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..b71829c
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,65 @@
+# Contributing to Jim
+
+Please take a moment to review this document in order to make the contribution
+process easy and effective for everyone involved.
+
+Following these guidelines helps to communicate that you respect the time of
+the developers managing and developing this open source project. In return,
+they should reciprocate that respect in addressing your issue, assessing
+changes, and helping you finalize your pull requests.
+
+## Bug reports and Feature requests
+
+The [issue tracker](https://github.com/msteveb/jimtcl/issues) is the preferred channel for bug reports
+and features requests.
+
+## Discussions
+
+If you wish to open a broader topic for discussion, consider using a [discussion topic](https://github.com/msteveb/jimtcl/discussions)
+
+## Pull requests
+
+[Pull requests](https://github.com/msteveb/jimtcl/pulls) are always welcome
+
+If you have never created a pull request before, [Here is a great tutorial](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github)
+on how to create a pull request.
+
+1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
+ and configure the remotes:
+
+ ```
+ # Clone your fork of the repo into the current directory
+ git clone https://github.com/<your-username>/<repo-name>
+ # Navigate to the newly cloned directory
+ cd <repo-name>
+ # Assign the original repo to a remote called "upstream"
+ git remote add upstream https://github.com/msteveb/jimtcl.git
+ ```
+
+2. If you cloned a while ago, get the latest changes from upstream:
+
+ ```
+ git checkout master
+ git pull upstream master
+ ```
+
+3. Create a new topic branch (off the main project development branch) to
+ contain your feature, change, or fix:
+
+ ```bash
+ git checkout -b <topic-branch-name>
+ ```
+
+4. Make sure to update, or add to the tests when appropriate.
+ Run `make test` to check that all tests pass after you've made changes.
+
+5. If you added or changed a feature, please add documentation to jim_tcl.txt.
+
+6. Push your topic branch up to your fork:
+
+ ```bash
+ git push origin <topic-branch-name>
+ ```
+
+7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
+ with a clear title and description.
diff --git a/DEVELOPING b/DEVELOPING
deleted file mode 100644
index 5156b28..0000000
--- a/DEVELOPING
+++ /dev/null
@@ -1,93 +0,0 @@
-Working on Jim
-==============
-
-Jim's sources are kept in Git Version Control System. Global repository of
-Jim project is placed on this Web site:
-
- http://repo.or.cz/w/jimtcl.git
-
-There are two ways of contributing to Jim project. First is suited for
-one-time fixes and small corrections. The second is more appropriate
-for long-term contributors interested in Jim internals.
-
-Small changes
-=============
-
-For small modifications, procedure of preparing a traditional 'patch'
-is enough. In order to prepare a patch, you first have to obtain the
-most recent copy of Jim Tcl. This can be done with following command:
-
- git clone http://repo.or.cz/r/jimtcl.git
-
-After entering newly created directory you can easily correct/fix/modify
-files. Once finished, patch can be easily generated:
-
- git diff > my_patch_fixing_x_y.patch
-
-If working without Git system, you'll have to backup files first, modify
-the original files and obtain a patch manually:
-
- cp jim.c jim.c.ORIGINAL
-
- [...] <- modifications go here
-
- diff -u jim.c.ORIGINAL jim.c > my_patch_fixing_z.patch
-
-Bigger changes
-==============
-
-In order to help extending and correcting Jim in a long term basis, one
-needs to create separate fork of Jim project and maintain his changes in a
-separate copy of a repository.
-
-By visiting this site, you'll have a chance to fork a project. This can
-be easily done with "fork" link. Form that will show up next refers to
-the project that is about to be started. The only thing that has to be
-taken care of is the project mode -- it should be "push mode".
-
-Once the project is created one must add a user that will actually
-start committing new files to the repo. It can also be done through the
-WWW interface, so nothing more is necessary.
-
-Once finished with setting up a project on the WWW panel, one can
-start playing with actual import of the files. In order to obtain copy
-of Jim sources, we have to clone the repository:
-
- git clone http://repo.or.cz/r/jimtcl.git
-
-Now, we must push fresh copy of Jim to your project URL:
-
- git push <URL> master
-
-So for example for me it was:
-
- git push ssh://repo.or.cz/srv/git/jimtcl/wkoszek.git master
-
-In order to add file we type "git add <file>". For remove, we do "git rm
-<file>". To remove all local changes that aren't in a repository you do "git
-reset --hard HEAD". Once inserted, files have to be committed with "git commit
--a". Once done with commits for today, "git push" can be used to propagate
-changes from your local disk to the remote repository.
-
-Right now you can verify whether this works by trying to clone your
-project's repository somewhere else, this time using anonymous HTTP
-access:
-
- git clone http://repo.or.cz/r/jimtcl/wkoszek.git
-
-Review, testing and publishing
-==============================
-
-Notification of work that can be considered finished is more than welcome on
-Jim-devel mailing list:
-
- http://jim.tcl.tk:8080/cgi-bin/mailman/listinfo/jim-devel
-
-Patches prepared with the procedures presented above are welcome. Before
-submitting patches, you can verify that your changes didn't bring any
-regressions to the Jim. In order to do so, sample regression tests have
-been implemented. You can execute them by typing:
-
- make test
-
-All tests should succeed.
diff --git a/Makefile.in b/Makefile.in
index 29c226b..2fba1c0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -118,7 +118,9 @@ install: all @TCL_EXTS@ install-exec install-docs
@srcdir@/jim-subcmd.h @srcdir@/jim-win32compat.h $(DESTDIR)@includedir@
$(INSTALL_DATA) jim-config.h $(DESTDIR)@includedir@
$(INSTALL_DATA_DIR) $(DESTDIR)@bindir@
+@if BUILD_JIM_EXT
$(INSTALL_DATA) build-jim-ext $(DESTDIR)@bindir@
+@endif
$(INSTALL_DATA_DIR) $(DESTDIR)@libdir@/pkgconfig
$(INSTALL_DATA) jimtcl.pc $(DESTDIR)@libdir@/pkgconfig
diff --git a/README.namespaces b/README.namespaces
index ef50769..9d23a74 100644
--- a/README.namespaces
+++ b/README.namespaces
@@ -115,6 +115,7 @@ Currently, the following namespace commands are supported.
* delete - deletes all variables and commands with the namespace prefix
* which - implemented
* upvar - implemented
+* ensemble - 'create' command is implemented
namespace children, exists, path
--------------------------------
@@ -126,12 +127,6 @@ or variable in the namespace.
Command resolution is always done by first looking in the namespace and then
at the global scope, so namespace path is not required.
-namespace ensemble
-------------------
-The namespace ensemble command is not currently supported. A future version
-of Jim Tcl will have a general-purpose ensemble creation and manipulation
-mechanism and namespace ensemble will be implemented in terms of that mechanism.
-
namespace import, export, forget, origin
----------------------------------------
Since Jim Tcl namespaces are implicit, there is no location to store export patterns.
diff --git a/Tcl_shipped.html b/Tcl_shipped.html
index 0f68a95..5f237f5 100644
--- a/Tcl_shipped.html
+++ b/Tcl_shipped.html
@@ -4,7 +4,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 10.2.0" />
+<meta name="generator" content="AsciiDoc 10.2.1" />
<title>Jim Tcl(n)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -739,7 +739,7 @@ Jim Tcl(n) Manual Page
</h1>
<h2>NAME</h2>
<div class="sectionbody">
-<p>Jim Tcl v0.82 -
+<p>Jim Tcl v0.83+ -
reference manual for the Jim Tcl scripting language
</p>
</div>
@@ -880,6 +880,71 @@ Support for UDP, IPv6, Unix-Domain sockets in addition to TCP sockets
<h2 id="_recent_changes">RECENT CHANGES</h2>
<div class="sectionbody">
<div class="sect2">
+<h3 id="_changes_since_0_83">Changes since 0.83</h3>
+<div class="olist arabic"><ol class="arabic">
+<li>
+<p>
+<a href="#_aio"><strong><code>aio</code></strong></a> - support for configurable read and write buffering
+</p>
+</li>
+</ol></div>
+</div>
+<div class="sect2">
+<h3 id="_changes_between_0_82_and_0_83">Changes between 0.82 and 0.83</h3>
+<div class="olist arabic"><ol class="arabic">
+<li>
+<p>
+Multi-level <a href="#_break"><strong><code>break</code></strong></a> and <a href="#_continue"><strong><code>continue</code></strong></a> are now supported
+</p>
+</li>
+<li>
+<p>
+<a href="#_info"><strong><code>info</code></strong></a> <code>frame</code> now only returns <em>proc</em> levels
+</p>
+</li>
+<li>
+<p>
+<a href="#_stacktrace"><strong><code>stacktrace</code></strong></a> is now a builtin command
+</p>
+</li>
+<li>
+<p>
+The stack trace on error now includes the full stack trace, not just back to where it was caught
+</p>
+</li>
+<li>
+<p>
+Improvements with <a href="#_aio"><strong><code>aio</code></strong></a>, related to eventloop and buffering. Add <a href="#_aio"><strong><code>aio</code></strong></a> <code>timeout</code>.
+</p>
+</li>
+<li>
+<p>
+<a href="#_socket"><strong><code>socket</code></strong></a> , <a href="#_open"><strong><code>open</code></strong></a> and <a href="#_aio"><strong><code>aio</code></strong></a> <code>accept</code> now support <em>-noclose</em>
+</p>
+</li>
+<li>
+<p>
+Add support for hinting with <a href="#_history"><strong><code>history</code></strong></a> <code>hints</code>
+</p>
+</li>
+<li>
+<p>
+Support for <a href="#_proc"><strong><code>proc</code></strong></a> statics by reference (lexical closure) rather than by value
+</p>
+</li>
+<li>
+<p>
+<a href="#_regsub"><strong><code>regsub</code></strong></a> now supports <em>-command</em> (per Tcl 8.7)
+</p>
+</li>
+<li>
+<p>
+Add support for <a href="#_lsort"><strong><code>lsort</code></strong></a> <code>-dict</code>
+</p>
+</li>
+</ol></div>
+</div>
+<div class="sect2">
<h3 id="_changes_between_0_81_and_0_82">Changes between 0.81 and 0.82</h3>
<div class="olist arabic"><ol class="arabic">
<li>
@@ -1827,9 +1892,9 @@ normal processing with the next character. For example, in the
command</p></div>
<div class="listingblock">
<div class="content">
-<pre><code> set \*a \\{foo</code></pre>
+<pre><code> set \*a \{foo</code></pre>
</div></div>
-<div class="paragraph"><p>The first argument to <a href="#_set"><strong><code>set</code></strong></a> will be <code>\*a</code> and the second
+<div class="paragraph"><p>The first argument to <a href="#_set"><strong><code>set</code></strong></a> will be <code>*a</code> and the second
argument will be <code>{foo</code>.</p></div>
<div class="paragraph"><p>If an argument is enclosed in braces, then backslash sequences inside
the argument are parsed but no substitution occurs (except for
@@ -1842,9 +1907,9 @@ For example, in the
command</p></div>
<div class="listingblock">
<div class="content">
-<pre><code> set a {{abc}</code></pre>
+<pre><code> set a {\{abc}</code></pre>
</div></div>
-<div class="paragraph"><p>the second argument to <a href="#_set"><strong><code>set</code></strong></a> will be <code>{abc</code>.</p></div>
+<div class="paragraph"><p>the second argument to <a href="#_set"><strong><code>set</code></strong></a> will be <code>\{abc</code>.</p></div>
<div class="paragraph"><p>This backslash mechanism is not sufficient to generate absolutely
any argument structure; it only covers the
most common cases. To produce particularly complicated arguments
@@ -2036,14 +2101,10 @@ it).</p></div>
<div class="paragraph"><p>String constants representing boolean constants
(<code><em>0</em></code>, <code><em>1</em></code>, <code><em>false</em></code>, <code><em>off</em></code>, <code><em>no</em></code>, <code><em>true</em></code>, <code><em>on</em></code>, <code><em>yes</em></code>)
are also recognized and can be used in logical operations.</p></div>
+<div class="paragraph"><p>Operands may be specified in any of the following ways:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
-Operands may be specified in any of the following ways:
-</p>
-</li>
-<li>
-<p>
As a numeric value, either integer or floating-point.
</p>
</li>
@@ -2897,6 +2958,24 @@ is no variable with the same name in the enclosing scope). However <code><em>b</
has an initialiser, so it is initialised to 2.</p></div>
<div class="paragraph"><p>Unlike a local variable, the value of a static variable is retained across
invocations of the procedure.</p></div>
+<div class="paragraph"><p>In addition to static variables by value, static variables may also be
+defined by "reference" by using a leading "&amp;" character. In this case,
+the statics point to the original variable and when one changes, they
+both change. For example, here <em>a</em> changes changes the value of the
+original <em>x</em>.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> . set x 1
+ . proc a {} {&amp;x} {
+ incr x
+ }
+ . a
+ 2
+ . a
+ 3
+ . puts $x
+ 3</code></pre>
+</div></div>
<div class="paragraph"><p>See the <a href="#_proc"><strong><code>proc</code></strong></a> command for information on how to define procedures
and what happens when they are invoked. See also <a href="#_namespaces">NAMESPACES</a>.</p></div>
</div>
@@ -3419,6 +3498,7 @@ cellspacing="0" cellpadding="4">
<td align="left" valign="top"><p class="table"><a href="#_tcl_prefix"><strong><code>tcl::prefix</code></strong></a></p></td>
</tr>
<tr>
+<td align="left" valign="top"><p class="table"><a href="#_tcl_stdhint"><strong><code>tcl::stdhint</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#_tell"><strong><code>tell</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#_throw"><strong><code>throw</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#_time"><strong><code>time</code></strong></a></p></td>
@@ -3426,9 +3506,9 @@ cellspacing="0" cellpadding="4">
<td align="left" valign="top"><p class="table"><a href="#_tree"><strong><code>tree</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#_try"><strong><code>try</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#_unknown"><strong><code>unknown</code></strong></a></p></td>
-<td align="left" valign="top"><p class="table"><a href="#cmd_3"><strong><code>unpack</code></strong></a></p></td>
</tr>
<tr>
+<td align="left" valign="top"><p class="table"><a href="#cmd_3"><strong><code>unpack</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#_unset"><strong><code>unset</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#_upcall"><strong><code>upcall</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#cmd_2"><strong><code>update</code></strong></a></p></td>
@@ -3436,9 +3516,9 @@ cellspacing="0" cellpadding="4">
<td align="left" valign="top"><p class="table"><a href="#_upvar"><strong><code>upvar</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#cmd_2"><strong><code>vwait</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#_wait"><strong><code>wait</code></strong></a></p></td>
-<td align="left" valign="top"><p class="table"><a href="#_while"><strong><code>while</code></strong></a></p></td>
</tr>
<tr>
+<td align="left" valign="top"><p class="table"><a href="#_while"><strong><code>while</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#_xtrace"><strong><code>xtrace</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"><a href="#_zlib"><strong><code>zlib</code></strong></a></p></td>
<td align="left" valign="top"><p class="table"></p></td>
@@ -3446,7 +3526,6 @@ cellspacing="0" cellpadding="4">
<td align="left" valign="top"><p class="table"></p></td>
<td align="left" valign="top"><p class="table"></p></td>
<td align="left" valign="top"><p class="table"></p></td>
-<td align="left" valign="top"><p class="table"></p></td>
</tr>
</tbody>
</table>
@@ -3591,10 +3670,23 @@ command. The legal <code><em>options</em></code> (which may be abbreviated) are
</div>
<div class="sect2">
<h3 id="_break">break</h3>
-<div class="paragraph"><p><code><strong>break</strong></code></p></div>
+<div class="paragraph"><p><code><strong>break</strong> ?n?</code></p></div>
<div class="paragraph"><p>This command may be invoked only inside the body of a loop command
-such as <a href="#_for"><strong><code>for</code></strong></a> or <a href="#_foreach"><strong><code>foreach</code></strong></a> or <a href="#_while"><strong><code>while</code></strong></a>. It returns a <code>JIM_BREAK</code> code
+such as <a href="#_for"><strong><code>for</code></strong></a>, <a href="#_foreach"><strong><code>foreach</code></strong></a>, <a href="#_while"><strong><code>while</code></strong></a> or <a href="#_loop"><strong><code>loop</code></strong></a>. It returns a <code>JIM_BREAK</code> code
to signal the innermost containing loop command to return immediately.</p></div>
+<div class="paragraph"><p>If <code><em>n</em></code> is given it breaks out of that many loops. <code><em>break 1</em></code> is equivalent
+to a simple <code><em>break</em></code> while in the following example, <code><em>break</em></code> will exit both
+loops.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> loop i 5 {
+ loop j 6 {
+ if {$i == 3 &amp;&amp; $j == 2} {
+ break 2
+ }
+ }
+ }</code></pre>
+</div></div>
</div>
<div class="sect2">
<h3 id="_case">case</h3>
@@ -3728,11 +3820,8 @@ compliant.</p></div>
<div class="sect2">
<h3 id="_close">close</h3>
<div class="paragraph"><p><code><strong>close</strong> <em>fileId</em></code></p></div>
-<div class="paragraph"><p><code><em>fileId</em> <strong>close</strong></code></p></div>
-<div class="paragraph"><p>Closes the file given by <code><em>fileId</em></code>.
-<code><em>fileId</em></code> must be the return value from a previous invocation
-of the <a href="#_open"><strong><code>open</code></strong></a> command; after this command, it should not be
-used anymore.</p></div>
+<div class="paragraph"><p>Tcl-compatible version of <code><em>fileId</em> <strong>close</strong></code></p></div>
+<div class="paragraph"><p>See <a href="#_aio"><strong><code>aio</code></strong></a> <code>close</code></p></div>
</div>
<div class="sect2">
<h3 id="_collect">collect</h3>
@@ -3760,15 +3849,17 @@ the command</p></div>
</div>
<div class="sect2">
<h3 id="_continue">continue</h3>
-<div class="paragraph"><p><code><strong>continue</strong></code></p></div>
+<div class="paragraph"><p><code><strong>continue</strong> ?n?</code></p></div>
<div class="paragraph"><p>This command may be invoked only inside the body of a loop command such
-as <a href="#_for"><strong><code>for</code></strong></a> or <a href="#_foreach"><strong><code>foreach</code></strong></a> or <a href="#_while"><strong><code>while</code></strong></a>. It returns a <code>JIM_CONTINUE</code> code to
+as <a href="#_for"><strong><code>for</code></strong></a>, <a href="#_foreach"><strong><code>foreach</code></strong></a>, <a href="#_while"><strong><code>while</code></strong></a> or <a href="#_loop"><strong><code>loop</code></strong></a>. It returns a <code>JIM_CONTINUE</code> code to
signal the innermost containing loop command to skip the remainder of
the loop&#8217;s body but continue with the next iteration of the loop.</p></div>
+<div class="paragraph"><p>If <code><em>n</em></code> is given it breaks out of <code><em>n-1</em></code> loops and then continues the <code><em>nth</em></code> loop.
+<code><em>continue 1</em></code> is equivalent to a simple <code><em>continue</em></code>. (See also <a href="#_break"><strong><code>break</code></strong></a>).</p></div>
</div>
<div class="sect2">
<h3 id="_curry">curry</h3>
-<div class="paragraph"><p><code><strong>alias</strong> <em>args...</em></code></p></div>
+<div class="paragraph"><p><code><strong>curry</strong> <em>args...</em></code></p></div>
<div class="paragraph"><p>Similar to <a href="#_alias"><strong><code>alias</code></strong></a> except it creates an anonymous procedure (lambda) instead of
a named procedure.</p></div>
<div class="paragraph"><p>the following creates a local, unnamed alias for the command <a href="#_info"><strong><code>info</code></strong></a> <code>exists</code>.</p></div>
@@ -3985,12 +4076,8 @@ and their values as <code>{name value ...}</code></p></div>
<div class="sect2">
<h3 id="_eof">eof</h3>
<div class="paragraph"><p><code><strong>eof</strong> <em>fileId</em></code></p></div>
-<div class="paragraph"><p><code><em>fileId</em> <strong>eof</strong></code></p></div>
-<div class="paragraph"><p>Returns 1 if an end-of-file condition has occurred on <code><em>fileId</em></code>,
-0 otherwise.</p></div>
-<div class="paragraph"><p><code><em>fileId</em></code> must have been the return value from a previous call to <a href="#_open"><strong><code>open</code></strong></a>,
-or it may be <code>stdin</code>, <code>stdout</code>, or <code>stderr</code> to refer to one of the
-standard I/O channels.</p></div>
+<div class="paragraph"><p>Tcl-compatible alternative to <code><em>fileId</em> <strong>eof</strong></code></p></div>
+<div class="paragraph"><p>See <a href="#_aio"><strong><code>aio</code></strong></a> <code>eof</code></p></div>
</div>
<div class="sect2">
<h3 id="_error">error</h3>
@@ -4274,6 +4361,21 @@ The following two are identical.</p></div>
<pre><code> set x [expr {3 * 2 + 1}]
set x $(3 * 2 + 1)</code></pre>
</div></div>
+<div class="paragraph"><p>However, note that the expr shorthand syntax may not be nested in an expression.
+This is to prevent the common mistake of writing:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> if {$(1 + 2) == 3} {
+ ...
+ }</code></pre>
+</div></div>
+<div class="paragraph"><p>rather than:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> if {(1 + 2) == 3} {
+ ...
+ }</code></pre>
+</div></div>
</div>
<div class="sect2">
<h3 id="_file">file</h3>
@@ -4602,12 +4704,8 @@ command.</p></div>
<div class="sect2">
<h3 id="_flush">flush</h3>
<div class="paragraph"><p><code><strong>flush</strong> <em>fileId</em></code></p></div>
-<div class="paragraph"><p><code><em>fileId</em> <strong>flush</strong></code></p></div>
-<div class="paragraph"><p>Flushes any output that has been buffered for <code><em>fileId</em></code>. <code><em>fileId</em></code> must
-have been the return value from a previous call to <a href="#_open"><strong><code>open</code></strong></a>, or it may be
-<code>stdout</code> or <code>stderr</code> to access one of the standard I/O streams; it must
-refer to a file that was opened for writing. This command returns an
-empty string.</p></div>
+<div class="paragraph"><p>Tcl-compatible alternative to <code><em>fileId</em> <strong>flush</strong></code></p></div>
+<div class="paragraph"><p>See <a href="#_aio"><strong><code>aio</code></strong></a> <code>flush</code></p></div>
</div>
<div class="sect2">
<h3 id="_for">for</h3>
@@ -4684,27 +4782,8 @@ be a valid reference create with the <a href="#_ref"><strong><code>ref</code></s
<div class="sect2">
<h3 id="_gets">gets</h3>
<div class="paragraph"><p><code><strong>gets</strong> <em>fileId ?varName?</em></code></p></div>
-<div class="paragraph"><p><code><em>fileId</em> <strong>gets</strong> <em>?varName?</em></code></p></div>
-<div class="paragraph"><p>Reads the next line from the file given by <code><em>fileId</em></code> and discards
-the terminating newline character.</p></div>
-<div class="paragraph"><p>If <code><em>varName</em></code> is specified, then the line is placed in the variable
-by that name and the return value is a count of the number of characters
-read (not including the newline).</p></div>
-<div class="paragraph"><p>If the end of the file is reached before reading
-any characters then -1 is returned and <code><em>varName</em></code> is set to an
-empty string.</p></div>
-<div class="paragraph"><p>If <code><em>varName</em></code> is not specified then the return value will be
-the line (minus the newline character) or an empty string if
-the end of the file is reached before reading any characters.</p></div>
-<div class="paragraph"><p>An empty string will also be returned if a line contains no characters
-except the newline, so <a href="#_eof"><strong><code>eof</code></strong></a> may have to be used to determine
-what really happened.</p></div>
-<div class="paragraph"><p>If the last character in the file is not a newline character, then
-<a href="#_gets"><strong><code>gets</code></strong></a> behaves as if there were an additional newline character
-at the end of the file.</p></div>
-<div class="paragraph"><p><code><em>fileId</em></code> must be <code>stdin</code> or the return value from a previous
-call to <a href="#_open"><strong><code>open</code></strong></a>; it must refer to a file that was opened
-for reading.</p></div>
+<div class="paragraph"><p>Tcl-compatible alterative version of <code><em>fileId</em> <strong>gets</strong> <em>?varName?</em></code></p></div>
+<div class="paragraph"><p>See <a href="#_aio"><strong><code>aio</code></strong></a> <code>gets</code></p></div>
</div>
<div class="sect2">
<h3 id="_glob">glob</h3>
@@ -5047,7 +5126,7 @@ The legal <code><em>option</em></code>'s (which may be abbreviated) are:
<dd>
<p>
After an error is caught with <a href="#_catch"><strong><code>catch</code></strong></a>, returns the stack trace as a list
- of <code>{procedure filename line ...}</code>.
+ of <code>{procedure filename line cmd ...}</code>.
</p>
</dd>
<dt class="hdlist1">
@@ -5554,31 +5633,52 @@ the list are to be matched against pattern and must have one of the values below
<div class="paragraph"><p><code><strong>lsort</strong> <em>?options? list</em></code></p></div>
<div class="paragraph"><p>Sort the elements of <code><em>list</em></code>, returning a new list in sorted order.
By default, ASCII (or UTF-8) sorting is used, with the result in increasing order.</p></div>
-<div class="paragraph"><p>Note that only one sort type may be selected with <code>-integer</code>, <code>-real</code>, <code>-nocase</code> or <code>-command</code>
+<div class="paragraph"><p>Note that only one sort type may be selected with <code>-ascii</code>, <code>-dict</code>, <code>-integer</code>, <code>-real</code>, <code>-nocase</code> or <code>-command</code>
with last option being used.</p></div>
<div class="dlist"><dl>
<dt class="hdlist1">
-<code><strong>-integer</strong></code>
+<code><strong>-ascii</strong></code>
</dt>
<dd>
<p>
- Sort using numeric (integer) comparison.
+ Sort using string comparison. This is the default.
</p>
</dd>
<dt class="hdlist1">
-<code><strong>-real</strong></code>
+<code><strong>-nocase</strong></code>
</dt>
<dd>
<p>
- Sort using floating point comparison.
+ Sort using using string comparison without regard for case.
</p>
</dd>
<dt class="hdlist1">
-<code><strong>-nocase</strong></code>
+<code><strong>-dict</strong></code>
</dt>
<dd>
<p>
Sort using using string comparison without regard for case.
+ Use dictionary-style comparison. This is the same as <em>-ascii</em>
+ except (a) case is ignored except as a tie-breaker and (b) if
+ two strings contain embedded numbers, the numbers compare as
+ integers, not characters. For example, in -dictionary mode,
+ x10y sorts between x9y and x11y.
+</p>
+</dd>
+<dt class="hdlist1">
+<code><strong>-integer</strong></code>
+</dt>
+<dd>
+<p>
+ Sort using numeric (integer) comparison.
+</p>
+</dd>
+<dt class="hdlist1">
+<code><strong>-real</strong></code>
+</dt>
+<dd>
+<p>
+ Sort using floating point comparison.
</p>
</dd>
<dt class="hdlist1">
@@ -5659,12 +5759,14 @@ with last option being used.</p></div>
</div>
<div class="sect2">
<h3 id="_open">open</h3>
-<div class="paragraph"><p><code><strong>open</strong> <em>fileName ?access?</em></code></p></div>
+<div class="paragraph"><p><code><strong>open</strong> <em>fileName <strong>?-noclose?</strong> ?access?</em></code></p></div>
<div class="paragraph"><p><code><strong>open</strong> <em>|command-pipeline ?access?</em></code></p></div>
<div class="paragraph"><p>Opens a file and returns an identifier
that may be used in future invocations
of commands like <a href="#_read"><strong><code>read</code></strong></a>, <a href="#_puts"><strong><code>puts</code></strong></a>, and <a href="#_close"><strong><code>close</code></strong></a>.
<code><em>fileName</em></code> gives the name of the file to open.</p></div>
+<div class="paragraph"><p>If <code><em>-noclose</em></code> is given, the returned handle is not automatically
+closed for child proceses.</p></div>
<div class="paragraph"><p>The <code><em>access</em></code> argument indicates the way in which the file is to be accessed.
It may have any of the following values:</p></div>
<div class="dlist"><dl>
@@ -5874,19 +5976,8 @@ procedure-as-a-whole will return that same error.</p></div>
<div class="sect2">
<h3 id="_puts">puts</h3>
<div class="paragraph"><p><code><strong>puts</strong> ?<strong>-nonewline</strong>? <em>?fileId? string</em></code></p></div>
-<div class="paragraph"><p><code><em>fileId</em> <strong>puts</strong> ?<strong>-nonewline</strong>? <em>string</em></code></p></div>
-<div class="paragraph"><p>Writes the characters given by <code><em>string</em></code> to the file given
-by <code><em>fileId</em></code>. <code><em>fileId</em></code> must have been the return
-value from a previous call to <a href="#_open"><strong><code>open</code></strong></a>, or it may be
-<code>stdout</code> or <code>stderr</code> to refer to one of the standard I/O
-channels; it must refer to a file that was opened for
-writing.</p></div>
-<div class="paragraph"><p>In the first form, if no <code><em>fileId</em></code> is specified then it defaults to <code>stdout</code>.
-<a href="#_puts"><strong><code>puts</code></strong></a> normally outputs a newline character after <code><em>string</em></code>,
-but this feature may be suppressed by specifying the <code>-nonewline</code>
-switch.</p></div>
-<div class="paragraph"><p>Output to files is buffered internally by Tcl; the <a href="#_flush"><strong><code>flush</code></strong></a>
-command may be used to force buffered characters to be output.</p></div>
+<div class="paragraph"><p>Tcl-compatible version of <code><em>fileId</em> <strong>puts</strong> ?<strong>-nonewline</strong>? <em>string</em></code></p></div>
+<div class="paragraph"><p>See <a href="#_aio"><strong><code>aio</code></strong></a> <code>puts</code></p></div>
</div>
<div class="sect2">
<h3 id="_pipe">pipe</h3>
@@ -5901,6 +5992,7 @@ command may be used to force buffered characters to be output.</p></div>
$r readable ...</code></pre>
</div></div>
+<div class="paragraph"><p>Note that if <em><code>-noclose</code></em> is desired, use <a href="#_socket"><strong><code>socket</code></strong></a> <code>-noclose pipe</code> instead.</p></div>
</div>
<div class="sect2">
<h3 id="_pwd">pwd</h3>
@@ -5934,35 +6026,9 @@ and ranging up to but not including <code><em>end</em></code> in steps of <code>
</div>
<div class="sect2">
<h3 id="_read">read</h3>
-<div class="paragraph"><p><code><strong>read</strong> ?<strong>-nonewline</strong>? <em>fileId</em></code></p></div>
-<div class="paragraph"><p><code><em>fileId</em> <strong>read</strong> ?<strong>-nonewline</strong>?</code></p></div>
-<div class="paragraph"><p><code><strong>read</strong> <em>fileId numBytes</em></code></p></div>
-<div class="paragraph"><p><code><em>fileId</em> <strong>read</strong> <em>numBytes</em></code></p></div>
-<div class="paragraph"><p><code><strong>read</strong> ?<strong>-pending</strong>? <em>fileId</em></code></p></div>
-<div class="paragraph"><p><code><em>fileId</em> <strong>read</strong> ?<strong>-pending</strong>?</code></p></div>
-<div class="paragraph"><p>In the first form, all of the remaining bytes are read from the file
-given by <code><em>fileId</em></code>; they are returned as the result of the command.
-If the <code>-nonewline</code> switch is specified then the last
-character of the file is discarded if it is a newline.</p></div>
-<div class="paragraph"><p>In the second form, the extra argument specifies how many bytes to read;
-exactly this many bytes will be read and returned, unless there are fewer than
-<code><em>numBytes</em></code> bytes left in the file; in this case, all the remaining
-bytes are returned.</p></div>
-<div class="paragraph"><p>The third form is currently only useful with SSL sockets. It reads at least 1 byte
-and then any additional data that is buffered. This allows for use in an event handler.
-e.g.</p></div>
-<div class="listingblock">
-<div class="content">
-<pre><code> $sock readable {
- set buf [$sock read -pending]
- }</code></pre>
-</div></div>
-<div class="paragraph"><p>This is necessary because otherwise pending data may be buffered, but
-the underlying socket will not be marked <em>readable</em>. This featured is not
-currently supported for regular sockets, and so these sockets must be
-set to unbufferred (<code>$sock buffering false</code>) to work in an event loop.</p></div>
-<div class="paragraph"><p><code><em>fileId</em></code> must be <code>stdin</code> or the return value from a previous call
-to <a href="#_open"><strong><code>open</code></strong></a>; it must refer to a file that was opened for reading.</p></div>
+<div class="paragraph"><p><code>*read ?-nonewline? <em>fileId ?length?</em></code></p></div>
+<div class="paragraph"><p>Tcl-compatible alterative version of <code><em>fileId</em> <strong>read ?-nonewline?</strong> <em>?length?</em></code></p></div>
+<div class="paragraph"><p>See <a href="#_aio"><strong><code>aio</code></strong></a> <code>read</code></p></div>
</div>
<div class="sect2">
<h3 id="_regexp">regexp</h3>
@@ -6076,7 +6142,7 @@ string otherwise.</p></div>
</div>
<div class="sect2">
<h3 id="_regsub">regsub</h3>
-<div class="paragraph"><p><code><strong>regsub ?-nocase? ?-all? ?-line? ?-start</strong> <em>offset</em>? ?<strong>--</strong>? <em>exp string subSpec ?varName?</em></code></p></div>
+<div class="paragraph"><p><code><strong>regsub ?-nocase? ?-all? ?-line? ?-command? ?-start</strong> <em>offset</em>? ?<strong>--</strong>? <em>exp string subSpec ?varName?</em></code></p></div>
<div class="paragraph"><p>This command matches the regular expression <code><em>exp</em></code> against
<code><em>string</em></code> using the rules described in REGULAR EXPRESSIONS
above.</p></div>
@@ -6142,6 +6208,36 @@ backslashes.</p></div>
</p>
</dd>
<dt class="hdlist1">
+<code><strong>-command</strong></code>
+</dt>
+<dd>
+<p>
+ Changes the handling of <code><em>subSpec</em></code> so that it is not treated
+ as a template for a substitution string and the substrings <code><strong>&amp;</strong></code>
+ and <code><strong>\n</strong></code> no longer have special meaning. Instead <code><em>subSpec</em></code> must
+ be a command prefix, that is, a non-empty list. The substring
+ of string that matches <code><em>exp</em></code>, and then each substring that matches
+ each capturing sub-RE within <code><em>exp</em></code>, are appended as additional
+ elements to that list. (The items appended to the list are much
+ like what <a href="#_regexp"><strong><code>regexp</code></strong></a> <code>-inline</code> would return). The completed list is
+ then evaluated as a Tcl command, and the result of that command
+ is the substitution string. Any error or exception from command
+ evaluation becomes an error or exception from the regsub command.
+</p>
+</dd>
+<dt class="hdlist1">
+
+</dt>
+<dd>
+<p>
+ If <code><strong>-all</strong></code> is not also given, the command callback will be invoked
+ at most once (exactly when the regular expression matches). If
+ <code><strong>-all</strong></code> is given, the command callback will be invoked for each
+ matched location, in sequence. The exact location indices that
+ matched are not made available to the script.
+</p>
+</dd>
+<dt class="hdlist1">
<code><strong>-start</strong> <em>offset</em></code>
</dt>
<dd>
@@ -6221,49 +6317,8 @@ specified for this conversion.</p></div>
<div class="sect2">
<h3 id="_seek">seek</h3>
<div class="paragraph"><p><code><strong>seek</strong> <em>fileId offset ?origin?</em></code></p></div>
-<div class="paragraph"><p><code><em>fileId</em> <strong>seek</strong> <em>offset ?origin?</em></code></p></div>
-<div class="paragraph"><p>Change the current access position for <code><em>fileId</em></code>.
-The <code><em>offset</em></code> and <code><em>origin</em></code> arguments specify the position at
-which the next read or write will occur for <code><em>fileId</em></code>.
-<code><em>offset</em></code> must be a number (which may be negative) and <code><em>origin</em></code>
-must be one of the following:</p></div>
-<div class="dlist"><dl>
-<dt class="hdlist1">
-<code><strong>start</strong></code>
-</dt>
-<dd>
-<p>
- The new access position will be <code><em>offset</em></code> bytes from the start
- of the file.
-</p>
-</dd>
-<dt class="hdlist1">
-<code><strong>current</strong></code>
-</dt>
-<dd>
-<p>
- The new access position will be <code><em>offset</em></code> bytes from the current
- access position; a negative <code><em>offset</em></code> moves the access position
- backwards in the file.
-</p>
-</dd>
-<dt class="hdlist1">
-<code><strong>end</strong></code>
-</dt>
-<dd>
-<p>
- The new access position will be <code><em>offset</em></code> bytes from the end of
- the file. A negative <code><em>offset</em></code> places the access position before
- the end-of-file, and a positive <code><em>offset</em></code> places the access position
- after the end-of-file.
-</p>
-</dd>
-</dl></div>
-<div class="paragraph"><p>The <code><em>origin</em></code> argument defaults to <code>start</code>.</p></div>
-<div class="paragraph"><p><code><em>fileId</em></code> must have been the return value from a previous call to
-<a href="#_open"><strong><code>open</code></strong></a>, or it may be <code>stdin</code>, <code>stdout</code>, or <code>stderr</code> to refer to one
-of the standard I/O channels.</p></div>
-<div class="paragraph"><p>This command returns an empty string.</p></div>
+<div class="paragraph"><p>Tcl-compatible version of <code><em>fileId</em> <strong>seek</strong> <em>offset ?origin?</em></code></p></div>
+<div class="paragraph"><p>See <a href="#_aio"><strong><code>aio</code></strong></a> <code>seek</code></p></div>
</div>
<div class="sect2">
<h3 id="_set">set</h3>
@@ -6460,8 +6515,8 @@ For example,</p></div>
<div class="sect2">
<h3 id="_stacktrace">stacktrace</h3>
<div class="paragraph"><p><code><strong>stacktrace</strong></code></p></div>
-<div class="paragraph"><p>Returns a live stack trace as a list of <code>proc file line proc file line ...</code>.
-Iteratively uses <a href="#_info"><strong><code>info</code></strong></a> <code>frame</code> to create the stack trace. This stack trace is in the
+<div class="paragraph"><p>Returns a live stack trace as a list of <code>proc file line cmd proc file line cmd ...</code>.
+uses the same information as <a href="#_info"><strong><code>info</code></strong></a> <code>frame</code> to create the stack trace. This stack trace is in the
same form as produced by <a href="#_catch"><strong><code>catch</code></strong></a> and <a href="#_info"><strong><code>info</code></strong></a> <code>stacktrace</code></p></div>
<div class="paragraph"><p>See also <a href="#_stackdump"><strong><code>stackdump</code></strong></a>.</p></div>
</div>
@@ -7102,12 +7157,8 @@ the current call frame. This is similar to <em>exec</em> in Bourne Shell.</p></d
<div class="sect2">
<h3 id="_tell">tell</h3>
<div class="paragraph"><p><code><strong>tell</strong> <em>fileId</em></code></p></div>
-<div class="paragraph"><p><code><em>fileId</em> <strong>tell</strong></code></p></div>
-<div class="paragraph"><p>Returns a decimal string giving the current access position in
-<code><em>fileId</em></code>.</p></div>
-<div class="paragraph"><p><code><em>fileId</em></code> must have been the return value from a previous call to
-<a href="#_open"><strong><code>open</code></strong></a>, or it may be <code>stdin</code>, <code>stdout</code>, or <code>stderr</code> to refer to one
-of the standard I/O channels.</p></div>
+<div class="paragraph"><p>Tcl-compatible version of <code><em>fileId</em> <strong>tell</strong></code></p></div>
+<div class="paragraph"><p>See <a href="#_aio"><strong><code>aio</code></strong></a> <code>tell</code></p></div>
</div>
<div class="sect2">
<h3 id="_throw">throw</h3>
@@ -7448,32 +7499,73 @@ what options were selected when Jim Tcl was built.</p></div>
<div class="sect1">
<h2 id="_ansi_i_o_aio_and_eventloop_api">ANSI I/O (aio) and EVENTLOOP API</h2>
<div class="sectionbody">
-<div class="paragraph"><p>Jim provides an alternative object-based API for I/O.</p></div>
-<div class="paragraph"><p>See <a href="#_open"><strong><code>open</code></strong></a> and <a href="#_socket"><strong><code>socket</code></strong></a> for commands which return an I/O handle.</p></div>
+<div class="paragraph"><p>In addition to the traditional Tcl I/O commands (<a href="#_gets"><strong><code>gets</code></strong></a>, <a href="#_read"><strong><code>read</code></strong></a>, <a href="#_puts"><strong><code>puts</code></strong></a>, <a href="#_close"><strong><code>close</code></strong></a>, <a href="#_seek"><strong><code>seek</code></strong></a>, <a href="#_tell"><strong><code>tell</code></strong></a>),
+Jim provides an alternative object-based API for I/O. Commands that create a channel, <a href="#_open"><strong><code>open</code></strong></a> and <a href="#_socket"><strong><code>socket</code></strong></a>,
+return a handle to an I/O channel that is used to control that channel.</p></div>
+<div class="paragraph"><p>For example, the traditional Tcl usage would be:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> set f [open file.txt]
+ while {[gets $f buf] &gt;= 0} {
+ puts stderr $buf
+ }
+ close $f</code></pre>
+</div></div>
+<div class="paragraph"><p>While the Jim usage would be:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> set f [open file.txt]
+ while {[$f gets buf] &gt;= 0} {
+ stderr puts $buf
+ }
+ $f close</code></pre>
+</div></div>
+<div class="paragraph"><p>Thus channels are commands that support the various subcommands. They can be renamed handled
+like any other command. In additional to file I/O and stream (TCP) sockets, Jim supports many
+kinds of socket streams including UDP, Unix domain sockets, psuedo-tty pairs, pipes and others.
+(See <a href="#_socket"><strong><code>socket</code></strong></a> for more detail). The TLS (SSL) protocol may also be seamlessly layered over a channel
+with the <code>ssl</code> command. In addition Jim I/O supports both blocking and non-blocking modes,
+fully integrates with the eventloop, supports serial ports and tty control.</p></div>
+<div class="paragraph"><p>Note that while most channels are stream channels, some channels (socket types with <em>dgram</em>) are
+datagram channels. For those channels, <a href="#_aio"><strong><code>aio</code></strong></a> <code>recv</code> and <a href="#_aio"><strong><code>aio</code></strong></a> <code>sendto</code> is generally preferable
+over <a href="#_aio"><strong><code>aio</code></strong></a> <code>read</code> and <a href="#_aio"><strong><code>aio</code></strong></a> <code>puts</code>.</p></div>
<div class="sect2">
<h3 id="_aio">aio</h3>
<div class="dlist"><dl>
<dt class="hdlist1">
-<code>$handle <strong>accept</strong> ?addrvar?</code>
+<code>$handle <strong>accept ?-noclose?</strong> ?addrvar?</code>
</dt>
<dd>
<p>
- Server socket only: Accept a connection and return stream.
- If <code><em>addrvar</em></code> is specified, the address of the connected client is stored
- in the named variable in the form <em>addr:port</em> for IP sockets or <em>path</em> for Unix domain sockets.
- See <a href="#_socket"><strong><code>socket</code></strong></a> for details.
+ Server socket only: Accept a connection and return a stream channel.
+ If <code><em>addrvar</em></code> is specified, the address of the connected client is
+ stored in the named variable in the form <em>addr:port</em> for IP sockets
+ or <em>path</em> for Unix domain sockets. See <a href="#_socket"><strong><code>socket</code></strong></a> for details.
+ If <code><em>-noclose</em></code> is given, the returned handle is not automatically
+ closed for child proceses. See <a href="#_socket"><strong><code>socket</code></strong></a> for details.
</p>
</dd>
<dt class="hdlist1">
-<code>$handle <strong>buffering none|line|full</strong></code>
+<code>$handle <strong>buffering none|line|full</strong> ?size?</code>
</dt>
<dd>
<p>
- Sets the buffering mode of the stream.
+ Sets the output buffering mode of the stream channel. <code><em>none</em></code> means
+ that puts immediately writes output. <code><em>line</em></code> means output (including
+ previously buffered output) is written if a newline is to be written.
+ <code><em>full</em></code> means that data is written when the output buffer is full
+ (default 64KB). Size may be specified in full mode.
+ Note that line buffering will also write
+ once the output buffer limit is reached, even if there is no newline.
+ Channels usually begin in full buffering mode, unless they identify
+ as a tty channel, in which case line buffering is used, and <code>stderr</code>
+ begins with no buffering. Returns the current buffering mode (including
+ size in full mode - e.g. <code><em>line</em></code> or <code><em>full 65536</code></em>.
+ See also <a href="#_aio"><strong><code>aio</code></strong></a> <code>puts</code> and <a href="#_aio"><strong><code>aio</code></strong></a> <code>flush</code>.
</p>
</dd>
<dt class="hdlist1">
-<code>$handle <strong>close ?r(ead)|w(rite)|-nodelete?</strong></code>
+<code>$handle <strong>close ?r(ead)|w(rite)? ?-nodelete?</strong></code>
</dt>
<dd>
<p>
@@ -7481,16 +7573,17 @@ what options were selected when Jim Tcl was built.</p></div>
The <code><em>read</em></code> and <code><em>write</em></code> arguments perform a "half-close" on a socket. See the <em>shutdown(2)</em> man page.
The <code><em>-nodelete</em></code> option is applicable only for Unix domain sockets. It closes the socket
but does not delete the bound path (e.g. after <a href="#cmd_1"><strong><code>os.fork</code></strong></a>).
+ After a full close, the channel handle is no longer valid.
</p>
</dd>
<dt class="hdlist1">
-<code>$handle <strong>copyto</strong> <em>tofd ?size?</em></code>
+<code>$handle <strong>copyto</strong> <em>$tohandle ?size?</em></code>
</dt>
<dd>
<p>
- Copy bytes to the file descriptor <code><em>tofd</em></code>. If <code><em>size</em></code> is specified, at most
+ Copy bytes to channel <code><em>$tohandle</em></code>. If <code><em>size</em></code> is specified, at most
that many bytes will be copied. Otherwise copying continues until the end
- of the input file. Returns the number of bytes actually copied.
+ of the input channel. Returns the number of bytes actually copied.
</p>
</dd>
<dt class="hdlist1">
@@ -7498,7 +7591,8 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Returns 1 if stream is at eof
+ Returns 1 if an end-of-file condition has occurred on the channel. Note that
+ this condition may only be checked after reading from the channel.
</p>
</dd>
<dt class="hdlist1">
@@ -7507,8 +7601,9 @@ what options were selected when Jim Tcl was built.</p></div>
<dd>
<p>
Returns the original filename associated with the handle.
- Handles returned by <a href="#_socket"><strong><code>socket</code></strong></a> provide different information.
- See <a href="#_socket"><strong><code>socket</code></strong></a> for each socket type.
+ Handles returned by <a href="#_socket"><strong><code>socket</code></strong></a> provide different information such as the peer address
+ or a generic name if no useful filename can be provided.
+ See <a href="#_socket"><strong><code>socket</code></strong></a> for each socket type.
</p>
</dd>
<dt class="hdlist1">
@@ -7516,15 +7611,42 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Flush the stream
+ Flushes any output that has been buffered for the channel.
+ In blocking mode, command does not return until all data has been written.
+ In non-blocking mode, the behaviour depends on whether an <a href="#_aio"><strong><code>aio</code></strong></a> <code>writable</code> handler
+ has been set. If it has, and not all data could be written and error will be returned
+ with the message "send buffer full". Otherwise an "autoflush" eventloop handler is installed
+ to flush the remaining data. As long as the eventloop runs (<a href="#cmd_2"><strong><code>vwait</code></strong></a>, <a href="#cmd_2"><strong><code>update</code></strong></a>), the write
+ data will be automatically flushed.
+</p>
+</dd>
+<dt class="hdlist1">
+<code>$handle <strong>gets</strong> <em>?varName?</em></code>
+</dt>
+<dd>
+<p>
+ Read one line from the cannel and return it or store it in the
+ var A terminating newline character is discarded. If <code><em>varName</em></code>
+ is specified, then the line is placed in the variable by that name
+ and the return value is a count of the number of characters read
+ (not including the newline). If the end of the file is reached
+ before reading any characters then -1 is returned and <code><em>varName</em></code>
+ is set to an empty string. If <code><em>varName</em></code> is not specified then
+ the return value will be the line (minus the newline character) or
+ an empty string if the end of the file is reached before reading
+ any characters. An empty string will also be returned if a line
+ contains no characters except the newline, so <a href="#_eof"><strong><code>eof</code></strong></a> may have to be
+ used to determine what really happened. If the last character in
+ the file is not a newline character, then <a href="#_gets"><strong><code>gets</code></strong></a> behaves as if there
+ were an additional newline character at the end of the file.
</p>
</dd>
<dt class="hdlist1">
-<code>$handle <strong>gets</strong> <em>?var?</em></code>
+<code>$handle <strong>getfd</strong></code>
</dt>
<dd>
<p>
- Read one line and return it or store it in the var
+ Returns the underlying file descriptor. On Unix platforms this is a small integer.
</p>
</dd>
<dt class="hdlist1">
@@ -7532,7 +7654,7 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Returns 1 if the stream is a tty device.
+ Returns 1 if the channel is a tty device.
</p>
</dd>
<dt class="hdlist1">
@@ -7540,13 +7662,12 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Apply a POSIX lock to the open file associated with the handle using
- <em>fcntl(F_SETLK)</em>, or <em>fcntl(F_SETLKW)</em> to wait for the lock to be available if <code><em>-wait</em></code>
- is specified.
- The handle must be open for write access.
- Returns 1 if the lock was successfully obtained, 0 otherwise.
- An error occurs if the handle is not suitable for locking (e.g.
- if it is not open for write)
+ Apply a POSIX lock to the open file associated with the channel using
+ <em>fcntl(F_SETLK)</em>, or <em>fcntl(F_SETLKW)</em> to wait for the lock to be
+ available if <code><em>-wait</em></code> is specified. The channel must be open for
+ write access. Returns 1 if the lock was successfully obtained,
+ 0 otherwise. An error occurs if the channel is not suitable for
+ locking (e.g. if it is not open for write)
</p>
</dd>
<dt class="hdlist1">
@@ -7554,9 +7675,9 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Set O_NDELAY (if arg). Returns current/new setting.
- Note that in general ANSI I/O interacts badly with non-blocking I/O.
- Use with care.
+ With no argument, returns the non-blocking status of the channel
+ (1 means non-blocking). With an arguments, sets the non-blocking
+ status of the channel.
</p>
</dd>
<dt class="hdlist1">
@@ -7568,11 +7689,14 @@ what options were selected when Jim Tcl was built.</p></div>
</p>
</dd>
<dt class="hdlist1">
-<code>$handle <strong>puts ?-nonewline?</strong> <em>str</em></code>
+<code>$handle <strong>puts ?-nonewline?</strong> <em>string</em></code>
</dt>
<dd>
<p>
- Write the string, with newline unless -nonewline
+ Writes the characters given by <code><em>string</em></code> to the channel given
+ With <code><em>-nonewline</em></code>, the string is written as-is to the channel.
+ Otherwise a newline character is written after the string.
+ See <a href="#_aio"><strong><code>aio</code></strong></a> <code>buffering</code> and <a href="#_aio"><strong><code>aio</code></strong></a> <code>flush</code> for how output is buffered.
</p>
</dd>
<dt class="hdlist1">
@@ -7580,7 +7704,26 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Read and return bytes from the stream. To eof if no len. See <a href="#_read"><strong><code>read</code></strong></a>.
+ Read and return bytes from the channel.
+ If <em>len</em> is not given, reads until end-of-file.
+ reading from non-blocking channels.
+ For backward compatibility, <code><em>-pending</em></code> is accepted, but ignored.
+ If the <code>-nonewline</code> switch is specified then the last
+ character (at end-of-file) is discarded if it is a newline.
+ Note that read on a non-blocking channel may read less than the
+ expected number of bytes (including zero). Use <a href="#_aio"><strong><code>aio</code></strong></a> <code>eof</code> to determine
+ if the end-of-file has been reached.
+</p>
+</dd>
+<dt class="hdlist1">
+<code>$handle <strong>readsize</strong> ?size?'</code>
+</dt>
+<dd>
+<p>
+ Sets or returns the current size of the read buffer used
+ for read, gets and copyto.
+ Defaults to 256, but can be increased to improve performance
+ for large reads.
</p>
</dd>
<dt class="hdlist1">
@@ -7588,7 +7731,7 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Receives a message from the handle via recvfrom(2) and returns it.
+ Receives a message from the datagram channel via recvfrom(2) and returns it.
At most <code><em>maxlen</em></code> bytes are read. If <code><em>addrvar</em></code> is specified, the sending address
of the message is stored in the named variable in the form <em>addr:port</em> for IP sockets
or <em>path</em> for Unix domain sockets. See <a href="#_socket"><strong><code>socket</code></strong></a> for details.
@@ -7599,15 +7742,55 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Seeks in the stream (default <em>current</em>)
+ Change the current access position for the channel. This is only applicable
+ to regular files, not sockets.
+ The <code><em>offset</em></code> and <code><em>origin</em></code> arguments specify the position at
+ which the next read or write will occur for <code><em>fileId</em></code>.
+ <code><em>offset</em></code> must be a number (which may be negative) and <code><em>origin</em></code>
+ must be one of the following:
</p>
</dd>
<dt class="hdlist1">
+<code><strong>start</strong></code>
+</dt>
+<dd>
+<p>
+ The new access position will be <code><em>offset</em></code> bytes from the start
+ of the file.
+</p>
+</dd>
+<dt class="hdlist1">
+<code><strong>current</strong></code>
+</dt>
+<dd>
+<p>
+ The new access position will be <code><em>offset</em></code> bytes from the current
+ access position; a negative <code><em>offset</em></code> moves the access position
+ backwards in the file.
+</p>
+</dd>
+<dt class="hdlist1">
+<code><strong>end</strong></code>
+</dt>
+<dd>
+<p>
+ The new access position will be <code><em>offset</em></code> bytes from the end of
+ the file. A negative <code><em>offset</em></code> places the access position before
+ the end-of-file, and a positive <code><em>offset</em></code> places the access position
+ after the end-of-file.
+</p>
+</dd>
+</dl></div>
+<div class="paragraph"><p>The <code><em>origin</em></code> argument defaults to <code>start</code>.</p></div>
+<div class="paragraph"><p>This command returns an empty string.</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
<code>$handle <strong>sendto</strong> <em>str ?address</em></code>
</dt>
<dd>
<p>
- Sends the string, <code><em>str</em></code>, to the given address (host:port or path) via the socket using <em>sendto(2)</em>.
+ Sends the string, <code><em>str</em></code>, to the given address (host:port or path) via datagram socket channel
+ using <em>sendto(2)</em>.
This is intended for udp/dgram sockets and may give an error or behave in unintended
ways for other handle types.
Returns the number of bytes written.
@@ -7618,7 +7801,7 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Returns the bound address or path of the socket. See <em>getsockname(2)</em>.
+ Returns the bound address or path of the socket channel. See <em>getsockname(2)</em>.
</p>
</dd>
<dt class="hdlist1">
@@ -7626,7 +7809,7 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Implements the same functionality as <a href="#_file"><strong><code>file</code></strong></a> <code>stat</code> for a filehandle.
+ Implements the same functionality as <a href="#_file"><strong><code>file</code></strong></a> <code>stat</code> for a file channel.
Only available on platforms that support <em>fstat(2)</em> or equivalent.
</p>
</dd>
@@ -7635,11 +7818,12 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- With no arguments, returns a dictionary of socket options currently set for the handle
- (will be empty for a non-socket). With <code><em>name</em></code> and <code><em>value</em></code>, sets the socket option
- to the given value. Currently supports the following boolean socket options:
- <code>broadcast, debug, keepalive, nosigpipe, oobinline, tcp_nodelay</code>, and the following
- integer socket options: <code>sndbuf, rcvbuf</code>
+ With no arguments, returns a dictionary of socket options currently
+ set for the socket channel (will be empty for a non-socket). With
+ <code><em>name</em></code> and <code><em>value</em></code>, sets the socket option to the given
+ value. Currently supports the following boolean socket options:
+ <code>broadcast, debug, keepalive, nosigpipe, oobinline, tcp_nodelay</code>,
+ and the following integer socket options: <code>sndbuf, rcvbuf</code>
</p>
</dd>
<dt class="hdlist1">
@@ -7647,8 +7831,11 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Flush the stream, then <em>fsync(2)</em> to commit any changes to storage.
+ Flushes the channel, then calls <em>fsync(2)</em> to commit any changes to storage.
Only available on platforms that support <em>fsync(2)</em>.
+ If the flush fails (perhaps because the channel is non-blocking), an error
+ will be returned instead. Although this is designed for normal files and
+ those should be used in blocking mode.
</p>
</dd>
<dt class="hdlist1">
@@ -7656,7 +7843,18 @@ what options were selected when Jim Tcl was built.</p></div>
</dt>
<dd>
<p>
- Returns the current seek position
+ Returns the current seek position or -1 if the channel is not seekable.
+</p>
+</dd>
+<dt class="hdlist1">
+<code>$handle <strong>timeout</strong> <em>?ms?</em></code>
+</dt>
+<dd>
+<p>
+ With no argument, returns the current timeout of the channel, in milliseconds.
+ If an argument is given, it is set as the timeout of the channel, in milliseconds.
+ See <a href="#_aio"><strong><code>aio</code></strong></a> <code>read</code> and <a href="#_aio"><strong><code>aio</code></strong></a> <code>gets</code> for command that use the timeout.
+ Note that the timeout is only used if the channel is in blocking mode.
</p>
</dd>
<dt class="hdlist1">
@@ -7665,7 +7863,7 @@ what options were selected when Jim Tcl was built.</p></div>
<dd>
<p>
If no arguments are given, returns a dictionary containing the tty settings for the stream.
- If arguments are given, they must either be a dictionary, or <code>setting value ...</code>
+ If arguments are given, they must either be a dictionary, or <code>setting value ...</code>.
Abbreviations are supported for both settings and values, so the following is acceptable:
<code>$f tty parity e input c out raw</code>.
Only available on platforms that support <em>termios(3)</em>. Supported settings are:
@@ -7753,6 +7951,63 @@ what options were selected when Jim Tcl was built.</p></div>
Timeout for noncanonical read (units of 0.1 seconds)
</p>
</dd>
+<dt class="hdlist1">
+<code><strong>vstart</strong> <em>char</em></code>
+</dt>
+<dd>
+<p>
+ Start character for xonoff, usually 0x11 (^Q)
+</p>
+</dd>
+<dt class="hdlist1">
+<code><strong>vstop</strong> <em>char</em></code>
+</dt>
+<dd>
+<p>
+ Stop character for xonoff, usually 0x13 (^S)
+</p>
+</dd>
+</dl></div>
+</dd>
+<dt class="hdlist1">
+<code>$handle <strong>ttycontrol</strong> ?settings?</code>
+</dt>
+<dd>
+<p>
+ If no arguments are given, returns a dictionary containing the modem control signals
+ from the stream (must be a serial-type device). e.g. <code>{rts 1 dtr 1 dcd 0 dsr 0 ring 0 cts 0}</code>.
+ Note that <code>rts</code> and <code>dtr</code> are controlled by the local system while the other signals reflect
+ the remote system.
+ If arguments are given, they must either be a dictionary, or <code>setting value ...</code>.
+ Abbreviations are supported for both settings and values.
+ Supported settings are:
+</p>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+<code><strong>rts 0|1</strong></code>
+</dt>
+<dd>
+<p>
+ Set the RTS (Request To Send) signal
+</p>
+</dd>
+<dt class="hdlist1">
+<code><strong>dtr 0|1</strong></code>
+</dt>
+<dd>
+<p>
+ Set the DTR (Data Terminal Ready) signal
+</p>
+</dd>
+<dt class="hdlist1">
+<code><strong>break</strong> <em>duration</em></code>
+</dt>
+<dd>
+<p>
+ Generate a break condition. <code>duration</code> is generally ignored but may be used
+ in a platform-dependent manner.
+</p>
+</dd>
</dl></div>
</dd>
<dt class="hdlist1">
@@ -7792,6 +8047,26 @@ what options were selected when Jim Tcl was built.</p></div>
</p>
</dd>
</dl></div>
+<div class="paragraph"><p><strong>Buffering, non-blocking and timeouts</strong></p></div>
+<div class="paragraph"><p>Channels normally operate in blocking mode. This means that reads (gets,
+read, copyto) block until data is received or end-of-file is reached,
+or an error occurs. Similarly, writes (puts, copyto) block if the channel
+is not current writable.</p></div>
+<div class="paragraph"><p>It is possible to set a timeout for blocking reads with <a href="#_aio"><strong><code>aio</code></strong></a> <code>timeout</code>,
+generally useful on stream socket channels. If a timeout is specified
+for a channel (the default is 0/indefinite), a blocking read will return
+with no data if the timeout expires without reading any data.</p></div>
+<div class="paragraph"><p>For some applications, and especially when using the eventloop, blocking
+I/O and timeouts are not appropriate. Instead we wish to read what is
+available, and write what is possible in the <code>readable</code> and <code>writable</code>
+scripts and then return until the next event. This can be achived by
+setting a channel non-blocking mode with <a href="#_aio"><strong><code>aio</code></strong></a> <code>ndelay</code>. In this case, <a href="#_aio"><strong><code>aio</code></strong></a> <code>read</code>, <a href="#_aio"><strong><code>aio</code></strong></a> <code>gets</code>
+and <a href="#_aio"><strong><code>aio</code></strong></a> <code>puts</code> will return early if they would otherwise block, performing
+us much work as posssible. For example, <a href="#_aio"><strong><code>aio</code></strong></a> <code>read</code> may return less data than requested
+and <a href="#_aio"><strong><code>aio</code></strong></a> <code>puts</code> may write less data than requested (although see <a href="#_aio"><strong><code>aio</code></strong></a> <code>flush</code> about
+additional write data can be automatically flushed). If <a href="#_aio"><strong><code>aio</code></strong></a> <code>gets</code> does not receive an
+entire line, it returns -1. In all these cases <a href="#_aio"><strong><code>aio</code></strong></a> <code>eof</code> can be used to determine
+if end-of-file was reached.</p></div>
</div>
<div class="sect2">
<h3 id="_fconfigure">fconfigure</h3>
@@ -7958,109 +8233,109 @@ to prevent infinite errors. (A time event handler is always removed after execut
</div>
<div class="sect2">
<h3 id="_socket">socket</h3>
-<div class="paragraph"><p>Various socket types may be created.</p></div>
+<div class="paragraph"><p>Various socket types may be created as follows.</p></div>
<div class="dlist"><dl>
<dt class="hdlist1">
-<code><strong>socket unix</strong> <em>path</em></code>
+<code><strong>socket ?-noclose? unix</strong> <em>path</em></code>
</dt>
<dd>
<p>
A unix domain socket client connected to <em>path</em>
- <em>filename</em> returns <code><em>path</em></code>
+ <em>filename</em> returns <code><em>path</em></code>
</p>
</dd>
<dt class="hdlist1">
-<code><strong>socket unix.server</strong> <em>path</em></code>
+<code><strong>socket ?-noclose? unix.server</strong> <em>path</em></code>
</dt>
<dd>
<p>
A unix domain socket server listening on <em>path</em>
- <em>filename</em> returns <code><em>path</em></code>
+ <em>filename</em> returns <code><em>path</em></code>
</p>
</dd>
<dt class="hdlist1">
-<code><strong>socket unix.dgram</strong> <em>?path?</em></code>
+<code><strong>socket ?-noclose? unix.dgram</strong> <em>?path?</em></code>
</dt>
<dd>
<p>
A unix domain socket datagram client, optionally connected to <em>path</em>
- <em>filename</em> returns <code><em>path</em></code> if provided or "dgram" if not
+ <em>filename</em> returns <code><em>path</em></code> if provided or "dgram" if not
</p>
</dd>
<dt class="hdlist1">
-<code><strong>socket unix.dgram.server</strong> <em>path</em></code>
+<code><strong>socket ?-noclose? unix.dgram.server</strong> <em>path</em></code>
</dt>
<dd>
<p>
A unix domain socket datagram server server listening on <em>path</em>
- <em>filename</em> returns <code><em>path</em></code>
+ <em>filename</em> returns <code><em>path</em></code>
</p>
</dd>
<dt class="hdlist1">
-<code><strong>socket ?-async? ?-ipv6? stream</strong> <em>addr:port</em></code>
+<code><strong>socket ?-noclose? ?-async? ?-ipv6? stream</strong> <em>addr:port</em></code>
</dt>
<dd>
<p>
A TCP socket client. (See the forms for <code><em>addr</em></code> below)
- <em>filename</em> returns <code><em>addr:port</em></code>
+ <em>filename</em> returns <code><em>addr:port</em></code>
</p>
</dd>
<dt class="hdlist1">
-<code><strong>socket ?-async? ?-ipv6? stream.server</strong> <em>?addr:?port</em></code>
+<code><strong>socket ?-noclose? ?-async? ?-ipv6? stream.server</strong> <em>?addr:?port</em></code>
</dt>
<dd>
<p>
A TCP socket server (<code><em>addr</em></code> defaults to <code>0.0.0.0</code> for IPv4 or <code>[::]</code> for IPv6).
- <em>filename</em> returns <code><em>addr:port</em></code>
+ <em>filename</em> returns <code><em>addr:port</em></code>
</p>
</dd>
<dt class="hdlist1">
-<code><strong>socket ?-async? ?-ipv6? dgram</strong> ?<em>addr:port</em>?</code>
+<code><strong>socket ?-noclose? ?-async? ?-ipv6? dgram</strong> ?<em>addr:port</em>?</code>
</dt>
<dd>
<p>
A UDP socket client. If the address is not specified,
the client socket will be unbound and <em>sendto</em> must be used
to indicated the destination.
- <em>filename</em> returns <code><em>addr:port</em></code> if provided or "dgram" if not
+ <em>filename</em> returns <code><em>addr:port</em></code> if provided or "dgram" if not
</p>
</dd>
<dt class="hdlist1">
-<code><strong>socket ?-async? ?-ipv6? dgram.server</strong> <em>addr:port</em></code>
+<code><strong>socket ?-noclose? ?-async? ?-ipv6? dgram.server</strong> <em>addr:port</em></code>
</dt>
<dd>
<p>
A UDP socket server.
- <em>filename</em> returns <code><em>addr:port</em></code>
+ <em>filename</em> returns <code><em>addr:port</em></code>
</p>
</dd>
<dt class="hdlist1">
-<code><strong>socket pipe</strong></code>
+<code><strong>socket ?-noclose? pipe</strong></code>
</dt>
<dd>
<p>
A synonym for <a href="#_pipe"><strong><code>pipe</code></strong></a>
- <em>filename</em> returns "pipe"
+ <em>filename</em> returns "pipe"
</p>
</dd>
<dt class="hdlist1">
-<code><strong>socket pair</strong></code>
+<code><strong>socket ?-noclose? pair</strong></code>
</dt>
<dd>
<p>
A socketpair (see socketpair(2)). Like <a href="#_pipe"><strong><code>pipe</code></strong></a>, this command returns
a list of two channels: {s1 s2}. These channels are both readable and writable.
- <em>filename</em> returns "pair"
+ <em>filename</em> returns "pair"
</p>
</dd>
<dt class="hdlist1">
-<code><strong>socket pty</strong></code>
+<code><strong>socket ?-noclose? pty</strong></code>
</dt>
<dd>
<p>
A pseudo-tty pair (see openpty(3)). Like <a href="#_pipe"><strong><code>pipe</code></strong></a>, this command returns
a list of two channels: {primary replica}. These channels are both readable and writable.
- <em>filename</em> for both handles returns the replica filename.
+ <em>filename</em> for both handles returns the replica filename.
</p>
</dd>
</dl></div>
@@ -8149,6 +8424,14 @@ will succeed if connected or fail if connect failed. Typical usage is as follows
vwait done</code></pre>
</div></div>
+<div class="paragraph"><p>If <em><code>-noclose</code></em> is specified, the socket is not automatically closed for child proceses. e.g.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> lassign [socket -noclose pipe] r w
+ # This file descriptor will be open in the child process
+ # with the file descriptors passed on the command line
+ exec subcommand [$r getfd] [$w getfd]</code></pre>
+</div></div>
</div>
<div class="sect2">
<h3 id="_syslog">syslog</h3>
@@ -8532,6 +8815,50 @@ be replaced with a custom command instead if desired.</p></div>
</dl></div>
</div>
<div class="sect2">
+<h3 id="_tcl_stdhint">tcl::stdhint</h3>
+<div class="paragraph"><p>Scriptable hinting is supported in the interactive shell, <em>jimsh</em>, through
+the <a href="#_tcl_stdhint"><strong><code>tcl::stdhint</code></strong></a> callback. A simple implementation is provided, however this may
+be replaced with a custom command instead if desired.</p></div>
+<div class="paragraph"><p>In the interactive shell, press &lt;TAB&gt; to activate command line completion.</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+<code><strong>tcl::stdhint</strong> <em>commandline</em></code>
+</dt>
+<dd>
+<p>
+ This command is called with the current command line. It should return a list of <code><strong>{hint ?ANSI cols?}</strong></code> or ""
+ if no hint is available.
+ For example, if passed <code><strong>"dict get"</strong></code> it could return <code><strong>{"dict get dictionary ?key &#8230;?" 36 1}</strong></code> to show the given hint
+ in light cyan.
+</p>
+</dd>
+</dl></div>
+<div class="paragraph"><p>The built-in <a href="#_tcl_stdhint"><strong><code>tcl::stdhint</code></strong></a> callback uses <em>tcl::stdhint_col</em> for the colour. <em>tcl::stdhint_cols</em> can be used
+to easily change this colour, e.g. in ~/.jimrc.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> . parray tcl::stdhint_cols
+ tcl::stdhint_cols(black) = 30
+ tcl::stdhint_cols(blue) = 34
+ tcl::stdhint_cols(cyan) = 36
+ tcl::stdhint_cols(gray) = 30 1
+ tcl::stdhint_cols(green) = 32
+ tcl::stdhint_cols(grey) = 30 1
+ tcl::stdhint_cols(lblue) = 34 1
+ tcl::stdhint_cols(lcyan) = 36 1
+ tcl::stdhint_cols(lgreen) = 32 1
+ tcl::stdhint_cols(lpurple) = 35 1
+ tcl::stdhint_cols(lred) = 31 1
+ tcl::stdhint_cols(lyellow) = 33 1
+ tcl::stdhint_cols(none) = 0
+ tcl::stdhint_cols(normal) = 37
+ tcl::stdhint_cols(purple) = 35
+ tcl::stdhint_cols(red) = 31
+ tcl::stdhint_cols(white) = 37 1
+ tcl::stdhint_cols(yellow) = 33</code></pre>
+</div></div>
+</div>
+<div class="sect2">
<h3 id="_history">history</h3>
<div class="paragraph"><p>The optional history extension provides script access to the command line editing
and history support available in <em>jimsh</em>. See <em>examples/jtclsh.tcl</em> for an example.
@@ -8567,6 +8894,15 @@ the remaining subcommands do nothing.</p></div>
</p>
</dd>
<dt class="hdlist1">
+<code><strong>history hints</strong> <em>command</em></code>
+</dt>
+<dd>
+<p>
+ Sets a hinting command (see <a href="#_tcl_stdhint"><strong><code>tcl::stdhint</code></strong></a>) that is active during <a href="#_history"><strong><code>history</code></strong></a> <code>getline</code>.
+ If the command is empty, hinting is disabled.
+</p>
+</dd>
+<dt class="hdlist1">
<code><strong>history add</strong> <em>line</em></code>
</dt>
<dd>
@@ -8971,14 +9307,16 @@ by the Tcl library.</p></div>
</dl></div>
<div class="listingblock">
<div class="content">
-<pre><code> tcl_platform(byteOrder) = littleEndian
+<pre><code> tcl_platform(bootstrap) = 0
+ tcl_platform(byteOrder) = littleEndian
tcl_platform(engine) = Jim
- tcl_platform(os) = Darwin
+ tcl_platform(os) = darwin
+ tcl_platform(pathSeparator) = :
tcl_platform(platform) = unix
tcl_platform(pointerSize) = 8
+ tcl_platform(stackFormat) = 4
tcl_platform(threaded) = 0
- tcl_platform(wordSize) = 8
- tcl_platform(pathSeparator) = :</code></pre>
+ tcl_platform(wordSize) = 8</code></pre>
</div></div>
<div class="dlist"><dl>
<dt class="hdlist1">
@@ -9016,6 +9354,15 @@ by the Tcl library.</p></div>
The value of argv[0] when jimsh was invoked.
</p>
</dd>
+<dt class="hdlist1">
+<code><strong>jim::lineedit</strong></code>
+</dt>
+<dd>
+<p>
+ This variables is set to 1 if jimsh was configured with line editing support,
+ or 0 if not.
+</p>
+</dd>
</dl></div>
<div class="paragraph"><p>The following variables have special meaning to Jim Tcl:</p></div>
<div class="dlist"><dl>
diff --git a/auto.def b/auto.def
index c3ff6e6..81ee889 100644
--- a/auto.def
+++ b/auto.def
@@ -1,7 +1,7 @@
# vim:se syn=tcl:
#
-define JIM_VERSION 82
+define JIM_VERSION 84
options-defaults {
silent-rules 1
@@ -549,7 +549,7 @@ if {$withinfo(without) eq "default"} {
# Now go check everything - see autosetup/local.tcl
array set extinfo [check-extensions [opt-bool allextmod]]
-set buildjimext 1
+define BUILD_JIM_EXT 1
# Now special checks
if {[have-feature windows]} {
@@ -560,7 +560,7 @@ if {[have-feature windows]} {
user-error "cygwin/mingw require --shared for dynamic modules"
} else {
user-notice "Building static library, so build-jim-ext will not work on cygwin/mingw"
- set buildjimext 0
+ define BUILD_JIM_EXT 0
}
}
} else {
@@ -668,7 +668,7 @@ make-config-header jimautoconf.h -auto {jim_ext_* TCL_PLATFORM_* TCL_LIBRARY USE
make-template Makefile.in
make-template tests/Makefile.in
make-template examples.api/Makefile.in
-if {$buildjimext} {
+if {[get-define BUILD_JIM_EXT]} {
make-template build-jim-ext.in
catch {exec chmod +x build-jim-ext}
}
diff --git a/autosetup/README.autosetup b/autosetup/README.autosetup
index 30bef32..3952980 100644
--- a/autosetup/README.autosetup
+++ b/autosetup/README.autosetup
@@ -1,4 +1,4 @@
-README.autosetup created by autosetup v0.7.1+
+README.autosetup created by autosetup v0.7.2
This is the autosetup directory for a local install of autosetup.
It contains autosetup, support files and loadable modules.
diff --git a/autosetup/autosetup b/autosetup/autosetup
index e4d5a31..90f5454 100755
--- a/autosetup/autosetup
+++ b/autosetup/autosetup
@@ -6,7 +6,7 @@
dir=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"
# Note that the version has a trailing + on unreleased versions
-set autosetup(version) 0.7.1+
+set autosetup(version) 0.7.2
# Can be set to 1 to debug early-init problems
set autosetup(debug) [expr {"--debug" in $argv}]
@@ -566,7 +566,10 @@ proc options-show {what} {
set indent [string repeat " " [expr {$max+4}]]
set cols [getenv COLUMNS 80]
catch {
- lassign [exec stty size] rows cols
+ lassign [exec stty size] _ sttycols
+ if {[string is integer -strict $sttycols]} {
+ set cols $sttycols
+ }
}
incr cols -1
# Now output
@@ -910,8 +913,7 @@ proc list-non-empty {list} {
# Searches the path for an executable with the given name.
# Note that the name may include some parameters, e.g. 'cc -mbig-endian',
# in which case the parameters are ignored.
-# The full path to the executable if found, or "" if not found.
-# Returns 1 if found, or 0 if not.
+# Returns the full path to the executable if found, or "" if not found.
#
proc find-executable-path {name} {
# Ignore any parameters
diff --git a/autosetup/autosetup-config.guess b/autosetup/autosetup-config.guess
index e81d3ae..48a6846 100755
--- a/autosetup/autosetup-config.guess
+++ b/autosetup/autosetup-config.guess
@@ -1,14 +1,14 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2021 Free Software Foundation, Inc.
+# Copyright 1992-2024 Free Software Foundation, Inc.
# shellcheck disable=SC2006,SC2268 # see below for rationale
-timestamp='2021-06-03'
+timestamp='2024-07-27'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
+# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
@@ -47,7 +47,7 @@ me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION]
-Output the configuration name of the system \`$me' is run on.
+Output the configuration name of the system '$me' is run on.
Options:
-h, --help print this help, then exit
@@ -60,13 +60,13 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2021 Free Software Foundation, Inc.
+Copyright 1992-2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help="
-Try \`$me --help' for more information."
+Try '$me --help' for more information."
# Parse command line
while test $# -gt 0 ; do
@@ -102,8 +102,8 @@ GUESS=
# temporary files to be created and, as you can see below, it is a
# headache to deal with in a portable fashion.
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
-# use `HOST_CC' if defined, but it is deprecated.
+# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
+# use 'HOST_CC' if defined, but it is deprecated.
# Portable tmp directory creation inspired by the Autoconf team.
@@ -123,7 +123,7 @@ set_cc_for_build() {
dummy=$tmp/dummy
case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
,,) echo "int x;" > "$dummy.c"
- for driver in cc gcc c89 c99 ; do
+ for driver in cc gcc c17 c99 c89 ; do
if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
CC_FOR_BUILD=$driver
break
@@ -155,6 +155,9 @@ Linux|GNU|GNU/*)
set_cc_for_build
cat <<-EOF > "$dummy.c"
+ #if defined(__ANDROID__)
+ LIBC=android
+ #else
#include <features.h>
#if defined(__UCLIBC__)
LIBC=uclibc
@@ -162,6 +165,8 @@ Linux|GNU|GNU/*)
LIBC=dietlibc
#elif defined(__GLIBC__)
LIBC=gnu
+ #elif defined(__LLVM_LIBC__)
+ LIBC=llvm
#else
#include <stdarg.h>
/* First heuristic to detect musl libc. */
@@ -169,6 +174,7 @@ Linux|GNU|GNU/*)
LIBC=musl
#endif
#endif
+ #endif
EOF
cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
eval "$cc_set_libc"
@@ -437,7 +443,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
# This test works for both compilers.
if test "$CC_FOR_BUILD" != no_compiler_found; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
SUN_ARCH=x86_64
@@ -459,7 +465,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
UNAME_RELEASE=`uname -v`
;;
esac
- # Japanese Language versions have a version number like `4.1.3-JL'.
+ # Japanese Language versions have a version number like '4.1.3-JL'.
SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
GUESS=sparc-sun-sunos$SUN_REL
;;
@@ -628,7 +634,8 @@ EOF
sed 's/^ //' << EOF > "$dummy.c"
#include <sys/systemcfg.h>
- main()
+ int
+ main ()
{
if (!__power_pc())
exit(1);
@@ -712,7 +719,8 @@ EOF
#include <stdlib.h>
#include <unistd.h>
- int main ()
+ int
+ main ()
{
#if defined(_SC_KERNEL_BITS)
long bits = sysconf(_SC_KERNEL_BITS);
@@ -904,7 +912,7 @@ EOF
fi
;;
*:FreeBSD:*:*)
- UNAME_PROCESSOR=`/usr/bin/uname -p`
+ UNAME_PROCESSOR=`uname -p`
case $UNAME_PROCESSOR in
amd64)
UNAME_PROCESSOR=x86_64 ;;
@@ -929,6 +937,9 @@ EOF
i*:PW*:*)
GUESS=$UNAME_MACHINE-pc-pw32
;;
+ *:SerenityOS:*:*)
+ GUESS=$UNAME_MACHINE-pc-serenity
+ ;;
*:Interix*:*)
case $UNAME_MACHINE in
x86)
@@ -963,11 +974,37 @@ EOF
GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
;;
+ x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
+ ;;
+ *:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
+ ;;
*:Minix:*:*)
GUESS=$UNAME_MACHINE-unknown-minix
;;
aarch64:Linux:*:*)
- GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ set_cc_for_build
+ CPU=$UNAME_MACHINE
+ LIBCABI=$LIBC
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ ABI=64
+ sed 's/^ //' << EOF > "$dummy.c"
+ #ifdef __ARM_EABI__
+ #ifdef __ARM_PCS_VFP
+ ABI=eabihf
+ #else
+ ABI=eabi
+ #endif
+ #endif
+EOF
+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+ eval "$cc_set_abi"
+ case $ABI in
+ eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
+ esac
+ fi
+ GUESS=$CPU-unknown-linux-$LIBCABI
;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
@@ -1033,7 +1070,16 @@ EOF
k1om:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;;
- loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
+ kvx:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ kvx:cos:*:*)
+ GUESS=$UNAME_MACHINE-unknown-cos
+ ;;
+ kvx:mbr:*:*)
+ GUESS=$UNAME_MACHINE-unknown-mbr
+ ;;
+ loongarch32:Linux:*:* | loongarch64:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;;
m32r*:Linux:*:*)
@@ -1148,16 +1194,27 @@ EOF
;;
x86_64:Linux:*:*)
set_cc_for_build
+ CPU=$UNAME_MACHINE
LIBCABI=$LIBC
if test "$CC_FOR_BUILD" != no_compiler_found; then
- if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_X32 >/dev/null
- then
- LIBCABI=${LIBC}x32
- fi
+ ABI=64
+ sed 's/^ //' << EOF > "$dummy.c"
+ #ifdef __i386__
+ ABI=x86
+ #else
+ #ifdef __ILP32__
+ ABI=x32
+ #endif
+ #endif
+EOF
+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+ eval "$cc_set_abi"
+ case $ABI in
+ x86) CPU=i686 ;;
+ x32) LIBCABI=${LIBC}x32 ;;
+ esac
fi
- GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI
+ GUESS=$CPU-pc-linux-$LIBCABI
;;
xtensa*:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
@@ -1177,7 +1234,7 @@ EOF
GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
;;
i*86:OS/2:*:*)
- # If we were able to find `uname', then EMX Unix compatibility
+ # If we were able to find 'uname', then EMX Unix compatibility
# is probably installed.
GUESS=$UNAME_MACHINE-pc-os2-emx
;;
@@ -1318,7 +1375,7 @@ EOF
GUESS=ns32k-sni-sysv
fi
;;
- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
# says <Richard.M.Bartel@ccMail.Census.GOV>
GUESS=i586-unisys-sysv4
;;
@@ -1364,8 +1421,11 @@ EOF
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
GUESS=i586-pc-haiku
;;
- x86_64:Haiku:*:*)
- GUESS=x86_64-unknown-haiku
+ ppc:Haiku:*:*) # Haiku running on Apple PowerPC
+ GUESS=powerpc-apple-haiku
+ ;;
+ *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat)
+ GUESS=$UNAME_MACHINE-unknown-haiku
;;
SX-4:SUPER-UX:*:*)
GUESS=sx4-nec-superux$UNAME_RELEASE
@@ -1522,6 +1582,9 @@ EOF
i*86:rdos:*:*)
GUESS=$UNAME_MACHINE-pc-rdos
;;
+ i*86:Fiwix:*:*)
+ GUESS=$UNAME_MACHINE-pc-fiwix
+ ;;
*:AROS:*:*)
GUESS=$UNAME_MACHINE-unknown-aros
;;
@@ -1534,6 +1597,9 @@ EOF
*:Unleashed:*:*)
GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
;;
+ *:Ironclad:*:*)
+ GUESS=$UNAME_MACHINE-unknown-ironclad
+ ;;
esac
# Do we have a guess based on uname results?
@@ -1557,6 +1623,7 @@ cat > "$dummy.c" <<EOF
#endif
#endif
#endif
+int
main ()
{
#if defined (sony)
diff --git a/autosetup/autosetup-config.sub b/autosetup/autosetup-config.sub
index d80c5d7..4aaae46 100755
--- a/autosetup/autosetup-config.sub
+++ b/autosetup/autosetup-config.sub
@@ -1,14 +1,14 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2021 Free Software Foundation, Inc.
+# Copyright 1992-2024 Free Software Foundation, Inc.
-# shellcheck disable=SC2006,SC2268 # see below for rationale
+# shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale
-timestamp='2021-07-03'
+timestamp='2024-05-27'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
+# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
@@ -76,13 +76,13 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2021 Free Software Foundation, Inc.
+Copyright 1992-2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help="
-Try \`$me --help' for more information."
+Try '$me --help' for more information."
# Parse command line
while test $# -gt 0 ; do
@@ -120,15 +120,16 @@ case $# in
esac
# Split fields of configuration type
-# shellcheck disable=SC2162
+saved_IFS=$IFS
IFS="-" read field1 field2 field3 field4 <<EOF
$1
EOF
+IFS=$saved_IFS
# Separate into logical components for further validation
case $1 in
*-*-*-*-*)
- echo Invalid configuration \`"$1"\': more than four components >&2
+ echo "Invalid configuration '$1': more than four components" >&2
exit 1
;;
*-*-*-*)
@@ -140,10 +141,21 @@ case $1 in
# parts
maybe_os=$field2-$field3
case $maybe_os in
- nto-qnx* | linux-* | uclinux-uclibc* \
- | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
- | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
- | storm-chaos* | os2-emx* | rtmk-nova*)
+ cloudabi*-eabi* \
+ | kfreebsd*-gnu* \
+ | knetbsd*-gnu* \
+ | kopensolaris*-gnu* \
+ | linux-* \
+ | managarm-* \
+ | netbsd*-eabi* \
+ | netbsd*-gnu* \
+ | nto-qnx* \
+ | os2-emx* \
+ | rtmk-nova* \
+ | storm-chaos* \
+ | uclinux-gnu* \
+ | uclinux-uclibc* \
+ | windows-* )
basic_machine=$field1
basic_os=$maybe_os
;;
@@ -158,8 +170,12 @@ case $1 in
esac
;;
*-*)
- # A lone config we happen to match not fitting any pattern
case $field1-$field2 in
+ # Shorthands that happen to contain a single dash
+ convex-c[12] | convex-c3[248])
+ basic_machine=$field2-convex
+ basic_os=
+ ;;
decstation-3100)
basic_machine=mips-dec
basic_os=
@@ -167,24 +183,88 @@ case $1 in
*-*)
# Second component is usually, but not always the OS
case $field2 in
- # Prevent following clause from handling this valid os
+ # Do not treat sunos as a manufacturer
sun*os*)
basic_machine=$field1
basic_os=$field2
;;
# Manufacturers
- dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
- | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
- | unicom* | ibm* | next | hp | isi* | apollo | altos* \
- | convergent* | ncr* | news | 32* | 3600* | 3100* \
- | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
- | ultra | tti* | harris | dolphin | highlevel | gould \
- | cbm | ns | masscomp | apple | axis | knuth | cray \
- | microblaze* | sim | cisco \
- | oki | wec | wrs | winbond)
+ 3100* \
+ | 32* \
+ | 3300* \
+ | 3600* \
+ | 7300* \
+ | acorn \
+ | altos* \
+ | apollo \
+ | apple \
+ | atari \
+ | att* \
+ | axis \
+ | be \
+ | bull \
+ | cbm \
+ | ccur \
+ | cisco \
+ | commodore \
+ | convergent* \
+ | convex* \
+ | cray \
+ | crds \
+ | dec* \
+ | delta* \
+ | dg \
+ | digital \
+ | dolphin \
+ | encore* \
+ | gould \
+ | harris \
+ | highlevel \
+ | hitachi* \
+ | hp \
+ | ibm* \
+ | intergraph \
+ | isi* \
+ | knuth \
+ | masscomp \
+ | microblaze* \
+ | mips* \
+ | motorola* \
+ | ncr* \
+ | news \
+ | next \
+ | ns \
+ | oki \
+ | omron* \
+ | pc533* \
+ | rebel \
+ | rom68k \
+ | rombug \
+ | semi \
+ | sequent* \
+ | siemens \
+ | sgi* \
+ | siemens \
+ | sim \
+ | sni \
+ | sony* \
+ | stratus \
+ | sun \
+ | sun[234]* \
+ | tektronix \
+ | tti* \
+ | ultra \
+ | unicom* \
+ | wec \
+ | winbond \
+ | wrs)
basic_machine=$field1-$field2
basic_os=
;;
+ zephyr*)
+ basic_machine=$field1-unknown
+ basic_os=$field2
+ ;;
*)
basic_machine=$field1
basic_os=$field2
@@ -265,26 +345,6 @@ case $1 in
basic_machine=arm-unknown
basic_os=cegcc
;;
- convex-c1)
- basic_machine=c1-convex
- basic_os=bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- basic_os=bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- basic_os=bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- basic_os=bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- basic_os=bsd
- ;;
cray)
basic_machine=j90-cray
basic_os=unicos
@@ -707,15 +767,26 @@ case $basic_machine in
vendor=dec
basic_os=tops20
;;
- delta | 3300 | motorola-3300 | motorola-delta \
- | 3300-motorola | delta-motorola)
+ delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300)
cpu=m68k
vendor=motorola
;;
- dpx2*)
+ # This used to be dpx2*, but that gets the RS6000-based
+ # DPX/20 and the x86-based DPX/2-100 wrong. See
+ # https://oldskool.silicium.org/stations/bull_dpx20.htm
+ # https://www.feb-patrimoine.com/english/bull_dpx2.htm
+ # https://www.feb-patrimoine.com/english/unix_and_bull.htm
+ dpx2 | dpx2[23]00 | dpx2[23]xx)
cpu=m68k
vendor=bull
- basic_os=sysv3
+ ;;
+ dpx2100 | dpx21xx)
+ cpu=i386
+ vendor=bull
+ ;;
+ dpx20)
+ cpu=rs6000
+ vendor=bull
;;
encore | umax | mmax)
cpu=ns32k
@@ -830,18 +901,6 @@ case $basic_machine in
next | m*-next)
cpu=m68k
vendor=next
- case $basic_os in
- openstep*)
- ;;
- nextstep*)
- ;;
- ns2*)
- basic_os=nextstep2
- ;;
- *)
- basic_os=nextstep3
- ;;
- esac
;;
np1)
cpu=np1
@@ -930,12 +989,13 @@ case $basic_machine in
;;
*-*)
- # shellcheck disable=SC2162
+ saved_IFS=$IFS
IFS="-" read cpu vendor <<EOF
$basic_machine
EOF
+ IFS=$saved_IFS
;;
- # We use `pc' rather than `unknown'
+ # We use 'pc' rather than 'unknown'
# because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users.
i*86 | x86_64)
@@ -963,15 +1023,19 @@ unset -v basic_machine
# Decode basic machines in the full and proper CPU-Company form.
case $cpu-$vendor in
- # Here we handle the default manufacturer of certain CPU types in canonical form. It is in
- # some cases the only manufacturer, in others, it is the most popular.
+ # Here we handle the default manufacturer of certain CPU types in canonical form.
+ # It is in some cases the only manufacturer, in others, it is the most popular.
+ c[12]-convex | c[12]-unknown | c3[248]-convex | c3[248]-unknown)
+ vendor=convex
+ basic_os=${basic_os:-bsd}
+ ;;
craynv-unknown)
vendor=cray
basic_os=${basic_os:-unicosmp}
;;
c90-unknown | c90-cray)
vendor=cray
- basic_os=${Basic_os:-unicos}
+ basic_os=${basic_os:-unicos}
;;
fx80-unknown)
vendor=alliant
@@ -1012,11 +1076,34 @@ case $cpu-$vendor in
;;
# Here we normalize CPU types with a missing or matching vendor
- dpx20-unknown | dpx20-bull)
- cpu=rs6000
- vendor=bull
+ armh-unknown | armh-alt)
+ cpu=armv7l
+ vendor=alt
+ basic_os=${basic_os:-linux-gnueabihf}
+ ;;
+
+ # Normalized CPU+vendor pairs that imply an OS, if not otherwise specified
+ m68k-isi)
+ basic_os=${basic_os:-sysv}
+ ;;
+ m68k-sony)
+ basic_os=${basic_os:-newsos}
+ ;;
+ m68k-tektronix)
+ basic_os=${basic_os:-bsd}
+ ;;
+ m88k-harris)
+ basic_os=${basic_os:-sysv3}
+ ;;
+ i386-bull | m68k-bull)
+ basic_os=${basic_os:-sysv3}
+ ;;
+ rs6000-bull)
basic_os=${basic_os:-bosx}
;;
+ mips-sni)
+ basic_os=${basic_os:-sysv4}
+ ;;
# Here we normalize CPU types irrespective of the vendor
amd64-*)
@@ -1024,7 +1111,7 @@ case $cpu-$vendor in
;;
blackfin-*)
cpu=bfin
- basic_os=linux
+ basic_os=${basic_os:-linux}
;;
c54x-*)
cpu=tic54x
@@ -1047,7 +1134,7 @@ case $cpu-$vendor in
;;
m68knommu-*)
cpu=m68k
- basic_os=linux
+ basic_os=${basic_os:-linux}
;;
m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
cpu=s12z
@@ -1057,12 +1144,12 @@ case $cpu-$vendor in
;;
parisc-*)
cpu=hppa
- basic_os=linux
+ basic_os=${basic_os:-linux}
;;
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
cpu=i586
;;
- pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+ pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*)
cpu=i686
;;
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
@@ -1071,9 +1158,6 @@ case $cpu-$vendor in
pentium4-*)
cpu=i786
;;
- pc98-*)
- cpu=i386
- ;;
ppc-* | ppcbe-*)
cpu=powerpc
;;
@@ -1107,13 +1191,10 @@ case $cpu-$vendor in
tx39el-*)
cpu=mipstx39el
;;
- x64-*)
- cpu=x86_64
- ;;
xscale-* | xscalee[bl]-*)
cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
;;
- arm64-*)
+ arm64-* | aarch64le-*)
cpu=aarch64
;;
@@ -1165,114 +1246,231 @@ case $cpu-$vendor in
# Recognize the canonical CPU types that are allowed with any
# company name.
case $cpu in
- 1750a | 580 \
+ 1750a \
+ | 580 \
+ | [cjt]90 \
| a29k \
- | aarch64 | aarch64_be \
+ | aarch64 \
+ | aarch64_be \
+ | aarch64c \
| abacus \
- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
- | alphapca5[67] | alpha64pca5[67] \
+ | alpha \
+ | alpha64 \
+ | alpha64ev56 \
+ | alpha64ev6[78] \
+ | alpha64ev[4-8] \
+ | alpha64pca5[67] \
+ | alphaev56 \
+ | alphaev6[78] \
+ | alphaev[4-8] \
+ | alphapca5[67] \
| am33_2.0 \
| amdgcn \
- | arc | arceb | arc32 | arc64 \
- | arm | arm[lb]e | arme[lb] | armv* \
- | avr | avr32 \
+ | arc \
+ | arc32 \
+ | arc64 \
+ | arceb \
+ | arm \
+ | arm64e \
+ | arm64ec \
+ | arm[lb]e \
+ | arme[lb] \
+ | armv* \
| asmjs \
+ | avr \
+ | avr32 \
| ba \
- | be32 | be64 \
- | bfin | bpf | bs2000 \
- | c[123]* | c30 | [cjt]90 | c4x \
- | c8051 | clipper | craynv | csky | cydra \
- | d10v | d30v | dlx | dsp16xx \
- | e2k | elxsi | epiphany \
- | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
- | h8300 | h8500 \
- | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | be32 \
+ | be64 \
+ | bfin \
+ | bpf \
+ | bs2000 \
+ | c30 \
+ | c4x \
+ | c8051 \
+ | c[123]* \
+ | clipper \
+ | craynv \
+ | csky \
+ | cydra \
+ | d10v \
+ | d30v \
+ | dlx \
+ | dsp16xx \
+ | e2k \
+ | elxsi \
+ | epiphany \
+ | f30[01] \
+ | f700 \
+ | fido \
+ | fr30 \
+ | frv \
+ | ft32 \
+ | fx80 \
+ | h8300 \
+ | h8500 \
| hexagon \
- | i370 | i*86 | i860 | i960 | ia16 | ia64 \
- | ip2k | iq2000 \
+ | hppa \
+ | hppa1.[01] \
+ | hppa2.0 \
+ | hppa2.0[nw] \
+ | hppa64 \
+ | i*86 \
+ | i370 \
+ | i860 \
+ | i960 \
+ | ia16 \
+ | ia64 \
+ | ip2k \
+ | iq2000 \
+ | javascript \
| k1om \
- | le32 | le64 \
+ | kvx \
+ | le32 \
+ | le64 \
| lm32 \
- | loongarch32 | loongarch64 | loongarchx32 \
- | m32c | m32r | m32rle \
- | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
- | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
- | m88110 | m88k | maxq | mb | mcore | mep | metag \
- | microblaze | microblazeel \
- | mips | mipsbe | mipseb | mipsel | mipsle \
- | mips16 \
- | mips64 | mips64eb | mips64el \
- | mips64octeon | mips64octeonel \
- | mips64orion | mips64orionel \
- | mips64r5900 | mips64r5900el \
- | mips64vr | mips64vrel \
- | mips64vr4100 | mips64vr4100el \
- | mips64vr4300 | mips64vr4300el \
- | mips64vr5000 | mips64vr5000el \
- | mips64vr5900 | mips64vr5900el \
- | mipsisa32 | mipsisa32el \
- | mipsisa32r2 | mipsisa32r2el \
- | mipsisa32r3 | mipsisa32r3el \
- | mipsisa32r5 | mipsisa32r5el \
- | mipsisa32r6 | mipsisa32r6el \
- | mipsisa64 | mipsisa64el \
- | mipsisa64r2 | mipsisa64r2el \
- | mipsisa64r3 | mipsisa64r3el \
- | mipsisa64r5 | mipsisa64r5el \
- | mipsisa64r6 | mipsisa64r6el \
- | mipsisa64sb1 | mipsisa64sb1el \
- | mipsisa64sr71k | mipsisa64sr71kel \
- | mipsr5900 | mipsr5900el \
- | mipstx39 | mipstx39el \
+ | loongarch32 \
+ | loongarch64 \
+ | m32c \
+ | m32r \
+ | m32rle \
+ | m5200 \
+ | m68000 \
+ | m680[012346]0 \
+ | m6811 \
+ | m6812 \
+ | m68360 \
+ | m683?2 \
+ | m68hc11 \
+ | m68hc12 \
+ | m68hcs12x \
+ | m68k \
+ | m88110 \
+ | m88k \
+ | maxq \
+ | mb \
+ | mcore \
+ | mep \
+ | metag \
+ | microblaze \
+ | microblazeel \
+ | mips* \
| mmix \
- | mn10200 | mn10300 \
+ | mn10200 \
+ | mn10300 \
| moxie \
- | mt \
| msp430 \
- | nds32 | nds32le | nds32be \
+ | mt \
+ | nanomips* \
+ | nds32 \
+ | nds32be \
+ | nds32le \
| nfp \
- | nios | nios2 | nios2eb | nios2el \
- | none | np1 | ns16k | ns32k | nvptx \
+ | nios \
+ | nios2 \
+ | nios2eb \
+ | nios2el \
+ | none \
+ | np1 \
+ | ns16k \
+ | ns32k \
+ | nvptx \
| open8 \
| or1k* \
| or32 \
| orion \
+ | pdp10 \
+ | pdp11 \
| picochip \
- | pdp10 | pdp11 | pj | pjl | pn | power \
- | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
+ | pj \
+ | pjl \
+ | pn \
+ | power \
+ | powerpc \
+ | powerpc64 \
+ | powerpc64le \
+ | powerpcle \
+ | powerpcspe \
| pru \
| pyramid \
- | riscv | riscv32 | riscv32be | riscv64 | riscv64be \
- | rl78 | romp | rs6000 | rx \
- | s390 | s390x \
+ | riscv \
+ | riscv32 \
+ | riscv32be \
+ | riscv64 \
+ | riscv64be \
+ | rl78 \
+ | romp \
+ | rs6000 \
+ | rx \
+ | s390 \
+ | s390x \
| score \
- | sh | shl \
- | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
- | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
- | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
+ | sh \
+ | sh64 \
+ | sh64le \
+ | sh[12345][lb]e \
+ | sh[1234] \
+ | sh[1234]e[lb] \
+ | sh[23]e \
+ | sh[23]ele \
+ | sh[24]a \
+ | sh[24]ae[lb] \
+ | sh[lb]e \
+ | she[lb] \
+ | shl \
+ | sparc \
+ | sparc64 \
+ | sparc64b \
+ | sparc64v \
+ | sparc86x \
+ | sparclet \
| sparclite \
- | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
+ | sparcv8 \
+ | sparcv9 \
+ | sparcv9b \
+ | sparcv9v \
| spu \
+ | sv1 \
+ | sx* \
| tahoe \
| thumbv7* \
- | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
+ | tic30 \
+ | tic4x \
+ | tic54x \
+ | tic55x \
+ | tic6x \
+ | tic80 \
| tron \
| ubicom32 \
- | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+ | v70 \
+ | v810 \
+ | v850 \
+ | v850e \
+ | v850e1 \
+ | v850e2 \
+ | v850e2v3 \
+ | v850es \
| vax \
+ | vc4 \
| visium \
| w65 \
- | wasm32 | wasm64 \
+ | wasm32 \
+ | wasm64 \
| we32k \
- | x86 | x86_64 | xc16x | xgate | xps100 \
- | xstormy16 | xtensa* \
+ | x86 \
+ | x86_64 \
+ | xc16x \
+ | xgate \
+ | xps100 \
+ | xstormy16 \
+ | xtensa* \
| ymp \
- | z8k | z80)
+ | z80 \
+ | z8k)
;;
*)
- echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+ echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2
exit 1
;;
esac
@@ -1293,11 +1491,12 @@ esac
# Decode manufacturer-specific aliases for certain operating systems.
-if test x$basic_os != x
+if test x"$basic_os" != x
then
-# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
+# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
# set os.
+obj=
case $basic_os in
gnu/linux*)
kernel=linux
@@ -1312,10 +1511,11 @@ case $basic_os in
os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
;;
*-*)
- # shellcheck disable=SC2162
+ saved_IFS=$IFS
IFS="-" read kernel os <<EOF
$basic_os
EOF
+ IFS=$saved_IFS
;;
# Default OS when just kernel was specified
nto*)
@@ -1326,6 +1526,10 @@ EOF
kernel=linux
os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
;;
+ managarm*)
+ kernel=managarm
+ os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
+ ;;
*)
kernel=
os=$basic_os
@@ -1353,6 +1557,23 @@ case $os in
unixware*)
os=sysv4.2uw
;;
+ # The marketing names for NeXT's operating systems were
+ # NeXTSTEP, NeXTSTEP 2, OpenSTEP 3, OpenSTEP 4. 'openstep' is
+ # mapped to 'openstep3', but 'openstep1' and 'openstep2' are
+ # mapped to 'nextstep' and 'nextstep2', consistent with the
+ # treatment of SunOS/Solaris.
+ ns | ns1 | nextstep | nextstep1 | openstep1)
+ os=nextstep
+ ;;
+ ns2 | nextstep2 | openstep2)
+ os=nextstep2
+ ;;
+ ns3 | nextstep3 | openstep | openstep3)
+ os=openstep3
+ ;;
+ ns4 | nextstep4 | openstep4)
+ os=openstep4
+ ;;
# es1800 is here to avoid being matched by es* (a different OS)
es1800*)
os=ose
@@ -1423,6 +1644,7 @@ case $os in
;;
utek*)
os=bsd
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|tektronix|'`
;;
dynix*)
os=bsd
@@ -1439,21 +1661,25 @@ case $os in
386bsd)
os=bsd
;;
- ctix* | uts*)
+ ctix*)
os=sysv
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|convergent|'`
;;
- nova*)
- os=rtmk-nova
+ uts*)
+ os=sysv
;;
- ns2)
- os=nextstep2
+ nova*)
+ kernel=rtmk
+ os=nova
;;
# Preserve the version number of sinix5.
sinix5.*)
os=`echo "$os" | sed -e 's|sinix|sysv|'`
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
;;
sinix*)
os=sysv4
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
;;
tpf*)
os=tpf
@@ -1491,10 +1717,16 @@ case $os in
os=eabi
;;
*)
- os=elf
+ os=
+ obj=elf
;;
esac
;;
+ aout* | coff* | elf* | pe*)
+ # These are machine code file formats, not OSes
+ obj=$os
+ os=
+ ;;
*)
# No normalization, but not necessarily accepted, that comes below.
;;
@@ -1513,12 +1745,15 @@ else
# system, and we'll never get to this point.
kernel=
+obj=
case $cpu-$vendor in
score-*)
- os=elf
+ os=
+ obj=elf
;;
spu-*)
- os=elf
+ os=
+ obj=elf
;;
*-acorn)
os=riscix1.2
@@ -1528,28 +1763,35 @@ case $cpu-$vendor in
os=gnu
;;
arm*-semi)
- os=aout
+ os=
+ obj=aout
;;
c4x-* | tic4x-*)
- os=coff
+ os=
+ obj=coff
;;
c8051-*)
- os=elf
+ os=
+ obj=elf
;;
clipper-intergraph)
os=clix
;;
hexagon-*)
- os=elf
+ os=
+ obj=elf
;;
tic54x-*)
- os=coff
+ os=
+ obj=coff
;;
tic55x-*)
- os=coff
+ os=
+ obj=coff
;;
tic6x-*)
- os=coff
+ os=
+ obj=coff
;;
# This must come before the *-dec entry.
pdp10-*)
@@ -1571,28 +1813,43 @@ case $cpu-$vendor in
os=sunos3
;;
m68*-cisco)
- os=aout
+ os=
+ obj=aout
;;
mep-*)
- os=elf
+ os=
+ obj=elf
+ ;;
+ # The -sgi and -siemens entries must be before the mips- entry
+ # or we get the wrong os.
+ *-sgi)
+ os=irix
+ ;;
+ *-siemens)
+ os=sysv4
;;
mips*-cisco)
- os=elf
+ os=
+ obj=elf
;;
- mips*-*)
- os=elf
+ mips*-*|nanomips*-*)
+ os=
+ obj=elf
;;
or32-*)
- os=coff
+ os=
+ obj=coff
;;
- *-tti) # must be before sparc entry or we get the wrong os.
+ # This must be before the sparc-* entry or we get the wrong os.
+ *-tti)
os=sysv3
;;
sparc-* | *-sun)
os=sunos4.1.1
;;
pru-*)
- os=elf
+ os=
+ obj=elf
;;
*-be)
os=beos
@@ -1616,7 +1873,7 @@ case $cpu-$vendor in
os=hpux
;;
*-hitachi)
- os=hiux
+ os=hiuxwe2
;;
i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
os=sysv
@@ -1660,12 +1917,6 @@ case $cpu-$vendor in
*-encore)
os=bsd
;;
- *-sgi)
- os=irix
- ;;
- *-siemens)
- os=sysv4
- ;;
*-masscomp)
os=rtu
;;
@@ -1673,10 +1924,12 @@ case $cpu-$vendor in
os=uxpv
;;
*-rom68k)
- os=coff
+ os=
+ obj=coff
;;
*-*bug)
- os=coff
+ os=
+ obj=coff
;;
*-apple)
os=macos
@@ -1694,10 +1947,11 @@ esac
fi
-# Now, validate our (potentially fixed-up) OS.
+# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ).
+
case $os in
# Sometimes we do "kernel-libc", so those need to count as OSes.
- musl* | newlib* | uclibc*)
+ llvm* | musl* | newlib* | relibc* | uclibc*)
;;
# Likewise for "kernel-abi"
eabi* | gnueabi*)
@@ -1705,81 +1959,308 @@ case $os in
# VxWorks passes extra cpu info in the 4th filed.
simlinux | simwindows | spe)
;;
+ # See `case $cpu-$os` validation below
+ ghcjs)
+ ;;
# Now accept the basic system types.
- # The portable systems comes first.
# Each alternative MUST end in a * to match a version number.
- gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
- | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \
- | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
- | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
- | hiux* | abug | nacl* | netware* | windows* \
- | os9* | macos* | osx* | ios* \
- | mpw* | magic* | mmixware* | mon960* | lnews* \
- | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
- | aos* | aros* | cloudabi* | sortix* | twizzler* \
- | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
- | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
- | mirbsd* | netbsd* | dicos* | openedition* | ose* \
- | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
- | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
- | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
- | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
- | udi* | lites* | ieee* | go32* | aux* | hcos* \
- | chorusrdb* | cegcc* | glidix* | serenity* \
- | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
- | midipix* | mingw32* | mingw64* | mint* \
- | uxpv* | beos* | mpeix* | udk* | moxiebox* \
- | interix* | uwin* | mks* | rhapsody* | darwin* \
- | openstep* | oskit* | conix* | pw32* | nonstopux* \
- | storm-chaos* | tops10* | tenex* | tops20* | its* \
- | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \
- | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \
- | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
- | skyos* | haiku* | rdos* | toppers* | drops* | es* \
- | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
- | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
- | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
+ abug \
+ | aix* \
+ | amdhsa* \
+ | amigados* \
+ | amigaos* \
+ | android* \
+ | aof* \
+ | aos* \
+ | aros* \
+ | atheos* \
+ | auroraux* \
+ | aux* \
+ | beos* \
+ | bitrig* \
+ | bme* \
+ | bosx* \
+ | bsd* \
+ | cegcc* \
+ | chorusos* \
+ | chorusrdb* \
+ | clix* \
+ | cloudabi* \
+ | cnk* \
+ | conix* \
+ | cos* \
+ | cxux* \
+ | cygwin* \
+ | darwin* \
+ | dgux* \
+ | dicos* \
+ | dnix* \
+ | domain* \
+ | dragonfly* \
+ | drops* \
+ | ebmon* \
+ | ecoff* \
+ | ekkobsd* \
+ | emscripten* \
+ | emx* \
+ | es* \
+ | fiwix* \
+ | freebsd* \
+ | fuchsia* \
+ | genix* \
+ | genode* \
+ | glidix* \
+ | gnu* \
+ | go32* \
+ | haiku* \
+ | hcos* \
+ | hiux* \
+ | hms* \
+ | hpux* \
+ | ieee* \
+ | interix* \
+ | ios* \
+ | iris* \
+ | irix* \
+ | ironclad* \
+ | isc* \
+ | its* \
+ | l4re* \
+ | libertybsd* \
+ | lites* \
+ | lnews* \
+ | luna* \
+ | lynxos* \
+ | mach* \
+ | macos* \
+ | magic* \
+ | mbr* \
+ | midipix* \
+ | midnightbsd* \
+ | mingw32* \
+ | mingw64* \
+ | minix* \
+ | mint* \
+ | mirbsd* \
+ | mks* \
+ | mlibc* \
+ | mmixware* \
+ | mon960* \
+ | morphos* \
+ | moss* \
+ | moxiebox* \
+ | mpeix* \
+ | mpw* \
+ | msdos* \
+ | msys* \
+ | mvs* \
+ | nacl* \
+ | netbsd* \
+ | netware* \
+ | newsos* \
+ | nextstep* \
+ | nindy* \
+ | nonstopux* \
+ | nova* \
+ | nsk* \
+ | nucleus* \
+ | nx6 \
+ | nx7 \
+ | oabi* \
+ | ohos* \
+ | onefs* \
+ | openbsd* \
+ | openedition* \
+ | openstep* \
+ | os108* \
+ | os2* \
+ | os400* \
+ | os68k* \
+ | os9* \
+ | ose* \
+ | osf* \
+ | oskit* \
+ | osx* \
+ | palmos* \
+ | phoenix* \
+ | plan9* \
+ | powermax* \
+ | powerunix* \
+ | proelf* \
+ | psos* \
+ | psp* \
+ | ptx* \
+ | pw32* \
+ | qnx* \
+ | rdos* \
+ | redox* \
+ | rhapsody* \
+ | riscix* \
+ | riscos* \
+ | rtems* \
+ | rtmk* \
+ | rtu* \
+ | scout* \
+ | secbsd* \
+ | sei* \
+ | serenity* \
+ | sim* \
+ | skyos* \
+ | solaris* \
+ | solidbsd* \
+ | sortix* \
+ | storm-chaos* \
+ | sunos \
+ | sunos[34]* \
+ | superux* \
+ | syllable* \
+ | sym* \
+ | sysv* \
+ | tenex* \
+ | tirtos* \
+ | toppers* \
+ | tops10* \
+ | tops20* \
+ | tpf* \
+ | tvos* \
+ | twizzler* \
+ | uclinux* \
+ | udi* \
+ | udk* \
+ | ultrix* \
+ | unicos* \
+ | uniplus* \
+ | unleashed* \
+ | unos* \
+ | uwin* \
+ | uxpv* \
+ | v88r* \
+ |*vms* \
+ | vos* \
+ | vsta* \
+ | vxsim* \
+ | vxworks* \
+ | wasi* \
+ | watchos* \
+ | wince* \
+ | windiss* \
+ | windows* \
+ | winnt* \
+ | xenix* \
+ | xray* \
+ | zephyr* \
+ | zvmoe* )
;;
# This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
# Don't forget version if it is 3.2v4 or newer.
;;
+ # This refers to builds using the UEFI calling convention
+ # (which depends on the architecture) and PE file format.
+ # Note that this is both a different calling convention and
+ # different file format than that of GNU-EFI
+ # (x86_64-w64-mingw32).
+ uefi)
+ ;;
none)
;;
+ kernel* | msvc* )
+ # Restricted further below
+ ;;
+ '')
+ if test x"$obj" = x
+ then
+ echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2
+ fi
+ ;;
*)
- echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
+ echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2
+ exit 1
+ ;;
+esac
+
+case $obj in
+ aout* | coff* | elf* | pe*)
+ ;;
+ '')
+ # empty is fine
+ ;;
+ *)
+ echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we handle the constraint that a (synthetic) cpu and os are
+# valid only in combination with each other and nowhere else.
+case $cpu-$os in
+ # The "javascript-unknown-ghcjs" triple is used by GHC; we
+ # accept it here in order to tolerate that, but reject any
+ # variations.
+ javascript-ghcjs)
+ ;;
+ javascript-* | *-ghcjs)
+ echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2
exit 1
;;
esac
# As a final step for OS-related things, validate the OS-kernel combination
# (given a valid OS), if there is a kernel.
-case $kernel-$os in
- linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
+case $kernel-$os-$obj in
+ linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \
+ | linux-mlibc*- | linux-musl*- | linux-newlib*- \
+ | linux-relibc*- | linux-uclibc*- | linux-ohos*- )
;;
- uclinux-uclibc* )
+ uclinux-uclibc*- | uclinux-gnu*- )
;;
- -dietlibc* | -newlib* | -musl* | -uclibc* )
+ managarm-mlibc*- | managarm-kernel*- )
+ ;;
+ windows*-msvc*-)
+ ;;
+ -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \
+ | -uclibc*- )
# These are just libc implementations, not actual OSes, and thus
# require a kernel.
- echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
+ echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2
exit 1
;;
- kfreebsd*-gnu* | kopensolaris*-gnu*)
+ -kernel*- )
+ echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2
+ exit 1
;;
- vxworks-simlinux | vxworks-simwindows | vxworks-spe)
+ *-kernel*- )
+ echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2
+ exit 1
;;
- nto-qnx*)
+ *-msvc*- )
+ echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
+ exit 1
;;
- os2-emx)
+ kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-)
+ ;;
+ vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
+ ;;
+ nto-qnx*-)
;;
- *-eabi* | *-gnueabi*)
+ os2-emx-)
;;
- -*)
+ rtmk-nova-)
+ ;;
+ *-eabi*- | *-gnueabi*-)
+ ;;
+ none--*)
+ # None (no kernel, i.e. freestanding / bare metal),
+ # can be paired with an machine code file format
+ ;;
+ -*-)
# Blank kernel with real OS is always fine.
;;
- *-*)
- echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
+ --*)
+ # Blank kernel and OS with real machine code file format is always fine.
+ ;;
+ *-*-*)
+ echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2
exit 1
;;
esac
@@ -1792,7 +2273,7 @@ case $vendor in
*-riscix*)
vendor=acorn
;;
- *-sunos*)
+ *-sunos* | *-solaris*)
vendor=sun
;;
*-cnk* | *-aix*)
@@ -1862,7 +2343,7 @@ case $vendor in
;;
esac
-echo "$cpu-$vendor-${kernel:+$kernel-}$os"
+echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
exit
# Local variables:
diff --git a/autosetup/autosetup-find-tclsh b/autosetup/autosetup-find-tclsh
index 0029f17..f0fd98c 100755
--- a/autosetup/autosetup-find-tclsh
+++ b/autosetup/autosetup-find-tclsh
@@ -9,7 +9,7 @@ for tclsh in ./jimsh0 $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6 tclsh8.7; d
done
echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
for cc in ${CC_FOR_BUILD:-cc} gcc; do
- { $cc -o jimsh0 "$d/jimsh0.c"; } 2>/dev/null || continue
+ { $cc -o jimsh0 "$d/jimsh0.c"; } 2>&1 >/dev/null || continue
./jimsh0 "$d/${1-autosetup-test-tclsh}" && exit 0
done
echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
diff --git a/autosetup/cc.tcl b/autosetup/cc.tcl
index f45cc2e..05c1b1c 100644
--- a/autosetup/cc.tcl
+++ b/autosetup/cc.tcl
@@ -5,7 +5,7 @@
#
# The 'cc' module supports checking various 'features' of the C or C++
# compiler/linker environment. Common commands are 'cc-check-includes',
-# 'cc-check-types', 'cc-check-functions', 'cc-with', 'make-config-header' and 'make-template'.
+# 'cc-check-types', 'cc-check-functions', 'cc-with' and 'make-config-header'
#
# The following environment variables are used if set:
#
@@ -677,80 +677,82 @@ proc calc-define-output-type {name spec} {
return ""
}
-# Initialise some values from the environment or commandline or default settings
-foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS CFLAGS} {
- lassign $i var default
- define $var [get-env $var $default]
-}
+proc cc-init {} {
+ global autosetup
-if {[env-is-set CC]} {
- # Set by the user, so don't try anything else
- set try [list [get-env CC ""]]
-} else {
- # Try some reasonable options
- set try [list [get-define cross]cc [get-define cross]gcc]
-}
-define CC [find-an-executable {*}$try]
-if {[get-define CC] eq ""} {
- user-error "Could not find a C compiler. Tried: [join $try ", "]"
-}
+ # Initialise some values from the environment or commandline or default settings
+ foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS CFLAGS} {
+ lassign $i var default
+ define $var [get-env $var $default]
+ }
-define CPP [get-env CPP "[get-define CC] -E"]
+ if {[env-is-set CC]} {
+ # Set by the user, so don't try anything else
+ set try [list [get-env CC ""]]
+ } else {
+ # Try some reasonable options
+ set try [list [get-define cross]cc [get-define cross]gcc]
+ }
+ define CC [find-an-executable {*}$try]
+ if {[get-define CC] eq ""} {
+ user-error "Could not find a C compiler. Tried: [join $try ", "]"
+ }
-# XXX: Could avoid looking for a C++ compiler until requested
-# If CXX isn't found, it is set to the empty string.
-if {[env-is-set CXX]} {
- define CXX [find-an-executable -required [get-env CXX ""]]
-} else {
- define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++]
-}
+ define CPP [get-env CPP "[get-define CC] -E"]
-# CXXFLAGS default to CFLAGS if not specified
-define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]
+ # XXX: Could avoid looking for a C++ compiler until requested
+ # If CXX isn't found, it is set to the empty string.
+ if {[env-is-set CXX]} {
+ define CXX [find-an-executable -required [get-env CXX ""]]
+ } else {
+ define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++]
+ }
-# May need a CC_FOR_BUILD, so look for one
-define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]
+ # CXXFLAGS default to CFLAGS if not specified
+ define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]
-if {[get-define CC] eq ""} {
- user-error "Could not find a C compiler. Tried: [join $try ", "]"
-}
+ # May need a CC_FOR_BUILD, so look for one
+ define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]
-# These start empty and never come from the user or environment
-define AS_CFLAGS ""
-define AS_CPPFLAGS ""
-define AS_CXXFLAGS ""
+ # These start empty and never come from the user or environment
+ define AS_CFLAGS ""
+ define AS_CPPFLAGS ""
+ define AS_CXXFLAGS ""
-define CCACHE [find-an-executable [get-env CCACHE ccache]]
+ define CCACHE [find-an-executable [get-env CCACHE ccache]]
-# If any of these are set in the environment, propagate them to the AUTOREMAKE commandline
-foreach i {CC CXX CCACHE CPP CFLAGS CXXFLAGS CXXFLAGS LDFLAGS LIBS CROSS CPPFLAGS LINKFLAGS CC_FOR_BUILD LD} {
- if {[env-is-set $i]} {
- # Note: If the variable is set on the command line, get-env will return that value
- # so the command line will continue to override the environment
- define-append-argv AUTOREMAKE $i=[get-env $i ""]
+ # If any of these are set in the environment, propagate them to the AUTOREMAKE commandline
+ foreach i {CC CXX CCACHE CPP CFLAGS CXXFLAGS CXXFLAGS LDFLAGS LIBS CROSS CPPFLAGS LINKFLAGS CC_FOR_BUILD LD} {
+ if {[env-is-set $i]} {
+ # Note: If the variable is set on the command line, get-env will return that value
+ # so the command line will continue to override the environment
+ define-append-argv AUTOREMAKE $i=[get-env $i ""]
+ }
}
-}
-# Initial cctest settings
-cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
-set autosetup(cc-include-deps) {}
+ # Initial cctest settings
+ cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
+ set autosetup(cc-include-deps) {}
-msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS] [get-define CPPFLAGS]"
-if {[get-define CXX] ne "false"} {
- msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS] [get-define CPPFLAGS]"
-}
-msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
-
-# On Darwin, we prefer to use -g0 to avoid creating .dSYM directories
-# but some compilers may not support it, so test here.
-switch -glob -- [get-define host] {
- *-*-darwin* {
- if {[cctest -cflags {-g0}]} {
- define cc-default-debug -g0
+ msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS] [get-define CPPFLAGS]"
+ if {[get-define CXX] ne "false"} {
+ msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS] [get-define CPPFLAGS]"
+ }
+ msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
+
+ # On Darwin, we prefer to use -g0 to avoid creating .dSYM directories
+ # but some compilers may not support it, so test here.
+ switch -glob -- [get-define host] {
+ *-*-darwin* {
+ if {[cctest -cflags {-g0}]} {
+ define cc-default-debug -g0
+ }
}
}
-}
-if {![cc-check-includes stdlib.h]} {
- user-error "Compiler does not work. See config.log"
+ if {![cc-check-includes stdlib.h]} {
+ user-error "Compiler does not work. See config.log"
+ }
}
+
+cc-init
diff --git a/autosetup/jimsh0.c b/autosetup/jimsh0.c
index f3ec997..8f6f7ea 100644
--- a/autosetup/jimsh0.c
+++ b/autosetup/jimsh0.c
@@ -1,8 +1,9 @@
/* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
-#define JIM_TCL_COMPAT
+#define JIM_COMPAT
#define JIM_ANSIC
#define JIM_REGEXP
#define HAVE_NO_AUTOCONF
+#define JIM_TINY
#define _JIMAUTOCONF_H
#define TCL_LIBRARY "."
#define jim_ext_bootstrap
@@ -12,7 +13,6 @@
#define jim_ext_file
#define jim_ext_glob
#define jim_ext_exec
-#define jim_ext_posix
#define jim_ext_clock
#define jim_ext_array
#define jim_ext_stdlib
@@ -62,7 +62,7 @@
#define HAVE_PIPE
#define _FILE_OFFSET_BITS 64
#endif
-#define JIM_VERSION 82
+#define JIM_VERSION 84
#ifndef JIM_WIN32COMPAT_H
#define JIM_WIN32COMPAT_H
@@ -95,6 +95,9 @@ char *dlerror(void);
#include <limits.h>
#define jim_wide _int64
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG
+#endif
#ifndef LLONG_MAX
#define LLONG_MAX 9223372036854775807I64
#endif
@@ -109,11 +112,7 @@ char *dlerror(void);
#include <io.h>
-struct timeval {
- long tv_sec;
- long tv_usec;
-};
-
+#include <winsock.h>
int gettimeofday(struct timeval *tv, void *unused);
#define HAVE_OPENDIR
@@ -576,7 +575,7 @@ typedef struct Jim_Interp {
Jim_Obj *result;
int unused_errorLine;
Jim_Obj *currentFilenameObj;
- int unused_addStackTrace;
+ int break_level;
int maxCallFrameDepth;
int maxEvalDepth;
int evalDepth;
@@ -720,6 +719,14 @@ JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
Jim_Obj **resObjPtrPtr, int flags);
+JIM_EXPORT Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ int *lineptr);
+
+JIM_EXPORT void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *fileNameObj, int lineNumber);
+
+
+
JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
@@ -1155,7 +1162,7 @@ int Jim_OpenForWrite(const char *filename, int append);
int Jim_OpenForRead(const char *filename);
-#if defined(__MINGW32__)
+#if defined(__MINGW32__) || defined(_WIN32)
#ifndef STRICT
#define STRICT
#endif
@@ -1190,6 +1197,7 @@ int Jim_OpenForRead(const char *filename);
#define Jim_Stat _stat64
#define Jim_FileStat _fstat64
#define Jim_Lseek _lseeki64
+ #define O_TEXT _O_TEXT
#else
#if defined(HAVE_STAT64)
@@ -1232,10 +1240,11 @@ int Jim_OpenForRead(const char *filename);
#define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
#endif
#endif
-#endif
-#ifndef O_TEXT
-#define O_TEXT 0
+ #ifndef O_TEXT
+ #define O_TEXT 0
+ #endif
+
#endif
@@ -1284,8 +1293,14 @@ int Jim_initjimshInit(Jim_Interp *interp)
" if {[string match \"*/*\" $jim::argv0]} {\n"
" set jim::exe [file join [pwd] $jim::argv0]\n"
" } else {\n"
-" foreach path [split [env PATH \"\"] $tcl_platform(pathSeparator)] {\n"
-" set exec [file join [pwd] [string map {\\\\ /} $path] $jim::argv0]\n"
+" set jim::argv0 [file tail $jim::argv0]\n"
+" set path [split [env PATH \"\"] $tcl_platform(pathSeparator)]\n"
+" if {$tcl_platform(platform) eq \"windows\"} {\n"
+"\n"
+" set path [lmap p [list \"\" {*}$path] { string map {\\\\ /} $p }]\n"
+" }\n"
+" foreach p $path {\n"
+" set exec [file join [pwd] $p $jim::argv0]\n"
" if {[file executable $exec]} {\n"
" set jim::exe $exec\n"
" break\n"
@@ -1938,9 +1953,6 @@ int Jim_tclcompatInit(Jim_Interp *interp)
" if {$cmd eq \"pid\"} {\n"
" return $pids\n"
" }\n"
-" if {$cmd eq \"getfd\"} {\n"
-" $f getfd\n"
-" }\n"
" if {$cmd eq \"close\"} {\n"
" $f close\n"
"\n"
@@ -2040,8 +2052,8 @@ int Jim_tclcompatInit(Jim_Interp *interp)
#define AIO_CMD_LEN 32
-#define AIO_BUF_LEN 256
-#define AIO_WBUF_FULL_SIZE (64 * 1024)
+#define AIO_DEFAULT_RBUF_LEN 256
+#define AIO_DEFAULT_WBUF_LIMIT (64 * 1024)
#define AIO_KEEPOPEN 1
#define AIO_NODELETE 2
@@ -2049,6 +2061,8 @@ int Jim_tclcompatInit(Jim_Interp *interp)
#define AIO_WBUF_NONE 8
#define AIO_NONBLOCK 16
+#define AIO_ONEREAD 32
+
enum wbuftype {
WBUF_OPT_NONE,
WBUF_OPT_LINE,
@@ -2123,11 +2137,20 @@ typedef struct AioFile
const JimAioFopsType *fops;
Jim_Obj *readbuf;
Jim_Obj *writebuf;
+ char *rbuf;
+ size_t rbuf_len;
+ size_t wbuf_limit;
} AioFile;
+static void aio_consume(Jim_Obj *objPtr, int n);
+
static int stdio_writer(struct AioFile *af, const char *buf, int len)
{
- return write(af->fd, buf, len);
+ int ret = write(af->fd, buf, len);
+ if (ret < 0 && errno == EPIPE) {
+ aio_consume(af->writebuf, Jim_Length(af->writebuf));
+ }
+ return ret;
}
static int stdio_reader(struct AioFile *af, char *buf, int len, int nb)
@@ -2264,7 +2287,22 @@ static void aio_consume(Jim_Obj *objPtr, int n)
}
-static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask);
+static int aio_flush(Jim_Interp *interp, AioFile *af);
+
+#ifdef jim_ext_eventloop
+static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask)
+{
+ AioFile *af = clientData;
+
+ aio_flush(interp, af);
+ if (Jim_Length(af->writebuf) == 0) {
+
+ return -1;
+ }
+ return 0;
+}
+#endif
+
static int aio_flush(Jim_Interp *interp, AioFile *af)
{
@@ -2299,19 +2337,7 @@ static int aio_flush(Jim_Interp *interp, AioFile *af)
return JIM_OK;
}
-static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask)
-{
- AioFile *af = clientData;
-
- aio_flush(interp, af);
- if (Jim_Length(af->writebuf) == 0) {
-
- return -1;
- }
- return 0;
-}
-
-static int aio_read_len(Jim_Interp *interp, AioFile *af, int nb, char *buf, size_t buflen, int neededLen)
+static int aio_read_len(Jim_Interp *interp, AioFile *af, unsigned flags, int neededLen)
{
if (!af->readbuf) {
af->readbuf = Jim_NewStringObj(interp, NULL, 0);
@@ -2329,25 +2355,32 @@ static int aio_read_len(Jim_Interp *interp, AioFile *af, int nb, char *buf, size
int readlen;
if (neededLen == -1) {
- readlen = AIO_BUF_LEN;
+ readlen = af->rbuf_len;
}
else {
- readlen = (neededLen > AIO_BUF_LEN ? AIO_BUF_LEN : neededLen);
+ readlen = (neededLen > af->rbuf_len ? af->rbuf_len : neededLen);
+ }
+
+ if (!af->rbuf) {
+ af->rbuf = Jim_Alloc(af->rbuf_len);
}
- retval = af->fops->reader(af, buf, readlen, nb);
+ retval = af->fops->reader(af, af->rbuf, readlen, flags & AIO_NONBLOCK);
if (retval > 0) {
- Jim_AppendString(interp, af->readbuf, buf, retval);
+ if (retval) {
+ Jim_AppendString(interp, af->readbuf, af->rbuf, retval);
+ }
if (neededLen != -1) {
neededLen -= retval;
}
+ if (flags & AIO_ONEREAD) {
+ return JIM_OK;
+ }
continue;
}
- if (JimCheckStreamError(interp, af)) {
+ if ((flags & AIO_ONEREAD) || JimCheckStreamError(interp, af)) {
return JIM_ERR;
}
- if (nb || af->timeout) {
- return JIM_OK;
- }
+ break;
}
return JIM_OK;
@@ -2415,6 +2448,7 @@ static void JimAioDelProc(Jim_Interp *interp, void *privData)
Jim_FreeNewObj(interp, af->readbuf);
}
+ Jim_Free(af->rbuf);
Jim_Free(af);
}
@@ -2428,7 +2462,6 @@ static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
int option;
int nb;
Jim_Obj *objPtr;
- char buf[AIO_BUF_LEN];
if (argc) {
if (*Jim_String(argv[0]) == '-') {
@@ -2462,7 +2495,7 @@ static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
nb = aio_start_nonblocking(af);
- if (aio_read_len(interp, af, nb, buf, sizeof(buf), neededLen) != JIM_OK) {
+ if (aio_read_len(interp, af, nb ? AIO_NONBLOCK : 0, neededLen) != JIM_OK) {
aio_set_nonblocking(af, nb);
return JIM_ERR;
}
@@ -2517,11 +2550,6 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
AioFile *af = Jim_CmdPrivData(interp);
jim_wide count = 0;
jim_wide maxlen = JIM_WIDE_MAX;
-
- char buf[AIO_BUF_LEN];
-
- char *bufp = buf;
- int buflen = sizeof(buf);
int ok = 1;
Jim_Obj *objv[4];
@@ -2547,10 +2575,10 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
while (count < maxlen) {
jim_wide len = maxlen - count;
- if (len > buflen) {
- len = buflen;
+ if (len > af->rbuf_len) {
+ len = af->rbuf_len;
}
- if (aio_read_len(interp, af, 0, bufp, buflen, len) != JIM_OK) {
+ if (aio_read_len(interp, af, 0, len) != JIM_OK) {
ok = 0;
break;
}
@@ -2563,17 +2591,13 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
if (aio_eof(af)) {
break;
}
- if (count >= 16384 && bufp == buf) {
+ if (count >= 16384 && af->rbuf_len < 65536) {
- buflen = 65536;
- bufp = Jim_Alloc(buflen);
+ af->rbuf_len = 65536;
+ af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
}
}
- if (bufp != buf) {
- Jim_Free(bufp);
- }
-
Jim_DecrRefCount(interp, objv[1]);
Jim_DecrRefCount(interp, objv[2]);
@@ -2589,10 +2613,10 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
AioFile *af = Jim_CmdPrivData(interp);
- char buf[AIO_BUF_LEN];
Jim_Obj *objPtr = NULL;
int len;
int nb;
+ unsigned flags = AIO_ONEREAD;
char *nl = NULL;
int offset = 0;
@@ -2600,38 +2624,33 @@ static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
nb = aio_start_nonblocking(af);
-
- if (!af->readbuf) {
- af->readbuf = Jim_NewStringObj(interp, NULL, 0);
+ if (nb) {
+ flags |= AIO_NONBLOCK;
}
while (!aio_eof(af)) {
- const char *pt = Jim_GetString(af->readbuf, &len);
- nl = memchr(pt + offset, '\n', len - offset);
- if (nl) {
+ if (af->readbuf) {
+ const char *pt = Jim_GetString(af->readbuf, &len);
+ nl = memchr(pt + offset, '\n', len - offset);
+ if (nl) {
- objPtr = Jim_NewStringObj(interp, pt, nl - pt);
-
- aio_consume(af->readbuf, nl - pt + 1);
- break;
- }
-
- offset = len;
- len = af->fops->reader(af, buf, AIO_BUF_LEN, nb);
- if (len <= 0) {
- if (nb || af->timeout) {
+ objPtr = Jim_NewStringObj(interp, pt, nl - pt);
+ aio_consume(af->readbuf, nl - pt + 1);
break;
}
+ offset = len;
}
- else {
- Jim_AppendString(interp, af->readbuf, buf, len);
+
+
+ if (aio_read_len(interp, af, flags, -1) != JIM_OK) {
+ break;
}
}
aio_set_nonblocking(af, nb);
- if (!nl && aio_eof(af)) {
+ if (!nl && aio_eof(af) && af->readbuf) {
objPtr = af->readbuf;
af->readbuf = NULL;
@@ -2680,6 +2699,13 @@ static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
strObj = argv[0];
}
+#ifdef JIM_MAINTAINER
+ if (Jim_IsShared(af->writebuf)) {
+ Jim_DecrRefCount(interp, af->writebuf);
+ af->writebuf = Jim_DuplicateObj(interp, af->writebuf);
+ Jim_IncrRefCount(af->writebuf);
+ }
+#endif
Jim_AppendObj(interp, af->writebuf, strObj);
if (nl) {
Jim_AppendString(interp, af->writebuf, "\n", 1);
@@ -2701,7 +2727,7 @@ static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
break;
case WBUF_OPT_FULL:
- if (wlen >= AIO_WBUF_FULL_SIZE) {
+ if (wlen >= af->wbuf_limit) {
wnow = 1;
}
break;
@@ -2870,6 +2896,7 @@ static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
AioFile *af = Jim_CmdPrivData(interp);
+ Jim_Obj *resultObj;
static const char * const options[] = {
"none",
@@ -2878,17 +2905,57 @@ static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
NULL
};
- if (Jim_GetEnum(interp, argv[0], options, &af->wbuft, NULL, JIM_ERRMSG) != JIM_OK) {
- return JIM_ERR;
+ if (argc) {
+ if (Jim_GetEnum(interp, argv[0], options, &af->wbuft, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ if (af->wbuft == WBUF_OPT_FULL && argc == 2) {
+ long l;
+ if (Jim_GetLong(interp, argv[1], &l) != JIM_OK || l <= 0) {
+ return JIM_ERR;
+ }
+ af->wbuf_limit = l;
+ }
+
+ if (af->wbuft == WBUF_OPT_NONE) {
+ if (aio_flush(interp, af) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+
}
- if (af->wbuft == WBUF_OPT_NONE) {
- return aio_flush(interp, af);
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, resultObj, Jim_NewStringObj(interp, options[af->wbuft], -1));
+ if (af->wbuft == WBUF_OPT_FULL) {
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, af->wbuf_limit));
}
+ Jim_SetResult(interp, resultObj);
return JIM_OK;
}
+static int aio_cmd_readsize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (argc) {
+ long l;
+ if (Jim_GetLong(interp, argv[0], &l) != JIM_OK || l <= 0) {
+ return JIM_ERR;
+ }
+ af->rbuf_len = l;
+ if (af->rbuf) {
+ af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
+ }
+ }
+ Jim_SetResultInt(interp, af->rbuf_len);
+
+ return JIM_OK;
+}
+
+#ifdef jim_ext_eventloop
static int aio_cmd_timeout(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
#ifdef HAVE_SELECT
@@ -2906,7 +2973,6 @@ static int aio_cmd_timeout(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
#endif
}
-#ifdef jim_ext_eventloop
static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask,
int argc, Jim_Obj * const *argv)
{
@@ -3074,9 +3140,16 @@ static const jim_subcmd_type aio_command_table[] = {
},
#endif
{ "buffering",
- "none|line|full",
+ "?none|line|full? ?size?",
aio_cmd_buffering,
- 1,
+ 0,
+ 2,
+
+ },
+ { "readsize",
+ "?size?",
+ aio_cmd_readsize,
+ 0,
1,
},
@@ -3319,6 +3392,9 @@ static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
af->writebuf = Jim_NewStringObj(interp, NULL, 0);
Jim_IncrRefCount(af->writebuf);
+ af->wbuf_limit = AIO_DEFAULT_WBUF_LIMIT;
+ af->rbuf_len = AIO_DEFAULT_RBUF_LEN;
+
Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
@@ -3772,27 +3848,30 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
int regcomp_flags = 0;
int regexec_flags = 0;
int opt_all = 0;
+ int opt_command = 0;
int offset = 0;
regex_t *regex;
const char *p;
- int result;
+ int result = JIM_OK;
regmatch_t pmatch[MAX_SUB_MATCHES + 1];
int num_matches = 0;
int i, j, n;
Jim_Obj *varname;
Jim_Obj *resultObj;
+ Jim_Obj *cmd_prefix = NULL;
+ Jim_Obj *regcomp_obj = NULL;
const char *source_str;
int source_len;
- const char *replace_str;
+ const char *replace_str = NULL;
int replace_len;
const char *pattern;
int option;
enum {
- OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_END
+ OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_COMMAND, OPT_END
};
static const char * const options[] = {
- "-nocase", "-line", "-all", "-start", "--", NULL
+ "-nocase", "-line", "-all", "-start", "-command", "--", NULL
};
if (argc < 4) {
@@ -3836,20 +3915,39 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_ERR;
}
break;
+
+ case OPT_COMMAND:
+ opt_command = 1;
+ break;
}
}
if (argc - i != 3 && argc - i != 4) {
goto wrongNumArgs;
}
- regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
+
+ regcomp_obj = Jim_DuplicateObj(interp, argv[i]);
+ Jim_IncrRefCount(regcomp_obj);
+ regex = SetRegexpFromAny(interp, regcomp_obj, regcomp_flags);
if (!regex) {
+ Jim_DecrRefCount(interp, regcomp_obj);
return JIM_ERR;
}
pattern = Jim_String(argv[i]);
source_str = Jim_GetString(argv[i + 1], &source_len);
- replace_str = Jim_GetString(argv[i + 2], &replace_len);
+ if (opt_command) {
+ cmd_prefix = argv[i + 2];
+ if (Jim_ListLength(interp, cmd_prefix) == 0) {
+ Jim_SetResultString(interp, "command prefix must be a list of at least one element", -1);
+ Jim_DecrRefCount(interp, regcomp_obj);
+ return JIM_ERR;
+ }
+ Jim_IncrRefCount(cmd_prefix);
+ }
+ else {
+ replace_str = Jim_GetString(argv[i + 2], &replace_len);
+ }
varname = argv[i + 3];
@@ -3893,35 +3991,58 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
+ if (opt_command) {
- for (j = 0; j < replace_len; j++) {
- int idx;
- int c = replace_str[j];
+ Jim_Obj *cmdListObj = Jim_DuplicateObj(interp, cmd_prefix);
+ for (j = 0; j < MAX_SUB_MATCHES; j++) {
+ if (pmatch[j].rm_so == -1) {
+ break;
+ }
+ else {
+ Jim_Obj *srcObj = Jim_NewStringObj(interp, p + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
+ Jim_ListAppendElement(interp, cmdListObj, srcObj);
+ }
+ }
+ Jim_IncrRefCount(cmdListObj);
- if (c == '&') {
- idx = 0;
+ result = Jim_EvalObj(interp, cmdListObj);
+ Jim_DecrRefCount(interp, cmdListObj);
+ if (result != JIM_OK) {
+ goto cmd_error;
}
- else if (c == '\\' && j < replace_len) {
- c = replace_str[++j];
- if ((c >= '0') && (c <= '9')) {
- idx = c - '0';
+ Jim_AppendString(interp, resultObj, Jim_String(Jim_GetResult(interp)), -1);
+ }
+ else {
+
+ for (j = 0; j < replace_len; j++) {
+ int idx;
+ int c = replace_str[j];
+
+ if (c == '&') {
+ idx = 0;
}
- else if ((c == '\\') || (c == '&')) {
- Jim_AppendString(interp, resultObj, replace_str + j, 1);
- continue;
+ else if (c == '\\' && j < replace_len) {
+ c = replace_str[++j];
+ if ((c >= '0') && (c <= '9')) {
+ idx = c - '0';
+ }
+ else if ((c == '\\') || (c == '&')) {
+ Jim_AppendString(interp, resultObj, replace_str + j, 1);
+ continue;
+ }
+ else {
+ Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2);
+ continue;
+ }
}
else {
- Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2);
+ Jim_AppendString(interp, resultObj, replace_str + j, 1);
continue;
}
- }
- else {
- Jim_AppendString(interp, resultObj, replace_str + j, 1);
- continue;
- }
- if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
- Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
- pmatch[idx].rm_eo - pmatch[idx].rm_so);
+ if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
+ Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
+ pmatch[idx].rm_eo - pmatch[idx].rm_so);
+ }
}
}
@@ -3958,22 +4079,34 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
Jim_AppendString(interp, resultObj, p, -1);
+cmd_error:
+ if (result == JIM_OK) {
- if (argc - i == 4) {
- result = Jim_SetVariable(interp, varname, resultObj);
+ if (argc - i == 4) {
+ result = Jim_SetVariable(interp, varname, resultObj);
- if (result == JIM_OK) {
- Jim_SetResultInt(interp, num_matches);
+ if (result == JIM_OK) {
+ Jim_SetResultInt(interp, num_matches);
+ }
+ else {
+ Jim_FreeObj(interp, resultObj);
+ }
}
else {
- Jim_FreeObj(interp, resultObj);
+ Jim_SetResult(interp, resultObj);
+ result = JIM_OK;
}
}
else {
- Jim_SetResult(interp, resultObj);
- result = JIM_OK;
+ Jim_FreeObj(interp, resultObj);
+ }
+
+ if (opt_command) {
+ Jim_DecrRefCount(interp, cmd_prefix);
}
+ Jim_DecrRefCount(interp, regcomp_obj);
+
return result;
}
@@ -6355,6 +6488,7 @@ static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
}
+ tm.tm_isdst = options.gmt ? 0 : -1;
Jim_SetResultInt(interp, options.gmt ? jim_timegm(&tm) : mktime(&tm));
return JIM_OK;
@@ -6659,53 +6793,6 @@ int Jim_arrayInit(Jim_Interp *interp)
Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL);
return JIM_OK;
}
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-
-#ifdef HAVE_SYS_SYSINFO_H
-#include <sys/sysinfo.h>
-#endif
-
-static void Jim_PosixSetError(Jim_Interp *interp)
-{
- Jim_SetResultString(interp, strerror(errno), -1);
-}
-
-#if defined(HAVE_FORK)
-static int Jim_PosixForkCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
-{
- pid_t pid;
-
- JIM_NOTUSED(argv);
-
- if (argc != 1) {
- Jim_WrongNumArgs(interp, 1, argv, "");
- return JIM_ERR;
- }
- if ((pid = fork()) == -1) {
- Jim_PosixSetError(interp);
- return JIM_ERR;
- }
- Jim_SetResultInt(interp, (jim_wide) pid);
- return JIM_OK;
-}
-#endif
-
-
-int Jim_posixInit(Jim_Interp *interp)
-{
- Jim_PackageProvideCheck(interp, "posix");
-#ifdef HAVE_FORK
- Jim_CreateCommand(interp, "os.fork", Jim_PosixForkCommand, NULL, NULL);
-#endif
- return JIM_OK;
-}
int Jim_InitStaticExtensions(Jim_Interp *interp)
{
extern int Jim_bootstrapInit(Jim_Interp *);
@@ -6715,7 +6802,6 @@ extern int Jim_regexpInit(Jim_Interp *);
extern int Jim_fileInit(Jim_Interp *);
extern int Jim_globInit(Jim_Interp *);
extern int Jim_execInit(Jim_Interp *);
-extern int Jim_posixInit(Jim_Interp *);
extern int Jim_clockInit(Jim_Interp *);
extern int Jim_arrayInit(Jim_Interp *);
extern int Jim_stdlibInit(Jim_Interp *);
@@ -6727,14 +6813,15 @@ Jim_regexpInit(interp);
Jim_fileInit(interp);
Jim_globInit(interp);
Jim_execInit(interp);
-Jim_posixInit(interp);
Jim_clockInit(interp);
Jim_arrayInit(interp);
Jim_stdlibInit(interp);
Jim_tclcompatInit(interp);
return JIM_OK;
}
+#ifndef JIM_TINY
#define JIM_OPTIMIZATION
+#endif
#include <stdio.h>
#include <stdlib.h>
@@ -6794,7 +6881,9 @@ return JIM_OK;
#define JIM_INTEGER_SPACE 24
-const char *jim_tt_name(int type);
+#if defined(DEBUG_SHOW_SCRIPT) || defined(DEBUG_SHOW_SCRIPT_TOKENS) || defined(JIM_DEBUG_COMMAND) || defined(DEBUG_SHOW_SUBST)
+static const char *jim_tt_name(int type);
+#endif
#ifdef JIM_DEBUG_PANIC
static void JimPanicDump(int fail_condition, const char *fmt, ...);
@@ -6830,7 +6919,6 @@ static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv);
static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr);
-static void JimSetErrorStack(Jim_Interp *interp);
static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
#define JIM_DICT_SUGAR 100
@@ -7809,6 +7897,7 @@ struct JimParserCtx
int inquote;
int comment;
struct JimParseMissing missing;
+ const char *errmsg;
};
static int JimParseScript(struct JimParserCtx *pc);
@@ -9509,17 +9598,6 @@ void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
}
-static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
- Jim_Obj *fileNameObj, int lineNumber)
-{
- JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object"));
- JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typed object"));
- Jim_IncrRefCount(fileNameObj);
- objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
- objPtr->internalRep.sourceValue.lineNumber = lineNumber;
- objPtr->typePtr = &sourceObjType;
-}
-
static const Jim_ObjType scriptLineObjType = {
"scriptline",
NULL,
@@ -9580,6 +9658,7 @@ typedef struct ScriptObj
static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
static int JimParseCheckMissing(Jim_Interp *interp, int ch);
static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
+static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script);
void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
{
@@ -9795,7 +9874,7 @@ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
token->objPtr = JimMakeScriptObj(interp, t);
Jim_IncrRefCount(token->objPtr);
- JimSetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
+ Jim_SetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
token++;
}
}
@@ -9855,6 +9934,39 @@ static int JimParseCheckMissing(Jim_Interp *interp, int ch)
return JIM_ERR;
}
+Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, int *lineptr)
+{
+ int line;
+ Jim_Obj *fileNameObj;
+
+ if (objPtr->typePtr == &sourceObjType) {
+ fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+ line = objPtr->internalRep.sourceValue.lineNumber;
+ }
+ else if (objPtr->typePtr == &scriptObjType) {
+ ScriptObj *script = JimGetScript(interp, objPtr);
+ fileNameObj = script->fileNameObj;
+ line = script->firstline;
+ }
+ else {
+ fileNameObj = interp->emptyObj;
+ line = 1;
+ }
+ *lineptr = line;
+ return fileNameObj;
+}
+
+void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *fileNameObj, int lineNumber)
+{
+ JimPanic((Jim_IsShared(objPtr), "Jim_SetSourceInfo called with shared object"));
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_IncrRefCount(fileNameObj);
+ objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
+ objPtr->internalRep.sourceValue.lineNumber = lineNumber;
+ objPtr->typePtr = &sourceObjType;
+}
+
static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
ParseTokenList *tokenlist)
{
@@ -9883,12 +9995,11 @@ static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
struct JimParserCtx parser;
struct ScriptObj *script;
ParseTokenList tokenlist;
- int line = 1;
+ Jim_Obj *fileNameObj;
+ int line;
- if (objPtr->typePtr == &sourceObjType) {
- line = objPtr->internalRep.sourceValue.lineNumber;
- }
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
ScriptTokenListInit(&tokenlist);
@@ -9907,12 +10018,7 @@ static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
script = Jim_Alloc(sizeof(*script));
memset(script, 0, sizeof(*script));
script->inUse = 1;
- if (objPtr->typePtr == &sourceObjType) {
- script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
- }
- else {
- script->fileNameObj = interp->emptyObj;
- }
+ script->fileNameObj = fileNameObj;
Jim_IncrRefCount(script->fileNameObj);
script->missing = parser.missing.ch;
script->linenr = parser.missing.line;
@@ -11377,6 +11483,9 @@ void Jim_FreeInterp(Jim_Interp *i)
JimFreeCallFrame(i, cf, JIM_FCF_FULL);
}
+
+ Jim_FreeHashTable(&i->commands);
+
Jim_DecrRefCount(i, i->emptyObj);
Jim_DecrRefCount(i, i->trueObj);
Jim_DecrRefCount(i, i->falseObj);
@@ -11391,7 +11500,6 @@ void Jim_FreeInterp(Jim_Interp *i)
Jim_InterpIncrProcEpoch(i);
- Jim_FreeHashTable(&i->commands);
#ifdef JIM_REFERENCES
Jim_FreeHashTable(&i->references);
#endif
@@ -11590,16 +11698,24 @@ static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
interp->errorFlag = 1;
}
-static void JimSetErrorStack(Jim_Interp *interp)
+static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script)
{
if (!interp->errorFlag) {
int i;
Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0);
- for (i = 0; i <= interp->procLevel; i++) {
- Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
- if (frame) {
- JimAddStackFrame(interp, frame, stackTrace);
+ if (interp->procLevel == 0 && script) {
+ Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
+ Jim_ListAppendElement(interp, stackTrace, script->fileNameObj);
+ Jim_ListAppendElement(interp, stackTrace, Jim_NewIntObj(interp, script->linenr));
+ Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
+ }
+ else {
+ for (i = 0; i <= interp->procLevel; i++) {
+ Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
+ if (frame) {
+ JimAddStackFrame(interp, frame, stackTrace);
+ }
}
}
JimSetStackTrace(interp, stackTrace);
@@ -12290,14 +12406,7 @@ static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
}
- if (objPtr->typePtr == &sourceObjType) {
- fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
- linenr = objPtr->internalRep.sourceValue.lineNumber;
- }
- else {
- fileNameObj = interp->emptyObj;
- linenr = 1;
- }
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &linenr);
Jim_IncrRefCount(fileNameObj);
@@ -12319,7 +12428,7 @@ static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
continue;
elementPtr = JimParserGetTokenObj(interp, &parser);
- JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
+ Jim_SetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
ListAppendElement(objPtr, elementPtr);
}
}
@@ -12374,7 +12483,8 @@ struct lsort_info {
JIM_LSORT_NOCASE,
JIM_LSORT_INTEGER,
JIM_LSORT_REAL,
- JIM_LSORT_COMMAND
+ JIM_LSORT_COMMAND,
+ JIM_LSORT_DICT
} type;
int order;
Jim_Obj **indexv;
@@ -12407,6 +12517,43 @@ static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
}
+static int ListSortDict(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+
+ const char *left = Jim_String(*lhsObj);
+ const char *right = Jim_String(*rhsObj);
+
+ while (1) {
+ if (isdigit(UCHAR(*left)) && isdigit(UCHAR(*right))) {
+
+ jim_wide lint, rint;
+ char *lend, *rend;
+ lint = jim_strtoull(left, &lend);
+ rint = jim_strtoull(right, &rend);
+ if (lint != rint) {
+ return JimSign(lint - rint) * sort_info->order;
+ }
+ if (lend -left != rend - right) {
+ return JimSign((lend - left) - (rend - right)) * sort_info->order;
+ }
+ left = lend;
+ right = rend;
+ }
+ else {
+ int cl, cr;
+ left += utf8_tounicode_case(left, &cl, 1);
+ right += utf8_tounicode_case(right, &cr, 1);
+ if (cl != cr) {
+ return JimSign(cl - cr) * sort_info->order;
+ }
+ if (cl == 0) {
+
+ return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
+ }
+ }
+ }
+}
+
static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
{
jim_wide lhs = 0, rhs = 0;
@@ -12521,6 +12668,9 @@ static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsor
case JIM_LSORT_COMMAND:
fn = ListSortCommand;
break;
+ case JIM_LSORT_DICT:
+ fn = ListSortDict;
+ break;
default:
fn = NULL;
JimPanic((1, "ListSort called with invalid sort type"));
@@ -12570,6 +12720,11 @@ static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *co
int i;
Jim_Obj **point;
+ if (elemc == 0) {
+
+ return;
+ }
+
if (requiredLen > listPtr->internalRep.listValue.maxLen) {
if (currentLen) {
@@ -14334,6 +14489,8 @@ static const struct Jim_ExprOperator Jim_ExprOperators[] = {
static int JimParseExpression(struct JimParserCtx *pc)
{
+ pc->errmsg = NULL;
+
while (1) {
while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
@@ -14384,6 +14541,7 @@ singlechar:
else {
if (pc->tt == JIM_TT_EXPRSUGAR) {
+ pc->errmsg = "nesting expr in expr is not allowed";
return JIM_ERR;
}
return JIM_OK;
@@ -14528,6 +14686,7 @@ static int JimParseExprOperator(struct JimParserCtx *pc)
p++;
}
if (*p != '(') {
+ pc->errmsg = "function requires parentheses";
return JIM_ERR;
}
}
@@ -14539,31 +14698,6 @@ static int JimParseExprOperator(struct JimParserCtx *pc)
return JIM_OK;
}
-const char *jim_tt_name(int type)
-{
- static const char * const tt_names[JIM_TT_EXPR_OP] =
- { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
- "DBL", "BOO", "$()" };
- if (type < JIM_TT_EXPR_OP) {
- return tt_names[type];
- }
- else if (type == JIM_EXPROP_UNARYMINUS) {
- return "-VE";
- }
- else if (type == JIM_EXPROP_UNARYPLUS) {
- return "+VE";
- }
- else {
- const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type);
- static char buf[20];
-
- if (op->name) {
- return op->name;
- }
- sprintf(buf, "(%d)", type);
- return buf;
- }
-}
static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
@@ -14869,7 +15003,7 @@ missingoperand:
objPtr = Jim_NewStringObj(interp, t->token, t->len);
if (t->type == JIM_TT_CMD) {
- JimSetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
+ Jim_SetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
}
}
@@ -14967,14 +15101,7 @@ static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
int rc = JIM_ERR;
- if (objPtr->typePtr == &sourceObjType) {
- fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
- line = objPtr->internalRep.sourceValue.lineNumber;
- }
- else {
- fileNameObj = interp->emptyObj;
- line = 1;
- }
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
Jim_IncrRefCount(fileNameObj);
exprText = Jim_GetString(objPtr, &exprTextLen);
@@ -14987,6 +15114,9 @@ static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
if (JimParseExpression(&parser) != JIM_OK) {
ScriptTokenListFree(&tokenlist);
Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
+ if (parser.errmsg) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), ": ", parser.errmsg, NULL);
+ }
expr = NULL;
goto err;
}
@@ -15006,10 +15136,17 @@ static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
}
#endif
- if (JimParseCheckMissing(interp, parser.missing.ch) == JIM_ERR) {
+ if (tokenlist.count <= 1) {
+ Jim_SetResultString(interp, "empty expression", -1);
+ rc = JIM_ERR;
+ }
+ else {
+ rc = JimParseCheckMissing(interp, parser.missing.ch);
+ }
+ if (rc != JIM_OK) {
ScriptTokenListFree(&tokenlist);
Jim_DecrRefCount(interp, fileNameObj);
- return JIM_ERR;
+ return rc;
}
@@ -15860,13 +15997,18 @@ static int JimTraceCallback(Jim_Interp *interp, const char *type, int argc, Jim_
Jim_Obj *nargv[7];
Jim_Obj *traceCmdObj = interp->traceCmdObj;
Jim_Obj *resultObj = Jim_GetResult(interp);
+ ScriptObj *script = NULL;
- ScriptObj *script = JimGetScript(interp, interp->evalFrame->scriptObj);
+
+
+ if (interp->evalFrame->scriptObj) {
+ script = JimGetScript(interp, interp->evalFrame->scriptObj);
+ }
nargv[0] = traceCmdObj;
nargv[1] = Jim_NewStringObj(interp, type, -1);
- nargv[2] = script->fileNameObj;
- nargv[3] = Jim_NewIntObj(interp, script->linenr);
+ nargv[2] = script ? script->fileNameObj : interp->emptyObj;
+ nargv[3] = Jim_NewIntObj(interp, script ? script->linenr : 1);
nargv[4] = resultObj;
nargv[5] = argv[0];
nargv[6] = Jim_NewListObj(interp, argv + 1, argc - 1);
@@ -15988,7 +16130,7 @@ tailcall:
retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
}
if (retcode == JIM_ERR) {
- JimSetErrorStack(interp);
+ JimSetErrorStack(interp, NULL);
}
}
@@ -16023,7 +16165,7 @@ out:
JimDecrCmdRefCount(interp, cmdPtr);
if (retcode == JIM_ERR) {
- JimSetErrorStack(interp);
+ JimSetErrorStack(interp, NULL);
}
if (interp->framePtr->tailcallObj) {
@@ -16045,6 +16187,7 @@ int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
for (i = 0; i < objc; i++)
Jim_IncrRefCount(objv[i]);
+
JimPushEvalFrame(interp, &frame, NULL);
retcode = JimInvokeCommand(interp, objc, objv);
@@ -16183,7 +16326,9 @@ static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * tok
}
else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
- JimSetSourceInfo(interp, objPtr, intv[0]->internalRep.sourceValue.fileNameObj, intv[0]->internalRep.sourceValue.lineNumber);
+ int line;
+ Jim_Obj *fileNameObj = Jim_GetSourceInfo(interp, intv[0], &line);
+ Jim_SetSourceInfo(interp, objPtr, fileNameObj, line);
}
@@ -16250,7 +16395,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
Jim_IncrRefCount(scriptObjPtr);
script = JimGetScript(interp, scriptObjPtr);
if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
- JimSetErrorStack(interp);
+ JimSetErrorStack(interp, script);
Jim_DecrRefCount(interp, scriptObjPtr);
return JIM_ERR;
}
@@ -16422,7 +16567,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
if (retcode == JIM_ERR) {
- JimSetErrorStack(interp);
+ JimSetErrorStack(interp, NULL);
}
JimPopEvalFrame(interp);
@@ -16650,7 +16795,7 @@ int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const c
scriptObjPtr = Jim_NewStringObj(interp, script, -1);
Jim_IncrRefCount(scriptObjPtr);
if (filename) {
- JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
+ Jim_SetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
}
retval = Jim_EvalObj(interp, scriptObjPtr);
Jim_DecrRefCount(interp, scriptObjPtr);
@@ -16732,7 +16877,7 @@ int Jim_EvalFile(Jim_Interp *interp, const char *filename)
}
filenameObj = Jim_NewStringObj(interp, filename, -1);
- JimSetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
+ Jim_SetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj);
@@ -16773,7 +16918,9 @@ static void JimParseSubst(struct JimParserCtx *pc, int flags)
}
pc->tstart = pc->p;
- flags |= JIM_SUBST_NOVAR;
+
+ pc->p++;
+ pc->len--;
}
while (pc->len) {
if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
@@ -17276,7 +17423,7 @@ static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
static int JimCheckLoopRetcode(Jim_Interp *interp, int retval)
{
if (retval == JIM_BREAK || retval == JIM_CONTINUE) {
- if (--interp->returnLevel > 0) {
+ if (--interp->break_level > 0) {
return 1;
}
}
@@ -17466,15 +17613,14 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv
while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
retval = Jim_EvalObj(interp, argv[4]);
-
+ if (JimCheckLoopRetcode(interp, retval)) {
+ immediate++;
+ break;
+ }
if (retval == JIM_OK || retval == JIM_CONTINUE) {
JIM_IF_OPTIM(evalnext:)
retval = Jim_EvalObj(interp, argv[3]);
- if (JimCheckLoopRetcode(interp, retval)) {
- immediate++;
- goto out;
- }
if (retval == JIM_OK || retval == JIM_CONTINUE) {
JIM_IF_OPTIM(testcond:)
@@ -17505,7 +17651,7 @@ static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
{
int retval;
jim_wide i;
- jim_wide limit;
+ jim_wide limit = 0;
jim_wide incr = 1;
Jim_Obj *bodyObjPtr;
@@ -18329,17 +18475,19 @@ static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const arg
{
static const char * const options[] = {
"-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique",
- "-stride", NULL
+ "-stride", "-dictionary", NULL
};
enum {
OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE,
- OPT_STRIDE
+ OPT_STRIDE, OPT_DICT
};
Jim_Obj *resObj;
int i;
int retCode;
int shared;
long stride = 1;
+ Jim_Obj **elements;
+ int listlen;
struct lsort_info info;
@@ -18366,6 +18514,9 @@ wrongargs:
case OPT_ASCII:
info.type = JIM_LSORT_ASCII;
break;
+ case OPT_DICT:
+ info.type = JIM_LSORT_DICT;
+ break;
case OPT_NOCASE:
info.type = JIM_LSORT_NOCASE;
break;
@@ -18420,13 +18571,17 @@ badindex:
}
}
resObj = argv[argc - 1];
+ JimListGetElements(interp, resObj, &listlen, &elements);
+ if (listlen <= 1) {
+
+ Jim_SetResult(interp, resObj);
+ return JIM_OK;
+ }
+
if (stride > 1) {
Jim_Obj *tmpListObj;
- Jim_Obj **elements;
- int listlen;
int i;
- JimListGetElements(interp, resObj, &listlen, &elements);
if (listlen % stride) {
Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
return JIM_ERR;
@@ -18614,7 +18769,7 @@ static int JimBreakContinueHelper(Jim_Interp *interp, int argc, Jim_Obj *const *
if (ret != JIM_OK) {
return ret;
}
- interp->returnLevel = level;
+ interp->break_level = level;
}
return retcode;
}
@@ -20332,7 +20487,6 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
return JIM_OK;
case INFO_SOURCE:{
- jim_wide line;
Jim_Obj *resObjPtr;
Jim_Obj *fileNameObj;
@@ -20341,26 +20495,16 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
return JIM_ERR;
}
if (argc == 5) {
+ jim_wide line;
if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) {
return JIM_ERR;
}
resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2]));
- JimSetSourceInfo(interp, resObjPtr, argv[3], line);
+ Jim_SetSourceInfo(interp, resObjPtr, argv[3], line);
}
else {
- if (argv[2]->typePtr == &sourceObjType) {
- fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj;
- line = argv[2]->internalRep.sourceValue.lineNumber;
- }
- else if (argv[2]->typePtr == &scriptObjType) {
- ScriptObj *script = JimGetScript(interp, argv[2]);
- fileNameObj = script->fileNameObj;
- line = script->firstline;
- }
- else {
- fileNameObj = interp->emptyObj;
- line = 1;
- }
+ int line;
+ fileNameObj = Jim_GetSourceInfo(interp, argv[2], &line);
resObjPtr = Jim_NewListObj(interp, NULL, 0);
Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
@@ -20819,11 +20963,12 @@ char **Jim_GetEnviron(void)
{
#if defined(HAVE__NSGETENVIRON)
return *_NSGetEnviron();
+#elif defined(_environ)
+ return _environ;
#else
#if !defined(NO_ENVIRON_EXTERN)
extern char **environ;
#endif
-
return environ;
#endif
}
@@ -20832,6 +20977,8 @@ void Jim_SetEnviron(char **env)
{
#if defined(HAVE__NSGETENVIRON)
*_NSGetEnviron() = env;
+#elif defined(_environ)
+ _environ = env;
#else
#if !defined(NO_ENVIRON_EXTERN)
extern char **environ;
@@ -23450,7 +23597,7 @@ void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno()));
}
-#if defined(__MINGW32__)
+#if defined(_WIN32) || defined(WIN32)
#include <sys/stat.h>
int Jim_Errno(void)
@@ -23646,7 +23793,9 @@ int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unli
}
+#ifdef HAVE_UMASK
mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
+#endif
#ifdef HAVE_MKSTEMP
fd = mkstemp(filenameObj->bytes);
#else
@@ -23657,7 +23806,9 @@ int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unli
fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
}
#endif
+#ifdef HAVE_UMASK
umask(mask);
+#endif
if (fd < 0) {
Jim_SetResultErrno(interp, Jim_String(filenameObj));
Jim_FreeNewObj(interp, filenameObj);
@@ -24260,6 +24411,11 @@ int main(int argc, char *const argv[])
Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
+#ifdef USE_LINENOISE
+ Jim_SetVariableStrWithStr(interp, "jim::lineedit", "1");
+#else
+ Jim_SetVariableStrWithStr(interp, "jim::lineedit", "0");
+#endif
retcode = Jim_initjimshInit(interp);
if (argc == 1) {
diff --git a/autosetup/system.tcl b/autosetup/system.tcl
index f23781b..05d378a 100644
--- a/autosetup/system.tcl
+++ b/autosetup/system.tcl
@@ -55,6 +55,8 @@ options {
program-prefix:
program-suffix:
program-transform-name:
+ x-includes:
+ x-libraries:
}
# @check-feature name { script }
@@ -318,95 +320,101 @@ proc make-template {template {out {}}} {
}
}
-# build/host tuples and cross-compilation prefix
-opt-str build build ""
-define build_alias $build
-if {$build eq ""} {
- define build [config_guess]
-} else {
- define build [config_sub $build]
-}
+proc system-init {} {
+ global autosetup
-opt-str host host ""
-define host_alias $host
-if {$host eq ""} {
- define host [get-define build]
- set cross ""
-} else {
- define host [config_sub $host]
- set cross $host-
-}
-define cross [get-env CROSS $cross]
+ # build/host tuples and cross-compilation prefix
+ opt-str build build ""
+ define build_alias $build
+ if {$build eq ""} {
+ define build [config_guess]
+ } else {
+ define build [config_sub $build]
+ }
-# build/host _cpu, _vendor and _os
-foreach type {build host} {
- set v [get-define $type]
- if {![regexp {^([^-]+)-([^-]+)-(.*)$} $v -> cpu vendor os]} {
- user-error "Invalid canonical $type: $v"
+ opt-str host host ""
+ define host_alias $host
+ if {$host eq ""} {
+ define host [get-define build]
+ set cross ""
+ } else {
+ define host [config_sub $host]
+ set cross $host-
}
- define ${type}_cpu $cpu
- define ${type}_vendor $vendor
- define ${type}_os $os
-}
+ define cross [get-env CROSS $cross]
-opt-str prefix prefix /usr/local
-
-# These are for compatibility with autoconf
-define target [get-define host]
-define prefix $prefix
-define builddir $autosetup(builddir)
-define srcdir $autosetup(srcdir)
-define top_srcdir $autosetup(srcdir)
-define abs_top_srcdir [file-normalize $autosetup(srcdir)]
-define abs_top_builddir [file-normalize $autosetup(builddir)]
-
-# autoconf supports all of these
-define exec_prefix [opt-str exec-prefix exec_prefix $prefix]
-foreach {name defpath} {
- bindir /bin
- sbindir /sbin
- libexecdir /libexec
- libdir /lib
-} {
- define $name [opt-str $name o $exec_prefix$defpath]
-}
-foreach {name defpath} {
- datadir /share
- sharedstatedir /com
- infodir /share/info
- mandir /share/man
- includedir /include
-} {
- define $name [opt-str $name o $prefix$defpath]
-}
-if {$prefix ne {/usr}} {
- opt-str sysconfdir sysconfdir $prefix/etc
-} else {
- opt-str sysconfdir sysconfdir /etc
-}
-define sysconfdir $sysconfdir
+ # build/host _cpu, _vendor and _os
+ foreach type {build host} {
+ set v [get-define $type]
+ if {![regexp {^([^-]+)-([^-]+)-(.*)$} $v -> cpu vendor os]} {
+ user-error "Invalid canonical $type: $v"
+ }
+ define ${type}_cpu $cpu
+ define ${type}_vendor $vendor
+ define ${type}_os $os
+ }
+
+ opt-str prefix prefix /usr/local
+
+ # These are for compatibility with autoconf
+ define target [get-define host]
+ define prefix $prefix
+ define builddir $autosetup(builddir)
+ define srcdir $autosetup(srcdir)
+ define top_srcdir $autosetup(srcdir)
+ define abs_top_srcdir [file-normalize $autosetup(srcdir)]
+ define abs_top_builddir [file-normalize $autosetup(builddir)]
+
+ # autoconf supports all of these
+ define exec_prefix [opt-str exec-prefix exec_prefix $prefix]
+ foreach {name defpath} {
+ bindir /bin
+ sbindir /sbin
+ libexecdir /libexec
+ libdir /lib
+ } {
+ define $name [opt-str $name o $exec_prefix$defpath]
+ }
+ foreach {name defpath} {
+ datadir /share
+ sharedstatedir /com
+ infodir /share/info
+ mandir /share/man
+ includedir /include
+ } {
+ define $name [opt-str $name o $prefix$defpath]
+ }
+ if {$prefix ne {/usr}} {
+ opt-str sysconfdir sysconfdir $prefix/etc
+ } else {
+ opt-str sysconfdir sysconfdir /etc
+ }
+ define sysconfdir $sysconfdir
-define localstatedir [opt-str localstatedir o /var]
-define runstatedir [opt-str runstatedir o /run]
+ define localstatedir [opt-str localstatedir o /var]
+ define runstatedir [opt-str runstatedir o /run]
-define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
+ define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
-# These could be used to generate Makefiles following some automake conventions
-define AM_SILENT_RULES [opt-bool silent-rules]
-define AM_MAINTAINER_MODE [opt-bool maintainer-mode]
-define AM_DEPENDENCY_TRACKING [opt-bool dependency-tracking]
+ # These could be used to generate Makefiles following some automake conventions
+ define AM_SILENT_RULES [opt-bool silent-rules]
+ define AM_MAINTAINER_MODE [opt-bool maintainer-mode]
+ define AM_DEPENDENCY_TRACKING [opt-bool dependency-tracking]
-# Windows vs. non-Windows
-switch -glob -- [get-define host] {
- *-*-ming* - *-*-cygwin - *-*-msys {
- define-feature windows
- define EXEEXT .exe
- }
- default {
- define EXEEXT ""
+ # Windows vs. non-Windows
+ switch -glob -- [get-define host] {
+ *-*-ming* - *-*-cygwin - *-*-msys {
+ define-feature windows
+ define EXEEXT .exe
+ }
+ default {
+ define EXEEXT ""
+ }
}
+
+ # Display
+ msg-result "Host System...[get-define host]"
+ msg-result "Build System...[get-define build]"
}
-# Display
-msg-result "Host System...[get-define host]"
-msg-result "Build System...[get-define build]"
+system-init
diff --git a/initjimsh.tcl b/initjimsh.tcl
index 6fa54c6..e632623 100644
--- a/initjimsh.tcl
+++ b/initjimsh.tcl
@@ -10,8 +10,14 @@ proc _jimsh_init {} {
if {[string match "*/*" $jim::argv0]} {
set jim::exe [file join [pwd] $jim::argv0]
} else {
- foreach path [split [env PATH ""] $tcl_platform(pathSeparator)] {
- set exec [file join [pwd] [string map {\\ /} $path] $jim::argv0]
+ set jim::argv0 [file tail $jim::argv0]
+ set path [split [env PATH ""] $tcl_platform(pathSeparator)]
+ if {$tcl_platform(platform) eq "windows"} {
+ # Windows searches the current directory first, and convert backslashes to slashes
+ set path [lmap p [list "" {*}$path] { string map {\\ /} $p }]
+ }
+ foreach p $path {
+ set exec [file join [pwd] $p $jim::argv0]
if {[file executable $exec]} {
set jim::exe $exec
break
diff --git a/jim-aio.c b/jim-aio.c
index 4c59e1d..221d7f5 100644
--- a/jim-aio.c
+++ b/jim-aio.c
@@ -85,8 +85,8 @@
#include "jimiocompat.h"
#define AIO_CMD_LEN 32 /* e.g. aio.handleXXXXXX */
-#define AIO_BUF_LEN 256 /* read size for gets, read */
-#define AIO_WBUF_FULL_SIZE (64 * 1024) /* This could be configurable */
+#define AIO_DEFAULT_RBUF_LEN 256 /* read size for gets, read */
+#define AIO_DEFAULT_WBUF_LIMIT (64 * 1024) /* max size of writebuf before flushing */
#define AIO_KEEPOPEN 1 /* don't set O_CLOEXEC, don't close on command delete */
#define AIO_NODELETE 2 /* don't delete AF_UNIX path on close */
@@ -94,6 +94,8 @@
#define AIO_WBUF_NONE 8 /* default to buffering=none */
#define AIO_NONBLOCK 16 /* socket is non-blocking */
+#define AIO_ONEREAD 32 /* passed to aio_read_len() to return after a single read */
+
enum wbuftype {
WBUF_OPT_NONE, /* write immediately */
WBUF_OPT_LINE, /* write if NL is seen */
@@ -114,10 +116,6 @@ enum wbuftype {
#define UNIX_SOCKETS 0
#endif
-#ifndef MAXPATHLEN
-#define MAXPATHLEN JIM_PATH_LEN
-#endif
-
#if defined(HAVE_SOCKETS) && !defined(JIM_BOOTSTRAP)
/* Avoid type punned pointers */
union sockaddr_any {
@@ -192,11 +190,22 @@ typedef struct AioFile
const JimAioFopsType *fops;
Jim_Obj *readbuf; /* Contains any buffered read data. NULL if empty. refcount=0 */
Jim_Obj *writebuf; /* Contains any buffered write data. refcount=1 */
+ char *rbuf; /* Temporary read buffer (NULL if not yet allocated) */
+ size_t rbuf_len; /* Length of rbuf */
+ size_t wbuf_limit; /* Max size of writebuf before flushing */
} AioFile;
+static void aio_consume(Jim_Obj *objPtr, int n);
+
static int stdio_writer(struct AioFile *af, const char *buf, int len)
{
- return write(af->fd, buf, len);
+ int ret = write(af->fd, buf, len);
+ if (ret < 0 && errno == EPIPE) {
+ /* Also discard the write buffer since otherwise when
+ * we try to flush on shutdown we may get SIGPIPE */
+ aio_consume(af->writebuf, Jim_Length(af->writebuf));
+ }
+ return ret;
}
static int stdio_reader(struct AioFile *af, char *buf, int len, int nb)
@@ -710,7 +719,26 @@ static void aio_consume(Jim_Obj *objPtr, int n)
}
/* forward declaration */
-static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask);
+static int aio_flush(Jim_Interp *interp, AioFile *af);
+
+#ifdef jim_ext_eventloop
+/**
+ * Called when the channel is writable.
+ * Write what we can and return -1 when the write buffer is empty to remove the handler.
+ */
+static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask)
+{
+ AioFile *af = clientData;
+
+ aio_flush(interp, af);
+ if (Jim_Length(af->writebuf) == 0) {
+ /* Done, so remove the handler */
+ return -1;
+ }
+ return 0;
+}
+#endif
+
/**
* Flushes af->writebuf to the channel and removes that data
@@ -759,30 +787,18 @@ static int aio_flush(Jim_Interp *interp, AioFile *af)
}
/**
- * Called when the channel is writable.
- * Write what we can and return -1 when the write buffer is empty to remove the handler.
- */
-static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask)
-{
- AioFile *af = clientData;
-
- aio_flush(interp, af);
- if (Jim_Length(af->writebuf) == 0) {
- /* Done, so remove the handler */
- return -1;
- }
- return 0;
-}
-
-/**
* Read until 'len' bytes are available in readbuf.
*
+ * If flags contains AIO_NONBLOCK, indicates a nonblocking read.
+ * If flags contains AIO_ONEREAD, return after a single read.
+ * (In this case JIM_ERR is also returned on timeout)
+ *
* If nonblocking or timeout, may return early.
* 'len' may be -1 to read until eof (or until no more data if nonblocking)
*
* Returns JIM_OK if data was read or JIM_ERR on error.
*/
-static int aio_read_len(Jim_Interp *interp, AioFile *af, int nb, char *buf, size_t buflen, int neededLen)
+static int aio_read_len(Jim_Interp *interp, AioFile *af, unsigned flags, int neededLen)
{
if (!af->readbuf) {
af->readbuf = Jim_NewStringObj(interp, NULL, 0);
@@ -800,20 +816,29 @@ static int aio_read_len(Jim_Interp *interp, AioFile *af, int nb, char *buf, size
int readlen;
if (neededLen == -1) {
- readlen = AIO_BUF_LEN;
+ readlen = af->rbuf_len;
}
else {
- readlen = (neededLen > AIO_BUF_LEN ? AIO_BUF_LEN : neededLen);
+ readlen = (neededLen > af->rbuf_len ? af->rbuf_len : neededLen);
}
- retval = af->fops->reader(af, buf, readlen, nb);
+ /* Allocate buffer if not already allocated */
+ if (!af->rbuf) {
+ af->rbuf = Jim_Alloc(af->rbuf_len);
+ }
+ retval = af->fops->reader(af, af->rbuf, readlen, flags & AIO_NONBLOCK);
if (retval > 0) {
- Jim_AppendString(interp, af->readbuf, buf, retval);
+ if (retval) {
+ Jim_AppendString(interp, af->readbuf, af->rbuf, retval);
+ }
if (neededLen != -1) {
neededLen -= retval;
}
+ if (flags & AIO_ONEREAD) {
+ return JIM_OK;
+ }
continue;
}
- if (JimCheckStreamError(interp, af)) {
+ if ((flags & AIO_ONEREAD) || JimCheckStreamError(interp, af)) {
return JIM_ERR;
}
break;
@@ -892,6 +917,7 @@ static void JimAioDelProc(Jim_Interp *interp, void *privData)
Jim_FreeNewObj(interp, af->readbuf);
}
+ Jim_Free(af->rbuf);
Jim_Free(af);
}
@@ -905,7 +931,6 @@ static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
int option;
int nb;
Jim_Obj *objPtr;
- char buf[AIO_BUF_LEN];
if (argc) {
if (*Jim_String(argv[0]) == '-') {
@@ -939,7 +964,7 @@ static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
/* reads are nonblocking if a timeout is given */
nb = aio_start_nonblocking(af);
- if (aio_read_len(interp, af, nb, buf, sizeof(buf), neededLen) != JIM_OK) {
+ if (aio_read_len(interp, af, nb ? AIO_NONBLOCK : 0, neededLen) != JIM_OK) {
aio_set_nonblocking(af, nb);
return JIM_ERR;
}
@@ -997,11 +1022,6 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
AioFile *af = Jim_CmdPrivData(interp);
jim_wide count = 0;
jim_wide maxlen = JIM_WIDE_MAX;
- /* Small, static buffer for small files */
- char buf[AIO_BUF_LEN];
- /* Will be allocated if the file is large */
- char *bufp = buf;
- int buflen = sizeof(buf);
int ok = 1;
Jim_Obj *objv[4];
@@ -1031,10 +1051,10 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
while (count < maxlen) {
jim_wide len = maxlen - count;
- if (len > buflen) {
- len = buflen;
+ if (len > af->rbuf_len) {
+ len = af->rbuf_len;
}
- if (aio_read_len(interp, af, 0, bufp, buflen, len) != JIM_OK) {
+ if (aio_read_len(interp, af, 0, len) != JIM_OK) {
ok = 0;
break;
}
@@ -1047,17 +1067,13 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
if (aio_eof(af)) {
break;
}
- if (count >= 16384 && bufp == buf) {
+ if (count >= 16384 && af->rbuf_len < 65536) {
/* Heuristic check - for large copy speed-up */
- buflen = 65536;
- bufp = Jim_Alloc(buflen);
+ af->rbuf_len = 65536;
+ af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
}
}
- if (bufp != buf) {
- Jim_Free(bufp);
- }
-
Jim_DecrRefCount(interp, objv[1]);
Jim_DecrRefCount(interp, objv[2]);
@@ -1073,10 +1089,10 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
AioFile *af = Jim_CmdPrivData(interp);
- char buf[AIO_BUF_LEN];
Jim_Obj *objPtr = NULL;
int len;
int nb;
+ unsigned flags = AIO_ONEREAD;
char *nl = NULL;
int offset = 0;
@@ -1084,33 +1100,33 @@ static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
/* reads are non-blocking if a timeout has been given */
nb = aio_start_nonblocking(af);
-
- if (!af->readbuf) {
- af->readbuf = Jim_NewStringObj(interp, NULL, 0);
+ if (nb) {
+ flags |= AIO_NONBLOCK;
}
while (!aio_eof(af)) {
- const char *pt = Jim_GetString(af->readbuf, &len);
- nl = memchr(pt + offset, '\n', len - offset);
- if (nl) {
- /* got a line */
- objPtr = Jim_NewStringObj(interp, pt, nl - pt);
- /* And consume it plus the newline */
- aio_consume(af->readbuf, nl - pt + 1);
- break;
+ if (af->readbuf) {
+ const char *pt = Jim_GetString(af->readbuf, &len);
+ nl = memchr(pt + offset, '\n', len - offset);
+ if (nl) {
+ /* got a line */
+ objPtr = Jim_NewStringObj(interp, pt, nl - pt);
+ /* And consume it plus the newline */
+ aio_consume(af->readbuf, nl - pt + 1);
+ break;
+ }
+ offset = len;
}
- offset = len;
- len = af->fops->reader(af, buf, AIO_BUF_LEN, nb);
- if (len <= 0) {
+ /* Not got a line yet, so read more */
+ if (aio_read_len(interp, af, flags, -1) != JIM_OK) {
break;
}
- Jim_AppendString(interp, af->readbuf, buf, len);
}
aio_set_nonblocking(af, nb);
- if (!nl && aio_eof(af)) {
+ if (!nl && aio_eof(af) && af->readbuf) {
/* Just take what we have as the line */
objPtr = af->readbuf;
af->readbuf = NULL;
@@ -1162,6 +1178,15 @@ static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
/* Keep it simple and always go via the writebuf instead of trying to optimise
* the case that we can write immediately
*/
+#ifdef JIM_MAINTAINER
+ if (Jim_IsShared(af->writebuf)) {
+ /* This should generally never happen since this object isn't accessible,
+ * but it is possible with 'debug objects' */
+ Jim_DecrRefCount(interp, af->writebuf);
+ af->writebuf = Jim_DuplicateObj(interp, af->writebuf);
+ Jim_IncrRefCount(af->writebuf);
+ }
+#endif
Jim_AppendObj(interp, af->writebuf, strObj);
if (nl) {
Jim_AppendString(interp, af->writebuf, "\n", 1);
@@ -1183,7 +1208,7 @@ static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
break;
case WBUF_OPT_FULL:
- if (wlen >= AIO_WBUF_FULL_SIZE) {
+ if (wlen >= af->wbuf_limit) {
wnow = 1;
}
break;
@@ -1597,6 +1622,7 @@ static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
AioFile *af = Jim_CmdPrivData(interp);
+ Jim_Obj *resultObj;
static const char * const options[] = {
"none",
@@ -1605,17 +1631,79 @@ static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
NULL
};
- if (Jim_GetEnum(interp, argv[0], options, &af->wbuft, NULL, JIM_ERRMSG) != JIM_OK) {
- return JIM_ERR;
+ if (argc) {
+ if (Jim_GetEnum(interp, argv[0], options, &af->wbuft, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ if (af->wbuft == WBUF_OPT_FULL && argc == 2) {
+ long l;
+ if (Jim_GetLong(interp, argv[1], &l) != JIM_OK || l <= 0) {
+ return JIM_ERR;
+ }
+ af->wbuf_limit = l;
+ }
+
+ if (af->wbuft == WBUF_OPT_NONE) {
+ if (aio_flush(interp, af) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+ /* don't bother flushing when switching from full to line */
}
- if (af->wbuft == WBUF_OPT_NONE) {
- return aio_flush(interp, af);
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, resultObj, Jim_NewStringObj(interp, options[af->wbuft], -1));
+ if (af->wbuft == WBUF_OPT_FULL) {
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, af->wbuf_limit));
+ }
+ Jim_SetResult(interp, resultObj);
+
+ return JIM_OK;
+}
+
+static int aio_cmd_translation(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ enum {OPT_BINARY, OPT_TEXT};
+ static const char * const options[] = {
+ "binary",
+ "text",
+ NULL
+ };
+ int opt;
+
+ if (Jim_GetEnum(interp, argv[0], options, &opt, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+#if defined(Jim_SetMode)
+ else {
+ AioFile *af = Jim_CmdPrivData(interp);
+ Jim_SetMode(af->fd, opt == OPT_BINARY ? O_BINARY : O_TEXT);
+ }
+#endif
+ return JIM_OK;
+}
+
+static int aio_cmd_readsize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (argc) {
+ long l;
+ if (Jim_GetLong(interp, argv[0], &l) != JIM_OK || l <= 0) {
+ return JIM_ERR;
+ }
+ af->rbuf_len = l;
+ if (af->rbuf) {
+ af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
+ }
}
- /* don't bother flushing when switching from full to line */
+ Jim_SetResultInt(interp, af->rbuf_len);
+
return JIM_OK;
}
+#ifdef jim_ext_eventloop
static int aio_cmd_timeout(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
#ifdef HAVE_SELECT
@@ -1633,7 +1721,6 @@ static int aio_cmd_timeout(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
#endif
}
-#ifdef jim_ext_eventloop
static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask,
int argc, Jim_Obj * const *argv)
{
@@ -2107,11 +2194,25 @@ static const jim_subcmd_type aio_command_table[] = {
},
#endif
{ "buffering",
- "none|line|full",
+ "?none|line|full? ?size?",
aio_cmd_buffering,
+ 0,
+ 2,
+ /* Description: Sets or returns write buffering */
+ },
+ { "translation",
+ "binary|text",
+ aio_cmd_translation,
1,
1,
- /* Description: Sets buffering */
+ /* Description: Sets output translation mode */
+ },
+ { "readsize",
+ "?size?",
+ aio_cmd_readsize,
+ 0,
+ 1,
+ /* Description: Sets or returns read size */
},
#if defined(jim_ext_file) && defined(Jim_FileStat)
{ "stat",
@@ -2448,6 +2549,9 @@ static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
/* Create an empty write buf */
af->writebuf = Jim_NewStringObj(interp, NULL, 0);
Jim_IncrRefCount(af->writebuf);
+ af->wbuf_limit = AIO_DEFAULT_WBUF_LIMIT;
+ af->rbuf_len = AIO_DEFAULT_RBUF_LEN;
+ /* Don't allocate rbuf or readbuf until we need it */
Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
diff --git a/jim-file.c b/jim-file.c
index 4a8380b..01e305a 100644
--- a/jim-file.c
+++ b/jim-file.c
@@ -67,14 +67,6 @@
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
-# ifndef MAXPATHLEN
-# ifdef PATH_MAX
-# define MAXPATHLEN PATH_MAX
-# else
-# define MAXPATHLEN JIM_PATH_LEN
-# endif
-# endif
-
#if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
#define ISWINDOWS 1
/* Even if we have symlink it isn't compatible enought to use */
@@ -568,8 +560,8 @@ static int mkdir_all(char *path)
/* Create the parent and try again */
continue;
}
- /* Maybe it already exists as a directory */
- if (errno == EEXIST) {
+ /* Maybe it already exists as a directory. MorphOS can return ENOTDIR instead of EEXIST */
+ if (errno == EEXIST || errno == ENOTDIR) {
jim_stat_t sb;
if (Jim_Stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
diff --git a/jim-json.c b/jim-json.c
index 2d613b7..69a2afc 100644
--- a/jim-json.c
+++ b/jim-json.c
@@ -38,6 +38,8 @@ typedef enum {
} json_schema_t;
struct json_state {
+ Jim_Obj *fileNameObj;
+ int line;
Jim_Obj *nullObj;
const char *json;
jsmntok_t *tok;
@@ -219,6 +221,7 @@ json_decode_dump_value(Jim_Interp *interp, struct json_state *state, Jim_Obj *li
Jim_Obj *elem;
int len = t->end - t->start;
const char *p = state->json + t->start;
+ int set_source = 1;
if (t->type == JSMN_STRING) {
/* Do we need to process backslash escapes? */
if (state->need_subst == 0 && memchr(p, '\\', len) != NULL) {
@@ -227,6 +230,7 @@ json_decode_dump_value(Jim_Interp *interp, struct json_state *state, Jim_Obj *li
elem = Jim_NewStringObj(interp, p, len);
} else if (p[0] == 'n') { /* null */
elem = state->nullObj;
+ set_source = 0;
} else if (p[0] == 'I') {
elem = Jim_NewStringObj(interp, "Inf", -1);
} else if (p[0] == '-' && p[1] == 'I') {
@@ -234,6 +238,10 @@ json_decode_dump_value(Jim_Interp *interp, struct json_state *state, Jim_Obj *li
} else { /* number, true or false */
elem = Jim_NewStringObj(interp, p, len);
}
+ if (set_source) {
+ /* Note we need to subtract 1 because both are 1-based values */
+ Jim_SetSourceInfo(interp, elem, state->fileNameObj, state->line + t->line - 1);
+ }
Jim_ListAppendElement(interp, list, elem);
state->tok++;
@@ -371,6 +379,10 @@ json_decode(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
Jim_SetResultString(interp, "empty JSON string", -1);
goto done;
}
+
+ /* Save any source information from the original string */
+ state.fileNameObj = Jim_GetSourceInfo(interp, argv[argc - 1], &state.line);
+
if ((tokens = json_decode_tokenize(interp, state.json, len)) == NULL) {
goto done;
}
diff --git a/jim-namespace.c b/jim-namespace.c
index 0bdb0a9..d1a02f5 100644
--- a/jim-namespace.c
+++ b/jim-namespace.c
@@ -231,7 +231,7 @@ static int JimNamespaceCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
JIM_DEF_SUBCMD("tail", "string", 1, 1),
JIM_DEF_SUBCMD("upvar", "ns ?arg ...?", 1, -1),
JIM_DEF_SUBCMD("which", "?-command|-variable? name", 1, 2),
- { /* null terminator */ }
+ { NULL }
};
const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, namespace_cmds, argc, argv);
if (ct) {
diff --git a/jim-package.c b/jim-package.c
index 69af074..18b64fe 100644
--- a/jim-package.c
+++ b/jim-package.c
@@ -148,6 +148,16 @@ int Jim_PackageRequire(Jim_Interp *interp, const char *name, int flags)
return JIM_OK;
}
+static int package_cmd_forget(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ Jim_DeleteHashEntry(&interp->packages, Jim_String(argv[i]));
+ }
+ return JIM_OK;
+}
+
/*
*----------------------------------------------------------------------
*
@@ -216,6 +226,14 @@ static int package_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
static const jim_subcmd_type package_command_table[] = {
{
+ "forget",
+ "package ...",
+ package_cmd_forget,
+ 1,
+ -1,
+ /* Description: Forget that the given packages were loaded */
+ },
+ {
"provide",
"name ?version?",
package_cmd_provide,
diff --git a/jim-readline.c b/jim-readline.c
index 5715b2c..c83e649 100644
--- a/jim-readline.c
+++ b/jim-readline.c
@@ -34,6 +34,8 @@
#include <jim.h>
+#include <stdio.h>
+
#include <readline/readline.h>
#include <readline/history.h>
diff --git a/jim-win32compat.h b/jim-win32compat.h
index 16133b5..acb47c8 100644
--- a/jim-win32compat.h
+++ b/jim-win32compat.h
@@ -30,6 +30,9 @@ char *dlerror(void);
#include <limits.h>
#define jim_wide _int64
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG
+#endif
#ifndef LLONG_MAX
#define LLONG_MAX 9223372036854775807I64
#endif
@@ -43,12 +46,8 @@ char *dlerror(void);
#define strtoull _strtoui64
#include <io.h>
-
-struct timeval {
- long tv_sec;
- long tv_usec;
-};
-
+/* For struct timeval */
+#include <winsock.h>
int gettimeofday(struct timeval *tv, void *unused);
#define HAVE_OPENDIR
diff --git a/jim.c b/jim.c
index fba53ac..ecf4c8b 100644
--- a/jim.c
+++ b/jim.c
@@ -2613,7 +2613,7 @@ int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)
const char *sA = Jim_GetString(aObjPtr, &Alen);
const char *sB = Jim_GetString(bObjPtr, &Blen);
- return Alen == Blen && memcmp(sA, sB, Alen) == 0;
+ return Alen == Blen && *sA == *sB && memcmp(sA, sB, Alen) == 0;
}
}
@@ -3199,17 +3199,6 @@ void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
}
-static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
- Jim_Obj *fileNameObj, int lineNumber)
-{
- JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object"));
- JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typed object"));
- Jim_IncrRefCount(fileNameObj);
- objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
- objPtr->internalRep.sourceValue.lineNumber = lineNumber;
- objPtr->typePtr = &sourceObjType;
-}
-
/* -----------------------------------------------------------------------------
* ScriptLine Object
*
@@ -3611,7 +3600,7 @@ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
/* Every object is initially a string of type 'source', but the
* internal type may be specialized during execution of the
* script. */
- JimSetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
+ Jim_SetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
token++;
}
}
@@ -3694,6 +3683,39 @@ static int JimParseCheckMissing(Jim_Interp *interp, int ch)
return JIM_ERR;
}
+Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, int *lineptr)
+{
+ int line;
+ Jim_Obj *fileNameObj;
+
+ if (objPtr->typePtr == &sourceObjType) {
+ fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+ line = objPtr->internalRep.sourceValue.lineNumber;
+ }
+ else if (objPtr->typePtr == &scriptObjType) {
+ ScriptObj *script = JimGetScript(interp, objPtr);
+ fileNameObj = script->fileNameObj;
+ line = script->firstline;
+ }
+ else {
+ fileNameObj = interp->emptyObj;
+ line = 1;
+ }
+ *lineptr = line;
+ return fileNameObj;
+}
+
+void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *fileNameObj, int lineNumber)
+{
+ JimPanic((Jim_IsShared(objPtr), "Jim_SetSourceInfo called with shared object"));
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_IncrRefCount(fileNameObj);
+ objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
+ objPtr->internalRep.sourceValue.lineNumber = lineNumber;
+ objPtr->typePtr = &sourceObjType;
+}
+
/**
* Similar to ScriptObjAddTokens(), but for subst objects.
*/
@@ -3732,12 +3754,11 @@ static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
struct JimParserCtx parser;
struct ScriptObj *script;
ParseTokenList tokenlist;
- int line = 1;
+ Jim_Obj *fileNameObj;
+ int line;
/* Try to get information about filename / line number */
- if (objPtr->typePtr == &sourceObjType) {
- line = objPtr->internalRep.sourceValue.lineNumber;
- }
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
/* Initially parse the script into tokens (in tokenlist) */
ScriptTokenListInit(&tokenlist);
@@ -3756,12 +3777,7 @@ static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
script = Jim_Alloc(sizeof(*script));
memset(script, 0, sizeof(*script));
script->inUse = 1;
- if (objPtr->typePtr == &sourceObjType) {
- script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
- }
- else {
- script->fileNameObj = interp->emptyObj;
- }
+ script->fileNameObj = fileNameObj;
Jim_IncrRefCount(script->fileNameObj);
script->missing = parser.missing.ch;
script->linenr = parser.missing.line;
@@ -3981,7 +3997,7 @@ static int JimCommandsHT_KeyCompare(void *privdata, const void *key1, const void
int len1, len2;
const char *str1 = Jim_GetStringNoQualifier((Jim_Obj *)key1, &len1);
const char *str2 = Jim_GetStringNoQualifier((Jim_Obj *)key2, &len2);
- return len1 == len2 && memcmp(str1, str2, len1) == 0;
+ return len1 == len2 && *str1 == *str2 && memcmp(str1, str2, len1) == 0;
}
static void JimCommandsHT_ValDestructor(void *interp, void *val)
@@ -5809,6 +5825,9 @@ void Jim_FreeInterp(Jim_Interp *i)
JimFreeCallFrame(i, cf, JIM_FCF_FULL);
}
+ /* Must be done before freeing singletons */
+ Jim_FreeHashTable(&i->commands);
+
Jim_DecrRefCount(i, i->emptyObj);
Jim_DecrRefCount(i, i->trueObj);
Jim_DecrRefCount(i, i->falseObj);
@@ -5820,8 +5839,6 @@ void Jim_FreeInterp(Jim_Interp *i)
Jim_DecrRefCount(i, i->nullScriptObj);
Jim_DecrRefCount(i, i->currentFilenameObj);
- Jim_FreeHashTable(&i->commands);
-
/* This will disard any cached commands */
Jim_InterpIncrProcEpoch(i);
@@ -6812,14 +6829,7 @@ static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
}
/* Try to preserve information about filename / line number */
- if (objPtr->typePtr == &sourceObjType) {
- fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
- linenr = objPtr->internalRep.sourceValue.lineNumber;
- }
- else {
- fileNameObj = interp->emptyObj;
- linenr = 1;
- }
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &linenr);
Jim_IncrRefCount(fileNameObj);
/* Get the string representation */
@@ -6843,7 +6853,7 @@ static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
continue;
elementPtr = JimParserGetTokenObj(interp, &parser);
- JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
+ Jim_SetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
ListAppendElement(objPtr, elementPtr);
}
}
@@ -6904,7 +6914,8 @@ struct lsort_info {
JIM_LSORT_NOCASE,
JIM_LSORT_INTEGER,
JIM_LSORT_REAL,
- JIM_LSORT_COMMAND
+ JIM_LSORT_COMMAND,
+ JIM_LSORT_DICT
} type;
int order;
Jim_Obj **indexv;
@@ -6937,6 +6948,45 @@ static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
}
+static int ListSortDict(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ /* XXX Does not compare past embedded nulls */
+ const char *left = Jim_String(*lhsObj);
+ const char *right = Jim_String(*rhsObj);
+
+ while (1) {
+ if (isdigit(UCHAR(*left)) && isdigit(UCHAR(*right))) {
+ /* extract and compare integers */
+ jim_wide lint, rint;
+ char *lend, *rend;
+ lint = jim_strtoull(left, &lend);
+ rint = jim_strtoull(right, &rend);
+ if (lint != rint) {
+ return JimSign(lint - rint) * sort_info->order;
+ }
+ /* If the integers are equal but of unequal length, then one must have more leading
+ * zeros. The shorter one compares less */
+ if (lend -left != rend - right) {
+ return JimSign((lend - left) - (rend - right)) * sort_info->order;
+ }
+ left = lend;
+ right = rend;
+ }
+ else {
+ int cl, cr;
+ left += utf8_tounicode_case(left, &cl, 1);
+ right += utf8_tounicode_case(right, &cr, 1);
+ if (cl != cr) {
+ return JimSign(cl - cr) * sort_info->order;
+ }
+ if (cl == 0) {
+ /* If they compare equal, use a case sensitive comparison as a tie breaker */
+ return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
+ }
+ }
+ }
+}
+
static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
{
jim_wide lhs = 0, rhs = 0;
@@ -7056,6 +7106,9 @@ static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsor
case JIM_LSORT_COMMAND:
fn = ListSortCommand;
break;
+ case JIM_LSORT_DICT:
+ fn = ListSortDict;
+ break;
default:
fn = NULL; /* avoid warning */
JimPanic((1, "ListSort called with invalid sort type"));
@@ -8399,6 +8452,13 @@ static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
case JIM_EXPROP_NOT:
wC = !bA;
break;
+ case JIM_EXPROP_UNARYPLUS:
+ case JIM_EXPROP_UNARYMINUS:
+ rc = JIM_ERR;
+ Jim_SetResultFormatted(interp,
+ "can't use non-numeric string as operand of \"%s\"",
+ node->type == JIM_EXPROP_UNARYPLUS ? "+" : "-");
+ break;
default:
abort();
}
@@ -9642,7 +9702,7 @@ missingoperand:
objPtr = Jim_NewStringObj(interp, t->token, t->len);
if (t->type == JIM_TT_CMD) {
/* Only commands need source info */
- JimSetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
+ Jim_SetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
}
}
@@ -9742,14 +9802,7 @@ static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
int rc = JIM_ERR;
/* Try to get information about filename / line number */
- if (objPtr->typePtr == &sourceObjType) {
- fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
- line = objPtr->internalRep.sourceValue.lineNumber;
- }
- else {
- fileNameObj = interp->emptyObj;
- line = 1;
- }
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
Jim_IncrRefCount(fileNameObj);
exprText = Jim_GetString(objPtr, &exprTextLen);
@@ -11108,7 +11161,9 @@ static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * tok
}
else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
/* The first interpolated token is source, so preserve the source info */
- JimSetSourceInfo(interp, objPtr, intv[0]->internalRep.sourceValue.fileNameObj, intv[0]->internalRep.sourceValue.lineNumber);
+ int line;
+ Jim_Obj *fileNameObj = Jim_GetSourceInfo(interp, intv[0], &line);
+ Jim_SetSourceInfo(interp, objPtr, fileNameObj, line);
}
@@ -11629,7 +11684,7 @@ int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const c
scriptObjPtr = Jim_NewStringObj(interp, script, -1);
Jim_IncrRefCount(scriptObjPtr);
if (filename) {
- JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
+ Jim_SetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
}
retval = Jim_EvalObj(interp, scriptObjPtr);
Jim_DecrRefCount(interp, scriptObjPtr);
@@ -11716,7 +11771,7 @@ int Jim_EvalFile(Jim_Interp *interp, const char *filename)
}
filenameObj = Jim_NewStringObj(interp, filename, -1);
- JimSetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
+ Jim_SetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj);
@@ -12555,7 +12610,7 @@ static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
{
int retval;
jim_wide i;
- jim_wide limit;
+ jim_wide limit = 0;
jim_wide incr = 1;
Jim_Obj *bodyObjPtr;
@@ -13413,11 +13468,11 @@ static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const arg
{
static const char * const options[] = {
"-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique",
- "-stride", NULL
+ "-stride", "-dictionary", NULL
};
enum {
OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE,
- OPT_STRIDE
+ OPT_STRIDE, OPT_DICT
};
Jim_Obj *resObj;
int i;
@@ -13452,6 +13507,9 @@ wrongargs:
case OPT_ASCII:
info.type = JIM_LSORT_ASCII;
break;
+ case OPT_DICT:
+ info.type = JIM_LSORT_DICT;
+ break;
case OPT_NOCASE:
info.type = JIM_LSORT_NOCASE;
break;
@@ -13646,7 +13704,7 @@ static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
JIM_DEF_SUBCMD("refcount", "object", 1, 1),
JIM_DEF_SUBCMD("scriptlen", "script", 1, 1),
JIM_DEF_SUBCMD("show", "object", 1, 1),
- { /* null terminator */ }
+ { NULL }
};
const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
@@ -14409,7 +14467,7 @@ static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a
JIM_DEF_SUBCMD("trim", "string ?trimchars?", 1, 2),
JIM_DEF_SUBCMD("trimleft", "string ?trimchars?", 1, 2),
JIM_DEF_SUBCMD("trimright", "string ?trimchars?", 1, 2),
- { /* null terminator */ }
+ { NULL }
};
const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
if (!ct) {
@@ -14965,16 +15023,22 @@ wrongargs:
}
else if (errorCodeObj) {
int len = Jim_ListLength(interp, argv[idx + 1]);
- int i;
-
- ret = JIM_OK;
- /* Try to match the sublist against errorcode */
- for (i = 0; i < len; i++) {
- Jim_Obj *matchObj = Jim_ListGetIndex(interp, argv[idx + 1], i);
- Jim_Obj *objPtr = Jim_ListGetIndex(interp, errorCodeObj, i);
- if (Jim_StringCompareObj(interp, matchObj, objPtr, 0) != 0) {
- ret = -1;
- break;
+
+ if (len > Jim_ListLength(interp, errorCodeObj)) {
+ /* More elements in the sublist than in the errorCode so we can't match */
+ ret = -1;
+ }
+ else {
+ int i;
+ ret = JIM_OK;
+ /* Try to match the sublist against errorcode */
+ for (i = 0; i < len; i++) {
+ Jim_Obj *matchObj = Jim_ListGetIndex(interp, argv[idx + 1], i);
+ Jim_Obj *objPtr = Jim_ListGetIndex(interp, errorCodeObj, i);
+ if (Jim_StringCompareObj(interp, matchObj, objPtr, 0) != 0) {
+ ret = -1;
+ break;
+ }
}
}
}
@@ -15441,7 +15505,7 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
JIM_DEF_SUBCMD("for", "vars dictionary script", 3, 3),
JIM_DEF_SUBCMD("replace", "dictionary ?key value ...?", 1, -1),
JIM_DEF_SUBCMD("update", "varName ?arg ...? script", 2, -1),
- { /* null terminator */ }
+ { NULL }
};
const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
if (!ct) {
@@ -15479,7 +15543,7 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
}
case OPT_SET:
- return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG);
+ return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG | JIM_UNSHARED);
case OPT_EXISTS:{
int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_NONE);
@@ -15491,7 +15555,7 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
}
case OPT_UNSET:
- if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE) != JIM_OK) {
+ if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_UNSHARED) != JIM_OK) {
return JIM_ERR;
}
return JIM_OK;
@@ -15650,7 +15714,7 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
JIM_DEF_SUBCMD("statics", "procname", 1, 1),
JIM_DEF_SUBCMD("vars", "?pattern?", 0, 1),
JIM_DEF_SUBCMD("version", NULL, 0, 0),
- { /* null terminator */ }
+ { NULL }
};
const jim_subcmd_type *ct;
#ifdef jim_ext_namespace
@@ -15743,7 +15807,6 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
return JIM_OK;
case INFO_SOURCE:{
- jim_wide line;
Jim_Obj *resObjPtr;
Jim_Obj *fileNameObj;
@@ -15752,26 +15815,16 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
return JIM_ERR;
}
if (argc == 5) {
+ jim_wide line;
if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) {
return JIM_ERR;
}
resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2]));
- JimSetSourceInfo(interp, resObjPtr, argv[3], line);
+ Jim_SetSourceInfo(interp, resObjPtr, argv[3], line);
}
else {
- if (argv[2]->typePtr == &sourceObjType) {
- fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj;
- line = argv[2]->internalRep.sourceValue.lineNumber;
- }
- else if (argv[2]->typePtr == &scriptObjType) {
- ScriptObj *script = JimGetScript(interp, argv[2]);
- fileNameObj = script->fileNameObj;
- line = script->firstline;
- }
- else {
- fileNameObj = interp->emptyObj;
- line = 1;
- }
+ int line;
+ fileNameObj = Jim_GetSourceInfo(interp, argv[2], &line);
resObjPtr = Jim_NewListObj(interp, NULL, 0);
Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
@@ -16233,11 +16286,12 @@ char **Jim_GetEnviron(void)
{
#if defined(HAVE__NSGETENVIRON)
return *_NSGetEnviron();
+#elif defined(_environ)
+ return _environ;
#else
#if !defined(NO_ENVIRON_EXTERN)
extern char **environ;
#endif
-
return environ;
#endif
}
@@ -16246,6 +16300,8 @@ void Jim_SetEnviron(char **env)
{
#if defined(HAVE__NSGETENVIRON)
*_NSGetEnviron() = env;
+#elif defined(_environ)
+ _environ = env;
#else
#if !defined(NO_ENVIRON_EXTERN)
extern char **environ;
diff --git a/jim.h b/jim.h
index 66eb95c..f9acd35 100644
--- a/jim.h
+++ b/jim.h
@@ -699,6 +699,14 @@ JIM_EXPORT int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj
JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
Jim_Obj **resObjPtrPtr, int flags);
+/* source information */
+JIM_EXPORT Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ int *lineptr);
+/* may only be called on an unshared object */
+JIM_EXPORT void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *fileNameObj, int lineNumber);
+
+
/* stack */
JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
diff --git a/jim_tcl.txt b/jim_tcl.txt
index 9cfa6f8..29d5505 100644
--- a/jim_tcl.txt
+++ b/jim_tcl.txt
@@ -3,7 +3,7 @@ Jim Tcl(n)
NAME
----
-Jim Tcl v0.82+ - reference manual for the Jim Tcl scripting language
+Jim Tcl v0.83+ - reference manual for the Jim Tcl scripting language
SYNOPSIS
--------
@@ -33,128 +33,136 @@ available only in Jim Tcl.
Some notable differences with Tcl 8.5/8.6/8.7 are:
-1. Object-based I/O (aio), but with a Tcl-compatibility layer
-2. I/O: Support for sockets and pipes including udp, unix domain sockets and IPv6
-3. Integers are 64bit
-4. Support for references (`ref`/`getref`/`setref`) and garbage collection
-5. Builtin dictionary type (`dict`) with some limitations compared to Tcl 8.6
-6. `env` command to access environment variables
-7. Operating system features: `os.fork`, `os.uptime`, `wait`, `signal`, `alarm`, `sleep`
-8. Much better error reporting. `info stacktrace` as a replacement for '$errorInfo', '$errorCode'
-9. Support for "static" variables in procedures
-10. Threads and coroutines are not supported
-11. Command and variable traces are not supported
-12. Built-in command line editing
-13. Expression shorthand syntax: +$(...)+
-14. Modular build allows many features to be omitted or built as dynamic, loadable modules
-15. Highly suitable for use in an embedded environment
-16. Support for UDP, IPv6, Unix-Domain sockets in addition to TCP sockets
+#. Object-based I/O (aio), but with a Tcl-compatibility layer
+#. I/O: Support for sockets and pipes including udp, unix domain sockets and IPv6
+#. Integers are 64bit
+#. Support for references (`ref`/`getref`/`setref`) and garbage collection
+#. Builtin dictionary type (`dict`) with some limitations compared to Tcl 8.6
+#. `env` command to access environment variables
+#. Operating system features: `os.fork`, `os.uptime`, `wait`, `signal`, `alarm`, `sleep`
+#. Much better error reporting. `info stacktrace` as a replacement for '$errorInfo', '$errorCode'
+#. Support for "static" variables in procedures
+#. Threads and coroutines are not supported
+#. Command and variable traces are not supported
+#. Built-in command line editing
+#. Expression shorthand syntax: +$(...)+
+#. Modular build allows many features to be omitted or built as dynamic, loadable modules
+#. Highly suitable for use in an embedded environment
+#. Support for UDP, IPv6, Unix-Domain sockets in addition to TCP sockets
+#. Jim does not convert backslash-newline within braces (in order to preserve accurate line numbers)
RECENT CHANGES
--------------
-Changes since 0.82
+Changes since 0.83
~~~~~~~~~~~~~~~~~~
-1. Multi-level `break` and `continue` are now supported
-2. `info frame` now only returns 'proc' levels
-3. `stacktrace` is now a builtin command
-4. The stack trace on error now includes the full stack trace, not just back to where it was caught
-5. Improvements with `aio`, related to eventloop and buffering. Add `aio timeout`.
-6. `socket` , `open` and `aio accept` now support '-noclose'
-7. Add support for hinting with `history hints`
-8. Support for `proc` statics by reference (lexical closure) rather than by value
-9. `regsub` now supports '-command' (per Tcl 8.7)
+#. `aio` - support for configurable read and write buffering
+#. Add support for `package forget`
+#. Add `aio translation` support (and fconfigure -translation)
+
+Changes between 0.82 and 0.83
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#. Multi-level `break` and `continue` are now supported
+#. `info frame` now only returns 'proc' levels
+#. `stacktrace` is now a builtin command
+#. The stack trace on error now includes the full stack trace, not just back to where it was caught
+#. Improvements with `aio`, related to eventloop and buffering. Add `aio timeout`.
+#. `socket` , `open` and `aio accept` now support '-noclose'
+#. Add support for hinting with `history hints`
+#. Support for `proc` statics by reference (lexical closure) rather than by value
+#. `regsub` now supports '-command' (per Tcl 8.7)
+#. Add support for `lsort -dict`
Changes between 0.81 and 0.82
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-1. `try` now supports trap to match on errorcode
-2. TIP 603, `aio stat` is now supported to stat a file handle
-3. Add support for `socket -async`
-4. The handles created by `socket pty` now make the replica name available via 'filename'
-5. `info frame` now returns a (largely) Tcl-compatible dictionary, and supports 'info frame 0'
-6. `vwait -signal` is now supported
-7. ./configure now defaults to '--full'
-8. New `timerate` command as an improvement over `time`, somewhat compatible with TIP 527
-9. Add `ensemble` command and support for `namespace ensemble` (as an optional extension)
+#. `try` now supports trap to match on errorcode
+#. TIP 603, `aio stat` is now supported to stat a file handle
+#. Add support for `socket -async`
+#. The handles created by `socket pty` now make the replica name available via 'filename'
+#. `info frame` now returns a (largely) Tcl-compatible dictionary, and supports 'info frame 0'
+#. `vwait -signal` is now supported
+#. ./configure now defaults to '--full'
+#. New `timerate` command as an improvement over `time`, somewhat compatible with TIP 527
+#. Add `ensemble` command and support for `namespace ensemble` (as an optional extension)
Changes between 0.80 and 0.81
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-1. TIP 582, comments allowed in expressions
-2. Many commands now accept "safe" integer expressions rather than simple integers:
+#. TIP 582, comments allowed in expressions
+#. Many commands now accept "safe" integer expressions rather than simple integers:
`loop`, `range`, `incr`, `string repeat`, `lrepeat`, `pack`, `unpack`, `rand`
-3. String and list indexes now accept integer expressions (<<_string_and_list_index_specifications,STRING AND LIST INDEX SPECIFICATIONS>>)
-4. `loop` can now omit the start value
-5. Add the `xtrace` command for execution trace support
-6. Add `history keep`
-7. Add support for `lsearch -index` and `lsearch -stride`, the latter per TIP 351
-8. `lsort -index` now supports multiple indices
-9. Add support for `lsort -stride`
-10. `open` now supports POSIX-style access arguments
-11. TIP 526, `expr` now only allows a single argument (unless --compat is enabled)
+#. String and list indexes now accept integer expressions (<<_string_and_list_index_specifications,STRING AND LIST INDEX SPECIFICATIONS>>)
+#. `loop` can now omit the start value
+#. Add the `xtrace` command for execution trace support
+#. Add `history keep`
+#. Add support for `lsearch -index` and `lsearch -stride`, the latter per TIP 351
+#. `lsort -index` now supports multiple indices
+#. Add support for `lsort -stride`
+#. `open` now supports POSIX-style access arguments
+#. TIP 526, `expr` now only allows a single argument (unless --compat is enabled)
Changes between 0.79 and 0.80
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-1. `regsub` now fully supports +{backslash}A+
-2. Add `socket pty` to create a pseudo-tty pair
-3. Null characters (\x00) are now supported in variable and proc names
-4. dictionaries and arrays now preserve insertion order, matching Tcl and the documentation
-5. Add `dict getwithdefault` (and the alias `dict getdef`) per TIP 342
-6. Add string comparison operators (lt, gt, le, ge) per TIP 461
-7. Implement 0d radix prefix for decimal per TIP 472
+#. `regsub` now fully supports +{backslash}A+
+#. Add `socket pty` to create a pseudo-tty pair
+#. Null characters (\x00) are now supported in variable and proc names
+#. dictionaries and arrays now preserve insertion order, matching Tcl and the documentation
+#. Add `dict getwithdefault` (and the alias `dict getdef`) per TIP 342
+#. Add string comparison operators (lt, gt, le, ge) per TIP 461
+#. Implement 0d radix prefix for decimal per TIP 472
Changes between 0.78 and 0.79
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-1. Add `file mtimeus` for high resolution file timestamps
-2. `aio` now supports datagram Unix-Domain sockets
-3. Add support for `aio lock -wait`
-4. Add `signal block` to prevent delivery of signals
-5. Add support for `file split`
-6. Add support for `json::encode` and `json::decode`
-7. `aio tty` now allows setting +echo+ without full +raw+ mode
+#. Add `file mtimeus` for high resolution file timestamps
+#. `aio` now supports datagram Unix-Domain sockets
+#. Add support for `aio lock -wait`
+#. Add `signal block` to prevent delivery of signals
+#. Add support for `file split`
+#. Add support for `json::encode` and `json::decode`
+#. `aio tty` now allows setting +echo+ without full +raw+ mode
Changes between 0.77 and 0.78
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-1. Add serial/tty support with `aio tty`
-2. Add support for 'jimsh -'
-3. Add hidden '-commands' option to many commands
-4. Add scriptable autocompletion support in interactive mode with `tcl::autocomplete`
-5. Add `aio sockopt`
-6. Add scriptable autocompletion support with `history completion`
-7. Add support for `tree delete`
-8. Add support for `defer` and '$jim::defer'
-9. Renamed `os.wait` to `wait`, now more Tcl-compatible and compatible with `exec ... &`
-10. `pipe` is now a synonym for `socket pipe`
-11. Closing a pipe open with `open |...` now returns Tcl-like status
-12. It is now possible to used `exec` redirection with a pipe opened with `open |...`
-13. Interactive line editing now supports multiline mode if $::history::multiline is set
+#. Add serial/tty support with `aio tty`
+#. Add support for 'jimsh -'
+#. Add hidden '-commands' option to many commands
+#. Add scriptable autocompletion support in interactive mode with `tcl::autocomplete`
+#. Add `aio sockopt`
+#. Add scriptable autocompletion support with `history completion`
+#. Add support for `tree delete`
+#. Add support for `defer` and '$jim::defer'
+#. Renamed `os.wait` to `wait`, now more Tcl-compatible and compatible with `exec ... &`
+#. `pipe` is now a synonym for `socket pipe`
+#. Closing a pipe open with `open |...` now returns Tcl-like status
+#. It is now possible to used `exec` redirection with a pipe opened with `open |...`
+#. Interactive line editing now supports multiline mode if $::history::multiline is set
Changes between 0.76 and 0.77
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-1. Add support for `aio sync`
-2. Add SSL and TLS support in aio
-3. Added `zlib`
-4. Added support for boolean constants in `expr`
-5. `string is` now supports 'boolean' class
-6. Add support for `aio lock` and `aio unlock`
-7. Add new `interp` command
+#. Add support for `aio sync`
+#. Add SSL and TLS support in aio
+#. Added `zlib`
+#. Added support for boolean constants in `expr`
+#. `string is` now supports 'boolean' class
+#. Add support for `aio lock` and `aio unlock`
+#. Add new `interp` command
Changes between 0.75 and 0.76
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-1. `glob` now supports the +-tails+ option
-2. Add support for `string cat`
-3. Allow `info source` to add source info
+#. `glob` now supports the +-tails+ option
+#. Add support for `string cat`
+#. Allow `info source` to add source info
Changes between 0.74 and 0.75
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-1. `binary`, `pack` and `unpack` now support floating point
-2. `file copy` +-force+ handles source and target as the same file
-3. `format` now supports +%b+ for binary conversion
-4. `lsort` now supports +-unique+ and +-real+
-5. Add support for half-close with `aio close` +?r|w?+
-6. Add `socket pair` for a bidirectional pipe
-7. Add '--random-hash' to randomise hash tables for greater security
-8. `dict` now supports 'for', 'values', 'incr', 'append', 'lappend', 'update', 'info' and 'replace'
-9. `file stat` no longer requires the variable name
-10. Add support for `file link`
+#. `binary`, `pack` and `unpack` now support floating point
+#. `file copy` +-force+ handles source and target as the same file
+#. `format` now supports +%b+ for binary conversion
+#. `lsort` now supports +-unique+ and +-real+
+#. Add support for half-close with `aio close` +?r|w?+
+#. Add `socket pair` for a bidirectional pipe
+#. Add '--random-hash' to randomise hash tables for greater security
+#. `dict` now supports 'for', 'values', 'incr', 'append', 'lappend', 'update', 'info' and 'replace'
+#. `file stat` no longer requires the variable name
+#. Add support for `file link`
TCL INTRODUCTION
-----------------
@@ -590,41 +598,12 @@ sequence is replaced by the given character:
+{backslash}v+::
Vertical tab (0xb).
-+{backslash}{+::
- Left brace ({).
-
-+{backslash}}+::
- Right brace (}).
-
-+{backslash}[+::
- Open bracket ([).
-
-+{backslash}]+::
- Close bracket (]).
-
-+{backslash}$+::
- Dollar sign ($).
-
-+{backslash}<space>+::
- Space ( ): doesn't terminate argument.
-
-+{backslash};+::
- Semi-colon: doesn't terminate command.
-
-+{backslash}"+::
- Double-quote.
-
-+{backslash}<newline>+::
- Nothing: this joins two lines together
- into a single line. This backslash feature is unique in that
- it will be applied even when the sequence occurs within braces.
-
-+{backslash}{backslash}+::
- Backslash ('{backslash}').
-
+{backslash}ddd+::
The digits +'ddd'+ (one, two, or three of them) give the octal value of
- the character. Note that Jim supports null characters in strings.
+ the byte. Note that Jim supports null characters in strings.
+
++{backslash}xnn+::
+ The hexidecimal digits +'nn'+ give the value of the byte.
+{backslash}unnnn+::
+{backslash}u\{nnn\}+::
@@ -633,32 +612,24 @@ sequence is replaced by the given character:
The 'u' form allows for one to four hex digits.
The 'U' form allows for one to eight hex digits.
The 'u\{nnn\}' form allows for one to eight hex digits, but makes it easier to insert
- characters UTF-8 characters which are followed by a hex digit.
-
-For example, in the command
-
-----
- set a \{x\[\ yz\141
-----
-
-the second argument to `set` will be +{x[ yza+.
+ UTF-8 characters that are followed by a hex digit.
If a backslash is followed by something other than one of the options
-described above, then the backslash is transmitted to the argument
-field without any special processing, and the Tcl scanner continues
+described above, the backslash is skipped and character following the backslash is treated
+as a normal character without any special meaning. The Tcl scanner continues
normal processing with the next character. For example, in the
command
+For example, in the command
+
----
- set \*a \\{foo
+ set a \\{x\[\ yz\141
----
-The first argument to `set` will be +*a+ and the second
-argument will be +{foo+.
+the second argument to `set` will be +{x[ yza+.
If an argument is enclosed in braces, then backslash sequences inside
-the argument are parsed but no substitution occurs (except for
-backslash-newline): the backslash
+the argument are parsed but no substitution occurs: the backslash
sequence is passed through to the argument as is, without making
any special interpretation of the characters in the backslash sequence.
In particular, backslashed braces are not counted in locating the
@@ -3495,18 +3466,29 @@ lsort
Sort the elements of +'list'+, returning a new list in sorted order.
By default, ASCII (or UTF-8) sorting is used, with the result in increasing order.
-Note that only one sort type may be selected with +-integer+, +-real+, +-nocase+ or +-command+
+Note that only one sort type may be selected with +-ascii+, +-dict+, +-integer+, +-real+, +-nocase+ or +-command+
with last option being used.
++*-ascii*+::
+ Sort using string comparison. This is the default.
+
++*-nocase*+::
+ Sort using using string comparison without regard for case.
+
++*-dict*+::
+ Sort using using string comparison without regard for case.
+ Use dictionary-style comparison. This is the same as '-ascii'
+ except (a) case is ignored except as a tie-breaker and (b) if
+ two strings contain embedded numbers, the numbers compare as
+ integers, not characters. For example, in -dictionary mode,
+ x10y sorts between x9y and x11y.
+
+*-integer*+::
Sort using numeric (integer) comparison.
+*-real*+::
Sort using floating point comparison.
-+*-nocase*+::
- Sort using using string comparison without regard for case.
-
+*-command* 'cmdname'+::
+'cmdname'+ is treated as a command name. For each comparison,
+'cmdname $value1 $value2+' is called which
@@ -3645,6 +3627,12 @@ See also `socket`, `pid`, `exec`
package
~~~~~~~
++*package forget* '?name ...?'+
+
+Removes the knowledge that the given packages were loaded. This allows new, replacement
+packages to be loaded. Note that it does not remove any effects of the previous packages
+being loaded.
+
+*package provide* 'name ?version?'+
Indicates that the current script provides the package named +'name'+.
@@ -4966,16 +4954,19 @@ aio
If +'-noclose'+ is given, the returned handle is not automatically
closed for child proceses. See `socket` for details.
-+$handle *buffering none|line|full*+::
++$handle *buffering none|line|full* ?size?+::
Sets the output buffering mode of the stream channel. +'none'+ means
that puts immediately writes output. +'line'+ means output (including
previously buffered output) is written if a newline is to be written.
+'full'+ means that data is written when the output buffer is full
- (currently approx 64KB). Note that line buffering will also write
+ (default 64KB). Size may be specified in full mode.
+ Note that line buffering will also write
once the output buffer limit is reached, even if there is no newline.
Channels usually begin in full buffering mode, unless they identify
as a tty channel, in which case line buffering is used, and `stderr`
- begins with no buffering. See also `aio puts` and `aio flush`.
+ begins with no buffering. Returns the current buffering mode (including
+ size in full mode - e.g. +'line'+ or +'full 65536+'.
+ See also `aio puts` and `aio flush`.
+$handle *close ?r(ead)|w(rite)? ?-nodelete?*+::
Closes the stream.
@@ -5063,6 +5054,12 @@ aio
expected number of bytes (including zero). Use `aio eof` to determine
if the end-of-file has been reached.
++$handle *readsize* ?size?'+::
+ Sets or returns the current size of the read buffer used
+ for read, gets and copyto.
+ Defaults to 256, but can be increased to improve performance
+ for large reads.
+
+$handle *recvfrom* 'maxlen ?addrvar?'+::
Receives a message from the datagram channel via recvfrom(2) and returns it.
At most +'maxlen'+ bytes are read. If +'addrvar'+ is specified, the sending address
@@ -5134,6 +5131,12 @@ This command returns an empty string.
See `aio read` and `aio gets` for command that use the timeout.
Note that the timeout is only used if the channel is in blocking mode.
++$handle *translation binary|text*+::
+ This has no effect on Unix platforms, but on Windows it changes the mode of the file
+ handle to binary or text. In general, use "wb" as the open mode instead, but this
+ can be useful on existing filehandles such as +stdout+ and +stderr+. It is probably
+ a good idea to do this immediately before sending any output.
+
+$handle *tty* ?settings?+::
If no arguments are given, returns a dictionary containing the tty settings for the stream.
If arguments are given, they must either be a dictionary, or +setting value \...+.
@@ -5245,7 +5248,7 @@ fconfigure
command is supported.
* `fconfigure ... -blocking` maps to `aio ndelay`
* `fconfigure ... -buffering` maps to `aio buffering`
- * `fconfigure ... -translation` is accepted but ignored
+ * `fconfigure ... -translation` maps to `aio translation` and suppports only +binary+ and +text+
[[cmd_2]]
eventloop: after, vwait, update
@@ -5746,6 +5749,11 @@ namespace
~~~~~~~~~
Provides namespace-related functions. See also: http://www.tcl.tk/man/tcl8.6/TclCmd/namespace.htm
++*namespace canonical* ?current? ?name?+::
+ Returns the full name of +'name'+ within namespace '+current+'.
+ If '+current+' is not given, `namespace current` is used.
+ If neither are given, returns the current namespace (not qualified with a leading '::').
+
+*namespace code* 'script'+::
Captures the current namespace context for later execution of
the script +'script'+. It returns a new script in which script has
@@ -5757,7 +5765,7 @@ Provides namespace-related functions. See also: http://www.tcl.tk/man/tcl8.6/Tcl
+*namespace delete* '?namespace ...?'+::
Deletes all commands and variables with the given namespace prefixes.
-+*namespace ensemble create*'+::
++*namespace ensemble create*+::
Creates an ensemble command for the current namespace (requires the 'ensemble' extension').
+*namespace eval* 'namespace arg ?arg...?'+::
diff --git a/jimiocompat.c b/jimiocompat.c
index 8e7f3f2..44a1387 100644
--- a/jimiocompat.c
+++ b/jimiocompat.c
@@ -6,7 +6,7 @@ void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno()));
}
-#if defined(__MINGW32__)
+#if defined(_WIN32) || defined(WIN32)
#include <sys/stat.h>
int Jim_Errno(void)
@@ -213,7 +213,9 @@ int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unli
}
/* Update the template name directly with the filename */
+#ifdef HAVE_UMASK
mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
+#endif
#ifdef HAVE_MKSTEMP
fd = mkstemp(filenameObj->bytes);
#else
@@ -224,7 +226,9 @@ int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unli
fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
}
#endif
+#ifdef HAVE_UMASK
umask(mask);
+#endif
if (fd < 0) {
Jim_SetResultErrno(interp, Jim_String(filenameObj));
Jim_FreeNewObj(interp, filenameObj);
diff --git a/jimiocompat.h b/jimiocompat.h
index 0837b73..0f807a0 100644
--- a/jimiocompat.h
+++ b/jimiocompat.h
@@ -31,7 +31,7 @@ int Jim_OpenForWrite(const char *filename, int append);
*/
int Jim_OpenForRead(const char *filename);
-#if defined(__MINGW32__)
+#if defined(__MINGW32__) || defined(_WIN32)
#ifndef STRICT
#define STRICT
#endif
@@ -69,6 +69,12 @@ int Jim_OpenForRead(const char *filename);
#define Jim_Stat _stat64
#define Jim_FileStat _fstat64
#define Jim_Lseek _lseeki64
+ #define O_TEXT _O_TEXT
+ #define O_BINARY _O_BINARY
+ #define Jim_SetMode _setmode
+ #ifndef STDIN_FILENO
+ #define STDIN_FILENO 0
+ #endif
#else
#if defined(HAVE_STAT64)
@@ -111,12 +117,21 @@ int Jim_OpenForRead(const char *filename);
#define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
#endif
#endif
-#endif
-#ifndef O_TEXT
-#define O_TEXT 0
+ #ifndef O_TEXT
+ #define O_TEXT 0
+ #endif
+
#endif
+# ifndef MAXPATHLEN
+# ifdef PATH_MAX
+# define MAXPATHLEN PATH_MAX
+# else
+# define MAXPATHLEN JIM_PATH_LEN
+# endif
+# endif
+
/* jim-file.c */
/* Note that this is currently an internal function only.
* It does not form part of the public Jim API
diff --git a/jimsh.c b/jimsh.c
index 6104afb..e9427d1 100644
--- a/jimsh.c
+++ b/jimsh.c
@@ -37,8 +37,9 @@
#include <stdlib.h>
#include <string.h>
-#include "jim.h"
#include "jimautoconf.h"
+#include "jim.h"
+#include "jimiocompat.h"
/* From initjimsh.tcl */
extern int Jim_initjimshInit(Jim_Interp *interp);
@@ -123,6 +124,10 @@ int main(int argc, char *const argv[])
}
if (retcode != JIM_EXIT) {
JimSetArgv(interp, 0, NULL);
+ if (!isatty(STDIN_FILENO)) {
+ /* Just read from stdin and evaluate */
+ goto eval_stdin;
+ }
retcode = Jim_InteractivePrompt(interp);
}
}
@@ -145,6 +150,7 @@ int main(int argc, char *const argv[])
Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
JimSetArgv(interp, argc - 2, argv + 2);
if (strcmp(argv[1], "-") == 0) {
+eval_stdin:
retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]");
} else {
retcode = Jim_EvalFile(interp, argv[1]);
diff --git a/jsmn/jsmn.c b/jsmn/jsmn.c
index 2de5ec2..2174df9 100644
--- a/jsmn/jsmn.c
+++ b/jsmn/jsmn.c
@@ -1,17 +1,24 @@
#include "jsmn.h"
+/* For json-decode we want strict mode so we don't get
+ * garbage for malformed json
+ */
+#define JSMN_STRICT
+
/**
* Allocates a fresh unused token from the token pool.
*/
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
jsmntok_t *tokens, size_t num_tokens) {
jsmntok_t *tok;
+ parser->count++;
if (parser->toknext >= num_tokens) {
return NULL;
}
tok = &tokens[parser->toknext++];
tok->start = tok->end = -1;
tok->size = 0;
+ tok->line = 0;
#ifdef JSMN_PARENT_LINKS
tok->parent = -1;
#endif
@@ -22,11 +29,12 @@ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
* Fills token type and boundaries.
*/
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
- int start, int end) {
+ int start, int end, int line) {
token->type = type;
token->start = start;
token->end = end;
token->size = 0;
+ token->line = line;
}
/**
@@ -41,11 +49,13 @@ static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
switch (js[parser->pos]) {
+ case '\n' :
+ parser->line++;
+ /* fall-thru */
#ifndef JSMN_STRICT
- /* In strict mode primitive must be followed by "," or "}" or "]" */
case ':':
#endif
- case '\t' : case '\r' : case '\n' : case ' ' :
+ case '\t' : case '\r' : case ' ' :
case ',' : case ']' : case '}' :
goto found;
}
@@ -61,16 +71,16 @@ static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
#endif
found:
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
if (tokens == NULL) {
parser->pos--;
return 0;
}
- token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
}
- jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+ jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos, parser->line);
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
@@ -95,15 +105,15 @@ static int jsmn_parse_string(jsmn_parser *parser, const char *js,
/* Quote: end of string */
if (c == '\"') {
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
if (tokens == NULL) {
return 0;
}
- token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
}
- jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
+ jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos, parser->line);
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
@@ -153,7 +163,6 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
int r;
int i;
jsmntok_t *token;
- int count = parser->toknext;
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
char c;
@@ -162,11 +171,10 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
c = js[parser->pos];
switch (c) {
case '{': case '[':
- count++;
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
if (tokens == NULL) {
break;
}
- token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL)
return JSMN_ERROR_NOMEM;
if (parser->toksuper != -1) {
@@ -235,11 +243,13 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
case '\"':
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
if (r < 0) return r;
- count++;
if (parser->toksuper != -1 && tokens != NULL)
tokens[parser->toksuper].size++;
break;
- case '\t' : case '\r' : case '\n' : case ' ':
+ case '\n' :
+ parser->line++;
+ /* fall-thru */
+ case '\t' : case '\r' : case ' ':
break;
case ':':
parser->toksuper = parser->toknext - 1;
@@ -262,35 +272,39 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
#endif
}
break;
+
+ default:
+ /* In non-strict mode every unquoted value is a primitive */
#ifdef JSMN_STRICT
- /* In strict mode primitives are: numbers and booleans */
- case '-': case '0': case '1' : case '2': case '3' : case '4':
- case '5': case '6': case '7' : case '8': case '9':
- case 't': case 'f': case 'n' :
- /* And they must not be keys of the object */
- if (tokens != NULL && parser->toksuper != -1) {
- jsmntok_t *t = &tokens[parser->toksuper];
- if (t->type == JSMN_OBJECT ||
- (t->type == JSMN_STRING && t->size != 0)) {
+ switch (c) {
+ /* In strict mode primitives are: numbers and booleans */
+ case '-': case '0': case '1' : case '2': case '3' : case '4':
+ case '5': case '6': case '7' : case '8': case '9':
+ case 't': case 'f': case 'n' :
+#ifndef JSMN_FULLY_STRICT
+ /* Allow Inf and NaN in any mode other than fully strict */
+ case 'I': case 'N':
+#endif
+ /* And they must not be keys of the object */
+ if (tokens != NULL && parser->toksuper != -1) {
+ jsmntok_t *t = &tokens[parser->toksuper];
+ if (t->type == JSMN_OBJECT ||
+ (t->type == JSMN_STRING && t->size != 0)) {
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ break;
+
+ default:
+ /* Unexpected char in strict mode */
return JSMN_ERROR_INVAL;
- }
}
-#else
- /* In non-strict mode every unquoted value is a primitive */
- default:
#endif
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
if (r < 0) return r;
- count++;
if (parser->toksuper != -1 && tokens != NULL)
tokens[parser->toksuper].size++;
break;
-
-#ifdef JSMN_STRICT
- /* Unexpected char in strict mode */
- default:
- return JSMN_ERROR_INVAL;
-#endif
}
}
@@ -303,7 +317,7 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
}
}
- return count;
+ return parser->count;
}
/**
@@ -314,5 +328,7 @@ void jsmn_init(jsmn_parser *parser) {
parser->pos = 0;
parser->toknext = 0;
parser->toksuper = -1;
+ parser->count = 0;
+ parser->line = 1;
}
diff --git a/jsmn/jsmn.h b/jsmn/jsmn.h
index 01ca99c..e6ee22c 100644
--- a/jsmn/jsmn.h
+++ b/jsmn/jsmn.h
@@ -42,6 +42,7 @@ typedef struct {
int start;
int end;
int size;
+ int line;
#ifdef JSMN_PARENT_LINKS
int parent;
#endif
@@ -54,7 +55,9 @@ typedef struct {
typedef struct {
unsigned int pos; /* offset in the JSON string */
unsigned int toknext; /* next token to allocate */
+ unsigned int count; /* number of tokens parsed */
int toksuper; /* superior token node, e.g parent object or array */
+ int line; /* current line number */
} jsmn_parser;
/**
diff --git a/linenoise.c b/linenoise.c
index 8b628fe..0d2fee5 100644
--- a/linenoise.c
+++ b/linenoise.c
@@ -1,3 +1,4 @@
+#line 1 "stringbuf.h"
#ifndef STRINGBUF_H
#define STRINGBUF_H
/**
@@ -135,6 +136,7 @@ char *sb_to_string(stringbuf *sb);
#endif
#endif
+#line 1 "stringbuf.c"
/**
* resizable string buffer
*
@@ -180,7 +182,7 @@ void sb_free(stringbuf *sb)
free(sb);
}
-void sb_realloc(stringbuf *sb, int newlen)
+static void sb_realloc(stringbuf *sb, int newlen)
{
sb->data = (char *)realloc(sb->data, newlen);
sb->remaining = newlen - sb->last;
@@ -308,6 +310,7 @@ void sb_clear(stringbuf *sb)
#endif
}
}
+#line 1 "linenoise.c"
/* linenoise.c -- guerrilla line editing library against the idea that a
* line editing lib needs to be 20,000 lines of C code.
*
@@ -425,10 +428,6 @@ void sb_clear(stringbuf *sb)
#define USE_WINCONSOLE
#ifdef __MINGW32__
#define HAVE_UNISTD_H
-#else
-/* Microsoft headers don't like old POSIX names */
-#define strdup _strdup
-#define snprintf _snprintf
#endif
#else
#include <termios.h>
@@ -451,6 +450,12 @@ void sb_clear(stringbuf *sb)
#include <stdlib.h>
#include <sys/types.h>
+#if defined(_WIN32) && !defined(__MINGW32__)
+/* Microsoft headers don't like old POSIX names */
+#define strdup _strdup
+#define snprintf _snprintf
+#endif
+
#include "linenoise.h"
#ifndef STRINGBUF_H
#include "stringbuf.h"
@@ -488,6 +493,7 @@ enum {
static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
static int history_len = 0;
+static int history_index = 0;
static char **history = NULL;
/* Structure to contain the status of the current (being edited) line */
@@ -504,6 +510,8 @@ struct current {
stringbuf *output; /* used only during refreshLine() - output accumulator */
#if defined(USE_TERMIOS)
int fd; /* Terminal fd */
+ int pending; /* pending char fd_read_char() */
+ int query_cursor_failed; /* if 1, don't try to query the cursor position again */
#elif defined(USE_WINCONSOLE)
HANDLE outh; /* Console output handle */
HANDLE inh; /* Console input handle */
@@ -530,6 +538,16 @@ static void setCursorPos(struct current *current, int x);
static void setOutputHighlight(struct current *current, const int *props, int nprops);
static void set_current(struct current *current, const char *str);
+static int fd_isatty(struct current *current)
+{
+#ifdef USE_TERMIOS
+ return isatty(current->fd);
+#else
+ (void)current;
+ return 0;
+#endif
+}
+
void linenoiseHistoryFree(void) {
if (history) {
int j;
@@ -832,25 +850,31 @@ void linenoiseClearScreen(void)
}
/**
- * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
+ * Reads a char from 'current->fd', waiting at most 'timeout' milliseconds.
*
* A timeout of -1 means to wait forever.
*
* Returns -1 if no char is received within the time or an error occurs.
*/
-static int fd_read_char(int fd, int timeout)
+static int fd_read_char(struct current *current, int timeout)
{
struct pollfd p;
unsigned char c;
- p.fd = fd;
+ if (current->pending) {
+ c = current->pending;
+ current->pending = 0;
+ return c;
+ }
+
+ p.fd = current->fd;
p.events = POLLIN;
if (poll(&p, 1, timeout) == 0) {
/* timeout */
return -1;
}
- if (read(fd, &c, 1) != 1) {
+ if (read(current->fd, &c, 1) != 1) {
return -1;
}
return c;
@@ -868,7 +892,11 @@ static int fd_read(struct current *current)
int i;
int c;
- if (read(current->fd, &buf[0], 1) != 1) {
+ if (current->pending) {
+ buf[0] = current->pending;
+ current->pending = 0;
+ }
+ else if (read(current->fd, &buf[0], 1) != 1) {
return -1;
}
n = utf8_charlen(buf[0]);
@@ -884,7 +912,7 @@ static int fd_read(struct current *current)
utf8_tounicode(buf, &c);
return c;
#else
- return fd_read_char(current->fd, -1);
+ return fd_read_char(current, -1);
#endif
}
@@ -898,6 +926,11 @@ static int queryCursor(struct current *current, int* cols)
struct esc_parser parser;
int ch;
+ if (current->query_cursor_failed) {
+ /* If it every fails, don't try again */
+ return 0;
+ }
+
/* Should not be buffering this output, it needs to go immediately */
assert(current->output == NULL);
@@ -906,7 +939,7 @@ static int queryCursor(struct current *current, int* cols)
/* Parse the response: ESC [ rows ; cols R */
initParseEscapeSeq(&parser, 'R');
- while ((ch = fd_read_char(current->fd, 100)) > 0) {
+ while ((ch = fd_read_char(current, 100)) > 0) {
switch (parseEscapeSequence(&parser, ch)) {
default:
continue;
@@ -917,11 +950,14 @@ static int queryCursor(struct current *current, int* cols)
}
break;
case EP_ERROR:
+ /* Push back the character that caused the error */
+ current->pending = ch;
break;
}
/* failed */
break;
}
+ current->query_cursor_failed = 1;
return 0;
}
@@ -988,20 +1024,20 @@ static int getWindowSize(struct current *current)
* If no additional char is received within a short time,
* CHAR_ESCAPE is returned.
*/
-static int check_special(int fd)
+static int check_special(struct current *current)
{
- int c = fd_read_char(fd, 50);
+ int c = fd_read_char(current, 50);
int c2;
if (c < 0) {
return CHAR_ESCAPE;
}
- else if (c >= 'a' && c <= 'z') {
- /* esc-a => meta-a */
- return meta(c);
- }
+ else if (c >= 'a' && c <= 'z') {
+ /* esc-a => meta-a */
+ return meta(c);
+ }
- c2 = fd_read_char(fd, 50);
+ c2 = fd_read_char(current, 50);
if (c2 < 0) {
return c2;
}
@@ -1024,7 +1060,7 @@ static int check_special(int fd)
}
if (c == '[' && c2 >= '1' && c2 <= '8') {
/* extended escape */
- c = fd_read_char(fd, 50);
+ c = fd_read_char(current, 50);
if (c == '~') {
switch (c2) {
case '2':
@@ -1043,7 +1079,7 @@ static int check_special(int fd)
}
while (c != -1 && c != '~') {
/* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */
- c = fd_read_char(fd, 50);
+ c = fd_read_char(current, 50);
}
}
@@ -1112,7 +1148,7 @@ static linenoiseHintsCallback *hintsCallback = NULL;
static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
static void *hintsUserdata = NULL;
-static void beep() {
+static void beep(void) {
#ifdef USE_TERMIOS
fprintf(stderr, "\x7");
fflush(stderr);
@@ -1783,6 +1819,26 @@ static int skip_nonspace(struct current *current, int dir)
return skip_space_nonspace(current, dir, 0);
}
+static void set_history_index(struct current *current, int new_index)
+{
+ if (history_len > 1) {
+ /* Update the current history entry before to
+ * overwrite it with the next one. */
+ free(history[history_len - 1 - history_index]);
+ history[history_len - 1 - history_index] = strdup(sb_str(current->buf));
+ /* Show the new entry */
+ history_index = new_index;
+ if (history_index < 0) {
+ history_index = 0;
+ } else if (history_index >= history_len) {
+ history_index = history_len - 1;
+ } else {
+ set_current(current, history[history_len - 1 - history_index]);
+ refreshLine(current);
+ }
+ }
+}
+
/**
* Returns the keycode to process, or 0 if none.
*/
@@ -1816,17 +1872,17 @@ static int reverseIncrementalSearch(struct current *current)
}
#ifdef USE_TERMIOS
if (c == CHAR_ESCAPE) {
- c = check_special(current->fd);
+ c = check_special(current);
}
#endif
- if (c == ctrl('P') || c == SPECIAL_UP) {
+ if (c == ctrl('R')) {
/* Search for the previous (earlier) match */
if (searchpos > 0) {
searchpos--;
}
skipsame = 1;
}
- else if (c == ctrl('N') || c == SPECIAL_DOWN) {
+ else if (c == ctrl('S')) {
/* Search for the next (later) match */
if (searchpos < history_len) {
searchpos++;
@@ -1834,6 +1890,18 @@ static int reverseIncrementalSearch(struct current *current)
searchdir = 1;
skipsame = 1;
}
+ else if (c == ctrl('P') || c == SPECIAL_UP) {
+ /* Exit Ctrl-R mode and go to the previous history line from the current search pos */
+ set_history_index(current, history_len - searchpos);
+ c = 0;
+ break;
+ }
+ else if (c == ctrl('N') || c == SPECIAL_DOWN) {
+ /* Exit Ctrl-R mode and go to the next history line from the current search pos */
+ set_history_index(current, history_len - searchpos - 2);
+ c = 0;
+ break;
+ }
else if (c >= ' ' && c <= '~') {
/* >= here to allow for null terminator */
if (rlen >= (int)sizeof(rbuf) - MAX_UTF8_LEN) {
@@ -1863,6 +1931,7 @@ static int reverseIncrementalSearch(struct current *current)
continue;
}
/* Copy the matching line and set the cursor position */
+ history_index = history_len - 1 - searchpos;
set_current(current,history[searchpos]);
current->pos = utf8_strlen(history[searchpos], p - history[searchpos]);
break;
@@ -1878,25 +1947,25 @@ static int reverseIncrementalSearch(struct current *current)
if (c == ctrl('G') || c == ctrl('C')) {
/* ctrl-g terminates the search with no effect */
set_current(current, "");
+ history_index = 0;
c = 0;
}
else if (c == ctrl('J')) {
/* ctrl-j terminates the search leaving the buffer in place */
+ history_index = 0;
c = 0;
}
-
/* Go process the char normally */
refreshLine(current);
return c;
}
static int linenoiseEdit(struct current *current) {
- int history_index = 0;
+ history_index = 0;
refreshLine(current);
while(1) {
- int dir = -1;
int c = fd_read(current);
#ifndef NO_COMPLETION
@@ -1915,7 +1984,7 @@ static int linenoiseEdit(struct current *current) {
#ifdef USE_TERMIOS
if (c == CHAR_ESCAPE) { /* escape sequence */
- c = check_special(current->fd);
+ c = check_special(current);
}
#endif
if (c == -1) {
@@ -2051,36 +2120,19 @@ static int linenoiseEdit(struct current *current) {
refreshLine(current);
}
break;
- case SPECIAL_PAGE_UP:
- dir = history_len - history_index - 1; /* move to start of history */
- goto history_navigation;
- case SPECIAL_PAGE_DOWN:
- dir = -history_index; /* move to 0 == end of history, i.e. current */
- goto history_navigation;
+ case SPECIAL_PAGE_UP: /* move to start of history */
+ set_history_index(current, history_len - 1);
+ break;
+ case SPECIAL_PAGE_DOWN: /* move to 0 == end of history, i.e. current */
+ set_history_index(current, 0);
+ break;
case ctrl('P'):
case SPECIAL_UP:
- dir = 1;
- goto history_navigation;
+ set_history_index(current, history_index + 1);
+ break;
case ctrl('N'):
case SPECIAL_DOWN:
-history_navigation:
- if (history_len > 1) {
- /* Update the current history entry before to
- * overwrite it with tne next one. */
- free(history[history_len - 1 - history_index]);
- history[history_len - 1 - history_index] = strdup(sb_str(current->buf));
- /* Show the new entry */
- history_index += dir;
- if (history_index < 0) {
- history_index = 0;
- break;
- } else if (history_index >= history_len) {
- history_index = history_len - 1;
- break;
- }
- set_current(current, history[history_len - 1 - history_index]);
- refreshLine(current);
- }
+ set_history_index(current, history_index - 1);
break;
case ctrl('A'): /* Ctrl+a, go to the start of the line */
case SPECIAL_HOME:
@@ -2115,10 +2167,10 @@ history_navigation:
refreshLine(current);
break;
default:
- if (c >= meta('a') && c <= meta('z')) {
- /* Don't insert meta chars that are not bound */
- break;
- }
+ if (c >= meta('a') && c <= meta('z')) {
+ /* Don't insert meta chars that are not bound */
+ break;
+ }
/* Only tab is allowed without ^V */
if (c == '\t' || c >= ' ') {
if (insert_char(current, current->pos, c) == 1) {
@@ -2169,7 +2221,7 @@ static stringbuf *sb_getline(FILE *fh)
/* ignore the effect of character count for partial utf8 sequences */
sb_append_len(sb, &ch, 1);
}
- if (n == 0) {
+ if (n == 0 || sb->data == NULL) {
sb_free(sb);
return NULL;
}
@@ -2188,6 +2240,10 @@ char *linenoiseWithInitial(const char *prompt, const char *initial)
printf("%s", prompt);
fflush(stdout);
sb = sb_getline(stdin);
+ if (sb && !fd_isatty(&current)) {
+ printf("%s\n", sb_str(sb));
+ fflush(stdout);
+ }
}
else {
current.buf = sb_alloc();
@@ -2195,9 +2251,9 @@ char *linenoiseWithInitial(const char *prompt, const char *initial)
current.nrows = 1;
current.prompt = prompt;
- /* The latest history entry is always our current buffer */
- linenoiseHistoryAdd(initial);
- set_current(&current, initial);
+ /* The latest history entry is always our current buffer */
+ linenoiseHistoryAdd(initial);
+ set_current(&current, initial);
count = linenoiseEdit(&current);
@@ -2216,11 +2272,11 @@ char *linenoiseWithInitial(const char *prompt, const char *initial)
char *linenoise(const char *prompt)
{
- return linenoiseWithInitial(prompt, "");
+ return linenoiseWithInitial(prompt, "");
}
/* Using a circular buffer is smarter, but a bit more complex to handle. */
-int linenoiseHistoryAddAllocated(char *line) {
+static int linenoiseHistoryAddAllocated(char *line) {
if (history_max_len == 0) {
notinserted:
diff --git a/make-bootstrap-jim b/make-bootstrap-jim
index 67ac71b..3a10ac6 100755
--- a/make-bootstrap-jim
+++ b/make-bootstrap-jim
@@ -40,16 +40,16 @@ EOF
echo "}"
}
-cexts="aio readdir regexp file exec clock array posix"
+cexts="aio readdir regexp file exec clock array"
tclexts="bootstrap initjimsh glob stdlib tclcompat"
# Note ordering
-allexts="bootstrap aio readdir regexp file glob exec posix clock array stdlib tclcompat"
+allexts="bootstrap aio readdir regexp file glob exec clock array stdlib tclcompat"
echo "/* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */"
# define some core features
-for i in JIM_TCL_COMPAT JIM_ANSIC JIM_REGEXP HAVE_NO_AUTOCONF JIM_TINY _JIMAUTOCONF_H; do
+for i in JIM_COMPAT JIM_ANSIC JIM_REGEXP HAVE_NO_AUTOCONF JIM_TINY _JIMAUTOCONF_H; do
echo "#define $i"
done
echo '#define TCL_LIBRARY "."'
@@ -92,7 +92,11 @@ cat <<EOF
#else
#define _GNU_SOURCE
#endif
+#ifndef __ixemul__
#define HAVE_FORK
+#else
+#define HAVE_VFORK
+#endif
#define HAVE_WAITPID
#define HAVE_ISATTY
#define HAVE_MKSTEMP
diff --git a/make-index b/make-index
index 5071d88..3532551 100755
--- a/make-index
+++ b/make-index
@@ -9,8 +9,16 @@ set lines {}
set commands {}
array set cdict {}
set c 0
+set numlist 1
while {[gets $f buf] >= 0} {
+ # Handle auto numbered lists
+ if {[string match "#. *" $buf]} {
+ set buf "$numlist. [string range $buf 3 end]"
+ incr numlist
+ } elseif {$buf eq ""} {
+ set numlist 1
+ }
if {[string match "~~*" $buf]} {
if {[string match "*: *" $prev]} {
incr c
diff --git a/make-release.sh b/make-release.sh
index 07030c7..e8b844e 100755
--- a/make-release.sh
+++ b/make-release.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-version=`sed -n -e 's/.*JIM_VERSION *\([0-9]*\).*/0.\1/p' jim.h`
+version=0.`sed -n -e 's/.*JIM_VERSION *\([0-9]*\).*/\1/p' auto.def`
if [ `git clean -nqx | wc -l` -ne 0 ]; then
git clean -nqx
diff --git a/regtest.tcl b/regtest.tcl
index a9ee5eb..99a65fe 100644
--- a/regtest.tcl
+++ b/regtest.tcl
@@ -388,6 +388,24 @@ puts "TEST 54 PASSED"
apply {{} {info frame 0}}
puts "TEST 55 PASSED"
+# json decode should not core dump on invalid input
+set json {
+{
+ "fossil":"9c65b5432e4aeecf3556e5550c338ce93fd861cc",
+ "timestamp":1435827337,
+ "command":"timeline/checkin", /* this is line 3 */
+ "procTimeUs":3333,
+}}
+catch {json::decode $json}
+puts "TEST 56 PASSED"
+
+if {[exists -command debug]} {
+ set f [open /dev/null w]
+ $f puts [debug objects]
+ $f close
+}
+puts "TEST 57 PASSED"
+
# TAKE THE FOLLOWING puts AS LAST LINE
puts "--- ALL TESTS PASSED ---"
diff --git a/tclcompat.tcl b/tclcompat.tcl
index 3485d00..14ce688 100644
--- a/tclcompat.tcl
+++ b/tclcompat.tcl
@@ -48,7 +48,7 @@ if {[exists -command stdout]} {
$f buffering $v
}
-tr* {
- # Just ignore -translation
+ $f translation $v
}
default {
return -code error "fconfigure: unknown option $n"
@@ -137,9 +137,6 @@ proc popen {cmd {mode r}} {
if {$cmd eq "pid"} {
return $pids
}
- if {$cmd eq "getfd"} {
- $f getfd
- }
if {$cmd eq "close"} {
$f close
# And wait for the child processes to complete
diff --git a/tcltest.tcl b/tcltest.tcl
index 1f13365..8d3d51e 100644
--- a/tcltest.tcl
+++ b/tcltest.tcl
@@ -168,8 +168,8 @@ proc basename-stacktrace {stacktrace} {
# If tcl, just use tcltest
if {[catch {info version}]} {
- package require Tcl 8.5
- package require tcltest 2.1
+ package require Tcl 8.5-
+ package require tcltest 2.1-
namespace import tcltest::*
if {$testinfo(verbose)} {
@@ -185,7 +185,6 @@ if {[catch {info version}]} {
incr skip
for {set level $skip} {$level < [info frame] - $last} {incr level} {
set frame [info frame -$level]
- puts $frame
if {[dict get $frame type] ne "source"} {
continue
}
diff --git a/tests/breakcontinue.test b/tests/breakcont.test
index ddf9438..ddf9438 100644
--- a/tests/breakcontinue.test
+++ b/tests/breakcont.test
diff --git a/tests/event.test b/tests/event.test
index 4f0b3c7..a81128e 100644
--- a/tests/event.test
+++ b/tests/event.test
@@ -78,18 +78,24 @@ test event-7.4 {bgerror throws an error} -constraints jim -body {
}
after 0 {error err1}
update
- }
+ } 2>gorp.err
+ set f [open gorp.err]
+ set err [read $f]
+ close $f
+ set err
} -result {stdin:3: Error: inside bgerror
Traceback (most recent call last):
File "stdin", line 6
bgerror err1
File "stdin", line 3, in bgerror
- error {inside bgerror}}
+ error {inside bgerror}
+} -cleanup {
+ file delete gorp.err
+}
# end of bgerror tests
catch {rename bgerror {}}
-
test event-10.1 {Tcl_Exit procedure} exec {
set cmd [list exec [info nameofexecutable] "<<exit 3"]
list [catch $cmd msg] [lindex $errorCode 0] \
@@ -170,9 +176,10 @@ test event-11.6 {Tcl_VwaitCmd procedure: round robin scheduling, same source} {s
list $x $y $z
} {3 3 done}
-test event-12.1 {Tcl_UpdateCmd procedure} {
- list [catch {update a b} msg] $msg
-} {1 {wrong # args: should be "update ?idletasks?"}}
+test event-12.1 {Tcl_UpdateCmd procedure - usage} -body {
+ update a b
+} -returnCodes error -result {wrong # args: should be "update ?idletasks?"}
+
test event-12.3 {Tcl_UpdateCmd procedure} {
foreach i [after info] {
after cancel $i
@@ -211,8 +218,8 @@ test event-13.1 "vwait/signal" signal {
signal handle ALRM
list [catch -signal {
alarm 0.1
- # This is just to prevent the vwait from exiting immediately
- stdin readable { format test }
+ # prevent the vwait from exiting immediately
+ after 1000 { }
vwait forever
} msg] $msg
} {5 SIGALRM}
diff --git a/tests/expr.test b/tests/expr.test
index 7e26c0a..bc52afd 100644
--- a/tests/expr.test
+++ b/tests/expr.test
@@ -154,5 +154,12 @@ test expr-5.3 {boolean in expression} {
expr {true ? 4 : 5}
} {4}
+test expr-6.1 "Unary negation on boolean - should return error" -body {
+ expr {-true}
+} -returnCodes error -result {can't use non-numeric string as operand of "-"}
+
+test expr-6.2 "Unary plus on boolean - should return error" -body {
+ expr {+true}
+} -returnCodes error -result {can't use non-numeric string as operand of "+"}
testreport
diff --git a/tests/forget-test.tcl b/tests/forget-test.tcl
new file mode 100644
index 0000000..8d4289b
--- /dev/null
+++ b/tests/forget-test.tcl
@@ -0,0 +1,3 @@
+# This is a dummy package used for testing package forget
+
+set forgotten 1
diff --git a/tests/io.test b/tests/io.test
new file mode 100644
index 0000000..1b06439
--- /dev/null
+++ b/tests/io.test
@@ -0,0 +1,26 @@
+source [file dirname [info script]]/testing.tcl
+
+# This is a proxy for tcl || tclcompat
+constraint cmd fconfigure
+
+# The tests in this file are intended to test Tcl-compatible I/O features
+
+test io-1.1 {translation binary} -body {
+ # write a file via stdout in binary mode
+ # This will always work on Unix
+ set script {
+ fconfigure stdout -translation binary
+ puts line1
+ puts line2
+ }
+ exec [info nameofexecutable] << $script >binary.out
+ # Read it back in binary mode
+ set f [open binary.out rb]
+ set buf [read $f]
+ close $f
+ set buf
+} -cleanup {
+ file delete binary.out
+} -result "line1\nline2\n"
+
+testreport
diff --git a/tests/jimsh.test b/tests/jimsh.test
index a02ed9f..8faf2d8 100644
--- a/tests/jimsh.test
+++ b/tests/jimsh.test
@@ -28,29 +28,17 @@ test jimsh-1.5 {jimsh --version} {
test jimsh-1.6 {jimsh -e with error} -body {
exec [info nameofexecutable] -e blah
-} -returnCodes error -result {invalid command name "blah"}
+} -returnCodes error -match glob -result {invalid command name "blah"*}
-test jimsh-1.7 {jimsh prompt} -body {
- exec [info nameofexecutable] << "set x 3\nincr x\nexit \$x\n"
-} -returnCodes error -match glob -result {Welcome to Jim version *
-. 3
-. 4
-. }
+test jimsh-1.7 {jimsh exit code} -body {
+ set script "set x 3\nincr x\nexit \$x\n"
+ set rc [catch {exec [info nameofexecutable] << $script} msg opts]
+ lassign [dict get $opts -errorcode] status pid exitcode
+ list $rc $status $exitcode
+} -result {1 CHILDSTATUS 4}
-test jimsh-1.8 {jimsh prompt - error} -body {
+test jimsh-1.8 {jimsh error} -body {
exec [info nameofexecutable] << "blah\n"
-} -match glob -result {Welcome to Jim version *
-. invalid command name "blah"
-\[error\] . }
-
-test jimsh-1.9 {jimsh prompt - error} -body {
- exec [info nameofexecutable] << "throw 99\n"
-} -match glob -result {Welcome to Jim version *
-. \[99\] . }
-
-test jimsh-1.10 {jimsh prompt - continuation} -body {
- exec [info nameofexecutable] << "set x {\nabc\n}\n"
-} -match glob -result "Welcome to Jim version *\n. {> {> \nabc\n\n. "
-
+} -returnCodes error -match glob -result {stdin:1: Error: invalid command name "blah"*}
testreport
diff --git a/tests/json.test b/tests/json.test
index ed73401..09c002c 100644
--- a/tests/json.test
+++ b/tests/json.test
@@ -3,7 +3,8 @@ source [file dirname [info script]]/testing.tcl
needs cmd json::decode json
needs cmd json::encode json
-set json {
+# Create a json string as though it was read from data.json
+set json [info source {
{
"fossil":"9c65b5432e4aeecf3556e5550c338ce93fd861cc",
"timestamp":1435827337,
@@ -24,7 +25,7 @@ set json {
"tags":["trunk"]
}]
}
-}}
+}} data.json 1]
test json-decode-001 {top level keys} {
lsort [dict keys [json::decode $json]]
@@ -60,6 +61,7 @@ test json-decode-012 {default null value} {
} {null}
test json-decode-1.1 {Number forms} {
+ # Note that this is not strictly correct JSON, but is usable in practice
json::decode {[ 1, 2, 3.0, 4, Infinity, NaN, -Infinity, -0.0, 1e5, -1e-5 ]}
} {1 2 3.0 4 Inf NaN -Inf -0.0 1e5 -1e-5}
@@ -80,15 +82,15 @@ test json-2.4 {schema tests} {
} {obj a num b num}
test json-2.5 {schema tests} {
- lindex [json::decode -schema {[1, 2, {a:"b", c:false}, "hello"]}] 1
+ lindex [json::decode -schema {[1, 2, {"a":"b", "c":false}, "hello"]}] 1
} {mixed num num {obj a str c bool} str}
test json-2.6 {schema tests} {
- lindex [json::decode -schema {[1, 2, {a:["b", 1, true, Infinity]}]}] 1
+ lindex [json::decode -schema {[1, 2, {"a":["b", 1, true, Infinity]}]}] 1
} {mixed num num {obj a {mixed str num bool num}}}
test json-2.7 {schema tests} {
- lindex [json::decode -schema {[1, 2, {a:["b", 1, true, ["d", "e", "f"]]}]}] 1
+ lindex [json::decode -schema {[1, 2, {"a":["b", 1, true, ["d", "e", "f"]]}]}] 1
} {mixed num num {obj a {mixed str num bool {list str}}}}
test json-2.8 {schema tests} {
@@ -96,10 +98,9 @@ test json-2.8 {schema tests} {
} {mixed num num bool bool}
test json-2.9 {schema tests} {
- lindex [json::decode -schema {[{a:1},{b:2}]}] 1
+ lindex [json::decode -schema {[{"a":1},{"b":2}]}] 1
} {mixed {obj a num} {obj b num}}
-
test json-3.1 {-index array} {
json::decode -index \
{[null, 1, 2, true, false, "hello"]}
@@ -122,6 +123,17 @@ test json-3.4 {-index array with -schema 2} {
} "{outer {0 {key value} 1 {key2 value2}}}\
{obj outer {mixed {obj key str} {obj key2 str}}}"
+test json-4.1 {source info preserved} -body {
+ info source [dict get [json::decode $json] fossil]
+} -result {data.json 3}
+
+test json-4.2 {source info preserved} -body {
+ info source [dict get [json::decode $json] procTimeUs]
+} -result {data.json 6}
+
+test json-4.3 {source info preserved} -body {
+ info source [dict get [lindex [dict get [json::decode $json] payload timeline] 0] comment]
+} -result {data.json 17}
unset -nocomplain json
diff --git a/tests/lsort.test b/tests/lsort.test
index 5297568..f60bc06 100644
--- a/tests/lsort.test
+++ b/tests/lsort.test
@@ -17,7 +17,7 @@ test lsort-1.1 {Tcl_LsortObjCmd procedure} jim {
} {1 {wrong # args: should be "lsort ?options? list"}}
test lsort-1.2 {Tcl_LsortObjCmd procedure} jim {
list [catch {lsort -foo {1 3 2 5}} msg] $msg
-} {1 {bad option "-foo": must be -ascii, -command, -decreasing, -increasing, -index, -integer, -nocase, -real, -stride, or -unique}}
+} {1 {bad option "-foo": must be -ascii, -command, -decreasing, -dictionary, -increasing, -index, -integer, -nocase, -real, -stride, or -unique}}
test lsort-1.3 {Tcl_LsortObjCmd procedure, default options} {
lsort {d e c b a \{ d35 d300}
} {a b c d d300 d35 e \{}
@@ -207,6 +207,12 @@ test lsort-5.1 "Sort case insensitive" {
lsort -nocase {ba aB aa ce}
} {aa aB ba ce}
+test cmdIL-1.8 {Tcl_LsortObjCmd procedure, -dictionary option} {
+ lsort -dictionary {d e c b a d35 d300}
+} {a b c d d35 d300 e}
+test cmdIL-1.9 {Tcl_LsortObjCmd procedure, -dictionary option} {
+ lsort -dictionary {1k 0k 10k}
+} {0k 1k 10k}
test cmdIL-1.30 {Tcl_LsortObjCmd procedure, -stride option} {
lsort -stride 2 {f e d c b a}
} {b a d c f e}
@@ -237,5 +243,126 @@ test cmdIL-1.41 {lsort -stride and -index} -body {
test cmdIL-1.42 {lsort -stride and-index} -body {
lsort -stride 2 -index -1-1 {a 2 b 1}
} -returnCodes error -result {index "-1-1" out of range}
+test cmdIL-3.8 {SortCompare procedure, -dictionary option} {
+ lsort -dictionary {d e c b a d35 d300 100 20}
+} {20 100 a b c d d35 d300 e}
+
+test cmdIL-4.1 {DictionaryCompare procedure, numerics, leading zeros} {
+ lsort -dictionary {a003b a03b}
+} {a03b a003b}
+test cmdIL-4.2 {DictionaryCompare procedure, numerics, leading zeros} {
+ lsort -dictionary {a3b a03b}
+} {a3b a03b}
+# This test fails in Jim because we don't bother falling back to a secondary
+# sort on case if the primary sort (with leading zeros) is equal.
+test cmdIL-4.3 {DictionaryCompare procedure, numerics, leading zeros} tcl {
+ lsort -dictionary {a3b A03b}
+} {A03b a3b}
+test cmdIL-4.4 {DictionaryCompare procedure, numerics, leading zeros} {
+ lsort -dictionary {a3b a03B}
+} {a3b a03B}
+test cmdIL-4.5 {DictionaryCompare procedure, numerics, leading zeros} {
+ lsort -dictionary {00000 000}
+} {000 00000}
+test cmdIL-4.6 {DictionaryCompare procedure, numerics, different lengths} {
+ lsort -dictionary {a321b a03210b}
+} {a321b a03210b}
+test cmdIL-4.7 {DictionaryCompare procedure, numerics, different lengths} {
+ lsort -dictionary {a03210b a321b}
+} {a321b a03210b}
+test cmdIL-4.8 {DictionaryCompare procedure, numerics} {
+ lsort -dictionary {48 6a 18b 22a 21aa 35 36}
+} {6a 18b 21aa 22a 35 36 48}
+test cmdIL-4.9 {DictionaryCompare procedure, numerics} {
+ lsort -dictionary {a123x a123b}
+} {a123b a123x}
+test cmdIL-4.10 {DictionaryCompare procedure, numerics} {
+ lsort -dictionary {a123b a123x}
+} {a123b a123x}
+test cmdIL-4.11 {DictionaryCompare procedure, numerics} {
+ lsort -dictionary {a1b aab}
+} {a1b aab}
+test cmdIL-4.12 {DictionaryCompare procedure, numerics} {
+ lsort -dictionary {a1b a!b}
+} {a!b a1b}
+test cmdIL-4.13 {DictionaryCompare procedure, numerics} {
+ lsort -dictionary {a1b2c a1b1c}
+} {a1b1c a1b2c}
+test cmdIL-4.14 {DictionaryCompare procedure, numerics} {
+ lsort -dictionary {a1b2c a1b3c}
+} {a1b2c a1b3c}
+test cmdIL-4.15 {DictionaryCompare procedure, long numbers} {
+ lsort -dictionary {a7654884321988762b a7654884321988761b}
+} {a7654884321988761b a7654884321988762b}
+test cmdIL-4.16 {DictionaryCompare procedure, long numbers} {
+ lsort -dictionary {a8765488432198876b a7654884321988761b}
+} {a7654884321988761b a8765488432198876b}
+test cmdIL-4.17 {DictionaryCompare procedure, case} {
+ lsort -dictionary {aBCd abcc}
+} {abcc aBCd}
+test cmdIL-4.18 {DictionaryCompare procedure, case} {
+ lsort -dictionary {aBCd abce}
+} {aBCd abce}
+test cmdIL-4.19 {DictionaryCompare procedure, case} {
+ lsort -dictionary {abcd ABcc}
+} {ABcc abcd}
+test cmdIL-4.20 {DictionaryCompare procedure, case} {
+ lsort -dictionary {abcd ABce}
+} {abcd ABce}
+test cmdIL-4.21 {DictionaryCompare procedure, case} {
+ lsort -dictionary {abCD ABcd}
+} {ABcd abCD}
+test cmdIL-4.22 {DictionaryCompare procedure, case} {
+ lsort -dictionary {ABcd aBCd}
+} {ABcd aBCd}
+test cmdIL-4.23 {DictionaryCompare procedure, case} {
+ lsort -dictionary {ABcd AbCd}
+} {ABcd AbCd}
+test cmdIL-4.24 {DictionaryCompare procedure, international characters} utf8 {
+ set result [lsort -dictionary "a b c A B C \xe3 \xc4"]
+ set result
+} "A a B b C c \xe3 \xc4"
+test cmdIL-4.25 {DictionaryCompare procedure, international characters} utf8 {
+ set result [lsort -dictionary "a23\xe3 a23\xc5 a23\xe4"]
+ set result
+} "a23\xe3 a23\xe4 a23\xc5"
+test cmdIL-4.26 {DefaultCompare procedure, signed characters} {
+ set l [lsort [list "abc\200" "abc"]]
+ set viewlist {}
+ foreach s $l {
+ set viewelem ""
+ set len [string length $s]
+ for {set i 0} {$i < $len} {incr i} {
+ set c [string index $s $i]
+ scan $c %c d
+ if {$d > 0 && $d < 128} {
+ append viewelem $c
+ } else {
+ append viewelem "\\[format %03o $d]"
+ }
+ }
+ lappend viewlist $viewelem
+ }
+ set viewlist
+} [list "abc" "abc\\200"]
+test cmdIL-4.27 {DictionaryCompare procedure, signed characters} {
+ set l [lsort -dictionary [list "abc\200" "abc"]]
+ set viewlist {}
+ foreach s $l {
+ set viewelem ""
+ set len [string length $s]
+ for {set i 0} {$i < $len} {incr i} {
+ set c [string index $s $i]
+ scan $c %c d
+ if {$d > 0 && $d < 128} {
+ append viewelem $c
+ } else {
+ append viewelem "\\[format %03o $d]"
+ }
+ }
+ lappend viewlist $viewelem
+ }
+ set viewlist
+} [list "abc" "abc\\200"]
testreport
diff --git a/tests/package.test b/tests/package.test
index b8afa18..1484bd6 100644
--- a/tests/package.test
+++ b/tests/package.test
@@ -20,5 +20,17 @@ test package-1.3 {package names} -body {
expr {"stdlib" in [package names]}
} -result 1
+test package-2.1 {package forget} -body {
+ # First pretend the package was loaded
+ package provide forget-test
+ # Now it won't load anything
+ package require forget-test
+ # Now forget it and another unloaded test
+ package forget forget-test missing
+ # And load the local package
+ package require forget-test
+ info exists forgotten
+} -result 1
+
testreport
diff --git a/tests/try.test b/tests/try.test
index 0d76865..36a9bf9 100644
--- a/tests/try.test
+++ b/tests/try.test
@@ -104,7 +104,7 @@ test try-2.1 "try ... trap" -body {
try {
a
} trap CUSTOM {msg opts} {
- list $msg $opts(-code) $opts(-errorcode)
+ list $msg [dict get $opts -code] [dict get $opts -errorcode]
}
} -result {{custom errorcode} 1 {CUSTOM RESULT}}
@@ -140,6 +140,13 @@ test try-2.5 "trap match first but not second" -body {
}
} -returnCodes error -result failed
+test try-2.6 "trap match too long" -body {
+ try {
+ apply {{} {return -code error -errorcode {FOO BAR} failed}}
+ } trap {FOO BAR BAZ} {msg opts} {
+ list trapped
+ }
+} -returnCodes error -result failed
proc c {} {
try {