system.pp 9.0 KB

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