123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2020,2021 by the Free Pascal development team.
- System unit for The WebAssembly System Interface (WASI).
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit system;
- interface
- {$DEFINE SYSTEM_HAS_FEATURE_MONITOR}
- {$define FPC_IS_SYSTEM}
- {$ifdef FPC_WASM_THREADS}
- {$define DISABLE_NO_THREAD_MANAGER}
- {$else FPC_WASM_THREADS}
- {$define USE_NOTHREADMANAGER}
- {$endif FPC_WASM_THREADS}
- {$I systemh.inc}
- const
- LineEnding = #10;
- LFNSupport = true;
- DirectorySeparator = '/';
- DriveSeparator = '';
- ExtensionSeparator = '.';
- PathSeparator = ':';
- AllowDirectorySeparators : set of AnsiChar = ['\','/'];
- AllowDriveSeparators : set of AnsiChar = [];
- { FileNameCaseSensitive and FileNameCasePreserving are defined below! }
- maxExitCode = 65535;
- MaxPathLen = 4096;
- AllFilesMask = '*';
- const
- UnusedHandle = -1;
- StdInputHandle = 0;
- StdOutputHandle = 1;
- StdErrorHandle = 2;
- FileNameCaseSensitive : boolean = true;
- FileNameCasePreserving: boolean = true;
- CtrlZMarksEOF: boolean = false; (* #26 not considered as end of file *)
- sLineBreak = LineEnding;
- DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsLF;
- var
- argc: longint;
- argv: PPAnsiChar;
- envp: PPAnsiChar;
- ___fpc_wasm_suspender: WasmExternRef; section 'WebAssembly.Global';
- function __fpc_get_wasm_suspender: WasmExternRef;
- procedure __fpc_set_wasm_suspender(v: WasmExternRef);
- property __fpc_wasm_suspender: WasmExternRef read __fpc_get_wasm_suspender write __fpc_set_wasm_suspender;
- implementation
- {$I wasitypes.inc}
- {$I wasiprocs.inc}
- function WasiAlloc (aLength : Longint) : Pointer; [public, alias: 'wasiAlloc'];
- begin
- Result:=GetMem(aLength);
- end;
- procedure WasiFree (aMem : pointer); [public, alias: 'wasiFree'];
- begin
- FreeMem(aMem);
- end;
- exports
- WasiAlloc,WasiFree;
- function __fpc_get_wasm_suspender: WasmExternRef;
- begin
- result:=___fpc_wasm_suspender;
- end;
- procedure __fpc_set_wasm_suspender(v: WasmExternRef);
- begin
- ___fpc_wasm_suspender:=v;
- end;
- function ConvertToFdRelativePath(path: RawByteString; out fd: LongInt; out relfd_path: RawByteString): Word; forward;
- function fpc_wasi_path_readlink_ansistring(
- fd: __wasi_fd_t;
- const path: PAnsiChar;
- path_len: size_t;
- out link: rawbytestring): __wasi_errno_t;[Public, Alias : 'FPC_WASI_PATH_READLINK_ANSISTRING'];
- const
- InitialBufLen=64;
- MaximumBufLen=16384;
- var
- CurrentBufLen: __wasi_size_t;
- BufUsed: __wasi_size_t;
- begin
- CurrentBufLen:=InitialBufLen div 2;
- repeat
- CurrentBufLen:=CurrentBufLen*2;
- SetLength(link,CurrentBufLen);
- result:=__wasi_path_readlink(fd,path,path_len,@(link[1]),CurrentBufLen,@BufUsed);
- until (result<>__WASI_ERRNO_SUCCESS) or ((result=__WASI_ERRNO_SUCCESS) and (BufUsed<CurrentBufLen)) or (CurrentBufLen>MaximumBufLen);
- if result=__WASI_ERRNO_SUCCESS then
- begin
- SetLength(link,BufUsed);
- setcodepage(link,DefaultRTLFileSystemCodePage,true);
- end
- else
- link:='';
- end;
- function HasDriveLetter(const path: rawbytestring): Boolean;
- begin
- HasDriveLetter:=(Length(path)>=2) and (UpCase(path[1]) in ['A'..'Z']) and (path[2] = ':');
- end;
- type
- PPreopenedDir = ^TPreopenedDir;
- TPreopenedDir = record
- dir_name: RawByteString;
- drive_str: RawByteString;
- fd: longint;
- end;
- PCurrentDir = ^TCurrentDir;
- TCurrentDir = record
- dir_name: RawByteString;
- drive_str: RawByteString;
- end;
- var
- preopened_dirs_count: longint;
- preopened_dirs: PPreopenedDir;
- drives_count: longint;
- current_dirs: PCurrentDir;
- current_drive: longint;
- {$I system.inc}
- var
- argv_size,
- argv_buf_size: __wasi_size_t;
- argv_buf: Pointer;
- environc,environ_buf_size,envp_size: __wasi_size_t;
- environ_buf: Pointer;
- function GetProcessID: SizeUInt;
- begin
- end;
- Procedure Randomize;
- Begin
- __wasi_random_get(@RandSeed,SizeOf(RandSeed));
- End;
- procedure System_exit;
- begin
- if ExitCode>=126 then
- begin
- writeln(stderr,'##WASI-EXITCODE: ',ExitCode,' -> 125##');
- ExitCode:=125;
- end;
- __wasi_proc_exit(ExitCode);
- End;
- function Do_ConvertToFdRelativePath(path: RawByteString; out fd: LongInt; out relfd_path: RawByteString): Word;
- var
- drive_nr,I,pdir_drive,longest_match,chridx: longint;
- IsAbsolutePath: Boolean;
- pdir: RawByteString;
- begin
- fd:=0;
- relfd_path:='';
- if HasDriveLetter(path) then
- begin
- drive_nr:=Ord(UpCase(path[1]))-(Ord('A')-1);
- delete(path,1,2);
- end
- else
- drive_nr:=current_drive;
- { path is relative to a current directory? }
- if (path='') or not (path[1] in AllowDirectorySeparators) then
- begin
- { if so, convert to absolute }
- if (drive_nr>=drives_count) or (current_dirs[drive_nr].dir_name='') then
- begin
- Do_ConvertToFdRelativePath:=15;
- exit;
- end;
- if current_dirs[drive_nr].dir_name[Length(current_dirs[drive_nr].dir_name)] in AllowDirectorySeparators then
- path:=current_dirs[drive_nr].dir_name+path
- else
- path:=current_dirs[drive_nr].dir_name+DirectorySeparator+path;
- end;
- { path is now absolute. Try to find it in the preopened dirs array }
- longest_match:=0;
- for I:=0 to preopened_dirs_count-1 do
- begin
- pdir:=preopened_dirs[I].dir_name;
- if preopened_dirs[I].drive_str<>'' then
- pdir_drive:=Ord(UpCase(preopened_dirs[I].drive_str[1]))-(Ord('A')-1)
- else
- pdir_drive:=0;
- if pdir_drive<>drive_nr then
- continue;
- if Length(pdir)>Length(path) then
- continue;
- if Copy(path,1,Length(pdir))<>pdir then
- continue;
- chridx:=Length(pdir)+1;
- if ((Length(pdir)<>1) or ((Length(pdir)=1) and not (pdir[1] in AllowDirectorySeparators))) and
- ((chridx>Length(path)) or not (path[chridx] in AllowDirectorySeparators)) then
- continue;
- if Length(pdir)>longest_match then
- begin
- longest_match:=Length(pdir);
- while (chridx<=Length(path)) and (path[chridx] in AllowDirectorySeparators) do
- Inc(chridx);
- fd:=preopened_dirs[I].fd;
- relfd_path:=Copy(path,chridx,Length(path)-chridx+1);
- end;
- end;
- if longest_match>0 then
- Do_ConvertToFdRelativePath:=0
- else
- Do_ConvertToFdRelativePath:=3;
- end;
- function ConvertToFdRelativePath(path: RawByteString; out fd: LongInt; out relfd_path: RawByteString): Word;[Public, Alias : 'FPC_WASI_CONVERTTOFDRELATIVEPATH'];
- begin
- ConvertToFdRelativePath:=Do_ConvertToFdRelativePath(ToSingleByteFileSystemEncodedFileName(path),fd,relfd_path);
- setcodepage(relfd_path,DefaultRTLFileSystemCodePage,true);
- end;
- procedure Setup_PreopenedDirs;
- var
- fd: __wasi_fd_t;
- prestat: __wasi_prestat_t;
- res: __wasi_errno_t;
- prestat_dir_name: RawByteString;
- drive_nr: longint;
- begin
- preopened_dirs_count:=0;
- preopened_dirs:=nil;
- drives_count:=0;
- current_dirs:=nil;
- current_drive:=0;
- fd:=3;
- repeat
- res:=__wasi_fd_prestat_get(fd, @prestat);
- if res=__WASI_ERRNO_SUCCESS then
- begin
- if (prestat.tag=__WASI_PREOPENTYPE_DIR) and (prestat.u.dir.pr_name_len>0) then
- begin
- SetLength(prestat_dir_name,prestat.u.dir.pr_name_len);
- if __wasi_fd_prestat_dir_name(fd,PByte(prestat_dir_name),prestat.u.dir.pr_name_len)=__WASI_ERRNO_SUCCESS then
- begin
- setcodepage(prestat_dir_name,DefaultRTLFileSystemCodePage,true);
- Inc(preopened_dirs_count);
- if preopened_dirs=nil then
- preopened_dirs:=AllocMem(preopened_dirs_count*SizeOf(TPreopenedDir))
- else
- ReAllocMem(preopened_dirs, preopened_dirs_count*SizeOf(TPreopenedDir));
- preopened_dirs[preopened_dirs_count-1].fd:=fd;
- if HasDriveLetter(prestat_dir_name) then
- begin
- drive_nr:=Ord(UpCase(prestat_dir_name[1]))-(Ord('A')-1);
- preopened_dirs[preopened_dirs_count-1].drive_str:=Copy(prestat_dir_name,1,2);
- preopened_dirs[preopened_dirs_count-1].dir_name:=Copy(prestat_dir_name,2,Length(prestat_dir_name)-2);
- end
- else
- begin
- drive_nr:=0;
- preopened_dirs[preopened_dirs_count-1].drive_str:='';
- preopened_dirs[preopened_dirs_count-1].dir_name:=prestat_dir_name;
- end;
- if (drive_nr+1)>drives_count then
- begin
- drives_count:=drive_nr+1;
- if current_dirs=nil then
- current_dirs:=AllocMem(drives_count*SizeOf(TCurrentDir))
- else
- ReAllocMem(current_dirs,drives_count*SizeOf(TCurrentDir));
- end;
- if current_dirs[drive_nr].dir_name='' then
- current_dirs[drive_nr].dir_name:=prestat_dir_name;
- end;
- end;
- end;
- Inc(fd);
- until res<>__WASI_ERRNO_SUCCESS;
- while (current_drive<(drives_count-1)) and (current_dirs[current_drive].dir_name='') do
- Inc(current_drive);
- for drive_nr:=0 to drives_count-1 do
- begin
- if drive_nr>0 then
- current_dirs[drive_nr].drive_str:=Chr(Ord('A')+drive_nr-1)+':';
- if current_dirs[drive_nr].dir_name='' then
- current_dirs[drive_nr].dir_name:=DirectorySeparator;
- end;
- end;
- procedure Setup_Environment;
- begin
- if envp<>nil then
- exit;
- if __wasi_environ_sizes_get(@environc, @environ_buf_size)<>__WASI_ERRNO_SUCCESS then
- begin
- envp:=nil;
- exit;
- end;
- envp_size:=(environc+1)*SizeOf(PAnsiChar);
- GetMem(envp, envp_size);
- GetMem(environ_buf, environ_buf_size);
- envp[environc]:=nil;
- if __wasi_environ_get(Pointer(envp), environ_buf)<>__WASI_ERRNO_SUCCESS then
- begin
- FreeMem(envp, envp_size);
- FreeMem(environ_buf, environ_buf_size);
- envp:=nil;
- end;
- end;
- procedure setup_arguments;
- begin
- if argv<>nil then
- exit;
- if __wasi_args_sizes_get(@argc, @argv_buf_size)<>__WASI_ERRNO_SUCCESS then
- begin
- argc:=0;
- argv:=nil;
- exit;
- end;
- argv_size:=(argc+1)*SizeOf(PAnsiChar);
- GetMem(argv, argv_size);
- GetMem(argv_buf, argv_buf_size);
- if __wasi_args_get(Pointer(argv), argv_buf)<>__WASI_ERRNO_SUCCESS then
- begin
- FreeMem(argv, argv_size);
- FreeMem(argv_buf, argv_buf_size);
- argc:=0;
- argv:=nil;
- end;
- end;
- Function ParamCount: Longint;
- Begin
- if argv=nil then
- setup_arguments;
- paramcount := argc - 1;
- End;
- function paramstr(l: longint) : shortstring;
- begin
- if argv=nil then
- setup_arguments;
- if (l>=0) and (l+1<=argc) then
- paramstr:=strpas(argv[l])
- else
- paramstr:='';
- end;
- procedure SysInitStdIO;
- begin
- OpenStdIO(Input,fmInput,StdInputHandle);
- OpenStdIO(Output,fmOutput,StdOutputHandle);
- OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
- OpenStdIO(StdOut,fmOutput,StdOutputHandle);
- OpenStdIO(StdErr,fmOutput,StdErrorHandle);
- end;
- function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
- begin
- end;
- begin
- { To be set if this is a GUI or console application }
- IsConsole := TRUE;
- {$ifdef FPC_HAS_FEATURE_DYNLIBS}
- { If dynlibs feature is disabled,
- IsLibrary is a constant, which can thus not be set to a value }
- { To be set if this is a library and not a program }
- IsLibrary := FALSE;
- {$endif def FPC_HAS_FEATURE_DYNLIBS}
- { Setup heap }
- InitHeap;
- SysInitExceptions;
- initunicodestringmanager;
- { Setup stdin, stdout and stderr }
- SysInitStdIO;
- { Reset IO Error }
- InOutRes:=0;
- {$ifdef FPC_HAS_FEATURE_THREADING}
- InitSystemThreads;
- {$endif}
- Setup_Environment;
- Setup_PreopenedDirs;
- end.
|