2 * Copyright (C) 2024, 2025 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
29 private fn unsafe_get_world : world;
30 fn recover_world(w old_w : world) : world;
31 fn atomic_enter~inline(w : world) : world;
32 fn atomic_exit~inline(w : world) : world;
33 fn wait_for_dereferenced(w : world) : world;
34 fn exit(w : world, n : int) : world;
35 fn exit_msg(w : world, n : int, m : bytes) : world;
41 private fn get_args(w : world) : list(bytes);
50 const open_flag_read : int;
51 const open_flag_write : int;
52 const open_flag_append : int;
53 const open_flag_create : int;
54 const open_flag_must_create : int;
55 const open_flag_no_follow : int;
56 const open_mode_ro_current_user : int;
57 const open_mode_ro_all_users : int;
58 const open_mode_rw_current_user : int;
59 const open_mode_read_all_users : int;
60 const open_mode_default : int;
62 fn ropen(w : world, d : dhandle, f : bytes, flags : int) : (world, handle);
63 fn read(w : world, h : handle, size : int) : (world, bytes);
64 fn read_full(w : world, h : handle) : (world, bytes);
65 fn read_partial(w : world, h : handle, size : int) : (world, bytes);
66 fn wopen(w : world, d : dhandle, f : bytes, flags : int, mode : int) : (world, handle);
67 fn write(w : world, h : handle, s : bytes) : world;
68 fn wcontiguous(w : world, h : handle, size : int64) : world;
70 fn ropen_lazy(d : dhandle, f : bytes, flags : int) : handle;
71 fn read_lazy~lazy(r : handle) : bytes;
73 private fn read_console_packet(w : world, h : handle) : (world, list(int32));
74 private fn write_console_packet(w : world, h : handle, cp : list(int32)) : world;
76 fn pipe(w : world) : (world, handle, handle);
78 fn bopen(w : world, d : dhandle, f : bytes, flags : int, mode : int) : (world, handle);
79 fn bread(w : world, h : handle, position : int64, size : int) : (world, bytes);
80 fn bwrite(w : world, h : handle, position : int64, s : bytes) : world;
81 fn bsize(w : world, h : handle) : (world, int64);
82 fn bdata(w : world, h : handle, off : int64) : (world, int64);
83 fn bhole(w : world, h : handle, off : int64) : (world, int64);
84 fn bsetsize(w : world, h : handle, size : int64) : world;
85 fn bcontiguous(w : world, h : handle, pos : int64, size : int64) : world;
86 fn bclone(w : world, src_h : handle, src_pos : int64, dst_h : handle, dst_pos : int64, size : int64) : world;
87 fn bopen_lazy(d : dhandle, f : bytes, flags : int) : handle;
88 fn bread_lazy~lazy(h : handle, position : int64) : bytes;
89 fn bsize_lazy(h : handle) : int64;
90 fn bdata_lazy(h : handle, off : int64) : int64;
91 fn bhole_lazy(h : handle, off : int64) : int64;
93 fn fdatasync(w : world, h : handle) : world;
94 fn fsync(w : world, h : handle) : world;
95 fn ffssync(w : world, h : handle) : world;
96 fn sync(w : world) : world;
98 fn droot(w : world) : dhandle;
99 private fn dcwd(w : world) : dhandle;
100 private fn dlib(w : world) : dhandle;
101 private fn dexe(w : world) : dhandle;
102 fn dnone(w : world) : dhandle;
103 private fn libpath : bytes;
104 fn dopen(w : world, d : dhandle, f : bytes, flags : int) : (world, dhandle);
105 fn dread(w : world, d : dhandle) : (world, list(bytes));
106 fn dpath(w : world, d : dhandle) : (world, bytes);
107 fn dopen_lazy(d : dhandle, f : bytes, flags : int) : dhandle;
108 fn dread_lazy(d : dhandle) : list(bytes);
109 fn dpath_lazy(d : dhandle) : bytes;
110 fn dmonitor(w : world, d : dhandle) : (world, world);
112 const stat_flag_devmajor : int;
113 const stat_flag_devminor : int;
114 const stat_flag_inode : int;
115 const stat_flag_type : int;
116 const stat_flag_mode : int;
117 const stat_flag_nlink : int;
118 const stat_flag_uid : int;
119 const stat_flag_gid : int;
120 const stat_flag_rdevmajor : int;
121 const stat_flag_rdevminor : int;
122 const stat_flag_size : int;
123 const stat_flag_optimaliosize : int;
124 const stat_flag_allocated : int;
125 const stat_flag_atime : int;
126 const stat_flag_mtime : int;
127 const stat_flag_ctime : int;
129 const stat_type_file : int;
130 const stat_type_directory : int;
131 const stat_type_link : int;
132 const stat_type_fifo : int;
133 const stat_type_chardev : int;
134 const stat_type_blockdev : int;
135 const stat_type_socket : int;
137 fn stat(w : world, d : dhandle, f : bytes, flags : int) : (world, list(int64));
138 fn lstat(w : world, d : dhandle, f : bytes, flags : int) : (world, list(int64));
139 fn fstat(w : world, h : handle, flags : int) : (world, list(int64));
141 fn stat_lazy(d : dhandle, f : bytes, flags : int) : list(int64);
142 fn lstat_lazy(d : dhandle, f : bytes, flags : int) : list(int64);
143 fn fstat_lazy(h : handle, flags : int) : list(int64);
145 const statfs_flag_bsize : int;
146 const statfs_flag_frsize : int;
147 const statfs_flag_frtotal : int;
148 const statfs_flag_frfree : int;
149 const statfs_flag_fravail : int;
150 const statfs_flag_intotal : int;
151 const statfs_flag_infree : int;
152 const statfs_flag_inavail : int;
153 const statfs_flag_fsid : int;
154 const statfs_flag_flags : int;
155 const statfs_flag_namelen : int;
157 const statfs_st_readonly : int;
158 const statfs_st_nosuid : int;
159 const statfs_st_nodev : int;
160 const statfs_st_noexec : int;
161 const statfs_st_synchronous : int;
162 const statfs_st_mandlock : int;
163 const statfs_st_noatime : int;
164 const statfs_st_nodiratime : int;
165 const statfs_st_relatime : int;
167 fn fstatfs(w : world, h : handle, flags : int) : (world, list(int64));
168 fn dstatfs(w : world, d : dhandle, flags : int) : (world, list(int64));
170 fn readlink(w : world, d : dhandle, f : bytes) : (world, bytes);
171 fn readlink_lazy(d : dhandle, f : bytes) : bytes;
173 fn unlink(w : world, d : dhandle, f : bytes) : world;
174 fn rmdir(w : world, d : dhandle, f : bytes) : world;
175 fn mkdir(w : world, d : dhandle, f : bytes, mode : int) : world;
176 fn mkpipe(w : world, d : dhandle, f : bytes, mode : int) : world;
177 fn mksocket(w : world, d : dhandle, f : bytes, mode : int) : world;
178 fn mkchardev(w : world, d : dhandle, f : bytes, mode major minor : int) : world;
179 fn mkblockdev(w : world, d : dhandle, f : bytes, mode major minor : int) : world;
180 fn mksymlink(w : world, d : dhandle, f t : bytes) : world;
181 fn mklink(w : world, d : dhandle, f : bytes, e : dhandle, t : bytes) : world;
182 fn rename(w : world, d : dhandle, f : bytes, e : dhandle, t : bytes) : world;
183 fn chmod(w : world, d : dhandle, f : bytes, m : int) : world;
184 fn chown(w : world, d : dhandle, f : bytes, uid gid : int) : world;
185 fn lchown(w : world, d : dhandle, f : bytes, uid gid : int) : world;
186 fn utime(w : world, d : dhandle, f : bytes, atime mtime : int64) : world;
187 fn lutime(w : world, d : dhandle, f : bytes, atime mtime : int64) : world;
188 fn mount_points(w : world) : (world, list(bytes));
190 const stty_flag_raw : int;
191 const stty_flag_noecho : int;
192 const stty_flag_nosignal : int;
193 const stty_flag_nocrlf : int;
195 fn stty(w : world, h : handle, flags : int) : world;
196 fn tty_size(w : world, h : handle) : (world, int, int, int, int);
197 fn tty_background(w : world) : world;
198 fn tty_foreground(w : world) : (world, bool);
200 const uname_flag_ajla_version : int;
201 const uname_flag_flavor : int;
202 const uname_flag_system : int;
203 const uname_flag_release : int;
204 const uname_flag_version : int;
205 const uname_flag_machine : int;
207 fn uname(flags : int) : list(bytes);
208 fn get_host_name(w : world) : (world, bytes);
210 fn get_real_time(w : world) : (world, int64);
211 fn get_monotonic_time(w : world) : (world, int64);
212 fn sleep(t : type, w : t, tm : int64) : t;
218 const path_separator : byte;
219 fn path_is_separator(b : byte) : bool;
220 fn path_is_dir_separator(b : byte) : bool;
221 fn path_compare(a b : bytes) : bool;
222 fn path_is_absolute(p : bytes) : bool;
223 fn path_is_root(p : bytes) : bool;
224 fn path_to_dir_file(p : bytes) : (bytes, bytes);
225 fn path_append(pd pf : bytes) : bytes;
226 fn path_contract(p : bytes) : bytes;
227 fn path_join(pd pf : bytes) : bytes;
228 fn path_canonical(w : world, d : dhandle, p : bytes) : (world, bytes);
229 fn path_get_cwd(implicit w : world, d : dhandle, env : treemap(bytes, bytes)) : (world, bytes);
230 fn path_shortcut_home(home : maybe(bytes), p : bytes) : bytes;
231 fn path_expand_home(home : maybe(bytes), p : bytes) : bytes;
232 fn path_mkdir(w : world, d : dhandle, f : bytes, mode : int) : world;
233 fn path_xdg(implicit w : world, env : treemap(bytes, bytes), xdg_env : bytes, deflt : bytes, appname : bytes) : (world, dhandle);
234 fn path_config(w : world, env : treemap(bytes, bytes), appname : bytes) : (world, dhandle);
235 fn path_write_atomic(w : world, d : dhandle, f : bytes, content : bytes) : world;
241 fn register_dependence(w : world, d : dhandle, p : bytes) : world;
257 fn unsafe_get_world : world
262 fn recover_world(w old_w : world) : world
264 if is_exception w then
269 fn atomic_enter~inline(w : world) : world
272 pcode IO IO_Atomic_Enter 1 1 0 =w2 w;
276 fn atomic_exit~inline(w : world) : world
279 pcode IO IO_Atomic_Exit 1 1 0 =w2 w;
283 fn wait_for_dereferenced(w : world) : world
286 pcode IO IO_Wait_For_Dereferenced 1 1 0 =w2 w;
290 fn exit(w : world, n : int) : world
292 var exc := exception_make(world, ec_exit, error_exit, n, false);
296 fn exit_msg(w : world, n : int, m : bytes) : world
298 var exc := exception_make_str(world, ec_exit, error_exit, n, false, m);
306 fn get_args(w : world) : list(bytes)
309 pcode IO IO_Get_Args 1 1 0 =r w;
317 type handle := internal_type;
318 type dhandle := internal_type;
320 const open_flag_read : int := IO_Open_Flag_Read;
321 const open_flag_write : int := IO_Open_Flag_Write;
322 const open_flag_append : int := IO_Open_Flag_Append;
323 const open_flag_create : int := IO_Open_Flag_Create;
324 const open_flag_must_create : int := IO_Open_Flag_Must_Create;
325 const open_flag_no_follow : int := IO_Open_Flag_No_Follow;
326 const open_mode_ro_current_user : int := #100;
327 const open_mode_ro_all_users : int := #124;
328 const open_mode_rw_current_user : int := #180;
329 const open_mode_read_all_users : int := #1a4;
330 const open_mode_default : int := #1b6;
332 fn ropen(w : world, d : dhandle, f : bytes, flags : int) : (world, handle)
337 pcode IO IO_Stream_Open_Read 2 5 0 =w2 =h w d f flags mode;
341 fn read(w : world, h : handle, size : int) : (world, bytes)
343 var read_so_far := 0;
345 while read_so_far < size do [
348 w2, s1 := read_partial~strict(w, h, size - read_so_far);
359 fn read_full(w : world, h : handle) : (world, bytes)
365 w2, s1 := read_partial~strict(w, h, 16384);
375 fn read_partial(w : world, h : handle, size : int) : (world, bytes)
379 pcode IO IO_Stream_Read_Partial 2 3 0 =w2 =s w h size;
383 fn wopen(w : world, d : dhandle, f : bytes, flags : int, mode : int) : (world, handle)
387 pcode IO IO_Stream_Open_Write 2 5 0 =w2 =h w d f flags mode;
391 fn write(w : world, h : handle, s : bytes) : world
393 while len_greater_than(byte, s, 0) do [
396 pcode IO IO_Stream_Write 2 3 0 =w2 =sz w h s;
403 fn wcontiguous(implicit w : world, h : handle, size : int64) : world
405 var offset := bsize(h);
406 bcontiguous(w, h, offset, size);
409 fn ropen_lazy(d : dhandle, f : bytes, flags : int) : handle
412 var w := unsafe_get_world;
413 w, h := ropen(w, d, f, flags);
417 fn read_lazy~lazy(r : handle) : bytes
420 var w := unsafe_get_world;
421 w, b := read_partial~strict(w, r, 16384);
424 return b + read_lazy(r);
427 fn read_console_packet(w : world, h : handle) : (world, list(int32))
429 var cp : list(int32);
431 pcode IO IO_Read_Console_Packet 2 2 0 =w2 =cp w h;
435 fn write_console_packet(w : world, h : handle, cp : list(int32)) : world
438 pcode IO IO_Write_Console_Packet 1 3 0 =w2 w h cp;
442 fn pipe(w : world) : (world, handle, handle)
444 var rh : handle, wh : handle;
446 pcode IO IO_Pipe 3 1 0 =w2 =rh =wh w;
450 fn bopen(w : world, d : dhandle, f : bytes, flags : int, mode : int) : (world, handle)
454 pcode IO IO_Block_Open 2 5 0 =w2 =h w d f flags mode;
458 fn bread(w : world, h : handle, position : int64, size : int) : (world, bytes)
462 pcode IO IO_Block_Read 2 4 0 =w2 =s w h size position;
466 fn bwrite(w : world, h : handle, position : int64, s : bytes) : world
468 while len_greater_than(byte, s, 0) do [
471 pcode IO IO_Block_Write 2 4 0 =w2 =sz w h s position;
479 fn bsize(w : world, h : handle) : (world, int64)
483 var off : int64 := 0;
484 pcode IO IO_LSeek 2 3 1 =w2 =sz w h off 2;
488 fn bdata(w : world, h : handle, off : int64) : (world, int64)
492 pcode IO IO_LSeek 2 3 1 =w2 =sz w h off 3;
496 fn bhole(w : world, h : handle, off : int64) : (world, int64)
500 pcode IO IO_LSeek 2 3 1 =w2 =sz w h off 4;
504 fn bsetsize(w : world, h : handle, size : int64) : world
507 pcode IO IO_FTruncate 1 3 0 =w2 w h size;
511 fn bcontiguous(w : world, h : handle, pos : int64, size : int64) : world
514 pcode IO IO_FAllocate 1 4 0 =w2 w h pos size;
518 fn bclone(w : world, src_h : handle, src_pos : int64, dst_h : handle, dst_pos : int64, size : int64) : world
521 pcode IO IO_CloneRange 1 6 0 =w2 w src_h src_pos dst_h dst_pos size;
525 fn bopen_lazy(d : dhandle, f : bytes, flags : int) : handle
528 if flags <> IO_Open_Flag_Read then [
529 h := exception_make(handle, ec_sync, error_invalid_operation, 0, true);
532 var w := unsafe_get_world;
533 w, h := bopen(w, d, f, flags, 0);
537 fn bread_lazy~lazy(h : handle, position : int64) : bytes
540 var w := unsafe_get_world;
541 w, b := bread(w, h, position, 16384);
542 if len(b) < 16384 then
544 return b + bread_lazy(h, position + 16384);
547 fn bsize_lazy(h : handle) : int64
550 var w := unsafe_get_world;
551 w, sz := bsize(w, h);
555 fn bdata_lazy(h : handle, off : int64) : int64
558 var w := unsafe_get_world;
559 w, sz := bdata(w, h, off);
563 fn bhole_lazy(h : handle, off : int64) : int64
566 var w := unsafe_get_world;
567 w, sz := bhole(w, h, off);
571 fn fdatasync(w : world, h : handle) : world
574 pcode IO IO_FSync 1 2 1 =w2 w h 0;
578 fn fsync(w : world, h : handle) : world
581 pcode IO IO_FSync 1 2 1 =w2 w h 1;
585 fn ffssync(w : world, h : handle) : world
588 pcode IO IO_FSync 1 2 1 =w2 w h 2;
592 fn sync(w : world) : world
595 pcode IO IO_Sync 1 1 0 =w2 w;
599 fn droot(w : world) : dhandle
602 pcode IO IO_Root_Dir 1 1 1 =dh w 1;
606 fn dcwd(w : world) : dhandle
609 pcode IO IO_Root_Dir 1 1 1 =dh w 2;
613 fn dlib(w : world) : dhandle
616 pcode IO IO_Root_Dir 1 1 1 =dh w 3;
620 fn dexe(w : world) : dhandle
623 pcode IO IO_Root_Dir 1 1 1 =dh w 4;
627 fn dnone(w : world) : dhandle
630 pcode IO IO_Root_Dir 1 1 1 =dh w 5;
634 private fn libpath : bytes
637 pcode IO IO_Lib_Path 1 0 0 =lp;
641 fn dopen(w : world, d : dhandle, f : bytes, flags : int) : (world, dhandle)
645 pcode IO IO_Open_Dir 2 4 0 =w2 =dh w d f flags;
649 fn dread(w : world, d : dhandle) : (world, list(bytes))
651 var res : list(bytes);
653 pcode IO IO_Read_Dir 2 2 0 =w2 =res w d;
657 fn dpath(w : world, d : dhandle) : (world, bytes)
661 pcode IO IO_Dir_Path 2 2 0 =w2 =res w d;
665 fn dopen_lazy(d : dhandle, f : bytes, flags : int) : dhandle
668 var w := unsafe_get_world;
669 w, res := dopen(w, d, f, flags);
673 fn dread_lazy(d : dhandle) : list(bytes)
675 var res : list(bytes);
676 var w := unsafe_get_world;
677 w, res := dread(w, d);
681 fn dpath_lazy(d : dhandle) : bytes
684 var w := unsafe_get_world;
685 w, res := dpath(w, d);
689 type mhandle := internal_type;
691 fn dmonitor_wait(w2 : world, h : mhandle) : world
694 pcode IO IO_DMonitor_Wait 1 2 0 =w3 w2 h;
698 fn dmonitor(w : world, d : dhandle) : (world, world)
702 pcode IO IO_DMonitor_Prepare 2 2 0 =w2 =h w d;
703 w3 := dmonitor_wait~spark(w2, h);
707 const stat_flag_devmajor : int := IO_Stat_Flag_DevMajor;
708 const stat_flag_devminor : int := IO_Stat_Flag_DevMinor;
709 const stat_flag_inode : int := IO_Stat_Flag_Inode;
710 const stat_flag_type : int := IO_Stat_Flag_Type;
711 const stat_flag_mode : int := IO_Stat_Flag_Mode;
712 const stat_flag_nlink : int := IO_Stat_Flag_NLink;
713 const stat_flag_uid : int := IO_Stat_Flag_UID;
714 const stat_flag_gid : int := IO_Stat_Flag_GID;
715 const stat_flag_rdevmajor : int := IO_Stat_Flag_RDevMajor;
716 const stat_flag_rdevminor : int := IO_Stat_Flag_RDevMinor;
717 const stat_flag_size : int := IO_Stat_Flag_Size;
718 const stat_flag_optimaliosize : int := IO_Stat_Flag_OptimalIOSize;
719 const stat_flag_allocated : int := IO_Stat_Flag_Allocated;
720 const stat_flag_atime : int := IO_Stat_Flag_ATime;
721 const stat_flag_mtime : int := IO_Stat_Flag_MTime;
722 const stat_flag_ctime : int := IO_Stat_Flag_CTime;
724 const stat_type_file : int := IO_Stat_Type_File;
725 const stat_type_directory : int := IO_Stat_Type_Directory;
726 const stat_type_link : int := IO_Stat_Type_Link;
727 const stat_type_fifo : int := IO_Stat_Type_Pipe;
728 const stat_type_chardev : int := IO_Stat_Type_CharDev;
729 const stat_type_blockdev : int := IO_Stat_Type_BlockDev;
730 const stat_type_socket : int := IO_Stat_Type_Socket;
732 fn stat(w : world, d : dhandle, f : bytes, flags : int) : (world, list(int64))
734 var res : list(int64);
736 pcode IO IO_Stat 2 4 1 =w2 =res w d f flags 1;
740 fn lstat(w : world, d : dhandle, f : bytes, flags : int) : (world, list(int64))
742 var res : list(int64);
744 pcode IO IO_Stat 2 4 1 =w2 =res w d f flags 2;
748 fn fstat(w : world, h : handle, flags : int) : (world, list(int64))
750 var res : list(int64);
752 pcode IO IO_FStat 2 3 0 =w2 =res w h flags;
756 fn stat_lazy(d : dhandle, f : bytes, flags : int) : list(int64)
758 var res : list(int64);
759 var w := unsafe_get_world;
760 w, res := stat(w, d, f, flags);
764 fn lstat_lazy(d : dhandle, f : bytes, flags : int) : list(int64)
766 var res : list(int64);
767 var w := unsafe_get_world;
768 w, res := lstat(w, d, f, flags);
772 fn fstat_lazy(h : handle, flags : int) : list(int64)
774 var res : list(int64);
775 var w := unsafe_get_world;
776 w, res := fstat(w, h, flags);
780 const statfs_flag_bsize : int := IO_StatFS_Flag_BSize;
781 const statfs_flag_frsize : int := IO_StatFS_Flag_FrSize;
782 const statfs_flag_frtotal : int := IO_StatFS_Flag_FrTotal;
783 const statfs_flag_frfree : int := IO_StatFS_Flag_FrFree;
784 const statfs_flag_fravail : int := IO_StatFS_Flag_FrAvail;
785 const statfs_flag_intotal : int := IO_StatFS_Flag_InTotal;
786 const statfs_flag_infree : int := IO_StatFS_Flag_InFree;
787 const statfs_flag_inavail : int := IO_StatFS_Flag_InAvail;
788 const statfs_flag_fsid : int := IO_StatFS_Flag_FSId;
789 const statfs_flag_flags : int := IO_StatFS_Flag_Flags;
790 const statfs_flag_namelen : int := IO_StatFS_Flag_NameLen;
792 const statfs_st_readonly : int := IO_StatFS_ST_ReadOnly;
793 const statfs_st_nosuid : int := IO_StatFS_ST_NoSuid;
794 const statfs_st_nodev : int := IO_StatFS_ST_NoDev;
795 const statfs_st_noexec : int := IO_StatFS_ST_NoExec;
796 const statfs_st_synchronous : int := IO_StatFS_ST_Synchronous;
797 const statfs_st_mandlock : int := IO_StatFS_ST_MandLock;
798 const statfs_st_noatime : int := IO_StatFS_ST_NoAtime;
799 const statfs_st_nodiratime : int := IO_StatFS_ST_NoDirAtime;
800 const statfs_st_relatime : int := IO_StatFS_ST_RelAtime;
802 fn fstatfs(w : world, h : handle, flags : int) : (world, list(int64))
804 var res : list(int64);
806 pcode IO IO_FStatFS 2 3 0 =w2 =res w h flags;
810 fn dstatfs(w : world, d : dhandle, flags : int) : (world, list(int64))
812 var res : list(int64);
814 pcode IO IO_DStatFS 2 3 0 =w2 =res w d flags;
818 fn readlink(w : world, d : dhandle, f : bytes) : (world, bytes)
822 pcode IO IO_ReadLink 2 3 0 =w2 =res w d f;
826 fn readlink_lazy(d : dhandle, f : bytes) : bytes
829 var w := unsafe_get_world;
830 w, res := readlink(w, d, f);
834 fn unlink(w : world, d : dhandle, f : bytes) : world
837 pcode IO IO_Dir_Action 1 3 1 =w2 w d f IO_Action_Rm;
841 fn rmdir(w : world, d : dhandle, f : bytes) : world
844 pcode IO IO_Dir_Action 1 3 1 =w2 w d f IO_Action_Rm_Dir;
848 fn mkdir(w : world, d : dhandle, f : bytes, mode : int) : world
851 pcode IO IO_Dir_Action 1 4 1 =w2 w d f mode IO_Action_Mk_Dir;
855 fn mkpipe(w : world, d : dhandle, f : bytes, mode : int) : world
858 pcode IO IO_Dir_Action 1 4 1 =w2 w d f mode IO_Action_Mk_Pipe;
862 fn mksocket(w : world, d : dhandle, f : bytes, mode : int) : world
865 pcode IO IO_Dir_Action 1 4 1 =w2 w d f mode IO_Action_Mk_Socket;
869 fn mkchardev(w : world, d : dhandle, f : bytes, mode major minor : int) : world
872 pcode IO IO_Dir_Action 1 6 1 =w2 w d f mode major minor IO_Action_Mk_CharDev;
876 fn mkblockdev(w : world, d : dhandle, f : bytes, mode major minor : int) : world
879 pcode IO IO_Dir_Action 1 6 1 =w2 w d f mode major minor IO_Action_Mk_BlockDev;
883 fn mksymlink(w : world, d : dhandle, f t : bytes) : world
886 pcode IO IO_Dir_Action 1 4 1 =w2 w d f t IO_Action_Mk_SymLink;
890 fn mklink(w : world, d : dhandle, f : bytes, e : dhandle, t : bytes) : world
893 pcode IO IO_Dir2_Action 1 5 1 =w2 w d f e t IO_Action_Mk_Link;
897 fn rename(w : world, d : dhandle, f : bytes, e : dhandle, t : bytes) : world
900 pcode IO IO_Dir2_Action 1 5 1 =w2 w d f e t IO_Action_Rename;
904 fn chmod(w : world, d : dhandle, f : bytes, m : int) : world
907 pcode IO IO_Dir_Action 1 4 1 =w2 w d f m IO_Action_ChMod;
911 fn chown(w : world, d : dhandle, f : bytes, uid gid : int) : world
914 pcode IO IO_Dir_Action 1 5 1 =w2 w d f uid gid IO_Action_ChOwn;
918 fn lchown(w : world, d : dhandle, f : bytes, uid gid : int) : world
921 pcode IO IO_Dir_Action 1 5 1 =w2 w d f uid gid IO_Action_LChOwn;
925 fn utime(w : world, d : dhandle, f : bytes, atime mtime : int64) : world
928 pcode IO IO_Dir_Action 1 5 1 =w2 w d f mtime atime IO_Action_UTime;
932 fn lutime(w : world, d : dhandle, f : bytes, atime mtime : int64) : world
935 pcode IO IO_Dir_Action 1 5 1 =w2 w d f mtime atime IO_Action_LUTime;
939 fn mount_points(implicit w : world) : (world, list(bytes))
941 var result := empty(bytes);
942 var os := sysprop(SystemProperty_OS);
943 if os = SystemProperty_OS_DOS or
944 os = SystemProperty_OS_OS2 or
945 os = SystemProperty_OS_Windows or
946 os = SystemProperty_OS_Cygwin then [
949 var is_minix := uname(uname_flag_system)[0] = "Minix";
951 var d := ropen(dnone(), "/etc/mtab", 0);
952 if not is_exception w then
956 d := ropen(dnone(), "/proc/mounts", 0);
957 if not is_exception w then
963 var mtab := read_full(d);
964 var lines := list_break_to_lines(mtab);
966 if len(l) = 0 or l[0] = '#' then
968 var brk := list_break_whitespace(l);
974 if is_exception q then
977 var qh := dopen(dnone(), q, 0);
978 var st := dstatfs(qh, statfs_flag_frtotal);
979 if is_exception st then [
983 //eval debug(q + " " + ntos(st[0]));
987 result := list_sort(result);
993 pcode IO IO_Drives 2 1 0 =w2 =drvs w;
995 return w, list_break(drvs, 0);
999 const stty_flag_raw : int := IO_Stty_Flag_Raw;
1000 const stty_flag_noecho : int := IO_Stty_Flag_Noecho;
1001 const stty_flag_nosignal : int := IO_Stty_Flag_Nosignal;
1002 const stty_flag_nocrlf : int := IO_Stty_Flag_NoCRLF;
1004 fn stty(w : world, h : handle, flags : int) : world
1007 pcode IO IO_Stty 1 3 0 =w2 w h flags;
1011 fn tty_size(w : world, h : handle) : (world, int, int, int, int)
1013 var nx ny ox oy : int;
1015 pcode IO IO_Tty_Size 5 2 0 =w2 =nx =ny =ox =oy w h;
1016 return w2, nx, ny, ox, oy;
1019 fn tty_background(w : world) : world
1022 pcode IO IO_Tty_Background 1 1 0 =w2 w;
1026 fn tty_foreground(w : world) : (world, bool)
1030 pcode IO IO_Tty_Foreground 2 1 0 =w2 =b w;
1035 const uname_flag_ajla_version : int := IO_UName_Flag_Ajla_Version;
1036 const uname_flag_flavor : int := IO_UName_Flag_Flavor;
1037 const uname_flag_system : int := IO_UName_Flag_System;
1038 const uname_flag_release : int := IO_UName_Flag_Release;
1039 const uname_flag_version : int := IO_UName_Flag_Version;
1040 const uname_flag_machine : int := IO_UName_Flag_Machine;
1042 fn uname(flags : int) : list(bytes)
1044 var res : list(bytes);
1045 pcode IO IO_UName 1 1 0 =res flags;
1049 fn get_host_name(w : world) : (world, bytes)
1053 pcode IO IO_GetHostName 2 1 0 =w2 =res w;
1058 fn get_real_time(w : world) : (world, int64)
1062 pcode IO IO_GetTime 2 1 1 =w2 =ret w 1;
1066 fn get_monotonic_time(w : world) : (world, int64)
1070 pcode IO IO_GetTime 2 1 1 =w2 =ret w 2;
1074 fn sleep(t : type, w : t, tm : int64) : t
1080 w3, u := get_monotonic_time(unsafe_get_world);
1082 pcode IO IO_Sleep 1 2 0 =w2 w u;
1090 const path_separator : byte
1092 var os := sysprop(SystemProperty_OS);
1093 if os = SystemProperty_OS_DOS or
1094 os = SystemProperty_OS_OS2 or
1095 os = SystemProperty_OS_Windows then
1100 fn path_is_separator(b : byte) : bool
1102 if b = '\' or b = ':' then [
1103 var os := sysprop(SystemProperty_OS);
1104 if os = SystemProperty_OS_DOS or
1105 os = SystemProperty_OS_OS2 or
1106 os = SystemProperty_OS_Cygwin or
1107 os = SystemProperty_OS_Windows then
1113 fn path_is_dir_separator(b : byte) : bool
1116 var os := sysprop(SystemProperty_OS);
1117 if os = SystemProperty_OS_DOS or
1118 os = SystemProperty_OS_OS2 or
1119 os = SystemProperty_OS_Cygwin or
1120 os = SystemProperty_OS_Windows then
1126 fn path_compare(a b : bytes) : bool
1128 var os := sysprop(SystemProperty_OS);
1129 if os = SystemProperty_OS_DOS or
1130 os = SystemProperty_OS_OS2 or
1131 os = SystemProperty_OS_Windows then [
1132 if len(a) <> len(b) then
1134 for i := 0 to len(a) do [
1137 if a1 >= 'a', a1 <= 'z' then
1139 if b1 >= 'a', b1 <= 'z' then
1149 fn dos_path_is_absolute(p : bytes) : bool
1151 if len_at_least(p, 3), (p[0] and #DF) >= 'A', (p[0] and #DF) <= 'Z', p[1] = ':', path_is_dir_separator(p[2]) then
1153 if len_at_least(p, 2), path_is_dir_separator(p[0]), path_is_dir_separator(p[1]) then
1158 fn path_is_absolute(p : bytes) : bool
1160 var os := sysprop(SystemProperty_OS);
1161 if os = SystemProperty_OS_DOS or
1162 os = SystemProperty_OS_OS2 or
1163 os = SystemProperty_OS_Windows then [
1164 return dos_path_is_absolute(p);
1166 if len_at_least(p, 1), path_is_dir_separator(p[0]) then
1168 if os = SystemProperty_OS_Cygwin then
1169 return dos_path_is_absolute(p);
1173 fn path_is_root(p : bytes) : bool
1175 p := path_contract(p);
1176 if len(p) = 1, path_is_dir_separator(p[0]) then
1178 var os := sysprop(SystemProperty_OS);
1179 if os = SystemProperty_OS_DOS or
1180 os = SystemProperty_OS_OS2 or
1181 os = SystemProperty_OS_Cygwin or
1182 os = SystemProperty_OS_Windows then [
1183 if len(p) = 3, (p[0] and #DF) >= 'A', (p[0] and #DF) <= 'Z', p[1] = ':', path_is_dir_separator(p[2]) then
1189 fn path_to_dir_file(p : bytes) : (bytes, bytes)
1191 var idx := list_search_backwards_fn(p, path_is_separator);
1192 var dir := p[ .. idx + 1];
1193 var file := p[idx + 1 .. ];
1194 if file = "." or file = ".." then [
1195 dir := p +< path_separator;
1199 dir := "." + bytes.[ path_separator ];
1200 if len(dir) > 1 then
1201 dir := dir[ .. len(dir) - 1];
1205 fn path_append(pd pf : bytes) : bytes
1207 if len(pd) > 0, not path_is_separator(pd[len(pd) - 1]) then
1208 pd += bytes.[ path_separator ];
1212 fn path_contract_unix(p : bytes, trim_dot : bool) : bytes
1214 for i := 0 to len(p) do [
1215 if path_is_dir_separator(p[i]) then
1218 var leading_slash := false;
1219 if len_at_least(p, 1), p[0] = '/' then [
1221 leading_slash := true;
1223 var components := list_break(p, '/');
1224 var result := empty(bytes);
1225 for i := 0 to len(components) do [
1226 if components[i] = "" then
1228 if components[i] = ".", trim_dot then
1230 if components[i] = ".." then [
1231 if len(result) >= 1 then [
1232 if result[len(result) - 1] = ".." then
1234 result := result[ .. len(result) - 1];
1237 if leading_slash then
1242 result +<= components[i];
1245 if leading_slash then
1246 r +<= path_separator;
1247 for i := 0 to len(result) do [
1249 r +<= path_separator;
1257 fn path_contract(p : bytes) : bytes
1259 if path_is_separator(':') then [
1260 if len_at_least(p, 2), (p[0] and #DF) >= 'A', (p[0] and #DF) <= 'Z', p[1] = ':' then
1261 return p[ .. 2] + path_contract_unix(p[2 .. ], true);
1262 if len_at_least(p, 2), path_is_dir_separator(p[0]), path_is_dir_separator(p[1]) then
1263 return [ path_separator ] + path_contract_unix(p[1 .. ], false);
1265 return path_contract_unix(p, true);
1268 fn path_join(pd pf : bytes) : bytes
1270 if path_is_absolute(pf) then
1271 return path_contract(pf);
1272 if path_is_separator(':') then [
1273 if len_at_least(pf, 1), path_is_separator(pf[0]) then [
1274 if len_at_least(pd, 2), (pd[0] and #DF) >= 'A', (pd[0] and #DF) <= 'Z', pd[1] = ':' then [
1275 return path_contract(pd[ .. 2] + pf);
1277 if len_at_least(pd, 2), path_is_dir_separator(pd[0]), path_is_dir_separator(pd[1]) then [
1278 return path_contract(pd[ .. 1] + pf);
1280 return path_contract(pf);
1282 if len_at_least(pf, 2), (pf[0] and #DF) >= 'A', (pf[0] and #DF) <= 'Z', pf[1] = ':' then [
1283 if len_at_least(pd, 3), (pd[0] and #DF) = (pf[0] and #DF), pd[1] = ':', path_is_dir_separator(pd[2]) then [
1286 return path_contract(pf[ .. 2] + [ path_separator ] + pf[2 .. ]);
1290 return path_contract(path_append(pd, pf));
1293 fn path_canonical(implicit w : world, d : dhandle, p : bytes) : (world, bytes)
1295 var dir, file := path_to_dir_file(p);
1296 var pd := dopen(d, dir, 0);
1297 var pdp := dpath(pd);
1298 var pj := path_append(pdp, file);
1302 fn path_get_cwd(implicit w : world, d : dhandle, env : treemap(bytes, bytes)) : (world, bytes)
1305 var t := treemap_search(env, "PWD");
1306 if t is j, path_is_absolute(t.j) then [
1307 var ctr := path_contract(t.j);
1309 var pd2 := dopen(dnone(), ctr, 0);
1310 if is_exception pd2 then [
1311 recover_world(old_w);
1315 var p2 := dpath(pd2);
1316 if is_exception p2 then [
1317 recover_world(old_w);
1326 fn path_shortcut_home(home : maybe(bytes), p : bytes) : bytes
1330 if not path_is_absolute(home.j) then
1332 var h := path_contract(home.j);
1335 if len(h) < len(p), path_compare(h, p[ .. len(h)]), path_is_dir_separator(p[len(h)]) then
1336 return "~" + p[len(h) .. ];
1340 fn path_expand_home(home : maybe(bytes), p : bytes) : bytes
1345 if not path_is_absolute(h) then
1347 h := path_contract(h);
1350 if len(p) >= 2, p[0] = '~', path_is_dir_separator(p[1]) then [
1352 while len(p) > i, path_is_dir_separator(p[i]) do
1354 return path_append(h, p[i .. ]);
1359 fn path_mkdir_step(implicit w : world, d : dhandle, f : bytes, mode : int) : world
1363 if is_exception w then [
1364 if exception_type w = error_system, exception_aux w = system_error_eexist then [
1370 fn path_mkdir(implicit w : world, d : dhandle, f : bytes, mode : int) : world
1373 path_mkdir_step(d, f, mode);
1374 if not is_exception w then
1379 while i < len(f), path_is_separator(f[i]) do
1381 if i = 0, path_is_absolute(f) then [
1382 while i < len(f), not path_is_separator(f[i]) do
1384 while i < len(f), path_is_separator(f[i]) do
1388 while i < len(f) do [
1389 while i < len(f), not path_is_separator(f[i]) do
1391 while i < len(f), path_is_separator(f[i]) do
1393 path_mkdir_step(d, f[ .. i], mode);
1398 fn path_xdg(implicit w : world, env : treemap(bytes, bytes), xdg_env : bytes, deflt : bytes, appname : bytes) : (world, dhandle)
1403 var x := treemap_search(env, xdg_env);
1405 if path_is_absolute(x.j) then [
1410 if sysprop(SystemProperty_OS) = SystemProperty_OS_Windows then [
1411 x := treemap_search(env, "APPDATA");
1415 x := treemap_search(env, "HOME");
1418 var a := path_append(x.j, deflt);
1419 if path_is_absolute(a) then [
1426 d := path_append(d, appname);
1427 path_mkdir(dnone(), d, #1c0);
1428 if is_exception w then [
1429 if len(deflt) > 0, deflt[0] = '.' then [
1431 deflt := deflt[1 .. ];
1435 return dopen(dnone(), d, 0);
1438 fn path_config(implicit w : world, env : treemap(bytes, bytes), appname : bytes) : (world, dhandle)
1440 return path_xdg(env, "XDG_CONFIG_HOME", ".config", appname);
1443 fn path_write_atomic(implicit w : world, d : dhandle, f : bytes, content : bytes) : world
1447 var i := len(tmp_file) - 1;
1449 if path_is_separator(tmp_file[i]) then
1451 if tmp_file[i] = '.' then [
1452 tmp_file := tmp_file[ .. i];
1461 var tmp_file_x := tmp_file + ntos(num);
1462 var wf := wopen(d, tmp_file_x, open_flag_create or open_flag_must_create, #180);
1463 if is_exception w, exception_aux w = system_error_eexist, not is_exception w1 then [
1469 rename(d, f, d, tmp_file_x);
1470 if is_exception w then [
1473 unlink(d, tmp_file);
1485 fn register_dependence(implicit w : world, d : dhandle, p : bytes) : world
1487 var cp := path_canonical(d, p);
1489 pcode IO IO_Register_Dependence 1 2 0 =w2 w cp;