system.pp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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: RawByteString; out fd: LongInt; out relfd_path: RawByteString): 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: RawByteString;
  54. drive_str: RawByteString;
  55. fd: longint;
  56. end;
  57. PCurrentDir = ^TCurrentDir;
  58. TCurrentDir = record
  59. dir_name: RawByteString;
  60. drive_str: RawByteString;
  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 Do_ConvertToFdRelativePath(path: RawByteString; out fd: LongInt; out relfd_path: RawByteString): Boolean;
  87. var
  88. drive_nr,I,pdir_drive,longest_match,chridx: longint;
  89. IsAbsolutePath: Boolean;
  90. pdir: RawByteString;
  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. Do_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. Do_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 ((Length(pdir)<>1) or ((Length(pdir)=1) and not (pdir[1] in AllowDirectorySeparators))) 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. Do_ConvertToFdRelativePath:=true;
  144. end;
  145. end;
  146. if longest_match>0 then
  147. InOutRes:=0
  148. else
  149. InOutRes:=3;
  150. end;
  151. function ConvertToFdRelativePath(path: RawByteString; out fd: LongInt; out relfd_path: RawByteString): Boolean;
  152. begin
  153. ConvertToFdRelativePath:=Do_ConvertToFdRelativePath(ToSingleByteFileSystemEncodedFileName(path),fd,relfd_path);
  154. setcodepage(relfd_path,DefaultRTLFileSystemCodePage,true);
  155. end;
  156. procedure Setup_PreopenedDirs;
  157. var
  158. fd: __wasi_fd_t;
  159. prestat: __wasi_prestat_t;
  160. res: __wasi_errno_t;
  161. prestat_dir_name: RawByteString;
  162. drive_nr: longint;
  163. begin
  164. preopened_dirs_count:=0;
  165. preopened_dirs:=nil;
  166. drives_count:=0;
  167. current_dirs:=nil;
  168. current_drive:=0;
  169. fd:=3;
  170. repeat
  171. res:=__wasi_fd_prestat_get(fd, @prestat);
  172. if res=__WASI_ERRNO_SUCCESS then
  173. begin
  174. if (prestat.tag=__WASI_PREOPENTYPE_DIR) and (prestat.u.dir.pr_name_len>0) then
  175. begin
  176. SetLength(prestat_dir_name,prestat.u.dir.pr_name_len);
  177. if __wasi_fd_prestat_dir_name(fd,PByte(prestat_dir_name),prestat.u.dir.pr_name_len)=__WASI_ERRNO_SUCCESS then
  178. begin
  179. setcodepage(prestat_dir_name,DefaultRTLFileSystemCodePage,true);
  180. Inc(preopened_dirs_count);
  181. if preopened_dirs=nil then
  182. preopened_dirs:=AllocMem(preopened_dirs_count*SizeOf(TPreopenedDir))
  183. else
  184. ReAllocMem(preopened_dirs, preopened_dirs_count*SizeOf(TPreopenedDir));
  185. preopened_dirs[preopened_dirs_count-1].fd:=fd;
  186. if HasDriveLetter(prestat_dir_name) then
  187. begin
  188. drive_nr:=Ord(UpCase(prestat_dir_name[1]))-(Ord('A')-1);
  189. preopened_dirs[preopened_dirs_count-1].drive_str:=Copy(prestat_dir_name,1,2);
  190. preopened_dirs[preopened_dirs_count-1].dir_name:=Copy(prestat_dir_name,2,Length(prestat_dir_name)-2);
  191. end
  192. else
  193. begin
  194. drive_nr:=0;
  195. preopened_dirs[preopened_dirs_count-1].drive_str:='';
  196. preopened_dirs[preopened_dirs_count-1].dir_name:=prestat_dir_name;
  197. end;
  198. if (drive_nr+1)>drives_count then
  199. begin
  200. drives_count:=drive_nr+1;
  201. if current_dirs=nil then
  202. current_dirs:=AllocMem(drives_count*SizeOf(TCurrentDir))
  203. else
  204. ReAllocMem(current_dirs,drives_count*SizeOf(TCurrentDir));
  205. end;
  206. if current_dirs[drive_nr].dir_name='' then
  207. current_dirs[drive_nr].dir_name:=prestat_dir_name;
  208. end;
  209. end;
  210. end;
  211. Inc(fd);
  212. until res<>__WASI_ERRNO_SUCCESS;
  213. while (current_drive<(drives_count-1)) and (current_dirs[current_drive].dir_name='') do
  214. Inc(current_drive);
  215. for drive_nr:=0 to drives_count-1 do
  216. begin
  217. if drive_nr>0 then
  218. current_dirs[drive_nr].drive_str:=Chr(Ord('A')+drive_nr-1)+':';
  219. if current_dirs[drive_nr].dir_name='' then
  220. current_dirs[drive_nr].dir_name:=DirectorySeparator;
  221. end;
  222. end;
  223. procedure Setup_Environment;
  224. begin
  225. if envp<>nil then
  226. exit;
  227. if __wasi_environ_sizes_get(@environc, @environ_buf_size)<>__WASI_ERRNO_SUCCESS then
  228. begin
  229. envp:=nil;
  230. exit;
  231. end;
  232. envp_size:=(environc+1)*SizeOf(PChar);
  233. GetMem(envp, envp_size);
  234. GetMem(environ_buf, environ_buf_size);
  235. envp[environc]:=nil;
  236. if __wasi_environ_get(Pointer(envp), environ_buf)<>__WASI_ERRNO_SUCCESS then
  237. begin
  238. FreeMem(envp, envp_size);
  239. FreeMem(environ_buf, environ_buf_size);
  240. envp:=nil;
  241. end;
  242. end;
  243. procedure setup_arguments;
  244. begin
  245. if argv<>nil then
  246. exit;
  247. if __wasi_args_sizes_get(@argc, @argv_buf_size)<>__WASI_ERRNO_SUCCESS then
  248. begin
  249. argc:=0;
  250. argv:=nil;
  251. exit;
  252. end;
  253. argv_size:=(argc+1)*SizeOf(PChar);
  254. GetMem(argv, argv_size);
  255. GetMem(argv_buf, argv_buf_size);
  256. if __wasi_args_get(Pointer(argv), argv_buf)<>__WASI_ERRNO_SUCCESS then
  257. begin
  258. FreeMem(argv, argv_size);
  259. FreeMem(argv_buf, argv_buf_size);
  260. argc:=0;
  261. argv:=nil;
  262. end;
  263. end;
  264. Function ParamCount: Longint;
  265. Begin
  266. if argv=nil then
  267. setup_arguments;
  268. paramcount := argc - 1;
  269. End;
  270. function paramstr(l: longint) : string;
  271. begin
  272. if argv=nil then
  273. setup_arguments;
  274. if (l>=0) and (l+1<=argc) then
  275. paramstr:=strpas(argv[l])
  276. else
  277. paramstr:='';
  278. end;
  279. procedure SysInitStdIO;
  280. begin
  281. OpenStdIO(Input,fmInput,StdInputHandle);
  282. OpenStdIO(Output,fmOutput,StdOutputHandle);
  283. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  284. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  285. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  286. end;
  287. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  288. begin
  289. end;
  290. begin
  291. { To be set if this is a GUI or console application }
  292. IsConsole := TRUE;
  293. {$ifdef FPC_HAS_FEATURE_DYNLIBS}
  294. { If dynlibs feature is disabled,
  295. IsLibrary is a constant, which can thus not be set to a value }
  296. { To be set if this is a library and not a program }
  297. IsLibrary := FALSE;
  298. {$endif def FPC_HAS_FEATURE_DYNLIBS}
  299. { Setup heap }
  300. InitHeap;
  301. SysInitExceptions;
  302. initunicodestringmanager;
  303. { Setup stdin, stdout and stderr }
  304. SysInitStdIO;
  305. { Reset IO Error }
  306. InOutRes:=0;
  307. {$ifdef FPC_HAS_FEATURE_THREADING}
  308. InitSystemThreads;
  309. {$endif}
  310. Setup_Environment;
  311. Setup_PreopenedDirs;
  312. end.