Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `randomNorm`
- `sqrt`
- `randomTri`
- `tempFileExt`

### Fixed

Expand Down
5 changes: 3 additions & 2 deletions doc/functions.inc.html
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ <h1 id="functions-file-directory">File and Directory <a class="section-link" hre
<tr> <td><code>isFile</code></td> <td>Test whether a path is a file.</td> <td><code>(<span class="sig-type sig-type-path">path</span> -- <span class="sig-type sig-type-bool">bool</span>)</code></td> </tr>
<tr> <td><code>fileExists</code></td> <td>Check whether a filesystem entry exists. Uses go <a href="https://pkg.go.dev/os#Lstat">os.Lstat</a> for determination. This means that broken symlink will return <code>true</code>. </td> <td><code>(<span class="sig-type sig-type-str">str</span>|<span class="sig-type sig-type-path">path</span> -- <span class="sig-type sig-type-bool">bool</span>)</code></td> </tr>
<tr> <td><code>hardLink</code></td> <td>Create a hard link.</td> <td><code>(<span class="sig-type sig-type-path">path</span>:source <span class="sig-type sig-type-path">path</span>:dest -- )</code></td> </tr>
<tr> <td><code>tempFile</code></td> <td>Create a temporary file and push its path.</td> <td><code>(-- <span class="sig-type sig-type-str">str</span>)</code></td> </tr>
<tr> <td><code>tempDir</code></td> <td>Return the OS-specific temporary directory via <a href="https://pkg.go.dev/os#TempDir" target="_blank" rel="noopener noreferrer"><code>os.TempDir</code></a> (for example, <code>$TMPDIR</code> on Unix or <code>%TMP%</code> on Windows).</td> <td><code>(-- <span class="sig-type sig-type-str">str</span>)</code></td> </tr>
<tr> <td><code>tempFile</code></td> <td>Create a temporary file and push its path. Uses go <a href="https://pkg.go.dev/os#CreateTemp" target="_blank" rel="noopener noreferrer"><code>os.CreateTemp</code></a> with <code>dir=""</code> (defaults to <a href="https://pkg.go.dev/os#TempDir" target="_blank" rel="noopener noreferrer"><code>os.TempDir</code></a>) and pattern <code>msh-</code>, so the filename starts with <code>msh-</code> plus a random suffix. The file is not removed automatically; use <code>rm</code>/<code>rmf</code> when you are done.</td> <td><code>(-- <span class="sig-type sig-type-path">path</span>)</code></td> </tr>
<tr> <td><code>tempFileExt</code></td> <td>Create a temporary file with a required extension and push its path. The extension input is canonicalized to start with <code>.</code> if needed. Uses go <a href="https://pkg.go.dev/os#CreateTemp" target="_blank" rel="noopener noreferrer"><code>os.CreateTemp</code></a> with <code>dir=""</code> (defaults to <a href="https://pkg.go.dev/os#TempDir" target="_blank" rel="noopener noreferrer"><code>os.TempDir</code></a>) and pattern <code>msh-*</code> plus the canonicalized extension, so the filename ends with the extension. The file is not removed automatically; use <code>rm</code>/<code>rmf</code> when you are done.</td> <td><code>(<span class="sig-type sig-type-str">str</span>|<span class="sig-type sig-type-path">path</span> -- <span class="sig-type sig-type-path">path</span>)</code></td> </tr>
<tr> <td><code>tempDir</code></td> <td>Return the OS-specific temporary directory via <a href="https://pkg.go.dev/os#TempDir" target="_blank" rel="noopener noreferrer"><code>os.TempDir</code></a> (for example, <code>$TMPDIR</code> on Unix or <code>%TMP%</code> on Windows).</td> <td><code>(-- <span class="sig-type sig-type-path">path</span>)</code></td> </tr>
<tr> <td><code>rm</code></td> <td>Remove a file; fails on IO errors.</td> <td><code>(<span class="sig-type sig-type-str">str</span> -- )</code></td> </tr>
<tr> <td><code>rmf</code></td> <td>Remove a file; ignore IO errors.</td> <td><code>(<span class="sig-type sig-type-str">str</span> -- )</code></td> </tr>
<tr> <td><code>cp</code></td> <td>Copy a file or directory.</td> <td><code>(<span class="sig-type sig-type-str">str</span>:source <span class="sig-type sig-type-str">str</span>:dest -- )</code></td> </tr>
Expand Down
5 changes: 3 additions & 2 deletions doc/mshell.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,9 @@ Metadata values must be static: strings (single or double quoted), integers, flo
- `isFile`: Check if path is a file. `(path -- bool)`
- `fileExists`: Check whether a file or directory exists. `(str|path -- bool)`
- `hardLink`: Create a hard link. `(existingSourcePath newTargetPath -- )`
- `tempFile`: Create a temporary file, and put the full path on the stack. `( -- str)`
- `tempDir`: Return path to the OS specific temporary directory. No checks on permission or existence, so never fails. See [`os.TempDir`](https://pkg.go.dev/os#TempDir) in golang. `$TMPDIR` or `/tmp` for Unix, `%TMP%`, `%TEMP%, %USERPROFILE%`, or the Windows directory (`C:\Windows`). `( -- str)`
- `tempFile`: Create a temporary file with go [`os.CreateTemp`](https://pkg.go.dev/os#CreateTemp) using `dir=""` (defaults to [`os.TempDir`](https://pkg.go.dev/os#TempDir)) and pattern `msh-`, so the filename starts with `msh-` plus a random suffix. Pushes the full path. The file is not removed automatically; use `rm`/`rmf` when you are done. `( -- path)`
- `tempFileExt`: Create a temporary file with a required extension. The extension input is canonicalized to start with `.` if needed. Uses go [`os.CreateTemp`](https://pkg.go.dev/os#CreateTemp) with `dir=""` (defaults to [`os.TempDir`](https://pkg.go.dev/os#TempDir)) and pattern `msh-*` plus the canonicalized extension, so the filename ends with the extension. Pushes the full path. The file is not removed automatically; use `rm`/`rmf` when you are done. `(str|path -- path)`
- `tempDir`: Return path to the OS specific temporary directory. No checks on permission or existence, so never fails. See [`os.TempDir`](https://pkg.go.dev/os#TempDir) in golang. `$TMPDIR` or `/tmp` for Unix, `%TMP%`, `%TEMP%, %USERPROFILE%`, or the Windows directory (`C:\Windows`). `( -- path)`
- `rm`: Remove file. Will stop execution on IO error, including file not found. `(str -- )`
- `rmf`: Remove file. Will not stop execution on IO error, including file not found. `(str -- )`
- `cp`: Copy file or directory. `(str:source str:dest -- )`
Expand Down
1 change: 1 addition & 0 deletions mshell/BuiltInList.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ var BuiltInList = map[string]struct{}{
"take": {},
"tempDir": {},
"tempFile": {},
"tempFileExt": {},
"title": {},
"toDt": {},
"toFixed": {},
Expand Down
27 changes: 27 additions & 0 deletions mshell/Evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2080,6 +2080,33 @@ MainLoop:
if err != nil {
return state.FailWithMessage(fmt.Sprintf("%d:%d: Error creating temporary file: %s\n", t.Line, t.Column, err.Error()))
}
if err := tmpfile.Close(); err != nil {
return state.FailWithMessage(fmt.Sprintf("%d:%d: Error closing temporary file: %s\n", t.Line, t.Column, err.Error()))
}
// Dump the full path to the stack
stack.Push(MShellPath{tmpfile.Name()})
} else if t.Lexeme == "tempFileExt" {
extValue, err := stack.Pop()
if err != nil {
return state.FailWithMessage(fmt.Sprintf("%d:%d: Cannot do 'tempFileExt' operation on an empty stack.\n", t.Line, t.Column))
}

extStr, err := extValue.CastString()
if err != nil {
return state.FailWithMessage(fmt.Sprintf("%d:%d: Cannot create tempFileExt with a %s.\n", t.Line, t.Column, extValue.TypeName()))
}

if extStr != "" && !strings.HasPrefix(extStr, ".") {
extStr = "." + extStr
}

tmpfile, err := os.CreateTemp("", "msh-*"+extStr)
if err != nil {
return state.FailWithMessage(fmt.Sprintf("%d:%d: Error creating temporary file: %s\n", t.Line, t.Column, err.Error()))
}
if err := tmpfile.Close(); err != nil {
return state.FailWithMessage(fmt.Sprintf("%d:%d: Error closing temporary file: %s\n", t.Line, t.Column, err.Error()))
}
// Dump the full path to the stack
stack.Push(MShellPath{tmpfile.Name()})
} else if t.Lexeme == "tempDir" {
Expand Down