system.pp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2020,2021 by the Free Pascal development team.
  4. System unit for The WebAssembly System Interface (WASI).
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit system;
  12. interface
  13. {$define FPC_IS_SYSTEM}
  14. {$I systemh.inc}
  15. const
  16. LineEnding = #10;
  17. LFNSupport = true;
  18. DirectorySeparator = '/';
  19. DriveSeparator = '';
  20. ExtensionSeparator = '.';
  21. PathSeparator = ':';
  22. AllowDirectorySeparators : set of char = ['\','/'];
  23. AllowDriveSeparators : set of char = [];
  24. { FileNameCaseSensitive and FileNameCasePreserving are defined below! }
  25. maxExitCode = 65535;
  26. MaxPathLen = 4096;
  27. AllFilesMask = '*';
  28. const
  29. UnusedHandle = -1;
  30. StdInputHandle = 0;
  31. StdOutputHandle = 1;
  32. StdErrorHandle = 2;
  33. FileNameCaseSensitive : boolean = true;
  34. FileNameCasePreserving: boolean = true;
  35. CtrlZMarksEOF: boolean = false; (* #26 not considered as end of file *)
  36. sLineBreak = LineEnding;
  37. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsLF;
  38. var
  39. argc: longint;
  40. argv: PPChar;
  41. envp: PPChar;
  42. preopened_dirs_count: longint;
  43. preopened_dirs: PPChar;
  44. drives_count: longint;
  45. current_dirs: PPChar;
  46. current_dir_fds: Plongint;
  47. current_drive: longint;
  48. function ConvertToFdRelativePath(path: PChar; out fd: LongInt; out relfd_path: PChar): Boolean;
  49. procedure DebugWrite(const P: PChar);
  50. procedure DebugWriteLn(const P: PChar);
  51. procedure DebugWriteChar(Ch: Char);
  52. procedure DebugWriteHexDigit(d: Byte);
  53. procedure DebugWriteHexByte(b: Byte);
  54. procedure DebugWriteHexWord(w: Word);
  55. procedure DebugWriteHexLongWord(lw: LongWord);
  56. implementation
  57. {$I wasitypes.inc}
  58. {$I wasiprocs.inc}
  59. {$I system.inc}
  60. var
  61. argv_size,
  62. argv_buf_size: __wasi_size_t;
  63. argv_buf: Pointer;
  64. environc,environ_buf_size,envp_size: __wasi_size_t;
  65. environ_buf: Pointer;
  66. function GetProcessID: SizeUInt;
  67. begin
  68. end;
  69. Procedure Randomize;
  70. Begin
  71. __wasi_random_get(@RandSeed,SizeOf(RandSeed));
  72. End;
  73. procedure System_exit;
  74. begin
  75. __wasi_proc_exit(ExitCode);
  76. End;
  77. function HasDriveLetter(const path: PChar): Boolean;
  78. begin
  79. HasDriveLetter:=(path<>nil) and (UpCase(path[0]) in ['A'..'Z']) and (path[1] = ':');
  80. end;
  81. function ConvertToFdRelativePath(path: PChar; out fd: LongInt; out relfd_path: PChar): Boolean;
  82. var
  83. drive_nr,I,pdir_drive,longest_match,pdir_length: longint;
  84. IsAbsolutePath: Boolean;
  85. pdir, savepath: PChar;
  86. begin
  87. fd:=0;
  88. relfd_path:=nil;
  89. if HasDriveLetter(path) then
  90. begin
  91. drive_nr:=Ord(UpCase(path[0]))-(Ord('A')-1);
  92. inc(path,2);
  93. end
  94. else
  95. drive_nr:=current_drive;
  96. if path[0] in ['/','\'] then
  97. begin
  98. { path is absolute. Try to find it in the preopened dirs array }
  99. InOutRes:=3;
  100. ConvertToFdRelativePath:=false;
  101. longest_match:=0;
  102. savepath:=path;
  103. for I:=0 to preopened_dirs_count-1 do
  104. begin
  105. path:=savepath;
  106. pdir:=preopened_dirs[I];
  107. if HasDriveLetter(pdir) then
  108. begin
  109. pdir_drive:=Ord(UpCase(pdir[0]))-(Ord('A')-1);
  110. Inc(pdir,2);
  111. end
  112. else
  113. pdir_drive:=0;
  114. if pdir_drive<>drive_nr then
  115. continue;
  116. pdir_length:=StrLen(pdir);
  117. if pdir_length>StrLen(path) then
  118. continue;
  119. if CompareByte(path^,pdir^,pdir_length)<>0 then
  120. continue;
  121. Inc(path,pdir_length);
  122. if not (path^ in [#0,'/','\']) then
  123. continue;
  124. if pdir_length>longest_match then
  125. begin
  126. longest_match:=pdir_length;
  127. while path^ in ['/','\'] do
  128. Inc(path);
  129. fd:=I+3;
  130. FreeMem(relfd_path);
  131. relfd_path:=GetMem(StrLen(path)+1);
  132. Move(path^,relfd_path^,StrLen(path)+1);
  133. InOutRes:=0;
  134. ConvertToFdRelativePath:=true;
  135. end;
  136. end;
  137. end
  138. else
  139. begin
  140. { path is relative to a current directory }
  141. if (drive_nr>=drives_count) or (current_dirs[drive_nr]=nil) then
  142. begin
  143. InOutRes:=15;
  144. ConvertToFdRelativePath:=false;
  145. exit;
  146. end;
  147. fd:=current_dir_fds[drive_nr];
  148. relfd_path:=GetMem(1+StrLen(path));
  149. Move(path^,relfd_path^,1+StrLen(path));
  150. ConvertToFdRelativePath:=true;
  151. end;
  152. end;
  153. procedure Setup_PreopenedDirs;
  154. var
  155. fd: __wasi_fd_t;
  156. prestat: __wasi_prestat_t;
  157. res: __wasi_errno_t;
  158. prestat_dir_name: PChar;
  159. drive_nr: longint;
  160. begin
  161. preopened_dirs_count:=0;
  162. preopened_dirs:=nil;
  163. drives_count:=0;
  164. current_dirs:=nil;
  165. current_dir_fds:=nil;
  166. current_drive:=0;
  167. fd:=3;
  168. repeat
  169. res:=__wasi_fd_prestat_get(fd, @prestat);
  170. if res=__WASI_ERRNO_SUCCESS then
  171. begin
  172. if (prestat.tag=__WASI_PREOPENTYPE_DIR) and (prestat.u.dir.pr_name_len>0) then
  173. begin
  174. GetMem(prestat_dir_name,prestat.u.dir.pr_name_len+1);
  175. if __wasi_fd_prestat_dir_name(fd,PByte(prestat_dir_name),prestat.u.dir.pr_name_len)=__WASI_ERRNO_SUCCESS then
  176. begin
  177. prestat_dir_name[prestat.u.dir.pr_name_len]:=#0;
  178. Inc(preopened_dirs_count);
  179. if preopened_dirs=nil then
  180. preopened_dirs:=AllocMem(preopened_dirs_count*SizeOf(PChar))
  181. else
  182. ReAllocMem(preopened_dirs, preopened_dirs_count*SizeOf(PChar));
  183. preopened_dirs[preopened_dirs_count-1]:=prestat_dir_name;
  184. if HasDriveLetter(prestat_dir_name) then
  185. drive_nr:=Ord(UpCase(prestat_dir_name[0]))-(Ord('A')-1)
  186. else
  187. drive_nr:=0;
  188. if (drive_nr+1)>drives_count then
  189. begin
  190. drives_count:=drive_nr+1;
  191. if current_dirs=nil then
  192. begin
  193. current_dirs:=AllocMem(drives_count*SizeOf(PChar));
  194. current_dir_fds:=AllocMem(drives_count*SizeOf(longint));
  195. end
  196. else
  197. begin
  198. ReAllocMem(current_dirs,drives_count*SizeOf(PChar));
  199. ReAllocMem(current_dir_fds,drives_count*SizeOf(longint));
  200. end;
  201. end;
  202. if current_dirs[drive_nr]=nil then
  203. begin
  204. current_dirs[drive_nr]:=GetMem(1+StrLen(prestat_dir_name));
  205. Move(prestat_dir_name^,current_dirs[drive_nr]^,StrLen(prestat_dir_name)+1);
  206. current_dir_fds[drive_nr]:=fd;
  207. end;
  208. end
  209. else
  210. FreeMem(prestat_dir_name,prestat.u.dir.pr_name_len+1);
  211. end;
  212. end;
  213. Inc(fd);
  214. until res<>__WASI_ERRNO_SUCCESS;
  215. while (current_drive<drives_count) and (current_dirs[current_drive]=nil) do
  216. Inc(current_drive);
  217. end;
  218. procedure Setup_Environment;
  219. begin
  220. if envp<>nil then
  221. exit;
  222. if __wasi_environ_sizes_get(@environc, @environ_buf_size)<>__WASI_ERRNO_SUCCESS then
  223. begin
  224. envp:=nil;
  225. exit;
  226. end;
  227. envp_size:=(environc+1)*SizeOf(PChar);
  228. GetMem(envp, envp_size);
  229. GetMem(environ_buf, environ_buf_size);
  230. envp[environc]:=nil;
  231. if __wasi_environ_get(Pointer(envp), environ_buf)<>__WASI_ERRNO_SUCCESS then
  232. begin
  233. FreeMem(envp, envp_size);
  234. FreeMem(environ_buf, environ_buf_size);
  235. envp:=nil;
  236. end;
  237. end;
  238. procedure setup_arguments;
  239. begin
  240. if argv<>nil then
  241. exit;
  242. if __wasi_args_sizes_get(@argc, @argv_buf_size)<>__WASI_ERRNO_SUCCESS then
  243. begin
  244. argc:=0;
  245. argv:=nil;
  246. exit;
  247. end;
  248. argv_size:=(argc+1)*SizeOf(PChar);
  249. GetMem(argv, argv_size);
  250. GetMem(argv_buf, argv_buf_size);
  251. if __wasi_args_get(Pointer(argv), argv_buf)<>__WASI_ERRNO_SUCCESS then
  252. begin
  253. FreeMem(argv, argv_size);
  254. FreeMem(argv_buf, argv_buf_size);
  255. argc:=0;
  256. argv:=nil;
  257. end;
  258. end;
  259. Function ParamCount: Longint;
  260. Begin
  261. if argv=nil then
  262. setup_arguments;
  263. paramcount := argc - 1;
  264. End;
  265. function paramstr(l: longint) : string;
  266. begin
  267. if argv=nil then
  268. setup_arguments;
  269. if (l>=0) and (l+1<=argc) then
  270. paramstr:=strpas(argv[l])
  271. else
  272. paramstr:='';
  273. end;
  274. procedure SysInitStdIO;
  275. begin
  276. OpenStdIO(Input,fmInput,StdInputHandle);
  277. OpenStdIO(Output,fmOutput,StdOutputHandle);
  278. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  279. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  280. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  281. end;
  282. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  283. begin
  284. end;
  285. procedure DebugWrite(const P: PChar);
  286. var
  287. our_iov: __wasi_ciovec_t;
  288. our_nwritten: longint;
  289. begin
  290. our_iov.buf := PByte(P);
  291. our_iov.buf_len := StrLen(P);
  292. __wasi_fd_write(1, @our_iov, 1, @our_nwritten);
  293. end;
  294. procedure DebugWriteLn(const P: PChar);
  295. begin
  296. DebugWrite(P);
  297. DebugWriteChar(#10);
  298. end;
  299. procedure DebugWriteChar(Ch: Char);
  300. var
  301. CharArr: array [0..1] of Char;
  302. begin
  303. CharArr[0] := Ch;
  304. CharArr[1] := #0;
  305. DebugWrite(@CharArr);
  306. end;
  307. procedure DebugWriteHexDigit(d: Byte);
  308. const
  309. HexDigits: array [0..15] of Char = '0123456789ABCDEF';
  310. begin
  311. DebugWriteChar(HexDigits[d]);
  312. end;
  313. procedure DebugWriteHexByte(b: Byte);
  314. begin
  315. DebugWriteHexDigit(b shr 4);
  316. DebugWriteHexDigit(b and 15);
  317. end;
  318. procedure DebugWriteHexWord(w: Word);
  319. begin
  320. DebugWriteHexByte(w shr 8);
  321. DebugWriteHexByte(Byte(w));
  322. end;
  323. procedure DebugWriteHexLongWord(lw: LongWord);
  324. begin
  325. DebugWriteHexWord(lw shr 16);
  326. DebugWriteHexWord(Word(lw));
  327. end;
  328. begin
  329. { To be set if this is a GUI or console application }
  330. IsConsole := TRUE;
  331. {$ifdef FPC_HAS_FEATURE_DYNLIBS}
  332. { If dynlibs feature is disabled,
  333. IsLibrary is a constant, which can thus not be set to a value }
  334. { To be set if this is a library and not a program }
  335. IsLibrary := FALSE;
  336. {$endif def FPC_HAS_FEATURE_DYNLIBS}
  337. { Setup heap }
  338. InitHeap;
  339. SysInitExceptions;
  340. initunicodestringmanager;
  341. { Setup stdin, stdout and stderr }
  342. SysInitStdIO;
  343. { Reset IO Error }
  344. InOutRes:=0;
  345. {$ifdef FPC_HAS_FEATURE_THREADING}
  346. InitSystemThreads;
  347. {$endif}
  348. Setup_Environment;
  349. Setup_PreopenedDirs;
  350. end.