file.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. package file
  2. import (
  3. "math/big"
  4. "os"
  5. "strconv"
  6. "src.elv.sh/pkg/eval"
  7. "src.elv.sh/pkg/eval/errs"
  8. "src.elv.sh/pkg/eval/vals"
  9. "src.elv.sh/pkg/parse"
  10. "src.elv.sh/pkg/sys"
  11. )
  12. var Ns = eval.BuildNsNamed("file").
  13. AddGoFns(map[string]any{
  14. "close": close,
  15. "is-tty": isTTY,
  16. "open": open,
  17. "pipe": pipe,
  18. "truncate": truncate,
  19. }).Ns()
  20. func isTTY(fm *eval.Frame, file any) (bool, error) {
  21. switch file := file.(type) {
  22. case *os.File:
  23. return sys.IsATTY(file.Fd()), nil
  24. case int:
  25. return sys.IsATTY(uintptr(file)), nil
  26. case string:
  27. var fd int
  28. if err := vals.ScanToGo(file, &fd); err != nil {
  29. return false, errs.BadValue{What: "argument to file:is-tty",
  30. Valid: "file value or numerical FD", Actual: parse.Quote(file)}
  31. }
  32. return sys.IsATTY(uintptr(fd)), nil
  33. default:
  34. return false, errs.BadValue{What: "argument to file:is-tty",
  35. Valid: "file value or numerical FD", Actual: vals.ToString(file)}
  36. }
  37. }
  38. func open(name string) (vals.File, error) {
  39. return os.Open(name)
  40. }
  41. func close(f vals.File) error {
  42. return f.Close()
  43. }
  44. func pipe() (vals.Pipe, error) {
  45. r, w, err := os.Pipe()
  46. return vals.NewPipe(r, w), err
  47. }
  48. func truncate(name string, rawSize vals.Num) error {
  49. var size int64
  50. switch rawSize := rawSize.(type) {
  51. case int:
  52. size = int64(rawSize)
  53. case *big.Int:
  54. if rawSize.IsInt64() {
  55. size = rawSize.Int64()
  56. } else {
  57. return truncateSizeOutOfRange(rawSize.String())
  58. }
  59. default:
  60. return errs.BadValue{
  61. What: "size argument to file:truncate",
  62. Valid: "integer", Actual: "non-integer",
  63. }
  64. }
  65. if size < 0 {
  66. return truncateSizeOutOfRange(strconv.FormatInt(size, 10))
  67. }
  68. return os.Truncate(name, size)
  69. }
  70. func truncateSizeOutOfRange(size string) error {
  71. return errs.OutOfRange{
  72. What: "size argument to file:truncate",
  73. ValidLow: "0",
  74. ValidHigh: "2^64-1",
  75. Actual: size,
  76. }
  77. }