* synchronized with trunk

git-svn-id: branches/wasm@47357 -
This commit is contained in:
nickysn 2020-11-09 00:06:32 +00:00
commit 93ecf5f155
34 changed files with 572 additions and 66 deletions

5
.gitattributes vendored
View File

@ -11941,6 +11941,9 @@ rtl/riscv64/strings.inc svneol=native#text/plain
rtl/riscv64/stringss.inc svneol=native#text/plain rtl/riscv64/stringss.inc svneol=native#text/plain
rtl/sinclairql/Makefile.fpc svneol=native#text/plain rtl/sinclairql/Makefile.fpc svneol=native#text/plain
rtl/sinclairql/buildrtl.pp svneol=native#text/plain rtl/sinclairql/buildrtl.pp svneol=native#text/plain
rtl/sinclairql/qdos.inc svneol=native#text/plain
rtl/sinclairql/qdosfuncs.inc svneol=native#text/plain
rtl/sinclairql/qdosh.inc svneol=native#text/plain
rtl/sinclairql/rtl.cfg svneol=native#text/plain rtl/sinclairql/rtl.cfg svneol=native#text/plain
rtl/sinclairql/rtldefs.inc svneol=native#text/plain rtl/sinclairql/rtldefs.inc svneol=native#text/plain
rtl/sinclairql/si_prc.pp svneol=native#text/plain rtl/sinclairql/si_prc.pp svneol=native#text/plain
@ -18559,6 +18562,8 @@ tests/webtbs/tw37969.pp svneol=native#text/pascal
tests/webtbs/tw38012.pp svneol=native#text/pascal tests/webtbs/tw38012.pp svneol=native#text/pascal
tests/webtbs/tw38022.pp svneol=native#text/pascal tests/webtbs/tw38022.pp svneol=native#text/pascal
tests/webtbs/tw3805.pp svneol=native#text/plain tests/webtbs/tw3805.pp svneol=native#text/plain
tests/webtbs/tw38051.pp svneol=native#text/pascal
tests/webtbs/tw38054.pp svneol=native#text/plain
tests/webtbs/tw3814.pp svneol=native#text/plain tests/webtbs/tw3814.pp svneol=native#text/plain
tests/webtbs/tw3827.pp svneol=native#text/plain tests/webtbs/tw3827.pp svneol=native#text/plain
tests/webtbs/tw3829.pp svneol=native#text/plain tests/webtbs/tw3829.pp svneol=native#text/plain

View File

@ -1522,6 +1522,8 @@ const
end end
else else
begin begin
if actasmtoken = AS_LPAREN then
oper.initref;
if not oper.SetupVar(expr,false) then if not oper.SetupVar(expr,false) then
begin begin
{ not a variable, check special variables.. } { not a variable, check special variables.. }

View File

@ -290,13 +290,14 @@ implementation
statement_syssym:=new_dispose_statement(false); statement_syssym:=new_dispose_statement(false);
end; end;
in_ord_x : in_ord_x,
in_chr_byte:
begin begin
consume(_LKLAMMER); consume(_LKLAMMER);
in_args:=true; in_args:=true;
p1:=comp_expr([ef_accept_equal]); p1:=comp_expr([ef_accept_equal]);
consume(_RKLAMMER); consume(_RKLAMMER);
p1:=geninlinenode(in_ord_x,false,p1); p1:=geninlinenode(l,false,p1);
statement_syssym := p1; statement_syssym := p1;
end; end;

View File

@ -382,7 +382,7 @@ implementation
{ create call to fpc_getmem } { create call to fpc_getmem }
para := ccallparanode.create(cordconstnode.create para := ccallparanode.create(cordconstnode.create
(tpointerdef(p.resultdef).pointeddef.size,s32inttype,true),nil); (tpointerdef(p.resultdef).pointeddef.size,ptruinttype,true),nil);
addstatement(newstatement,cassignmentnode.create( addstatement(newstatement,cassignmentnode.create(
ctemprefnode.create(temp), ctemprefnode.create(temp),
ccallnode.createintern('fpc_getmem',para))); ccallnode.createintern('fpc_getmem',para)));

View File

