1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
#+build darwin, linux, freebsd, openbsd, netbsd, haiku
package posix
import "core:c"
when ODIN_OS == .Darwin {
foreign import lib "system:System"
} else {
foreign import lib "system:c"
}
// dirent.h - format of directory entries
foreign lib {
/*
can be used as the comparison function for the scandir() function to sort the directory entries, d1 and d2, into alphabetical order.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/scandir.html ]]
*/
@(link_name=LALPHASORT)
alphasort :: proc([^]^dirent, [^]^dirent) -> c.int ---
/*
Scan the directory dir, calling the function referenced by sel on each directory entry.
Example:
list: [^]^posix.dirent
ret := posix.scandir(#directory, &list, nil, posix.alphasort)
if ret < 0 {
panic(string(posix.strerror(posix.errno())))
}
defer posix.free(list)
entries := list[:ret]
for entry in entries {
log.info(entry)
posix.free(entry)
}
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/scandir.html ]]
*/
@(link_name=LSCANDIR)
scandir :: proc(
dir: cstring,
sel: ^[^]^dirent,
filter: proc "c" (^dirent) -> b32 = nil,
compar: proc "c" ([^]^dirent, [^]^dirent) -> c.int = alphasort,
) -> c.int ---
/*
Close the directory stream referred to by the argument dirp.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/closedir.html ]]
*/
closedir :: proc(dirp: DIR) -> result ---
/*
Equivalent to the opendir() function except that the directory is specified by a file descriptor
rather than by a name.
The file offset associated with the file descriptor at the time of the call determines
which entries are returned.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopendir.html ]]
*/
@(link_name="fdopendir" + INODE_SUFFIX)
fdopendir :: proc(dirp: FD) -> DIR ---
/*
Open a directory stream corresponding to the directory named by the dirname argument.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopendir.html ]]
*/
@(link_name=LOPENDIR)
opendir :: proc(path: cstring) -> DIR ---
/*
Returns a pointer to a structure representing the directory entry at the current position
in the directory stream specified by the argument dirp, and position the directory stream at
the next entry.
Returns nil when the end is reached or an error occurred (which sets errno).
Example:
posix.set_errno(.NONE)
entry := posix.readdir(dirp)
if entry == nil {
if errno := posix.errno(); errno != .NONE {
panic(string(posix.strerror(errno)))
} else {
fmt.println("end of directory stream")
}
} else {
fmt.println(entry)
}
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/readdir.html ]]
*/
@(link_name=LREADDIR)
readdir :: proc(dirp: DIR) -> ^dirent ---
/*
Reset the position of the directory stream to which dirp refers to the beginning of the directory.
It shall also cause the directory stream to refer to the current state of the corresponding directory,
as a call to opendir() would have done.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/rewinddir.html ]]
*/
@(link_name="rewinddir" + INODE_SUFFIX)
rewinddir :: proc(dirp: DIR) ---
/*
The seekdir() function shall set the position of the next readdir() operation on the directory
stream specified by dirp to the position specified by loc.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/seekdir.html ]]
*/
@(link_name="seekdir" + INODE_SUFFIX)
seekdir :: proc(dirp: DIR, loc: dir_loc) ---
/*
The telldir() function shall obtain the current location associated with the directory stream
specified by dirp.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/telldir.html ]]
*/
@(link_name="telldir" + INODE_SUFFIX)
telldir :: proc(dirp: DIR) -> dir_loc ---
// deprecated.
// readdir_r :: proc(DIR, ^dirent, ^^dirent) -> c.int ---
}
DIR :: distinct rawptr
dir_loc :: c.long
// NOTE: `d_type` is not a POSIX standard field, but all targets we support add it.
D_Type :: enum c.uint8_t {
UNKNOWN = 0,
FIFO = 1,
CHR = 2,
DIR = 4,
BLK = 6,
REG = 8,
LNK = 10,
SOCK = 12,
WHT = 14,
}
when ODIN_OS == .NetBSD {
@(private) LALPHASORT :: "__alphasort30"
@(private) LSCANDIR :: "__scandir30"
@(private) LOPENDIR :: "__opendir30"
@(private) LREADDIR :: "__readdir30"
/*
Return a file descriptor referring to the same directory as the dirp argument.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dirfd.html ]]
*/
dirfd :: proc "c" (dirp: DIR) -> FD {
_dirdesc :: struct {
dd_fd: FD,
// more stuff...
}
return (^_dirdesc)(dirp).dd_fd
}
} else {
@(private) LALPHASORT :: "alphasort" + INODE_SUFFIX
@(private) LSCANDIR :: "scandir" + INODE_SUFFIX
@(private) LOPENDIR :: "opendir" + INODE_SUFFIX
@(private) LREADDIR :: "readdir" + INODE_SUFFIX
foreign lib {
/*
Return a file descriptor referring to the same directory as the dirp argument.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dirfd.html ]]
*/
dirfd :: proc(dirp: DIR) -> FD ---
}
}
when ODIN_OS == .Darwin {
dirent :: struct {
d_ino: ino_t, /* [PSX] file number of entry */
d_seekoff: c.uint64_t, /* seek offset */
d_reclen: c.uint16_t, /* length of this record */
d_namelen: c.uint16_t, /* length of string in d_name */
d_type: D_Type, /* file type */
d_name: [1024]c.char `fmt:"s,0"`, /* [PSX] entry name */
}
} else when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD {
dirent :: struct {
d_ino: ino_t, /* [PSX] file number of entry */
d_off: off_t, /* directory offset of the next entry */
d_reclen: c.uint16_t, /* length of this record */
d_type: D_Type, /* file type */
d_namelen: c.uint8_t, /* length of string in d_name */
d_pad0: c.uint32_t,
d_name: [256]c.char `fmt:"s,0"`, /* [PSX] entry name */
}
} else when ODIN_OS == .NetBSD {
dirent :: struct {
d_ino: ino_t, /* [PSX] file number of entry */
d_reclen: c.uint16_t, /* length of this record */
d_namelen: c.uint16_t, /* length of string in d_name */
d_type: D_Type, /* file type */
d_name: [512]c.char `fmt:"s,0"`, /* [PSX] entry name */
}
} else when ODIN_OS == .Linux {
dirent :: struct {
d_ino: u64, /* [PSX] file number of entry */
d_off: i64, /* directory offset of the next entry */
d_reclen: u16, /* length of this record */
d_type: D_Type, /* file type */
d_name: [256]c.char `fmt:"s,0"`, /* [PSX] entry name */
}
} else when ODIN_OS == .Haiku {
dirent :: struct {
d_dev: dev_t, /* device */
d_pdev: dev_t, /* parent device (only for queries) */
d_ino: ino_t, /* inode number */
d_pino: ino_t, /* parent inode (only for queries) */
d_reclen: c.ushort, /* length of this record, not the name */
d_name: [0]c.char `fmt:"s,0"`, /* name of the entry (null byte terminated) */
}
}
|