|
1 | 1 |
|
2 | 2 | import ../common
|
3 |
| - |
4 |
| -const DWin = defined(windows) |
| 3 | +import std/macros |
5 | 4 |
|
6 | 5 | type Time64 = int64
|
7 | 6 |
|
@@ -44,57 +43,91 @@ when DWin:
|
44 | 43 | {.pop.}
|
45 | 44 | else:
|
46 | 45 | import std/posix
|
47 |
| - |
48 |
| - template toTime(x): untyped = x.tv_sec |
49 |
| - template st_atime*(s: Stat): untyped = Time64 toTime s.st_atim |
50 |
| - template st_mtime*(s: Stat): untyped = Time64 toTime s.st_mtim |
51 |
| - template st_ctime*(s: Stat): untyped = Time64 toTime s.st_ctim |
52 |
| - |
53 |
| -const statHasMore = defined(linux) # XXX: this check is not suitable. |
54 |
| -when statHasMore: |
55 |
| - type |
56 |
| - stat_result* = tuple[ |
57 |
| - st_mode: Mode, st_ino: Ino, st_dev: Dev, st_nlink: Nlink, |
58 |
| - st_uid: Uid, st_gid: Gid, st_size: Off, |
59 |
| - st_atime, st_mtime, st_ctime: Time64, |
60 |
| - |
61 |
| - st_blocks: Blkcnt, |
62 |
| - st_blksize: Blksize, |
63 |
| - st_rdev: Dev, |
64 |
| - # st_flags |
65 |
| - ] ## Python's `os.stat_result` (a NamedTuple) |
66 |
| -else: |
67 |
| - type |
68 |
| - stat_result* = tuple[ |
69 |
| - st_mode: Mode, st_ino: Ino, st_dev: Dev, st_nlink: Nlink, |
70 |
| - st_uid: Uid, st_gid: Gid, st_size: Off, |
71 |
| - st_atime, st_mtime, st_ctime: Time64, |
72 |
| - ] ## Python's `os.stat_result` (a NamedTuple) |
73 | 46 |
|
74 |
| -import std/macros |
| 47 | +type |
| 48 | + stat_result* = ref object |
| 49 | + data*: Stat ## inner, used by `getattr` of `stat_result` |
| 50 | + |
| 51 | +macro genTimeGetter(amc: static[char]) = |
| 52 | + result = newStmtList() |
| 53 | + let s_st_xtim = "st_" & amc & "tim" |
| 54 | + template get(attr: string): NimNode = |
| 55 | + newDotExpr(x, ident(attr)) |
| 56 | + let |
| 57 | + xtim = ident s_st_xtim |
| 58 | + xtime = ident(s_st_xtim & 'e') |
| 59 | + let |
| 60 | + xtime_ns = ident(s_st_xtim & "e_ns") |
| 61 | + result = quote do: |
| 62 | + func `xtime`*(self: stat_result): float = |
| 63 | + when compiles(self.data.`xtim`): |
| 64 | + self.data.`xtim`.tv_sec.float + self.data.`xtim`.tv_nsec/1_000_000_000 |
| 65 | + else: |
| 66 | + self.data.`xtime`.float |
| 67 | + func `xtime_ns`*(self: stat_result): BiggestInt{.pysince(3,3).} = |
| 68 | + when compiles(self.data.`xtim`): |
| 69 | + self.data.`xtim`.tv_sec.BiggestInt * 1_000_000_000 + |
| 70 | + self.data.`xtim`.tv_nsec.BiggestInt |
| 71 | + else: |
| 72 | + self.data.`xtime`.BiggestInt * 1_000_000_000 |
75 | 73 |
|
76 |
| -macro to_result(s: Stat): stat_result = |
77 |
| - var templ: stat_result |
78 |
| - result = nnkTupleConstr.newNimNode |
79 |
| - for kStr, _ in templ.fieldPairs: |
80 |
| - let k = ident kStr |
81 |
| - result.add newColonExpr(k, newDotExpr(s, k)) |
82 |
| - # `k`: `s`.`k` |
83 |
| - |
84 |
| -proc statFor(st: var Stat, path: int|PathLike) = |
85 |
| - let ret = |
86 |
| - when path is int: |
87 |
| - fstat(path.cint, st) |
88 |
| - else: |
89 |
| - when DWin: |
90 |
| - wstat( newWideCString(path.fspath), st) |
| 74 | +genTimeGetter 'a' |
| 75 | +genTimeGetter 'm' |
| 76 | +genTimeGetter 'c' |
| 77 | + |
| 78 | +{.experimental: "dotOperators".} |
| 79 | +template `.`*(self: stat_result; attr): untyped = |
| 80 | + ## as Python's `__getattr__` |
| 81 | + self.data.attr |
| 82 | + |
| 83 | +const visible_size = 10 |
| 84 | + |
| 85 | +func getitem(self: stat_result, i: int): BiggestInt = |
| 86 | + # this proc was once generated by macro |
| 87 | + case i |
| 88 | + of 0: result = BiggestInt self.data.st_ino |
| 89 | + of 1: result = BiggestInt self.data.st_mode |
| 90 | + of 2: result = BiggestInt self.data.st_nlink |
| 91 | + of 3: result = BiggestInt self.data.st_uid |
| 92 | + of 4: result = BiggestInt self.data.st_gid |
| 93 | + of 5: result = BiggestInt self.data.st_dev |
| 94 | + of 6: result = BiggestInt self.data.st_size |
| 95 | + of 7: result = BiggestInt self.data.st_atime |
| 96 | + of 8: result = BiggestInt self.data.st_mtime |
| 97 | + of 9: result = BiggestInt self.data.st_ctime |
| 98 | + else: |
| 99 | + raise newException(IndexDefect, "tuple index out of range") |
| 100 | + |
| 101 | +func `[]`*(self: stat_result, i: int): BiggestInt = |
| 102 | + self.getitem(if i < 0: visible_size + i else: i) |
| 103 | + |
| 104 | +func to_result(s: sink Stat): stat_result = |
| 105 | + result = stat_result(data: s) |
| 106 | + |
| 107 | +when defined(js): |
| 108 | + proc statFor(st: var Stat, path: int|PathLike) = |
| 109 | + catchJsErrAndRaise: |
| 110 | + st = |
| 111 | + when path is int: |
| 112 | + fstatSync(path.cint) |
| 113 | + else: |
| 114 | + statSync cstring $path |
| 115 | + |
| 116 | +else: |
| 117 | + proc statFor(st: var Stat, path: int|PathLike) = |
| 118 | + let ret = |
| 119 | + when path is int: |
| 120 | + fstat(path.cint, st) |
| 121 | + else: |
| 122 | + when DWin: |
| 123 | + wstat( newWideCString(path.fspath), st) |
| 124 | + else: |
| 125 | + stat(cstring path.fspath, st) |
| 126 | + if ret != 0.cint: |
| 127 | + when path is int: |
| 128 | + raiseErrno($path) |
91 | 129 | else:
|
92 |
| - stat(cstring path.fspath, st) |
93 |
| - if ret != 0.cint: |
94 |
| - when path is int: |
95 |
| - raiseErrno($path) |
96 |
| - else: |
97 |
| - path.raiseErrnoWithPath() |
| 130 | + path.raiseErrnoWithPath() |
98 | 131 |
|
99 | 132 | template statAttr*(path: PathLike|int, attr: untyped): untyped =
|
100 | 133 | ## stat(`path`).`attr`
|
|
0 commit comments