fpc/rtl/os2/sysos2.pas
1998-03-25 11:18:12 +00:00

810 lines
15 KiB
ObjectPascal

{****************************************************************************
FPK-Pascal -- OS/2 runtime library
Copyright (c) 1993,95 by Florian Kl„mpfl
Copyright (c) 1997 by Dani‰l Mantione
FPK-Pascal is distributed under the GNU Public License v2. So is this unit.
The GNU Public License requires you to distribute the source code of this
unit with any product that uses it. We grant you an exception to this, and
that is, when you compile a program with the FPK Pascal compiler, you do not
need to ship source code with that program, AS LONG AS YOU ARE USING
UNMODIFIED CODE! If you modify this code, you MUST change the next line:
<This an official, unmodified FPK Pascal source code file.>
Send us your modified files, we can work together if you want!
****************************************************************************}
unit sysos2;
{$I os.inc}
interface
{ die betriebssystemunabhangigen Deklarationen einfuegen: }
{$I SYSTEMH.INC}
{$I heaph.inc}
type Tos=(osDOS,osOS2,osDPMI);
var os_mode:Tos;
first_meg:pointer;
type Psysthreadib=^Tsysthreadib;
Pthreadinfoblock=^Tthreadinfoblock;
Pprocessinfoblock=^Tprocessinfoblock;
Tbytearray=array[0..$ffff] of byte;
Pbytearray=^Tbytearray;
Tsysthreadib=record
tid,
priority,
version:longint;
MCcount,
MCforceflag:word;
end;
Tthreadinfoblock=record
pexchain,
stack,
stacklimit:pointer;
tib2:Psysthreadib;
version,
ordinal:longint;
end;
Tprocessinfoblock=record
pid,
parentpid,
hmte:longint;
cmd,
env:Pbytearray;
flstatus,
ttype:longint;
end;
procedure _DosGetInfoBlocks(var Atib:Pthreadinfoblock;
var Apib:Pprocessinfoblock);
implementation
{ die betriebssystemunabhangigen Implementationen einfuegen: }
{$I SYSTEM.INC}
procedure _DosGetInfoBlocks(var Atib:Pthreadinfoblock;
var Apib:Pprocessinfoblock);[C];
{****************************************************************************
Miscelleanious related routines.
****************************************************************************}
procedure halt;
begin
asm
movw $0x4c00,%ax
call ___syscall
end;
end;
procedure halt(errnum : byte);
begin
asm
movb $0x4c,%ah
movb errnum,%al
call ___syscall
end;
end;
function paramcount : longint;
begin
asm
movl _argc,%eax
decl %eax
leave
ret
end ['EAX'];
end;
function paramstr(l : longint):string;
function args : pointer;
begin
asm
movl _argv,%eax
leave
ret
end ['EAX'];
end;
var p:^Pchar;
begin
if (l>=0) and (l<=paramcount) then
begin
p:=args;
paramstr:=strpas(p[l]);
end
else paramstr:='';
end;
procedure randomize;
var hl:longint;
begin
asm
movb $0x2c,%ah
call ___syscall
movw %cx,-4(%ebp)
movw %dx,-2(%ebp)
end;
randseed:=hl;
end;
{****************************************************************************
Text-file I/O related routines.
****************************************************************************}
function open(f:Pchar;flags:longint):longint;
begin
asm
movb $0x3d,%ah
movl 8(%ebp),%edx
movb 12(%ebp),%al
call ___syscall
jnc LOPEN1
movw %ax,U_SYSOS2_INOUTRES;
xorl %eax,%eax
LOPEN1:
; Returnwert ist in EAX
leave
ret $8
end;
end;
function create(f : pchar):longint;
begin
asm
movb $0x3c,%ah
movl 8(%ebp),%edx
xor %ecx,%ecx
call ___syscall
jnc Lcreate1
movw %ax,U_SYSOS2_INOUTRES;
xorl %eax,%eax
Lcreate1:
; Returnwert ist in EAX
leave
ret $8
end;
end;
procedure do_close(h:longint);
begin
asm
movb $0x3e,%ah
mov h,%ebx
call ___syscall
end;
end;
function dosfilepos(handle:longint) : longint;
begin
asm
movb $0x42,%ah
movb $0x1,%al
movl 8(%ebp),%ebx
xorl %edx,%edx
call ___syscall
jnc LDOSFILEPOS
movw %ax,U_SYSOS2_INOUTRES;
xorl %eax,%eax
LDOSFILEPOS:
leave
ret $4
end;
end;
procedure dosseek(handle:longint;pos:longint);
begin
asm
movb $0x42,%ah
xorb %al,%al
movl 8(%ebp),%ebx
movl 12(%ebp),%edx
call ___syscall
jnc LDOSSEEK1
movw %ax,U_SYSOS2_INOUTRES;
LDOSSEEK1:
end;
end;
function dosfilesize(handle : longint):longint;
function set_at_end(handle:longint) : longint;
begin
asm
movb $0x42,%ah
movb $0x2,%al
; Vorsicht Stack: 0 %ebp; 4 retaddr;
; 8 nextstackframe; 12 handle
movl 12(%ebp),%ebx
xorl %edx,%edx
call ___syscall
jnc Lset_at_end
movw %ax,U_SYSOS2_INOUTRES;
xorl %eax,%eax
Lset_at_end:
leave
ret $8
end;
end;
var tempfilesize,aktfilepos:longint;
begin
aktfilepos:=dosfilepos(handle);
tempfilesize:=set_at_end(handle);
dosseek(handle,aktfilepos);
dosfilesize:=tempfilesize;
end;
procedure fileclosefunc(var t : textrec);
begin
do_close(t.handle);
t.mode:=fmclosed;
end;
procedure fileopenfunc(var f:textrec);
var b:array[0..255] of char;
size:longint;
begin
move(f.name[1],b,length(f.name));
b[length(f.name)]:=#0;
f.inoutfunc:=@fileinoutfunc;
f.flushfunc:=@fileinoutfunc;
f.closefunc:=@fileclosefunc;
case f.mode of
fminput:
f.handle:=open(b,0);
fmoutput:
f.handle:=create(b);
fmappend:
begin
f.handle:=open(b,1);
f.mode:=fmoutput;
size:=dosfilesize(f.handle);
if size>0 then
begin
{Set filepointer to eof character if present,
or to end of file if not. Any change to the
file causes the eof character to be overwritten,
so we get a correct text file.}
dosseek(f.handle,size-1);
dosread(f.handle,longint(@b),1);
if b[0]<>#26 then
dosseek(f.handle,size);
end;
end;
end;
end;
function eof(var t:text):boolean;[iocheck];
var zoekpos:byte;
begin
{ maybe we need new data }
if textrec(t).bufpos+3>=textrec(t).bufend then
dateifunc(textrec(t).inoutfunc)(textrec(t));
eof:=dosfilesize(textrec(t).handle)<=dosfilepos(textrec(t).handle);
if eof then
eof:=textrec(t).bufend<=textrec(t).bufpos;
if not eof then
begin
{If the next character is an end-of-file character,
or if we are at eoln and first character on next line
is eof then we should also return true.}
zoekpos:=textrec(t).bufpos;
while textrec(t).buffer[zoekpos] in [#13,#10] do
inc(zoekpos);
if zoekpos>textrec(t).bufpos+2 then
eof:=false
else
eof:=textrec(t).buffer[zoekpos]=#26;
end;
end;
{****************************************************************************
File I/O related routines.
****************************************************************************}
procedure doserase(p:Pchar);
begin
asm
movl 8(%ebp),%edx
movb $0x41,%ah
call ___syscall
jnc LERASE1
movw %ax,U_SYSOS2_INOUTRES;
LERASE1:
end;
end;
procedure dosrename(p1,p2:Pchar);
begin
asm
movl 8(%ebp),%edx
movl 12(%ebp),%edi
movb $0x56,%ah
call ___syscall
jnc LRENAME1
movw %ax,U_SYSOS2_INOUTRES;
LRENAME1:
end;
end;
function dosread(h,addr,len:longint):longint;
begin
asm
movl 16(%ebp),%ecx
movl 12(%ebp),%edx
movl 8(%ebp),%ebx
movb $0x3f,%ah
call ___syscall
jnc LDOSREAD1
movw %ax,U_SYSOS2_INOUTRES;
xorl %eax,%eax
LDOSREAD1:
leave
ret $12
end;
end;
function doswrite(h,addr,len:longint) : longint;
begin
asm
movl 16(%ebp),%ecx
movl 12(%ebp),%edx
movl 8(%ebp),%ebx
movb $0x40,%ah
call ___syscall
jnc LDOSWRITE1
movw %ax,U_SYSOS2_INOUTRES;
LDOSWRITE1:
movl %eax,-4(%ebp)
end;
end;
procedure rewrite(var f:file;l:word);
var b:array[0..255] of char;
begin
{According to Turbo Pascal helpfile, a file is automatically closed
if it's open.}
if filerec(f).mode<>fmclosed then
close(f);
filerec(f).mode:=fmoutput;
move(filerec(f).name[1],b,length(filerec(f).name));
b[length(filerec(f).name)]:=#0;
filerec(f).handle:=create(b);
filerec(f).recsize:=l;
end;
procedure rewrite(var f:file);
begin
rewrite(f,128);
end;
procedure reset(var f:file;l:word);
var b:array[0..255] of char;
begin
{According to Turbo Pascal helpfile, a file is automatically closed
if it's open.}
if filerec(f).mode<>fmclosed then
close(f);
move(filerec(f).name[1],b,length(filerec(f).name));
b[length(filerec(f).name)]:=#0;
case filemode of
0:
begin
filerec(f).mode:=fminput;
filerec(f).handle:=open(b,0);
end;
1:
begin
filerec(f).mode:=fmoutput;
filerec(f).handle:=open(b,1);
end;
2:
begin
filerec(f).mode:=fminout;
filerec(f).handle:=open(b,2);
end;
end;
filerec(f).recsize:=l;
end;
procedure reset(var f:file);
begin
reset(f,128);
end;
procedure blockwrite(var f:file;var buf;count:longint);
var p:pointer;
size:longint;
begin
p:=@buf;
doswrite(filerec(f).handle,longint(p),count*filerec(f).recsize);
end;
procedure blockread(var f:file;var buf;count:longint;var result:longint);
begin
result:=dosread(filerec(f).handle,longint(@buf),
count*filerec(f).recsize) div filerec(f).recsize;
end;
procedure blockread(var f:file;var buf;count:longint);
var result:longint;
begin
blockread(f,buf,count,result);
end;
procedure truncate (var f : file);[iocheck];
var p : pointer;
begin
doswrite(filerec(f).handle,longint(p),0);
end;
procedure close(var f:file);
begin
if (filerec(f).mode<>fmclosed) then
begin
filerec(f).mode:=fmclosed;
do_close(filerec(f).handle);
end;
end;
function filepos(var f:file):longint;
var l:longint;
begin
filepos:=dosfilepos(filerec(f).handle) div filerec(f).recsize;
end;
function filesize(var f:file) : longint;
begin
filesize:=dosfilesize(filerec(f).handle) div filerec(f).recsize;
end;
function eof(var f:file):boolean;[iocheck];
begin
eof:=filesize(f)<=filepos(f);
end;
procedure seek(var f:file;pos : longint);
begin
dosseek(filerec(f).handle,pos*filerec(f).recsize);
end;
{****************************************************************************
Directory related routines.
****************************************************************************}
procedure dos_dirs(func:byte;name:Pchar);
begin
asm
movl 10(%ebp),%edx
movb 8(%ebp),%ah
call ___syscall
jnc LDOS_DIRS1
movw %ax,U_SYSOS2_INOUTRES;
LDOS_DIRS1:
leave
ret $6
end;
end;
procedure _dir(func:byte;const s:string);
var buffer:array[0..255] of char;
begin
move(s[1],buffer,length(s));
buffer[length(s)]:=#0;
dos_dirs(func,buffer);
end;
procedure mkdir(const s:string);
begin
_dir($39,s);
end;
procedure rmdir(const s:string);
begin
_dir($3a,s);
end;
procedure chdir(const s:string);
begin
_dir($3b,s);
end;
{ thanks to Michael Van Canneyt <michael@tfdec1.fys.kuleuven.ac.be>, }
{ who wrote this code }
procedure getdir(drivenr:byte;var dir:string);
var temp:string;
sof:pointer;
i:byte;
begin
sof:=@dir[4];
{ dir[1..3] will contain '[drivenr]:\', but is not }
{ supplied by DOS, so we let dos string start at }
{ dir[4] }
asm
{ Get dir from drivenr:0=default, 1=A etc... }
movb drivenr,%dl
{ put (previously saved) offset in si }
movl sof,%esi
{ call msdos function 47H : Get dir }
mov $0x47,%ah
{ make the call }
call ___syscall
{ Rem: if call unsuccesfull, carry is set, and AX has }
{ error code }
end;
{ Now Dir should be filled with directory in ASCIIZ, }
{ starting from dir[4] }
dir[0]:=#3;
dir[2]:=':';
dir[3]:='\';
i:=4;
{ conversation to Pascal string }
while (dir[i]<>#0) do
begin
{ convert path name to DOS }
if dir[i]='/' then
dir[i]:='\';
dir[0]:=chr(i);
inc(i);
end;
{ upcase the string (FPKPascal function) }
dir:=upcase(dir);
if drivenr<>0 then { Drive was supplied. We know it }
dir[1]:=chr(65+drivenr-1)
else
begin
{ We need to get the current drive from DOS function 19H }
{ because the drive was the default, which can be unknown }
asm
movb $0x19,%ah
call ___syscall
addb $65,%al
movb %al,i
end;
dir[1]:=chr(i)
end;
end;
{****************************************************************************
Heap management releated routines.
****************************************************************************}
{ this function allows to extend the heap by calling
syscall $7f00 resizes the brk area}
function sbrk(size:longint):longint;
begin
asm
movl size,%edx
movl $0x7f00,%ax
int $0x21
movl %eax,__RESULT
end;
end;
function getheapstart:pointer;
begin
asm
movl __heap_base,%eax
leave
ret
end ['EAX'];
end;
{$i heap.inc}
{***************************************************************************
Runtime error checking related routines.
***************************************************************************}
{$S-}
procedure st1(stack_size:longint);[public,alias: 'STACKCHECK'];
begin
{ called when trying to get local stack }
{ if the compiler directive $S is set }
asm
movl stack_size,%ebx
movl %esp,%eax
subl %ebx,%eax
{$ifdef SYSTEMDEBUG}
movl U_SYSOS2_LOWESTSTACK,%ebx
cmpl %eax,%ebx
jb _is_not_lowest
movl %eax,U_SYSOS2_LOWESTSTACK
_is_not_lowest:
{$endif SYSTEMDEBUG}
cmpb $2,U_SYSOS2_OS_MODE
jne _running_in_dos
movl U_SYSOS2_STACKBOTTOM,%ebx
jmp _running_in_os2
_running_in_dos:
movl __heap_brk,%ebx
_running_in_os2:
cmpl %eax,%ebx
jae __short_on_stack
leave
ret $4
__short_on_stack:
end ['EAX','EBX'];
{ this needs a local variable }
{ so the function called itself !! }
{ Writeln('low in stack ');}
RunError(202);
end;
{no stack check in system }
{****************************************************************************
System unit initialization.
****************************************************************************}
var
pib:Pprocessinfoblock;
tib:Pthreadinfoblock;
begin
{Determine the operating system we are running on.}
asm
movw $0x7f0a,%ax
call ___syscall
test $512,%bx ; Bit 9 is OS/2 flag.
setnzb U_SYSOS2_OS_MODE
test $4096,%bx
jz _noRSX
movb $2,U_SYSOS2_OS_MODE
_noRSX:
end;
{Now request, if we are running under DOS,
read-access to the first meg. of memory.}
if os_mode in [osDOS,osDPMI] then
asm
mov $0x7f13,%ax
xor %ebx,%ebx
mov $0xfff,%ecx
xor %edx,%edx
call ___syscall
mov %eax,U_SYSOS2_FIRST_MEG
end
else
first_meg:=nil;
{At 0.9.2, case for enumeration does not work.}
case os_mode of
osDOS:
stackbottom:=0;
osOS2:
begin
_DosGetInfoBlocks(tib,pib);
stackbottom:=longint(tib^.stack);
end;
osDPMI:
stackbottom:=0; {Not sure how to get it, but seems to be
always zero.}
end;
exitproc:=nil;
{Initialize the heap.}
InitHeap;
{ to test stack depth }
loweststack:=maxlongint;
{Enable the brk area by initializing it with the initial heap size.}
asm
mov $0x7f01,%ax
movl HEAPSIZE,%edx
call ___syscall
end;
{ Ein- und Ausgabe initialisieren }
assign(input,'');
textrec(input).handle:=0;
textrec(input).mode:=fminput;
textrec(input).inoutfunc:=@fileinoutfunc;
textrec(input).flushfunc:=@fileinoutfunc;
assign(output,'');
textrec(output).handle:=1;
textrec(output).mode:=fmoutput;
textrec(output).inoutfunc:=@fileinoutfunc;
textrec(output).flushfunc:=@fileinoutfunc;
textrec(input).mode:=fminput;
{ kein Ein- Ausgabefehler }
inoutres:=0;
end.