{**************************************************************************** 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: Send us your modified files, we can work together if you want! FPK-Pascal 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. See the Library GNU General Public License for more details. You should have received a copy of the Library GNU General Public License along with FPK-Pascal; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ****************************************************************************} unit sysos2; {Changelog: People: DM - Dani‰l Mantione Date: Description of change: Changed by: - First released version 0.1. DM Coding style: My coding style is a bit unusual for Pascal. Nevertheless I friendly ask you to try to make your changes not look all to different. In general, set your IDE to use tab characters, optimal fill on and a tabsize of 4.} {$I os.inc} interface {Link the startup code.} {$l prt1.oo2} {$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; const UnusedHandle=$ffff; StdInputHandle=0; StdOutputHandle=1; StdErrorHandle=2; implementation { die betriebssystemunabhangigen Implementationen einfuegen: } {$I SYSTEM.INC} procedure dosgetinfoblocks(var Atib:Pthreadinfoblock; var Apib:Pprocessinfoblock); external 'DOSCALLS' index 312; {*************************************************************************** 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 } {**************************************************************************** Miscelleanious related routines. ****************************************************************************} 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; {**************************************************************************** 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 movw $0x7f00,%ax call ___SYSCALL movl %eax,__RESULT end; end; function getheapstart:pointer; begin asm movl __heap_base,%eax leave ret end ['EAX']; end; {$i heap.inc} {**************************************************************************** Low Level File Routines ****************************************************************************} procedure allowslash(p:Pchar); {Allow slash as backslash.} var i:longint; begin for i:=0 to strlen(p) do if p[i]='/' then p[i]:='\'; end; procedure do_close(h:longint); begin asm movb $0x3e,%ah mov h,%ebx call ___SYSCALL end; end; procedure do_erase(p:Pchar); begin allowslash(p); asm movl 8(%ebp),%edx movb $0x41,%ah call ___SYSCALL jnc LERASE1 movw %ax,U_SYSOS2_INOUTRES; LERASE1: end; end; procedure do_rename(p1,p2:Pchar); begin allowslash(p1); allowslash(p2); 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 do_read(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 do_write(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; function do_filepos(handle:longint):longint; begin asm movw $0x4201,%ax 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 do_seek(handle,pos:longint); begin asm movw $0x4200,%ax movl 8(%ebp),%ebx movl 12(%ebp),%edx call ___SYSCALL jnc .LDOSSEEK1 movw %ax,U_SYSOS2_INOUTRES; .LDOSSEEK1: leave ret $8 end; end; function do_seekend(handle:longint):longint; begin asm movw $0x4202,%ax movl 8(%ebp),%ebx xorl %edx,%edx call ___SYSCALL jnc .Lset_at_end1 movw %ax,U_SYSOS2_INOUTRES; xorl %eax,%eax .Lset_at_end1: leave ret $4 end; end; function do_filesize(handle:longint):longint; var aktfilepos:longint; begin aktfilepos:=do_filepos(handle); do_filesize:=do_seekend(handle); do_seek(handle,aktfilepos); end; procedure do_truncate(handle,pos:longint); begin asm movl $0x4200,%eax movl 8(%ebp),%ebx movl 12(%ebp),%edx call ___SYSCALL jc .LTruncate1 movl 8(%ebp),%ebx movl 12(%ebp),%edx movl %ebp,%edx xorl %ecx,%ecx movb $0x40,%ah call ___SYSCALL jnc .LTruncate2 .LTruncate1: movw %ax,U_SYSOS2_INOUTRES; .LTruncate2: leave ret $8 end; end; procedure do_open(var f;p:pchar;flags:longint); { filerec and textrec have both handle and mode as the first items so they could use the same routine for opening/creating. when (flags and $10) the file will be append when (flags and $100) the file will be truncate/rewritten when (flags and $1000) there is no check for close (needed for textfiles) } var oflags:byte; begin allowslash(p); { close first if opened } if ((flags and $1000)=0) then begin case filerec(f).mode of fminput,fmoutput,fminout : Do_Close(filerec(f).handle); fmclosed:; else begin inoutres:=102; {not assigned} exit; end; end; end; { reset file handle } filerec(f).handle:=high(word); oflags:=2; { convert filemode to filerec modes } case (flags and 3) of 0 : begin filerec(f).mode:=fminput; oflags:=0; end; 1 : filerec(f).mode:=fmoutput; 2 : filerec(f).mode:=fminout; end; if (flags and $100)<>0 then begin filerec(f).mode:=fmoutput; oflags:=2; end else if (flags and $10)<>0 then begin filerec(f).mode:=fmoutput; oflags:=2; end; { empty name is special } if p[0]=#0 then begin case filerec(f).mode of fminput:filerec(f).handle:=StdInputHandle; fmappend,fmoutput : begin filerec(f).handle:=StdOutputHandle; filerec(f).mode:=fmoutput; {fool fmappend} end; end; exit; end; if (flags and $100)<>0 then {Use create function.} asm movb $0x3c,%ah movl p,%edx xorw %cx,%cx call ___SYSCALL jnc LOPEN1 movw %ax,U_SYSOS2_INOUTRES; movw $0xffff,%ax LOPEN1: movl f,%edx movw %ax,(%edx) end else {Use open function.} asm movb $0x3d,%ah movb oflags,%al movl p,%edx call ___SYSCALL jnc LOPEN2 movw %ax,U_SYSOS2_INOUTRES; movw $0xffff,%ax LOPEN2: movl f,%edx movw %ax,(%edx) end; if (flags and $10)<>0 then do_seekend(filerec(f).handle); end; {***************************************************************************** UnTyped File Handling *****************************************************************************} {$i file.inc} {***************************************************************************** Typed File Handling *****************************************************************************} {$i typefile.inc} {***************************************************************************** Text File Handling *****************************************************************************} {$DEFINE EOF_CTRLZ} {$i text.inc} {**************************************************************************** Directory related routines. ****************************************************************************} {***************************************************************************** Directory Handling *****************************************************************************} procedure dosdir(func:byte;const s:string); var buffer:array[0..255] of char; begin move(s[1],buffer,length(s)); buffer[length(s)]:=#0; allowslash(Pchar(@buffer)); asm leal buffer,%edx movb 8(%ebp),%ah call ___SYSCALL jnc .LDOS_DIRS1 movw %ax,U_SYSOS2_INOUTRES; .LDOS_DIRS1: end; end; procedure mkdir(const s : string); begin DosDir($39,s); end; procedure rmdir(const s : string); begin DosDir($3a,s); end; procedure chdir(const s : string); begin DosDir($3b,s); end; procedure getdir(drivenr : byte;var dir : string); {Written by Michael Van Canneyt.} var temp:array[0..255] of char; sof:Pchar; i:byte; begin sof:=pchar(@dir[4]); { dir[1..3] will contain '[drivenr]:\', but is not } { supplied by DOS, so we let dos string start at } { dir[4] } { Get dir from drivenr : 0=default, 1=A etc... } asm movb drivenr,%dl movl sof,%esi mov $0x47,%ah call ___SYSCALL end; { Now Dir should be filled with directory in ASCIIZ, } { starting from dir[4] } dir[0]:=#3; dir[2]:=':'; dir[3]:='\'; i:=4; {Conversion to Pascal string } while (dir[i]<>#0) do begin { convert path name to DOS } if dir[i]='/' then dir[i]:='\'; dir[0]:=char(i); inc(i); end; { upcase the string (FPKPascal function) } dir:=upcase(dir); if drivenr<>0 then { Drive was supplied. We know it } dir[1]:=char(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]:=char(i); end; end; {**************************************************************************** System unit initialization. ****************************************************************************} procedure OpenStdIO(var f:text;mode:word;hdl:longint); begin Assign(f,''); TextRec(f).Handle:=hdl; TextRec(f).Mode:=mode; TextRec(f).InOutFunc:=@FileInOutFunc; TextRec(f).FlushFunc:=@FileInOutFunc; TextRec(f).Closefunc:=@fileclosefunc; end; 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; {Enable the brk area by initializing it with the initial heap size.} asm mov $0x7f01,%ax movl HEAPSIZE,%edx addl __heap_base,%edx call ___SYSCALL cmpl $-1,%eax jnz _heapok pushl $204 call _SYSOS2$$_RUNERROR$WORD _heapok: 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; {In DOS mode, heap_brk is also the stack bottom.} 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; OpenStdIO(Input,fmInput,StdInputHandle); OpenStdIO(Output,fmOutput,StdOutputHandle); OpenStdIO(StdErr,fmOutput,StdErrorHandle); { kein Ein- Ausgabefehler } inoutres:=0; end.