system.pp 9.5 KB

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