mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-14 02:57:52 +08:00
142 lines
3.1 KiB
Go
142 lines
3.1 KiB
Go
package file
|
|
|
|
import (
|
|
"math/big"
|
|
"os"
|
|
"strconv"
|
|
|
|
"src.elv.sh/pkg/eval"
|
|
"src.elv.sh/pkg/eval/errs"
|
|
"src.elv.sh/pkg/eval/vals"
|
|
)
|
|
|
|
var Ns = eval.BuildNsNamed("file").
|
|
AddGoFns(map[string]any{
|
|
"close": close,
|
|
"open": open,
|
|
"pipe": pipe,
|
|
"truncate": truncate,
|
|
}).Ns()
|
|
|
|
//elvdoc:fn open
|
|
//
|
|
// ```elvish
|
|
// file:open $filename
|
|
// ```
|
|
//
|
|
// Opens a file. Currently, `open` only supports opening a file for reading.
|
|
// File must be closed with `close` explicitly. Example:
|
|
//
|
|
// ```elvish-transcript
|
|
// ~> cat a.txt
|
|
// This is
|
|
// a file.
|
|
// ~> use file
|
|
// ~> var f = (file:open a.txt)
|
|
// ~> cat < $f
|
|
// This is
|
|
// a file.
|
|
// ~> close $f
|
|
// ```
|
|
//
|
|
// @cf file:close
|
|
|
|
func open(name string) (vals.File, error) {
|
|
return os.Open(name)
|
|
}
|
|
|
|
//elvdoc:fn close
|
|
//
|
|
// ```elvish
|
|
// file:close $file
|
|
// ```
|
|
//
|
|
// Closes a file opened with `open`.
|
|
//
|
|
// @cf file:open
|
|
|
|
func close(f vals.File) error {
|
|
return f.Close()
|
|
}
|
|
|
|
//elvdoc:fn pipe
|
|
//
|
|
// ```elvish
|
|
// file:pipe
|
|
// ```
|
|
//
|
|
// Create a new pipe that can be used in redirections. A pipe contains a read-end and write-end.
|
|
// Each pipe object is a [pseudo-map](language.html#pseudo-map) with fields `r` (the read-end [file
|
|
// object](./language.html#file)) and `w` (the write-end).
|
|
//
|
|
// When redirecting command input from a pipe with `<`, the read-end is used. When redirecting
|
|
// command output to a pipe with `>`, the write-end is used. Redirecting both input and output with
|
|
// `<>` to a pipe is not supported.
|
|
//
|
|
// Pipes have an OS-dependent buffer, so writing to a pipe without an active reader
|
|
// does not necessarily block. Pipes **must** be explicitly closed with `file:close`.
|
|
//
|
|
// Putting values into pipes will cause those values to be discarded.
|
|
//
|
|
// Examples (assuming the pipe has a large enough buffer):
|
|
//
|
|
// ```elvish-transcript
|
|
// ~> var p = (file:pipe)
|
|
// ~> echo 'lorem ipsum' > $p
|
|
// ~> head -n1 < $p
|
|
// lorem ipsum
|
|
// ~> put 'lorem ipsum' > $p
|
|
// ~> file:close $p[w] # close the write-end
|
|
// ~> head -n1 < $p # blocks unless the write-end is closed
|
|
// ~> file:close $p[r] # close the read-end
|
|
// ```
|
|
//
|
|
// @cf file:close
|
|
|
|
func pipe() (vals.Pipe, error) {
|
|
r, w, err := os.Pipe()
|
|
return vals.NewPipe(r, w), err
|
|
}
|
|
|
|
//elvdoc:fn truncate
|
|
//
|
|
// ```elvish
|
|
// file:truncate $filename $size
|
|
// ```
|
|
//
|
|
// changes the size of the named file. If the file is a symbolic link, it
|
|
// changes the size of the link's target. The size must be an integer between 0
|
|
// and 2^64-1.
|
|
|
|
func truncate(name string, rawSize vals.Num) error {
|
|
var size int64
|
|
switch rawSize := rawSize.(type) {
|
|
case int:
|
|
size = int64(rawSize)
|
|
case *big.Int:
|
|
if rawSize.IsInt64() {
|
|
size = rawSize.Int64()
|
|
} else {
|
|
return truncateSizeOutOfRange(rawSize.String())
|
|
}
|
|
default:
|
|
return errs.BadValue{
|
|
What: "size argument to file:truncate",
|
|
Valid: "integer", Actual: "non-integer",
|
|
}
|
|
}
|
|
if size < 0 {
|
|
return truncateSizeOutOfRange(strconv.FormatInt(size, 10))
|
|
}
|
|
return os.Truncate(name, size)
|
|
}
|
|
|
|
func truncateSizeOutOfRange(size string) error {
|
|
return errs.OutOfRange{
|
|
What: "size argument to file:truncate",
|
|
ValidLow: "0",
|
|
ValidHigh: "2^64-1",
|
|
Actual: size,
|
|
}
|
|
}
|