@ -50,7 +50,7 @@ const
CurrentPPUVersion = 208; CurrentPPUVersion = 208;
{ for any other changes to the ppu format, increase this version number { for any other changes to the ppu format, increase this version number
(it's a cardinal) } (it's a cardinal) }
CurrentPPULongVersion = 11; CurrentPPULongVersion = 12;
{ unit flags } { unit flags }
uf_big_endian = $000004; uf_big_endian = $000004;

View File

@ -70,6 +70,7 @@ implementation
systemunit.insert(csyssym.create('Slice',in_slice_x)); systemunit.insert(csyssym.create('Slice',in_slice_x));
systemunit.insert(csyssym.create('Seg',in_seg_x)); systemunit.insert(csyssym.create('Seg',in_seg_x));
systemunit.insert(csyssym.create('Ord',in_ord_x)); systemunit.insert(csyssym.create('Ord',in_ord_x));
systemunit.insert(csyssym.create('Chr',in_chr_byte));
systemunit.insert(csyssym.create('Pred',in_pred_x)); systemunit.insert(csyssym.create('Pred',in_pred_x));
systemunit.insert(csyssym.create('Succ',in_succ_x)); systemunit.insert(csyssym.create('Succ',in_succ_x));
systemunit.insert(csyssym.create('Exclude',in_exclude_x_y)); systemunit.insert(csyssym.create('Exclude',in_exclude_x_y));

View File

@ -35,6 +35,7 @@ type
private private
Origin: DWord; Origin: DWord;
UseVLink: boolean; UseVLink: boolean;
ExeLength: longint;
function WriteResponseFile(isdll: boolean): boolean; function WriteResponseFile(isdll: boolean): boolean;
procedure SetSinclairQLInfo; procedure SetSinclairQLInfo;
function MakeSinclairQLExe: boolean; function MakeSinclairQLExe: boolean;
@ -54,7 +55,7 @@ implementation
const const
DefaultOrigin = $20000; DefaultOrigin = $0;
constructor TLinkerSinclairQL.Create; constructor TLinkerSinclairQL.Create;
@ -83,7 +84,7 @@ begin
end end
else else
begin begin
ExeCmd[1]:='vlink -b rawbin1 $FLAGS $GCSECTIONS $OPT $STRIP -o $EXE -T $RES'; ExeCmd[1]:='vlink -b rawseg -q $FLAGS $GCSECTIONS $OPT $STRIP -o $EXE -T $RES';
end; end;
end; end;
end; end;
@ -105,10 +106,8 @@ end;
function TLinkerSinclairQL.WriteResponseFile(isdll: boolean): boolean; function TLinkerSinclairQL.WriteResponseFile(isdll: boolean): boolean;
var var
linkres : TLinkRes; linkres : TLinkRes;
i : longint;
HPath : TCmdStrListItem; HPath : TCmdStrListItem;
s : string; s : string;
linklibc : boolean;
begin begin
WriteResponseFile:=False; WriteResponseFile:=False;
@ -177,9 +176,13 @@ begin
Add('SECTIONS'); Add('SECTIONS');
Add('{'); Add('{');
Add(' . = 0x'+hexstr(Origin,8)+';'); Add(' . = 0x'+hexstr(Origin,8)+';');
Add(' .text : { *(.text .text.* _CODE _CODE.* ) }'); Add(' .text : {');
Add(' .data : { *(.data .data.* .rodata .rodata.* .fpc.* ) }'); Add(' _stext = .;');
Add(' .bss : { *(_BSS _BSS.*) *(.bss .bss.*) *(_BSSEND _BSSEND.*) *(_HEAP _HEAP.*) *(.stack .stack.*) *(_STACK _STACK.*) }'); Add(' *(.text .text.* _CODE _CODE.* ) ');
Add(' *(.data .data.* .rodata .rodata.* .fpc.* ) ');
Add(' *(_BSS _BSS.*) *(.bss .bss.*) *(_BSSEND _BSSEND.*) *(_HEAP _HEAP.*) *(.stack .stack.*) *(_STACK _STACK.*) ');
Add(' _etext = .;');
Add(' }');
Add('}'); Add('}');
end; end;
@ -200,6 +203,9 @@ var
GCSectionsStr : string; GCSectionsStr : string;
FlagsStr : string; FlagsStr : string;
ExeName: string; ExeName: string;
fd,fs: file;
buf: pointer;
bufread,bufsize: longint;
begin begin
StripStr:=''; StripStr:='';
GCSectionsStr:=''; GCSectionsStr:='';
@ -213,12 +219,10 @@ begin
if UseVLink then if UseVLink then
begin begin
if create_smartlink_sections then if create_smartlink_sections then
GCSectionsStr:='-gc-all -sc'; GCSectionsStr:='-gc-all';
end; end;
ExeName:=current_module.exefilename; ExeName:=current_module.exefilename;
if apptype = app_gui then
Replace(ExeName,target_info.exeext,'.prg');
{ Call linker } { Call linker }
SplitBinCmd(Info.ExeCmd[1],BinStr,CmdStr); SplitBinCmd(Info.ExeCmd[1],BinStr,CmdStr);
@ -232,12 +236,57 @@ begin
Replace(cmdstr,'$DYNLINK',DynLinkStr); Replace(cmdstr,'$DYNLINK',DynLinkStr);
MakeSinclairQLExe:=DoExec(BinStr,CmdStr,true,false); MakeSinclairQLExe:=DoExec(BinStr,CmdStr,true,false);
{ Kludge:
With the above linker script, vlink will produce two files,
"exename. text" and "exename. text.rel text". The former is the
binary itself, the second is the relocation info. Here we copy
the two together. I'll try to get vlink to do this for me in the
future. (KB) }
if MakeSinclairQLExe then
begin
ExeLength:=0;
bufsize:=16384;
{$push}
{$i-}
buf:=GetMem(bufsize);
assign(fd,exename);
rewrite(fd,1);
assign(fs,exename+'. text');
reset(fs,1);
repeat
blockread(fs,buf^,bufsize,bufread);
blockwrite(fd,buf^,bufread);
until eof(fs);
close(fs);
// erase(fs);
assign(fs,exename+'. text.rel text');
reset(fs,1);
repeat
blockread(fs,buf^,bufsize,bufread);
blockwrite(fd,buf^,bufread);
until eof(fs);
close(fs);
// erase(fs);
ExeLength:=FileSize(fd);
close(fd);
{$pop}
MakeSinclairQLExe:=not (ExeLength = 0);
end;
end; end;
function TLinkerSinclairQL.MakeExecutable:boolean; function TLinkerSinclairQL.MakeExecutable:boolean;
const
DefaultBootString = '10 $SYM=RESPR($BINSIZE):LBYTES"win1_$EXENAME",$SYM:CALL $SYM';
var var
success : boolean; success : boolean;
bootfile : TScript;
ExeName: String;
BootStr: String;
begin begin
if not(cs_link_nolink in current_settings.globalswitches) then if not(cs_link_nolink in current_settings.globalswitches) then
Message1(exec_i_linking,current_module.exefilename); Message1(exec_i_linking,current_module.exefilename);
@ -251,6 +300,24 @@ begin
if (success) and not(cs_link_nolink in current_settings.globalswitches) then if (success) and not(cs_link_nolink in current_settings.globalswitches) then
DeleteFile(outputexedir+Info.ResName); DeleteFile(outputexedir+Info.ResName);
if (success) then
begin
ExeName:=current_module.exefilename;
BootStr:=DefaultBootString;
Replace(BootStr,'$BINSIZE',tostr(ExeLength)); { FIX ME }
Replace(BootStr,'$EXENAME',ExeName);
Replace(ExeName,target_info.exeext,'');
Replace(BootStr,'$SYM',ExeName);
{ Write bootfile }
bootfile:=TScript.Create(outputexedir+ExeName);
bootfile.Add(BootStr);
bootfile.writetodisk;
bootfile.Free;
end;
MakeExecutable:=success; { otherwise a recursive call to link method } MakeExecutable:=success; { otherwise a recursive call to link method }
end; end;

View File

@ -178,8 +178,6 @@ unit cgx86;
winstackpagesize = 4096; winstackpagesize = 4096;
{$endif NOTARGETWIN} {$endif NOTARGETWIN}
function UseAVX: boolean;
function UseIncDec: boolean; function UseIncDec: boolean;
{ returns true, if the compiler should use leave instead of mov/pop } { returns true, if the compiler should use leave instead of mov/pop }
@ -196,12 +194,6 @@ unit cgx86;
paramgr,procinfo, paramgr,procinfo,
tgobj,ncgutil; tgobj,ncgutil;
function UseAVX: boolean;
begin
Result:={$ifdef i8086}false{$else i8086}(FPUX86_HAS_AVXUNIT in fpu_capabilities[current_settings.fputype]){$endif i8086};
end;
{ modern CPUs prefer add/sub over inc/dec because add/sub break instructions dependencies on flags { modern CPUs prefer add/sub over inc/dec because add/sub break instructions dependencies on flags
because they modify all flags } because they modify all flags }
function UseIncDec: boolean; function UseIncDec: boolean;

View File

@ -385,11 +385,15 @@ topsize2memsize: array[topsize] of integer =
function requires_fwait_on_8087(op: TAsmOp): boolean; function requires_fwait_on_8087(op: TAsmOp): boolean;
{$endif i8086} {$endif i8086}
function UseAVX: boolean;
function UseAVX512: boolean;
implementation implementation
uses uses
globtype, globtype,
rgbase,verbose; rgbase,verbose,
cpuinfo;
const const
{$if defined(x86_64)} {$if defined(x86_64)}
@ -948,4 +952,17 @@ implementation
{$endif i8086} {$endif i8086}
function UseAVX: boolean;
begin
Result:={$ifdef i8086}false{$else i8086}(FPUX86_HAS_AVXUNIT in fpu_capabilities[current_settings.fputype]){$endif i8086};
end;
function UseAVX512: boolean;
begin
// Result:=(current_settings.fputype in fpu_avx_instructionsets) {$ifndef i8086}or (CPUX86_HAS_AVXUNIT in cpu_capabilities[current_settings.cputype]){$endif i8086};
Result:=false;
end;
end. end.

View File

@ -1268,15 +1268,32 @@ unit nx86add;
{ we can use only right as left operand if the operation is commutative } { we can use only right as left operand if the operation is commutative }
if (right.location.loc=LOC_MMREGISTER) and (op in [OP_ADD,OP_MUL]) then if (right.location.loc=LOC_MMREGISTER) and (op in [OP_ADD,OP_MUL]) then
begin begin
location.register:=right.location.register; if UseAVX then
cg.a_opmm_loc_reg(current_asmdata.CurrAsmList,op,tfloat2tcgsize[tfloatdef(left.resultdef).floattype],left.location,location.register,nil); begin
location.register:=cg.getmmregister(current_asmdata.CurrAsmList,OS_VECTOR);
cg.a_opmm_loc_reg_reg(current_asmdata.CurrAsmList,op,tfloat2tcgsize[tfloatdef(left.resultdef).floattype],left.location,right.location.register,location.register,nil);
end
else
begin
location.register:=right.location.register;
cg.a_opmm_loc_reg(current_asmdata.CurrAsmList,op,tfloat2tcgsize[tfloatdef(left.resultdef).floattype],left.location,location.register,nil);
end;
end end
else else
begin begin
location_force_mmreg(current_asmdata.CurrAsmList,left.location,false); location_force_mmreg(current_asmdata.CurrAsmList,left.location,false);
location.register:=left.location.register; if UseAVX then
cg.a_opmm_loc_reg(current_asmdata.CurrAsmList,op, begin
tfloat2tcgsize[tfloatdef(tarraydef(left.resultdef).elementdef).floattype],right.location,location.register,nil); location.register:=cg.getmmregister(current_asmdata.CurrAsmList,OS_VECTOR);
cg.a_opmm_loc_reg_reg(current_asmdata.CurrAsmList,op,
tfloat2tcgsize[tfloatdef(tarraydef(left.resultdef).elementdef).floattype],right.location,left.location.register,location.register,nil);
end
else
begin
location.register:=left.location.register;
cg.a_opmm_loc_reg(current_asmdata.CurrAsmList,op,
tfloat2tcgsize[tfloatdef(tarraydef(left.resultdef).elementdef).floattype],right.location,location.register,nil);
end;
end; end;
end end
else else

View File

@ -392,13 +392,16 @@ end;
destructor TFBAdmin.Destroy; destructor TFBAdmin.Destroy;
begin begin
if FSvcHandle<>FB_API_NULLHANDLE then try
begin if FSvcHandle<>FB_API_NULLHANDLE then
WaitInterval:=100; begin
DisConnect; WaitInterval:=100;
DisConnect; // This can raise an exception
end;
Finally
FOutput.Destroy;
inherited Destroy;
end; end;
FOutput.Destroy;
inherited Destroy;
end; end;
function TFBAdmin.Connect: boolean; function TFBAdmin.Connect: boolean;

View File

@ -179,7 +179,8 @@ Resourcestring
SErrInvalidNumber = 'Number is not an integer or real number: %s'; SErrInvalidNumber = 'Number is not an integer or real number: %s';
SErrNoScanner = 'No scanner. No source specified ?'; SErrNoScanner = 'No scanner. No source specified ?';
SErrorAt = 'Error at line %d, Pos %d: '; SErrorAt = 'Error at line %d, Pos %d: ';
SErrGarbageFound = 'Expected EOF, but got %s';
{ TBaseJSONReader } { TBaseJSONReader }
@ -189,6 +190,14 @@ begin
if (FScanner=Nil) then if (FScanner=Nil) then
DoError(SErrNoScanner); DoError(SErrNoScanner);
DoParse(False,True); DoParse(False,True);
if joStrict in Options then
begin
Repeat
GetNextToken;
Until CurrentToken<>tkWhiteSpace;
If CurrentToken<>tkEOF then
DoError(Format(SErrGarbageFound,[CurrentTokenString]));
end;
end; end;
{ {

View File

@ -169,6 +169,8 @@ constructor TJSONScanner.Create(const aSource: RawByteString; AOptions: TJSONOpt
begin begin
FSource:=aSource; FSource:=aSource;
FCurPos:=PAnsiChar(FSource); FCurPos:=PAnsiChar(FSource);
if FCurPos<>Nil then
FCurRow:=1;
FOptions:=AOptions; FOptions:=AOptions;
end; end;

View File

@ -75,6 +75,8 @@ type
procedure TestMixed; procedure TestMixed;
Procedure TestComment; Procedure TestComment;
procedure TestErrors; procedure TestErrors;
procedure TestGarbageOK;
procedure TestGarbageFail;
end; end;
TTestReader = Class(TBaseTestReader) TTestReader = Class(TBaseTestReader)
@ -450,6 +452,18 @@ begin
end; end;
procedure TBaseTestReader.TestGarbageOK;
begin
TestRead('"a"sss',['string:a']);
TestRead('[null]xxx',['sa','null','ea']);
end;
procedure TBaseTestReader.TestGarbageFail;
begin
DoTestError('"a"sss',[joStrict]);
DoTestError('[null]aaa',[joStrict]);
end;
procedure TBaseTestReader.CallNoHandlerStream; procedure TBaseTestReader.CallNoHandlerStream;

View File

@ -36,6 +36,7 @@ Type
Private Private
FStrData : Array[0..StrDataCount] of string; FStrData : Array[0..StrDataCount] of string;
FCertData : Array[0..SSLDataCount] of TSSLData; FCertData : Array[0..SSLDataCount] of TSSLData;
FTrustedCertsDir: String;
function GetSSLData(AIndex: Integer): TSSLData; function GetSSLData(AIndex: Integer): TSSLData;
procedure SetSSLData(AIndex: Integer; AValue: TSSLData); procedure SetSSLData(AIndex: Integer; AValue: TSSLData);
function GetString(AIndex: Integer): String; function GetString(AIndex: Integer): String;
@ -54,6 +55,8 @@ Type
property PrivateKey : TSSLData Index 2 Read GetSSLData Write SetSSLData; property PrivateKey : TSSLData Index 2 Read GetSSLData Write SetSSLData;
property PFX: TSSLData Index 3 Read GetSSLData Write SetSSLData; property PFX: TSSLData Index 3 Read GetSSLData Write SetSSLData;
property CertCA: TSSLData Index 4 Read GetSSLData Write SetSSLData; property CertCA: TSSLData Index 4 Read GetSSLData Write SetSSLData;
// OpenSSL allows both a PEM file or a Dir. We separate out the dir.
Property TrustedCertsDir : String Read FTrustedCertsDir Write FTrustedCertsDir;
end; end;
{ TX509Certificate } { TX509Certificate }

View File

@ -51,9 +51,12 @@ Type
protected protected
Procedure SetSSLActive(aValue : Boolean); Procedure SetSSLActive(aValue : Boolean);
function DoVerifyCert: boolean; virtual; // if event define's change not accceptable, suggest to set virtual function DoVerifyCert: boolean; virtual; // if event define's change not accceptable, suggest to set virtual
Function GetLastSSLErrorString : String; virtual; abstract;
Function GetLastSSLErrorCode : Integer; virtual; abstract;
public public
constructor Create; override; constructor Create; override;
Destructor Destroy; override; Destructor Destroy; override;
Function GetLastErrorDescription : String;override;
// Class factory methods // Class factory methods
Class Procedure SetDefaultHandlerClass(aClass : TSSLSocketHandlerClass); Class Procedure SetDefaultHandlerClass(aClass : TSSLSocketHandlerClass);
Class Function GetDefaultHandlerClass : TSSLSocketHandlerClass; Class Function GetDefaultHandlerClass : TSSLSocketHandlerClass;
@ -64,6 +67,8 @@ Type
function CreateSelfSignedCertificate: Boolean; virtual; function CreateSelfSignedCertificate: Boolean; virtual;
Property CertGenerator : TX509Certificate Read FCertGenerator; Property CertGenerator : TX509Certificate Read FCertGenerator;
Property SSLActive: Boolean read FSSLActive; Property SSLActive: Boolean read FSSLActive;
Property LastSSLErrorString : String Read GetLastSSLErrorString;
Property LastSSLErrorCode : Integer Read GetLastSSLErrorCode;
published published
property SSLType: TSSLType read FSSLType write FSSLType; property SSLType: TSSLType read FSSLType write FSSLType;
property VerifyPeerCert: Boolean read FVerifyPeerCert Write FVerifyPeerCert; property VerifyPeerCert: Boolean read FVerifyPeerCert Write FVerifyPeerCert;
@ -92,6 +97,7 @@ Resourcestring
'Please include opensslsockets unit in program and recompile it.'; 'Please include opensslsockets unit in program and recompile it.';
SErrNoX509Certificate = SErrNoX509Certificate =
'Cannot create a X509 certificate without SLL support'; 'Cannot create a X509 certificate without SLL support';
SSSLErrorCode = 'SSL error code: %d';
{ TSSLSocketHandler } { TSSLSocketHandler }
@ -177,6 +183,19 @@ begin
inherited Destroy; inherited Destroy;
end; end;
function TSSLSocketHandler.GetLastErrorDescription: String;
begin
Result:='';
if LastSSLErrorCode<>0 then
Result:=Format(SSSLErrorCode,[GetLastSSLErrorCode]);
if LastSSLErrorString<>'' then
begin
if (Result<>'') then
Result:=Result+': ';
Result:=Result+LastSSLErrorString;
end;
end;
class procedure TSSLSocketHandler.SetDefaultHandlerClass(aClass: TSSLSocketHandlerClass); class procedure TSSLSocketHandler.SetDefaultHandlerClass(aClass: TSSLSocketHandlerClass);
begin begin
FDefaultHandlerClass:=aClass; FDefaultHandlerClass:=aClass;

View File

@ -70,6 +70,8 @@ type
function Recv(Const Buffer; Count: Integer): Integer; virtual; function Recv(Const Buffer; Count: Integer): Integer; virtual;
function Send(Const Buffer; Count: Integer): Integer; virtual; function Send(Const Buffer; Count: Integer): Integer; virtual;
function BytesAvailable: Integer; virtual; function BytesAvailable: Integer; virtual;
// Call this to get extra error info.
Function GetLastErrorDescription : String; virtual;
Property Socket : TSocketStream Read FSocket; Property Socket : TSocketStream Read FSocket;
Property LastError : Integer Read FLastError; Property LastError : Integer Read FLastError;
end; end;
@ -289,7 +291,7 @@ resourcestring
strSocketCreationFailed = 'Creation of socket failed: %s'; strSocketCreationFailed = 'Creation of socket failed: %s';
strSocketBindFailed = 'Binding of socket failed: %s'; strSocketBindFailed = 'Binding of socket failed: %s';
strSocketListenFailed = 'Listening on port #%d failed, error: %d'; strSocketListenFailed = 'Listening on port #%d failed, error: %d';
strSocketConnectFailed = 'Connect to %s failed.'; strSocketConnectFailed = 'Connect to %s failed: %s';
strSocketAcceptFailed = 'Could not accept a client connection on socket: %d, error %d'; strSocketAcceptFailed = 'Could not accept a client connection on socket: %d, error %d';
strSocketAcceptWouldBlock = 'Accept would block on socket: %d'; strSocketAcceptWouldBlock = 'Accept would block on socket: %d';
strSocketIOTimeOut = 'Failed to set IO Timeout to %d'; strSocketIOTimeOut = 'Failed to set IO Timeout to %d';
@ -380,6 +382,11 @@ begin
{ we need ioctlsocket here } { we need ioctlsocket here }
end; end;
function TSocketHandler.GetLastErrorDescription: String;
begin
Result:='';
end;
Function TSocketHandler.Close: Boolean; Function TSocketHandler.Close: Boolean;
begin begin
@ -401,7 +408,7 @@ begin
seAcceptFailed : s := strSocketAcceptFailed; seAcceptFailed : s := strSocketAcceptFailed;
seAcceptWouldBLock : S := strSocketAcceptWouldBlock; seAcceptWouldBLock : S := strSocketAcceptWouldBlock;
seIOTimeout : S := strSocketIOTimeOut; seIOTimeout : S := strSocketIOTimeOut;
seConnectTimeOut : s := strSocketConnectTimeout; seConnectTimeOut : s := strSocketConnectTimeout;
end; end;
s := Format(s, MsgArgs); s := Format(s, MsgArgs);
inherited Create(s); inherited Create(s);
@ -1117,6 +1124,7 @@ Var
IsError : Boolean; IsError : Boolean;
TimeOutResult : TCheckTimeOutResult; TimeOutResult : TCheckTimeOutResult;
Err: Integer; Err: Integer;
aErrMsg : String;
{$IFDEF HAVENONBLOCKING} {$IFDEF HAVENONBLOCKING}
FDS: TFDSet; FDS: TFDSet;
TimeV: TTimeVal; TimeV: TTimeVal;
@ -1171,7 +1179,10 @@ begin
if TimeoutResult=ctrTimeout then if TimeoutResult=ctrTimeout then
Raise ESocketError.Create(seConnectTimeOut, [Format('%s:%d',[FHost, FPort])]) Raise ESocketError.Create(seConnectTimeOut, [Format('%s:%d',[FHost, FPort])])
else else
Raise ESocketError.Create(seConnectFailed, [Format('%s:%d',[FHost, FPort])]); begin
aErrMsg:=FHandler.GetLastErrorDescription;
Raise ESocketError.Create(seConnectFailed, [Format('%s:%d',[FHost, FPort]),aErrMsg]);
end;
end; end;
{ --------------------------------------------------------------------- { ---------------------------------------------------------------------
@ -1203,7 +1214,7 @@ Var
begin begin
Str2UnixSockAddr(FFilename,UnixAddr,AddrLen); Str2UnixSockAddr(FFilename,UnixAddr,AddrLen);
If FpConnect(ASocket,@UnixAddr,AddrLen)<>0 then If FpConnect(ASocket,@UnixAddr,AddrLen)<>0 then
Raise ESocketError.Create(seConnectFailed,[FFilename]); Raise ESocketError.Create(seConnectFailed,[FFilename,'']);
end; end;
{$endif} {$endif}
end. end.

View File

@ -4,7 +4,7 @@ program httpget;
{$DEFINE USEGNUTLS} {$DEFINE USEGNUTLS}
uses uses
SysUtils, Classes, fphttpclient, SysUtils, Classes, fphttpclient, ssockets,
{$IFNDEF USEGNUTLS} {$IFNDEF USEGNUTLS}
fpopenssl, opensslsockets, fpopenssl, opensslsockets,
{$else} {$else}
@ -17,6 +17,9 @@ Type
{ TTestApp } { TTestApp }
TTestApp = Class(Tobject) TTestApp = Class(Tobject)
private
procedure DoHaveSocketHandler(Sender: TObject; AHandler: TSocketHandler);
procedure DoVerifyCertificate(Sender: TObject; AHandler: TSSLSocketHandler; var aAllow: Boolean);
procedure DoProgress(Sender: TObject; Const ContentLength, CurrentPos : Int64); procedure DoProgress(Sender: TObject; Const ContentLength, CurrentPos : Int64);
procedure DoHeaders(Sender : TObject); procedure DoHeaders(Sender : TObject);
procedure DoPassword(Sender: TObject; var RepeatRequest: Boolean); procedure DoPassword(Sender: TObject; var RepeatRequest: Boolean);
@ -84,6 +87,7 @@ begin
Writeln('Following redirect from ',ASrc,' ==> ',ADest); Writeln('Following redirect from ',ASrc,' ==> ',ADest);
end; end;
procedure TTestApp.Run; procedure TTestApp.Run;
begin begin
@ -99,6 +103,9 @@ begin
OnPassword:=@DoPassword; OnPassword:=@DoPassword;
OnDataReceived:=@DoProgress; OnDataReceived:=@DoProgress;
OnHeaders:=@DoHeaders; OnHeaders:=@DoHeaders;
VerifySSlCertificate:=True;
OnVerifySSLCertificate:=@DoVerifyCertificate;
AfterSocketHandlerCreate:=@DoHaveSocketHandler;
{ Set this if you want to try a proxy. { Set this if you want to try a proxy.
Proxy.Host:='195.207.46.20'; Proxy.Host:='195.207.46.20';
Proxy.Port:=8080; Proxy.Port:=8080;
@ -109,6 +116,30 @@ begin
end; end;
end; end;
procedure TTestApp.DoHaveSocketHandler(Sender: TObject; AHandler: TSocketHandler);
Var
SSLHandler : TSSLSocketHandler absolute aHandler;
begin
if (aHandler is TSSLSocketHandler) then
begin
SSLHandler.CertificateData.TrustedCertsDir:='/etc/ssl/certs/';
end
end;
procedure TTestApp.DoVerifyCertificate(Sender: TObject; AHandler: TSSLSocketHandler; var aAllow: Boolean);
Var
S : String;
begin
Writeln('SSL Certificate verification requested, allowing');
S:=TEncoding.ASCII.GetAnsiString( aHandler.CertificateData.Certificate.Value);
Writeln('Cert: ',S);
aAllow:=True;
end;
begin begin
With TTestApp.Create do With TTestApp.Create do
try try

View File

@ -14,17 +14,12 @@
**********************************************************************} **********************************************************************}
unit fphttpclient; unit fphttpclient;
{ ---------------------------------------------------------------------
Todo:
* Proxy support ?
---------------------------------------------------------------------}
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
interface interface
uses uses
Classes, SysUtils, ssockets, httpdefs, uriparser, base64; Classes, SysUtils, ssockets, httpdefs, uriparser, base64, sslsockets;
Const Const
// Socket Read buffer size // Socket Read buffer size
@ -42,6 +37,7 @@ Type
// Use this to set up a socket handler. UseSSL is true if protocol was https // Use this to set up a socket handler. UseSSL is true if protocol was https
TGetSocketHandlerEvent = Procedure (Sender : TObject; Const UseSSL : Boolean; Out AHandler : TSocketHandler) of object; TGetSocketHandlerEvent = Procedure (Sender : TObject; Const UseSSL : Boolean; Out AHandler : TSocketHandler) of object;
TSocketHandlerCreatedEvent = Procedure (Sender : TObject; AHandler : TSocketHandler) of object; TSocketHandlerCreatedEvent = Procedure (Sender : TObject; AHandler : TSocketHandler) of object;
THTTPVerifyCertificateEvent = Procedure (Sender : TObject; AHandler : TSSLSocketHandler; var aAllow : Boolean) of object;
TFPCustomHTTPClient = Class; TFPCustomHTTPClient = Class;
@ -79,6 +75,7 @@ Type
FOnHeaders: TNotifyEvent; FOnHeaders: TNotifyEvent;
FOnPassword: TPasswordEvent; FOnPassword: TPasswordEvent;
FOnRedirect: TRedirectEvent; FOnRedirect: TRedirectEvent;
FOnVerifyCertificate: THTTPVerifyCertificateEvent;
FPassword: String; FPassword: String;
FIOTimeout: Integer; FIOTimeout: Integer;
FConnectTimeout: Integer; FConnectTimeout: Integer;
@ -98,6 +95,7 @@ Type
FOnGetSocketHandler : TGetSocketHandlerEvent; FOnGetSocketHandler : TGetSocketHandlerEvent;
FAfterSocketHandlerCreated : TSocketHandlerCreatedEvent; FAfterSocketHandlerCreated : TSocketHandlerCreatedEvent;
FProxy : TProxyData; FProxy : TProxyData;
FVerifySSLCertificate: Boolean;
function CheckContentLength: Int64; function CheckContentLength: Int64;
function CheckTransferEncoding: string; function CheckTransferEncoding: string;
function GetCookies: TStrings; function GetCookies: TStrings;
@ -113,7 +111,8 @@ Type
Procedure ExtractHostPort(AURI: TURI; Out AHost: String; Out APort: Word); Procedure ExtractHostPort(AURI: TURI; Out AHost: String; Out APort: Word);
Procedure CheckConnectionCloseHeader; Procedure CheckConnectionCloseHeader;
protected protected
// Called with TSSLSocketHandler as sender
procedure DoVerifyCertificate(Sender: TObject; var Allow: Boolean); virtual;
Function NoContentAllowed(ACode : Integer) : Boolean; Function NoContentAllowed(ACode : Integer) : Boolean;
// Peform a request, close connection. // Peform a request, close connection.
Procedure DoNormalRequest(const AURI: TURI; const AMethod: string; Procedure DoNormalRequest(const AURI: TURI; const AMethod: string;
@ -305,9 +304,6 @@ Type
// Maximum chunk size: If chunk sizes bigger than this are encountered, an error will be raised. // Maximum chunk size: If chunk sizes bigger than this are encountered, an error will be raised.
// Set to zero to disable the check. // Set to zero to disable the check.
Property MaxChunkSize : SizeUInt Read FMaxChunkSize Write FMaxChunkSize; Property MaxChunkSize : SizeUInt Read FMaxChunkSize Write FMaxChunkSize;
// Called On redirect. Dest URL can be edited.
// If The DEST url is empty on return, the method is aborted (with redirect status).
Property OnRedirect : TRedirectEvent Read FOnRedirect Write FOnRedirect;
// Proxy support // Proxy support
Property Proxy : TProxyData Read GetProxy Write SetProxy; Property Proxy : TProxyData Read GetProxy Write SetProxy;
// Authentication. // Authentication.
@ -319,6 +315,11 @@ Type
Property Connected: Boolean read IsConnected; Property Connected: Boolean read IsConnected;
// Keep-Alive support. Setting to true will set HTTPVersion to 1.1 // Keep-Alive support. Setting to true will set HTTPVersion to 1.1
Property KeepConnection: Boolean Read FKeepConnection Write SetKeepConnection; Property KeepConnection: Boolean Read FKeepConnection Write SetKeepConnection;
// SSL certificate validation.
Property VerifySSLCertificate : Boolean Read FVerifySSLCertificate Write FVerifySSLCertificate;
// Called On redirect. Dest URL can be edited.
// If The DEST url is empty on return, the method is aborted (with redirect status).
Property OnRedirect : TRedirectEvent Read FOnRedirect Write FOnRedirect;
// If a request returns a 401, then the OnPassword event is fired. // If a request returns a 401, then the OnPassword event is fired.
// It can modify the username/password and set RepeatRequest to true; // It can modify the username/password and set RepeatRequest to true;
Property OnPassword : TPasswordEvent Read FOnPassword Write FOnPassword; Property OnPassword : TPasswordEvent Read FOnPassword Write FOnPassword;
@ -330,6 +331,8 @@ Type
Property OnGetSocketHandler : TGetSocketHandlerEvent Read FOnGetSocketHandler Write FOnGetSocketHandler; Property OnGetSocketHandler : TGetSocketHandlerEvent Read FOnGetSocketHandler Write FOnGetSocketHandler;
// Called after create socket handler was created, with the created socket handler. // Called after create socket handler was created, with the created socket handler.
Property AfterSocketHandlerCreate : TSocketHandlerCreatedEvent Read FAfterSocketHandlerCreated Write FAfterSocketHandlerCreated; Property AfterSocketHandlerCreate : TSocketHandlerCreatedEvent Read FAfterSocketHandlerCreated Write FAfterSocketHandlerCreated;
// Called when a SSL certificate must be verified.
Property OnVerifySSLCertificate : THTTPVerifyCertificateEvent Read FOnVerifyCertificate Write FOnVerifyCertificate;
end; end;
@ -357,6 +360,10 @@ Type
Property OnHeaders; Property OnHeaders;
Property OnGetSocketHandler; Property OnGetSocketHandler;
Property Proxy; Property Proxy;
Property VerifySSLCertificate;
Property AfterSocketHandlerCreate;
Property OnVerifySSLCertificate;
end; end;
EHTTPClient = Class(EHTTP); EHTTPClient = Class(EHTTP);
@ -366,8 +373,6 @@ Function DecodeURLElement(Const S : String) : String;
implementation implementation
uses sslsockets;
resourcestring resourcestring
SErrInvalidProtocol = 'Invalid protocol : "%s"'; SErrInvalidProtocol = 'Invalid protocol : "%s"';
SErrReadingSocket = 'Error reading data from socket'; SErrReadingSocket = 'Error reading data from socket';
@ -585,13 +590,21 @@ end;
function TFPCustomHTTPClient.GetSocketHandler(const UseSSL: Boolean): TSocketHandler; function TFPCustomHTTPClient.GetSocketHandler(const UseSSL: Boolean): TSocketHandler;
Var
SSLHandler : TSSLSocketHandler;
begin begin
Result:=Nil; Result:=Nil;
if Assigned(FonGetSocketHandler) then if Assigned(FonGetSocketHandler) then
FOnGetSocketHandler(Self,UseSSL,Result); FOnGetSocketHandler(Self,UseSSL,Result);
if (Result=Nil) then if (Result=Nil) then
If UseSSL then If UseSSL then
Result:=TSSLSocketHandler.GetDefaultHandler begin
SSLHandler:=TSSLSocketHandler.GetDefaultHandler;
SSLHandler.VerifyPeerCert:=FVerifySSLCertificate;
SSLHandler.OnVerifyCertificate:=@DoVerifyCertificate;
Result:=SSLHandler;
end
else else
Result:=TSocketHandler.Create; Result:=TSocketHandler.Create;
if Assigned(AfterSocketHandlerCreate) then if Assigned(AfterSocketHandlerCreate) then
@ -945,6 +958,12 @@ begin
end; end;
end; end;
procedure TFPCustomHTTPClient.DoVerifyCertificate(Sender: TObject; var Allow: Boolean);
begin
If Assigned(FOnVerifyCertificate) then
FOnVerifyCertificate(Self,Sender as TSSLSocketHandler,Allow);
end;
function TFPCustomHTTPClient.GetCookies: TStrings; function TFPCustomHTTPClient.GetCookies: TStrings;
begin begin
If (FCookies=Nil) then If (FCookies=Nil) then

View File

@ -128,7 +128,7 @@ Type
Destructor Destroy; override; Destructor Destroy; override;
// Owned by the JWT. The JSON header. // Owned by the JWT. The JSON header.
Property JOSE : TJOSE Read FJOSE Write SetJOSE; Property JOSE : TJOSE Read FJOSE Write SetJOSE;
// Owned by the JWT. The set of claims. The actuall class will depend on the descendant. // Owned by the JWT. The set of claims. The actual class will depend on the descendant.
Property Claims : TClaims Read FClaims Write SetClaims; Property Claims : TClaims Read FClaims Write SetClaims;
Property Signature : String Read FSignature Write FSignature; Property Signature : String Read FSignature Write FSignature;
end; end;

View File

@ -124,7 +124,7 @@ begin
else else
begin begin
D:=ADirectory; D:=ADirectory;
if Copy(D,1,1)<>'/' then if (D<>ExpandFileName(D)) then
D:=BaseDir+D; D:=BaseDir+D;
if not DirectoryExists(D) then if not DirectoryExists(D) then
Raise HTTPError.CreateFmt(SErrInvalidDirectory,[D]); Raise HTTPError.CreateFmt(SErrInvalidDirectory,[D]);

View File

@ -40,6 +40,8 @@ Type
function InitSession(AsServer: Boolean): Boolean; virtual; function InitSession(AsServer: Boolean): Boolean; virtual;
function DoneSession: Boolean; virtual; function DoneSession: Boolean; virtual;
function InitSslKeys: boolean;virtual; function InitSslKeys: boolean;virtual;
function GetLastSSLErrorCode: Integer; override;
function GetLastSSLErrorString: String; override;
Public Public
Constructor create; override; Constructor create; override;
destructor destroy; override; destructor destroy; override;
@ -288,7 +290,7 @@ begin
exit; exit;
Result:=DoHandShake; Result:=DoHandShake;
if Result and VerifyPeerCert then if Result and VerifyPeerCert then
Result:=(not DoVerifyCert); Result:=DoVerifyCert;
if Result then if Result then
SetSSLActive(True); SetSSLActive(True);
end; end;
@ -480,8 +482,8 @@ begin
Result:=LoadCertificate(CertificateData.Certificate,CertificateData.PrivateKey); Result:=LoadCertificate(CertificateData.Certificate,CertificateData.PrivateKey);
if Result and Not CertificateData.TrustedCertificate.Empty then if Result and Not CertificateData.TrustedCertificate.Empty then
Result:=LoadTrustedCertificate(CertificateData.TrustedCertificate); Result:=LoadTrustedCertificate(CertificateData.TrustedCertificate);
if Result and (CertificateData.CertCA.FileName<>'') then if Result and (CertificateData.TrustedCertsDir<>'') then
Result:=Result and SetTrustedCertificateDir(CertificateData.CertCA.FileName); Result:=Result and SetTrustedCertificateDir(CertificateData.TrustedCertsDir);
// If nothing was set, set defaults. // If nothing was set, set defaults.
if not Assigned(FCred) then if not Assigned(FCred) then
begin begin
@ -598,6 +600,16 @@ begin
Result:=FGNUTLSLastError; Result:=FGNUTLSLastError;
end; end;
function TGNUTLSSocketHandler.GetLastSSLErrorString: String;
begin
Result:=FGNUTLSLastErrorString;
end;
function TGNUTLSSocketHandler.GetLastSSLErrorCode: Integer;
begin
Result:=FGNUTLSLastError;
end;
initialization initialization
TSSLSocketHandler.SetDefaultHandlerClass(TGNUTLSSocketHandler); TSSLSocketHandler.SetDefaultHandlerClass(TGNUTLSSocketHandler);
end. end.

View File

@ -25,6 +25,8 @@ Type
function InitContext(NeedCertificate: Boolean): Boolean; virtual; function InitContext(NeedCertificate: Boolean): Boolean; virtual;
function DoneContext: Boolean; virtual; function DoneContext: Boolean; virtual;
function InitSslKeys: boolean;virtual; function InitSslKeys: boolean;virtual;
Function GetLastSSLErrorString : String; override;
Function GetLastSSLErrorCode : Integer; override;
Public Public
Constructor create; override; Constructor create; override;
destructor destroy; override; destructor destroy; override;
@ -171,12 +173,22 @@ begin
Result:=CheckSSL(FCTX.UseCertificate(CertificateData.Certificate)); Result:=CheckSSL(FCTX.UseCertificate(CertificateData.Certificate));
if Result and not CertificateData.PrivateKey.Empty then if Result and not CertificateData.PrivateKey.Empty then
Result:=CheckSSL(FCTX.UsePrivateKey(CertificateData.PrivateKey)); Result:=CheckSSL(FCTX.UsePrivateKey(CertificateData.PrivateKey));
if Result and (CertificateData.CertCA.FileName<>'') then if Result and ((CertificateData.CertCA.FileName<>'') or (CertificateData.TrustedCertsDir<>'')) then
Result:=CheckSSL(FCTX.LoadVerifyLocations(CertificateData.CertCA.FileName,'')); Result:=CheckSSL(FCTX.LoadVerifyLocations(CertificateData.CertCA.FileName,CertificateData.TrustedCertsDir));
if Result and not CertificateData.PFX.Empty then if Result and not CertificateData.PFX.Empty then
Result:=CheckSSL(FCTX.LoadPFX(CertificateData.PFX,CertificateData.KeyPassword)); Result:=CheckSSL(FCTX.LoadPFX(CertificateData.PFX,CertificateData.KeyPassword));
end; end;
function TOpenSSLSocketHandler.GetLastSSLErrorString: String;
begin
Result:=FSSLLastErrorString;
end;
function TOpenSSLSocketHandler.GetLastSSLErrorCode: Integer;
begin
Result:=FSSLLastError;
end;
constructor TOpenSSLSocketHandler.create; constructor TOpenSSLSocketHandler.create;
begin begin
inherited create; inherited create;

View File

@ -1293,7 +1293,9 @@ Function HexStr(Val:Pointer):shortstring;
{$endif CPUI8086} {$endif CPUI8086}
{ Char functions } { Char functions }
{$ifdef VER3_2}
Function Chr(b : byte) : Char; [INTERNPROC: fpc_in_chr_byte]; Function Chr(b : byte) : Char; [INTERNPROC: fpc_in_chr_byte];
{$endif VER3_2}
Function UpCase(c:Char):Char; Function UpCase(c:Char):Char;
Function LowerCase(c:Char):Char; overload; Function LowerCase(c:Char):Char; overload;
function Pos(const substr : shortstring;c:char; Offset: Sizeint = 1): SizeInt; function Pos(const substr : shortstring;c:char; Offset: Sizeint = 1): SizeInt;

91
rtl/sinclairql/qdos.inc Normal file
View File

@ -0,0 +1,91 @@
{
This file is part of the Free Pascal run time library.
Copyright (c) 2020 by Karoly Balogh
Interface QDOS OS functions used by the Sinclair QL RTL
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.
**********************************************************************}
{$i qdosh.inc}
const
_MT_ALCHP = $18;
_MT_RECHP = $19;
function mt_alchp(size: dword; sizegot: pdword; jobid: Tjobid): pointer; assembler; nostackframe; public name '_mt_alchp';
asm
movem.l d2-d3/a2-a3,-(sp)
move.l sizegot,-(sp)
move.l jobid,d2
move.l size,d1
moveq.l #_MT_ALCHP,d0
trap #1
move.l (sp)+,d2 // sizegot ptr
tst d0
bne @quit
move.l d2,a1
beq @nosizegot
move.l d1,(a1)
@nosizegot:
move.l a0,d0
@quit:
movem.l (sp)+,d2-d3/a2-a3
end;
procedure mt_rechp(area: pointer); assembler; nostackframe; public name '_mt_rechp';
asm
movem.l d2-d3/a2-a3,-(sp)
move.l area,a0
moveq.l #_MT_RECHP,d0
trap #1
movem.l (sp)+,d2-d3/a2-a3
end;
const
_IO_SBYTE = $05;
_IO_SSTRG = $07;
function io_sbyte(chan: Tchanid; timeout: Ttimeout; c: char): longint; assembler; public name '_io_sbyte';
asm
move.l d3,-(sp)
move.w timeout,d3
clr.l d1
move.b c,d1
move.l chan,a0
moveq.l #_IO_SBYTE,d0
trap #3
move.l (sp)+,d3
end;
function io_sstrg(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: smallint): smallint; assembler; public name '_io_sstrg';
asm
movem.l d2-d3,-(sp)
move.w len,d2
move.l buf,a1
move.w timeout,d3
move.l chan,a0
moveq.l #_IO_SSTRG,d0
trap #3
tst.l d0
beq @ok
cmp.w #ERR_EF,d0
beq @eof
cmp.w #ERR_NC,d0
bne @quit
@eof:
tst.w d1
beq @quit
@ok:
clr.l d0
move.w d1,d0
@quit:
movem.l (sp)+,d2-d3
end;

View File

@ -0,0 +1,22 @@
{
This file is part of the Free Pascal run time library.
Copyright (c) 2020 by Karoly Balogh
Headers to QDOS OS functions used by the Sinclair QL RTL
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.
**********************************************************************}
{$i qdosh.inc}
function mt_alchp(size: dword; sizegot: pdword; jobid: Tjobid): pointer; external name '_mt_alchp';
procedure mt_rechp(area: pointer); external name '_mt_rechp';
function io_sbyte(chan: Tchanid; timeout: Ttimeout; c: char): longint; external name '_io_sbyte';
function io_sstrg(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: smallint): smallint; external name '_io_sstrg';

43
rtl/sinclairql/qdosh.inc Normal file
View File

@ -0,0 +1,43 @@
{
This file is part of the Free Pascal run time library.
Copyright (c) 2020 by Karoly Balogh
Types and Constants used by QDOS OS functions in the Sinclair QL RTL
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.
**********************************************************************}
type
Tchanid = longint;
Tjobid = longint;
Ttimeout = smallint;
const
ERR_NC = -1; { Operation not complete }
ERR_NJ = -2; { Not a (valid) job. }
ERR_OM = -3; { Out of memory. }
ERR_OR = -4; { Out of range. }
ERR_BO = -5; { Buffer overflow. }
ERR_NO = -6; { Channel not open. }
ERR_NF = -7; { File or device not found. }
ERR_FX = -8; { File already exists. }
ERR_IU = -9; { File or device already in use. }
ERR_EF = -10; { End of file. }
ERR_DF = -11; { Drive full. }
ERR_BN = -12; { Bad device. }
ERR_TE = -13; { Transmission error. }
ERR_FF = -14; { Format failed. }
ERR_BP = -15; { Bad parameter. }
ERR_FE = -16; { File error. }
ERR_EX = -17; { Expression error. }
ERR_OV = -18; { Arithmetic overflow. }
ERR_NI = -19; { Not implemented. }
ERR_RO = -20; { Read only. }
ERR_BL = -21; { Bad line of Basic. }

View File

@ -19,23 +19,79 @@ interface
implementation implementation
{$i qdosfuncs.inc}
var var
procdesc: PPD; public name '__base';
stacktop: pointer; stacktop: pointer;
stackorig: pointer;
setjmpbuf: jmp_buf;
stklen: longint; external name '__stklen'; stklen: longint; external name '__stklen';
binstart: pointer; external name '_stext';
binend: pointer; external name '_etext';
procedure PascalMain; external name 'PASCALMAIN'; procedure PascalMain; external name 'PASCALMAIN';
{ this function must be the first in this unit which contains code } { this function must be the first in this unit which contains code }
{$OPTIMIZATION OFF} {$OPTIMIZATION OFF}
procedure _FPC_proc_start(pd: PPD); cdecl; public name '_start'; function _FPC_proc_start: longint; cdecl; public name '_start';
var
newstack: pointer;
begin begin
_FPC_proc_start:=0;
asm
move.l d7,-(sp)
{ relocation code }
{ get our actual position in RAM }
lea.l binstart(pc),a0
move.l a0,d0
{ get an offset to the end of the binary. this depends on the
fact that at this point the binary is not relocated yet }
lea.l binend,a1
add.l d0,a1
{ first item in the relocation table is the number of relocs }
move.l (a1),d7
beq @noreloc
{ zero out the number of relocs in RAM, so if our code is
called again, without reload, it won't relocate itself twice }
move.l #0,(a1)+
@relocloop:
{ we read the offsets and relocate them }
move.l (a1)+,d1
add.l d0,(a0,d1)
subq.l #1,d7
bne @relocloop
@noreloc:
move.l (sp)+,d7
{ save the original stack pointer }
move.l a7,stackorig
end;
newstack:=mt_alchp(stklen,nil,-1);
if not assigned(newstack) then
_FPC_proc_start:=ERR_OM
else
begin
asm
move.l newstack,sp
end;
if setjmp(setjmpbuf) = 0 then
PascalMain;
asm
move.l stackorig,sp
end;
mt_rechp(newstack);
end;
end; end;
procedure _FPC_proc_halt(_ExitCode: longint); cdecl; public name '_haltproc'; procedure _FPC_proc_halt(_ExitCode: longint); public name '_haltproc';
begin begin
longjmp(setjmpbuf,1);
end; end;

View File

@ -18,12 +18,15 @@
****************************************************************************} ****************************************************************************}
function SysOSAlloc(size: ptruint): pointer; function SysOSAlloc(size: ptruint): pointer;
begin begin
Result:=mt_alchp(size, nil, -1);
end; end;
{$define HAS_SYSOSFREE} {$define HAS_SYSOSFREE}
procedure SysOSFree(p: pointer; size: ptruint); procedure SysOSFree(p: pointer; size: ptruint);
begin begin
mt_rechp(p);
end; end;

View File

@ -15,6 +15,8 @@
**********************************************************************} **********************************************************************}
{$i qdos.inc}
procedure Error2InOutRes(errno: longint); procedure Error2InOutRes(errno: longint);
begin begin
end; end;

View File

@ -122,8 +122,12 @@ var
{***************************************************************************** {*****************************************************************************
System Dependent Exit code System Dependent Exit code
*****************************************************************************} *****************************************************************************}
procedure haltproc(e:longint); external name '_haltproc';
procedure system_exit; procedure system_exit;
begin begin
haltproc(exitcode);
end; end;
{***************************************************************************** {*****************************************************************************
@ -146,6 +150,19 @@ begin
CheckInitialStkLen := StkLen; CheckInitialStkLen := StkLen;
end; end;
procedure PrintStr(const s: shortstring);
begin
io_sstrg($00010001,-1,@s[1],ord(s[0]));
end;
procedure PrintStr2(const s: shortstring);
var
i: smallint;
begin
for i:=1 to ord(s[0]) do
io_sbyte($00010001,-1,s[i]);
end;
begin begin
StackLength := CheckInitialStkLen (InitialStkLen); StackLength := CheckInitialStkLen (InitialStkLen);
@ -160,7 +177,7 @@ begin
InitUnicodeStringManager; InitUnicodeStringManager;
{$endif FPC_HAS_FEATURE_UNICODESTRINGS} {$endif FPC_HAS_FEATURE_UNICODESTRINGS}
{ Setup stdin, stdout and stderr } { Setup stdin, stdout and stderr }
SysInitStdIO; (* SysInitStdIO;*)
{ Reset IO Error } { Reset IO Error }
InOutRes:=0; InOutRes:=0;
{ Setup command line arguments } { Setup command line arguments }

View File

@ -104,7 +104,7 @@ begin
end; end;
procedure DoGetLocalTimezone(info:pttinfo;const trans_start,trans_end:longint;var ATZInfo:TTZInfo); procedure DoGetLocalTimezone(info:pttinfo;const trans_start,trans_end:int64;var ATZInfo:TTZInfo);
begin begin
ATZInfo.validsince:=trans_start; ATZInfo.validsince:=trans_start;
ATZInfo.validuntil:=trans_end; ATZInfo.validuntil:=trans_end;

21
tests/webtbs/tw38051.pp Normal file
View File

@ -0,0 +1,21 @@
{ %NORUN }
program tw38051;
const cChr = chr(12); { Ok }
type Tcha = ord(3)..ord(12); { Ok }
type Tchz = 0000003..0000012; { Ok }
type Tcho = char(3)..char(12);{ Ok }
type Tchr = chr(3)..chr(12); { Error: Identifier not found "chr" }
type TArrChr = array [chr(3)..chr(12)] of char; { Ok }
var cz : 0000003..0000012; { Ok }
var ch : chr(3)..chr(12); { Error: Identifier not found "chr" }
var c : char;
begin
c:=chr(12); { Ok }
end.

12
tests/webtbs/tw38054.pp Normal file
View File

@ -0,0 +1,12 @@
{ %norun }
const
l = high(ptrint); // 2000 <--> 2100
type
t = array[ 1..l ]of int8; // 1.95 <--> 2.05 GiBy
var
p: ^t;
begin
new(p);
writeln( sizeof(p^) );
p^[l]:=0; writeln(p^[l])
end .