diff --git a/rtl/amiga/sysamiga.pas b/rtl/amiga/sysamiga.pas index a4a4a67b8b..4d342eaddd 100644 --- a/rtl/amiga/sysamiga.pas +++ b/rtl/amiga/sysamiga.pas @@ -1,1912 +1 @@ -{ - $Id$ - This file is part of the Free Pascal run time library. - Copyright (c) 1999-2000 by Carl Eric Codere - Some parts taken from - Marcel Timmermans - Modula 2 Compiler - Nils Sjoholm - Amiga porter - Matthew Dillon - Dice C (with his kind permission) - dillon@backplane.com - - 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 sysamiga; - -{--------------------------------------------------------------------} -{ LEFT TO DO: } -{--------------------------------------------------------------------} -{ o GetDir with different drive numbers } -{--------------------------------------------------------------------} - -{$I os.inc} - -{ AmigaOS uses character #10 as eoln only } -{$DEFINE SHORT_LINEBREAK} - - interface - - { used for single computations } - const BIAS4 = $7f-1; - - {$I systemh.inc} - - {$I heaph.inc} - -const - UnusedHandle : longint = -1; - StdInputHandle : longint = 0; - StdOutputHandle : longint = 0; - StdErrorHandle : longint = 0; - - _ExecBase:longint = $4; - _WorkbenchMsg : longint = 0; - - _IntuitionBase : pointer = nil; { intuition library pointer } - _DosBase : pointer = nil; { DOS library pointer } - _UtilityBase : pointer = nil; { utiity library pointer } - - { Required for crt unit } - function do_read(h,addr,len : longint) : longint; - function do_write(h,addr,len : longint) : longint; - - - - - - implementation - - const - - intuitionname : pchar = 'intuition.library'; - dosname : pchar = 'dos.library'; - utilityname : pchar = 'utility.library'; - argc : longint = 0; - { AmigaOS does not autoamtically deallocate memory on program termination } - { therefore we have to handle this manually. This is a list of allocated } - { pointers from the OS, we cannot use a linked list, because the linked } - { list itself uses the HEAP! } - pointerlist : array[1..8] of longint = - (0,0,0,0,0,0,0,0); - - - {$I exec.inc} - - TYPE - TDateStamp = packed record - ds_Days : Longint; { Number of days since Jan. 1, 1978 } - ds_Minute : Longint; { Number of minutes past midnight } - ds_Tick : Longint; { Number of ticks past minute } - end; - PDateStamp = ^TDateStamp; - - - PFileInfoBlock = ^TfileInfoBlock; - TFileInfoBlock = packed record - fib_DiskKey : Longint; - fib_DirEntryType : Longint; - { Type of Directory. If < 0, then a plain file. - If > 0 a directory } - fib_FileName : Array [0..107] of Char; - { Null terminated. Max 30 chars used for now } - fib_Protection : Longint; - { bit mask of protection, rwxd are 3-0. } - fib_EntryType : Longint; - fib_Size : Longint; { Number of bytes in file } - fib_NumBlocks : Longint; { Number of blocks in file } - fib_Date : TDateStamp; { Date file last changed } - fib_Comment : Array [0..79] of Char; - { Null terminated comment associated with file } - fib_Reserved : Array [0..35] of Char; - end; - - - TProcess = packed record - pr_Task : TTask; - pr_MsgPort : TMsgPort; { This is BPTR address from DOS functions } -{126} pr_Pad : Word; { Remaining variables on 4 byte boundaries } -{128} pr_SegList : Pointer; { Array of seg lists used by this process } -{132} pr_StackSize : Longint; { Size of process stack in bytes } -{136} pr_GlobVec : Pointer; { Global vector for this process (BCPL) } -{140} pr_TaskNum : Longint; { CLI task number of zero if not a CLI } -{144} pr_StackBase : BPTR; { Ptr to high memory end of process stack } -{148} pr_Result2 : Longint; { Value of secondary result from last call } -{152} pr_CurrentDir : BPTR; { Lock associated with current directory } -{156} pr_CIS : BPTR; { Current CLI Input Stream } -{160} pr_COS : BPTR; { Current CLI Output Stream } -{164} pr_ConsoleTask : Pointer; { Console handler process for current window} -{168} pr_FileSystemTask : Pointer; { File handler process for current drive } -{172} pr_CLI : BPTR; { pointer to ConsoleLineInterpreter } - pr_ReturnAddr : Pointer; { pointer to previous stack frame } - pr_PktWait : Pointer; { Function to be called when awaiting msg } - pr_WindowPtr : Pointer; { Window for error printing } - { following definitions are new with 2.0 } - pr_HomeDir : BPTR; { Home directory of executing program } - pr_Flags : Longint; { flags telling dos about process } - pr_ExitCode : Pointer; { code to call on exit of program OR NULL } - pr_ExitData : Longint; { Passed as an argument to pr_ExitCode. } - pr_Arguments : PChar; { Arguments passed to the process at start } - pr_LocalVars : TMinList; { Local environment variables } - pr_ShellPrivate : Longint; { for the use of the current shell } - pr_CES : BPTR; { Error stream - IF NULL, use pr_COS } - end; - PProcess = ^TProcess; - - { AmigaOS does not automatically close opened files on exit back to } - { the operating system, therefore as a precuation we close all files } - { manually on exit. } - PFileList = ^TFileList; - TFileList = record { no packed, must be correctly aligned } - Handle: longint; { Handle to file } - next: pfilelist; { Next file in list } - closed: boolean; { TRUE=file already closed } - end; - - - - - Const - CTRL_C = 20; { Error code on CTRL-C press } - SIGBREAKF_CTRL_C = $1000; { CTRL-C signal flags } - - _LVOFindTask = -294; - _LVOWaitPort = -384; - _LVOGetMsg = -372; - _LVOOpenLibrary = -552; - _LVOCloseLibrary = -414; - _LVOClose = -36; - _LVOOpen = -30; - _LVOIoErr = -132; - _LVOSeek = -66; - _LVODeleteFile = -72; - _LVORename = -78; - _LVOWrite = -48; - _LVORead = -42; - _LVOCreateDir = -120; - _LVOSetCurrentDirName = -558; - _LVOGetCurrentDirName = -564; - _LVOInput = -54; - _LVOOutput = -60; - _LVOUnLock = -90; - _LVOLock = -84; - _LVOCurrentDir = -126; - - _LVONameFromLock = -402; - _LVONameFromFH = -408; - _LVOGetProgramName = -576; - _LVOGetProgramDir = -600; - _LVODupLock = -96; - _LVOExamine = -102; - _LVOParentDir = -210; - _LVOSetFileSize = -456; - _LVOSetSignal = -306; - _LVOAllocVec = -684; - _LVOFreeVec = -690; - - - { Errors from IoErr(), etc. } - ERROR_NO_FREE_STORE = 103; - ERROR_TASK_TABLE_FULL = 105; - ERROR_BAD_TEMPLATE = 114; - ERROR_BAD_NUMBER = 115; - ERROR_REQUIRED_ARG_MISSING = 116; - ERROR_KEY_NEEDS_ARG = 117; - ERROR_TOO_MANY_ARGS = 118; - ERROR_UNMATCHED_QUOTES = 119; - ERROR_LINE_TOO_LONG = 120; - ERROR_FILE_NOT_OBJECT = 121; - ERROR_INVALID_RESIDENT_LIBRARY = 122; - ERROR_NO_DEFAULT_DIR = 201; - ERROR_OBJECT_IN_USE = 202; - ERROR_OBJECT_EXISTS = 203; - ERROR_DIR_NOT_FOUND = 204; - ERROR_OBJECT_NOT_FOUND = 205; - ERROR_BAD_STREAM_NAME = 206; - ERROR_OBJECT_TOO_LARGE = 207; - ERROR_ACTION_NOT_KNOWN = 209; - ERROR_INVALID_COMPONENT_NAME = 210; - ERROR_INVALID_LOCK = 211; - ERROR_OBJECT_WRONG_TYPE = 212; - ERROR_DISK_NOT_VALIDATED = 213; - ERROR_DISK_WRITE_PROTECTED = 214; - ERROR_RENAME_ACROSS_DEVICES = 215; - ERROR_DIRECTORY_NOT_EMPTY = 216; - ERROR_TOO_MANY_LEVELS = 217; - ERROR_DEVICE_NOT_MOUNTED = 218; - ERROR_SEEK_ERROR = 219; - ERROR_COMMENT_TOO_BIG = 220; - ERROR_DISK_FULL = 221; - ERROR_DELETE_PROTECTED = 222; - ERROR_WRITE_PROTECTED = 223; - ERROR_READ_PROTECTED = 224; - ERROR_NOT_A_DOS_DISK = 225; - ERROR_NO_DISK = 226; - ERROR_NO_MORE_ENTRIES = 232; - { added for 1.4 } - ERROR_IS_SOFT_LINK = 233; - ERROR_OBJECT_LINKED = 234; - ERROR_BAD_HUNK = 235; - ERROR_NOT_IMPLEMENTED = 236; - ERROR_RECORD_NOT_LOCKED = 240; - ERROR_LOCK_COLLISION = 241; - ERROR_LOCK_TIMEOUT = 242; - ERROR_UNLOCK_ERROR = 243; - - - - var - Initial: boolean; { Have successfully opened Std I/O } - errno : word; { AmigaOS IO Error number } - FileList : pFileList; { Linked list of opened files } - {old_exit: Pointer; not needed anymore } - FromHalt : boolean; - OrigDir : Longint; { Current lock on original startup directory } - - {$I system.inc} - {$I lowmath.inc} - - - - - { ************************ AMIGAOS STUB ROUTINES ************************* } - - procedure DateStamp(var ds : tDateStamp); - begin - asm - MOVE.L A6,-(A7) - MOVE.L ds,d1 - { LAST THING TO SETUP SHOULD BE A6, otherwise you can } - { not accept local variable, nor any parameters! :) } - MOVE.L _DOSBase,A6 - JSR -192(A6) - MOVE.L (A7)+,A6 - end; - end; - - - - { UNLOCK the BPTR pointed to in L } - Procedure Unlock(alock: longint); - Begin - asm - move.l alock,d1 - move.l a6,d6 { save base pointer } - move.l _DosBase,a6 - jsr _LVOUnlock(a6) - move.l d6,a6 { restore base pointer } - end; - end; - - { Change to the directory pointed to in the lock } - Function CurrentDir(alock : longint) : longint; - Begin - asm - move.l alock,d1 - move.l a6,d6 { save base pointer } - move.l _DosBase,a6 - jsr _LVOCurrentDir(a6) - move.l d6,a6 { restore base pointer } - move.l d0,@Result - end; - end; - - { Duplicate a lock } - Function DupLock(alock: longint): Longint; - Begin - asm - move.l alock,d1 - move.l a6,d6 { save base pointer } - move.l _DosBase,a6 - jsr _LVODupLock(a6) - move.l d6,a6 { restore base pointer } - move.l d0,@Result - end; - end; - - { Returns a lock on the directory was loaded from } - Function GetProgramLock: longint; - Begin - asm - move.l a6,d6 { save base pointer } - move.l _DosBase,a6 - jsr _LVOGetProgramDir(a6) - move.l d6,a6 { restore base pointer } - move.l d0,@Result - end; - end; - - - - Function Examine(alock :longint; var fib: TFileInfoBlock) : Boolean; - Begin - asm - move.l d2,-(sp) - move.l fib,d2 { pointer to FIB } - move.l alock,d1 - move.l a6,d6 { save base pointer } - move.l _DosBase,a6 - jsr _LVOExamine(a6) - move.l d6,a6 { restore base pointer } - tst.l d0 - bne @success - bra @end - @success: - move.b #1,d0 - @end: - move.b d0,@Result - move.l (sp)+,d2 - end; - end; - - { Returns the parent directory of a lock } - Function ParentDir(alock : longint): longint; - Begin - asm - move.l alock,d1 - move.l a6,d6 { save base pointer } - move.l _DosBase,a6 - jsr _LVOParentDir(a6) - move.l d6,a6 { restore base pointer } - move.l d0,@Result - end; - end; - - - Function FindTask(p : PChar): PProcess; - Begin - asm - move.l a6,d6 { Save base pointer } - move.l p,d0 - move.l d0,a1 - move.l _ExecBase,a6 - jsr _LVOFindTask(a6) - move.l d6,a6 { Restore base pointer } - move.l d0,@Result - end; - end; - - -{$S-} - Procedure stack_check; assembler; - { Check for local variable allocation } - { On Entry -> d0 : size of local stack we are trying to allocate } - asm - XDEF STACKCHECK - move.l sp,d1 { get value of stack pointer } - - { We must add some security, because Writing the RunError strings } - { requires a LOT of stack space (at least 1030 bytes!) } - add.l #2048,d0 - sub.l d0,d1 { sp - stack_size } - - move.l _ExecBase,a0 - move.l 276(A0),A0 { ExecBase.thisTask } - { if allocated stack_pointer - splower <= 0 then stack_ovf } - cmp.l 58(A0),D1 { Task.SpLower } - bgt @Ok - move.l #202,d0 - jsr HALT_ERROR { stack overflow } - @Ok: - end; - - - { This routine from EXEC determines if the Ctrl-C key has } - { been used since the last call to I/O routines. } - { Use to halt the program. } - { Returns the state of the old signals. } - Function SetSignal(newSignal: longint; SignalMask: longint): longint; - Begin - asm - move.l newSignal,d0 - move.l SignalMask,d1 - move.l a6,d6 { save Base pointer into scratch register } - move.l _ExecBase,a6 - jsr _LVOSetSignal(a6) - move.l d6,a6 - move.l d0,@Result - end; - end; - - - Function AllocVec(bytesize: longint; attributes: longint):longint; - Begin - asm - move.l bytesize,d0 - move.l attributes,d1 - move.l a6,d6 { save Base pointer into scratch register } - move.l _ExecBase,a6 - jsr _LVOAllocVec(a6) - move.l d6,a6 - move.l d0,@Result - end; - end; - - - Procedure FreeVec(p: longint); - Begin - asm - move.l p,a1 - move.l a6,d6 { save Base pointer into scratch register } - move.l _ExecBase,a6 - jsr _LVOFreeVec(a6) - move.l d6,a6 - end; - end; - - - { Converts an AMIGAOS error code to a TP compatible error code } - Procedure Error2InOut; - Begin - case errno of - ERROR_BAD_NUMBER, - ERROR_ACTION_NOT_KNOWN, - ERROR_NOT_IMPLEMENTED : InOutRes := 1; - - ERROR_OBJECT_NOT_FOUND : InOutRes := 2; - ERROR_DIR_NOT_FOUND : InOutRes := 3; - - ERROR_DISK_WRITE_PROTECTED : InOutRes := 150; - - ERROR_OBJECT_WRONG_TYPE : InOutRes := 151; - - ERROR_OBJECT_EXISTS, - ERROR_DELETE_PROTECTED, - ERROR_WRITE_PROTECTED, - ERROR_READ_PROTECTED, - ERROR_OBJECT_IN_USE, - ERROR_DIRECTORY_NOT_EMPTY : InOutRes := 5; - - ERROR_NO_MORE_ENTRIES : InOutRes := 18; - - ERROR_RENAME_ACROSS_DEVICES : InOutRes := 17; - - ERROR_DISK_FULL : InOutRes := 101; - - ERROR_INVALID_RESIDENT_LIBRARY : InoutRes := 153; - ERROR_BAD_HUNK : InOutRes := 153; - - ERROR_NOT_A_DOS_DISK : InOutRes := 157; - - ERROR_NO_DISK, - ERROR_DISK_NOT_VALIDATED, - ERROR_DEVICE_NOT_MOUNTED : InOutRes := 152; - - ERROR_SEEK_ERROR : InOutRes := 156; - - ERROR_LOCK_COLLISION, - ERROR_LOCK_TIMEOUT, - ERROR_UNLOCK_ERROR, - ERROR_INVALID_LOCK, - ERROR_INVALID_COMPONENT_NAME, - ERROR_BAD_STREAM_NAME, - ERROR_FILE_NOT_OBJECT : InOutRes := 6; - else - InOutres := errno; - end; - errno:=0; - end; - - - procedure CloseLibrary(lib : pointer); - { Close the library pointed to in lib } - Begin - asm - MOVE.L A6,-(A7) - MOVE.L lib,a1 - MOVE.L _ExecBase,A6 - JSR _LVOCloseLibrary(A6) - MOVE.L (A7)+,A6 - end; - end; - - - Function KickVersion: word; assembler; - asm - move.l _ExecBase, a0 { Get Exec Base } - move.w 20(a0), d0 { Return version - version at this offset } - end; - - - { ************************ AMIGAOS SUPP ROUTINES ************************* } - -(* Procedure CloseList(p: pFileList);*) - (***********************************************************************) - (* PROCEDURE CloseList *) - (* Description: This routine each time the program is about to *) - (* terminate, it closes all opened file handles, as this is not *) - (* handled by the operating system. *) - (* p -> Start of linked list of opened files *) - (***********************************************************************) -(* var - hp: pFileList; - hp1: pFileList; - h: longint; - Begin - hp:=p; - while Assigned(hp) do - Begin - if NOT hp^.closed then - Begin - h:=hp^.handle; - if (h <> StdInputHandle) and (h <> StdOutputHandle) and (h <> StdErrorHandle) then - Begin - { directly close file here, it is faster then doing } - { it do_close. } - asm - move.l h,d1 - move.l a6,d6 { save a6 } - move.l _DOSBase,a6 - jsr _LVOClose(a6) - move.l d6,a6 { restore a6 } - end; - end; - end; - hp1:=hp; - hp:=hp^.next; - dispose(hp1); - end; - end;*) - - -(* Procedure AddToList(var p: pFileList; h: longint);*) - (***********************************************************************) - (* PROCEDURE AddToList *) - (* Description: Adds a node to the linked list of files. *) - (* *) - (* p -> Start of File list linked list, if not allocated allocates *) - (* it for you. *) - (* h -> handle of file to add *) - (***********************************************************************) -(* var - hp: pFileList; - hp1: pFileList; - Begin - if p = nil then - Begin - new(p); - p^.handle:=h; - p^.closed := FALSE; - p^.next := nil; - exit; - end; - hp:=p; - { Find last list in entry } - while assigned(hp) do - Begin - if hp^.next = nil then break; - hp:=hp^.next; - end; - { Found last list in entry then add it to the list } - new(hp1); - hp^.next:=hp1; - hp1^.next:=nil; - hp1^.handle:=h; - hp1^.closed:=FALSE; - end; - - - Procedure SetClosedList(var p: pFileList; h: longint); - { Set the file flag to closed if the file is being closed } - var - hp: pFileList; - Begin - hp:=p; - while assigned(hp) do - Begin - if hp^.handle = h then - Begin - hp^.closed:=TRUE; - break; - end; - hp:=hp^.next; - end; - end;*) - - -{***************************************************************************** - System Dependent Exit code -*****************************************************************************} - Procedure system_exit; - var - i: byte; - Begin - { We must remove the CTRL-C FALG here because halt } - { may call I/O routines, which in turn might call } - { halt, so a recursive stack crash } - IF (SetSignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 THEN - SetSignal(0,SIGBREAKF_CTRL_C); - { Close remaining opened files } -{ CloseList(FileList); } - if (OrigDir <> 0) then - Begin - Unlock(CurrentDir(OrigDir)); - OrigDir := 0; - end; - { Is this a normal exit - YES, close libs } - IF NOT FromHalt then - Begin - { close the libraries } - If _UtilityBase <> nil then - CloseLibrary(_UtilityBase); - If _DosBase <> nil then - CloseLibrary(_DosBase); - If _IntuitionBase <> nil then - CloseLibrary(_IntuitionBase); - _UtilityBase := nil; - _DosBase := nil; - _IntuitionBase := nil; - end; - { Dispose of extraneous allocated pointers } - for I:=1 to 8 do - Begin - if pointerlist[i] <> 0 then FreeVec(pointerlist[i]); - end; - { exitproc:=old_exit;obsolete } - end; - - - procedure halt(errnum : byte); - begin - { Indicate to the SYSTEM EXIT procedure that we are calling it } - { from halt, and that its library will be closed HERE and not } - { in the exit procedure. } - FromHalt:=TRUE; - { We must remove the CTRL-C FALG here because halt } - { may call I/O routines, which in turn might call } - { halt, so a recursive stack crash } - IF (SetSignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 THEN - SetSignal(0,SIGBREAKF_CTRL_C); - { WE can only FLUSH the stdio } - { if the handles have correctly } - { been set. } - { No exit procedures exist } - { if in initial state } - If NOT Initial then - Begin - do_exit; - flush(stderr); - end; - { close the libraries } - If _UtilityBase <> nil then - CloseLibrary(_UtilityBase); - If _DosBase <> nil then - CloseLibrary(_DosBase); - If _IntuitionBase <> nil then - CloseLibrary(_IntuitionBase); - _UtilityBase := nil; - _DosBase := nil; - _IntuitionBase := nil; - asm - clr.l d0 - move.b errnum,d0 - move.l STKPTR,sp - rts - end; - end; - - - - { ************************ PARAMCOUNT/PARAMSTR *************************** } - - function paramcount : longint; - Begin - paramcount := argc; - end; - - - function args : pointer; assembler; - asm - move.l __ARGS,d0 - end; - - Function GetParamCount(const p: pchar): longint; - var - i: word; - count: word; - Begin - i:=0; - count:=0; - while p[count] <> #0 do - Begin - if (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) then - Begin - i:=i+1; - while (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) do - count:=count+1; - end; - if p[count] = #0 then break; - count:=count+1; - end; - GetParamCount:=longint(i); - end; - - - Function GetParam(index: word; const p : pchar): string; - { On Entry: index = string index to correct parameter } - { On exit: = correct character index into pchar array } - { Returns correct index to command line argument } - var - count: word; - localindex: word; - l: byte; - temp: string; - Begin - temp:=''; - count := 0; - { first index is one } - localindex := 1; - l:=0; - While p[count] <> #0 do - Begin - if (p[count] <> ' ') and (p[count] <> #9) then - Begin - if localindex = index then - Begin - while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) and (l < 256) do - Begin - temp:=temp+p[count]; - l:=l+1; - count:=count+1; - end; - temp[0]:=char(l); - GetParam:=temp; - exit; - end; - { Point to next argument in list } - while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) do - Begin - count:=count+1; - end; - localindex:=localindex+1; - end; - if p[count] = #0 then break; - count:=count+1; - end; - GetParam:=temp; - end; - - - Function GetProgramDir : String; - var - s1: string; - alock: longint; - counter : byte; - Begin - FillChar(@s1,255,#0); - { GetLock of program directory } - asm - move.l a6,d6 { save a6 } - move.l _DOSBase,a6 - jsr _LVOGetProgramDir(a6) - move.l d6,a6 { restore a6 } - move.l d0,alock { save the lock } - end; - if alock <> 0 then - Begin - { Get the name from the lock! } - asm - movem.l d2/d3,-(sp) { save used registers } - move.l alock,d1 - lea s1,a0 { Get pointer to string! } - move.l a0,d2 - add.l #1,d2 { let us point past the length byte! } - move.l #255,d3 - move.l a6,d6 { save a6 } - move.l _DOSBase,a6 - jsr _LVONameFromLock(a6) - move.l d6,a6 { restore a6 } - movem.l (sp)+,d2/d3 - end; - { no check out the length of the string } - counter := 1; - while s1[counter] <> #0 do - Inc(counter); - s1[0] := char(counter-1); - GetProgramDir := s1; - end - else - GetProgramDir := ''; - end; - - - Function GetProgramName : string; - { Returns ONLY the program name } - { There seems to be a bug in v39 since if the program is not } - { called from its home directory the program name will also } - { contain the path! } - var - s1: string; - counter : byte; - Begin - FillChar(@s1,255,#0); - asm - move.l d2,-(sp) { Save used register } - lea s1,a0 { Get pointer to string! } - move.l a0,d1 - add.l #1,d1 { point to correct offset } - move.l #255,d2 - move.l a6,d6 { save a6 } - move.l _DOSBase,a6 - jsr _LVOGetProgramName(a6) - move.l d6,a6 { restore a6 } - move.l (sp)+,d2 { restore saved register } - end; - { no check out and assign the length of the string } - counter := 1; - while s1[counter] <> #0 do - Inc(counter); - s1[0] := char(counter-1); - { now remove any component path which should not be there } - for counter:=length(s1) downto 1 do - if (s1[counter] = '/') or (s1[counter] = ':') then break; - { readjust counterv to point to character } - if counter <> 1 then - Inc(counter); - GetProgramName:=copy(s1,counter,length(s1)); - end; - - - function paramstr(l : longint) : string; - var - p : pchar; - s1 : string; - begin - { -> Call AmigaOS GetProgramName } - if l = 0 then - Begin - s1 := GetProgramDir; - { If this is a root, then simply don't add '/' } - if s1[length(s1)] = ':' then - paramstr:=s1+GetProgramName - else - { add backslash directory } - paramstr:=s1+'/'+GetProgramName - end - else - if (l>0) and (l<=paramcount) then - begin - p:=args; - paramstr:=GetParam(word(l),p); - end - else paramstr:=''; - end; - - { ************************************************************************ } - - procedure randomize; - - var - hl : longint; - time : TDateStamp; - begin - DateStamp(time); - randseed:=time.ds_tick; - end; - -function getheapstart:pointer;assembler; -asm - lea.l HEAP,a0 - move.l a0,d0 -end; - - -function getheapsize:longint;assembler; -asm - move.l HEAP_SIZE,d0 -end ['D0']; - - { This routine is used to grow the heap. } - { But here we do a trick, we say that the } - { heap cannot be regrown! } - function sbrk( size: longint): longint; - var - { on exit -1 = if fails. } - p: longint; - i: byte; - Begin - p:=0; - { Is the pointer list full } - if pointerlist[8] <> 0 then - begin - { yes, then don't allocate and simply exit } - sbrk:=-1; - exit; - end; - { Allocate best available memory } - p:=AllocVec(size,0); - if p = 0 then - sbrk:=-1 - else - Begin - i:=1; - { add it to the list of allocated pointers } - { first find the last pointer in the list } - while (i < 8) and (pointerlist[i] <> 0) do - i:=i+1; - pointerlist[i]:=p; - sbrk:=p; - end; - end; - - - -{$I heap.inc} - - -{**************************************************************************** - Low Level File Routines - ****************************************************************************} - -procedure do_close(h : longint); -{ We cannot check for CTRL-C because this routine will be called } -{ on HALT to close all remaining opened files. Therefore no } -{ CTRL-C checking otherwise a recursive call might result! } -{$ifdef debug} -var - buffer: array[0..255] of char; -{$endif} -begin - { check if the file handle is in the list } - { if so the put its field to closed } -{ SetClosedList(FileList,h);} -{$ifdef debug} - asm - move.l h,d1 - move.l a6,d6 - move.l d2,-(sp) - move.l d3,-(sp) - lea buffer,a0 - move.l a0,d2 - move.l #255,d3 - move.l _DosBase,a6 - jsr _LVONameFromFH(a6) - move.l d6,a6 - move.l (sp)+,d3 - move.l (sp)+,d2 - end; - WriteLn(Buffer); -{$endif debug} - asm - move.l h,d1 - move.l a6,d6 { save a6 } - move.l _DOSBase,a6 - jsr _LVOClose(a6) - move.l d6,a6 { restore a6 } - end; -end; - - -function do_isdevice(handle:longint):boolean; -begin - if (handle=stdoutputhandle) or (handle=stdinputhandle) or - (handle=stderrorhandle) then - do_isdevice:=TRUE - else - do_isdevice:=FALSE; -end; - - - -procedure do_erase(p : pchar); -begin - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - asm - move.l a6,d6 { save a6 } - - move.l p,d1 - move.l _DOSBase,a6 - jsr _LVODeleteFile(a6) - tst.l d0 { zero = failure } - bne @noerror - - jsr _LVOIoErr(a6) - move.w d0,errno - - @noerror: - move.l d6,a6 { restore a6 } - end; - if errno <> 0 then - Error2InOut; -end; - - -procedure do_rename(p1,p2 : pchar); -begin - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - asm - move.l a6,d6 { save a6 } - move.l d2,-(sp) { save d2 } - - move.l p1,d1 - move.l p2,d2 - move.l _DOSBase,a6 - jsr _LVORename(a6) - move.l (sp)+,d2 { restore d2 } - tst.l d0 - bne @dosreend { if zero = error } - jsr _LVOIoErr(a6) - move.w d0,errno - @dosreend: - move.l d6,a6 { restore a6 } - end; - if errno <> 0 then - Error2InOut; -end; - - -function do_write(h,addr,len : longint) : longint; -begin - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - if len <= 0 then - Begin - do_write:=0; - exit; - end; - asm - move.l a6,d6 - - movem.l d2/d3,-(sp) - move.l h,d1 { we must of course set up the } - move.l addr,d2 { parameters BEFORE getting } - move.l len,d3 { _DOSBase } - move.l _DOSBase,a6 - jsr _LVOWrite(a6) - movem.l (sp)+,d2/d3 - - cmp.l #-1,d0 - bne @doswrend { if -1 = error } - jsr _LVOIoErr(a6) - move.w d0,errno - bra @doswrend2 - @doswrend: - { we must restore the base pointer before setting the result } - move.l d6,a6 - move.l d0,@RESULT - bra @end - @doswrend2: - move.l d6,a6 - @end: - end; - If errno <> 0 then - Error2InOut; -end; - - -function do_read(h,addr,len : longint) : longint; -begin - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - if len <= 0 then - Begin - do_read:=0; - exit; - end; - asm - move.l a6,d6 - - movem.l d2/d3,-(sp) - move.l h,d1 { we must set up aparamters BEFORE } - move.l addr,d2 { setting up a6 for the OS call } - move.l len,d3 - move.l _DOSBase,a6 - jsr _LVORead(a6) - movem.l (sp)+,d2/d3 - - cmp.l #-1,d0 - bne @doswrend { if -1 = error } - jsr _LVOIoErr(a6) - move.w d0,errno - bra @doswrend2 - @doswrend: - { to store a result for the function } - { we must of course first get back the} - { base pointer! } - move.l d6,a6 - move.l d0,@RESULT - bra @end - @doswrend2: - move.l d6,a6 - @end: - end; - If errno <> 0 then - Error2InOut; -end; - - -function do_filepos(handle : longint) : longint; -begin - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - { Clear CTRL-C signal } - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - asm - move.l a6,d6 - - move.l handle,d1 - move.l d2,-(sp) - move.l d3,-(sp) { save registers } - - clr.l d2 { offset 0 } - move.l #0,d3 { OFFSET_CURRENT } - move.l _DOSBase,a6 - jsr _LVOSeek(a6) - - move.l (sp)+,d3 { restore registers } - move.l (sp)+,d2 - cmp.l #-1,d0 { is there a file access error? } - bne @noerr - jsr _LVOIoErr(a6) - move.w d0,errno - bra @fposend - @noerr: - move.l d6,a6 { restore a6 } - move.l d0,@Result - bra @end - @fposend: - move.l d6,a6 { restore a6 } - @end: - end; - If errno <> 0 then - Error2InOut; -end; - - -procedure do_seek(handle,pos : longint); -begin - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - { Clear CTRL-C signal } - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - asm - move.l a6,d6 - - move.l handle,d1 - move.l d2,-(sp) - move.l d3,-(sp) { save registers } - - move.l pos,d2 - { -1 } - move.l #$ffffffff,d3 { OFFSET_BEGINNING } - move.l _DOSBase,a6 - jsr _LVOSeek(a6) - - move.l (sp)+,d3 { restore registers } - move.l (sp)+,d2 - cmp.l #-1,d0 { is there a file access error? } - bne @noerr - jsr _LVOIoErr(a6) - move.w d0,errno - bra @seekend - @noerr: - @seekend: - move.l d6,a6 { restore a6 } - end; - If errno <> 0 then - Error2InOut; -end; - - -function do_seekend(handle:longint):longint; -begin - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - { Clear CTRL-C signal } - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - asm - { seek from end of file } - move.l a6,d6 - - move.l handle,d1 - move.l d2,-(sp) - move.l d3,-(sp) { save registers } - - clr.l d2 - move.l #1,d3 { OFFSET_END } - move.l _DOSBase,a6 - jsr _LVOSeek(a6) - - move.l (sp)+,d3 { restore registers } - move.l (sp)+,d2 - cmp.l #-1,d0 { is there a file access error? } - bne @noerr - jsr _LVOIoErr(a6) - move.w d0,errno - bra @seekend - @noerr: - move.l d6,a6 { restore a6 } - move.l d0,@Result - bra @end - @seekend: - move.l d6,a6 { restore a6 } - @end: - end; - If Errno <> 0 then - Error2InOut; -end; - - -function do_filesize(handle : longint) : longint; -var - aktfilepos : longint; -begin - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - { Clear CTRL-C signal } - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - aktfilepos:=do_filepos(handle); - { We have to do this two times, because seek returns the } - { OLD position } - do_filesize:=do_seekend(handle); - do_filesize:=do_seekend(handle); - do_seek(handle,aktfilepos); -end; - - -procedure do_truncate (handle,pos:longint); -begin - { Point to the end of the file } - { with the new size } - asm - @noerr_one: { Seek a second time } - move.l a6,d6 { Save base pointer } - - move.l handle,d1 - move.l d2,-(sp) - move.l d3,-(sp) { save registers } - - move.l pos,d2 - move.l #-1,d3 { Setup correct move type } - move.l _DOSBase,a6 { from beginning of file } - jsr _LVOSetFileSize(a6) - - move.l (sp)+,d3 { restore registers } - move.l (sp)+,d2 - cmp.l #-1,d0 { is there a file access error? } - bne @noerr - jsr _LVOIoErr(a6) - move.w d0,errno { Global variable, so no need } - @noerr: { to restore base pointer now } - move.l d6,a6 { Restore base pointer } - end; - If Errno <> 0 then - Error2InOut; -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 $100) the file will be append - when (flags and $1000) the file will be truncate/rewritten - when (flags and $10000) there is no check for close (needed for textfiles) -} -var - i,j : longint; - oflags: longint; - path : string; - buffer : array[0..255] of char; - index : integer; - s : string; -begin - path:=strpas(p); - for index:=1 to length(path) do - if path[index]='\' then path[index]:='/'; - { remove any dot characters and replace by their current } - { directory equivalent. } - if pos('../',path) = 1 then - { look for parent directory } - Begin - delete(path,1,3); - getdir(0,s); - j:=length(s); - while (s[j] <> '/') AND (s[j] <> ':') AND (j > 0 ) do - dec(j); - if j > 0 then - s:=copy(s,1,j); - path:=s+path; - end - else - if pos('./',path) = 1 then - { look for current directory } - Begin - delete(path,1,2); - getdir(0,s); - if (s[length(s)] <> '/') and (s[length(s)] <> ':') then - s:=s+'/'; - path:=s+path; - end; - move(path[1],buffer,length(path)); - buffer[length(path)]:=#0; - { close first if opened } - if ((flags and $10000)=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:=UnusedHandle; -{ convert filemode to filerec modes } - { READ/WRITE on existing file } - { RESET/APPEND } - oflags := 1005; - case (flags and 3) of - 0 : begin - filerec(f).mode:=fminput; - end; - 1 : filerec(f).mode:=fmoutput; - 2 : filerec(f).mode:=fminout; - end; - { READ/WRITE mode, create file in all cases } - { REWRITE } - if (flags and $1000)<>0 then - begin - filerec(f).mode:=fmoutput; - oflags := 1006; - end - else - { READ/WRITE mode on existing file } - { APPEND } - if (flags and $100)<>0 then - begin - filerec(f).mode:=fmoutput; - oflags := 1005; - 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; - asm - move.l a6,d6 { save a6 } - move.l d2,-(sp) - lea buffer,a0 - move.l a0,d1 - move.l oflags,d2 { MODE_READWRITE } - move.l _DOSBase,a6 - jsr _LVOOpen(a6) - tst.l d0 - bne @noopenerror { on zero an error occured } - jsr _LVOIoErr(a6) - move.w d0,errno - bra @openend - @noopenerror: - move.l (sp)+,d2 - move.l d6,a6 { restore a6 } - move.l d0,i { we need the base pointer to access this variable } - bra @end - @openend: - move.l d6,a6 { restore a6 } - move.l (sp)+,d2 - @end: - end; -(* if Errno = 0 then*) - { No error, add file handle to linked list } - { this must be checked before the call to } - { Error2InIOut since it resets Errno to 0 } -(* AddToList(FileList,i);*) - If Errno <> 0 then - Error2InOut; - - filerec(f).handle:=i; - if (flags and $100)<>0 then - do_seekend(filerec(f).handle); - -end; - -{***************************************************************************** - UnTyped File Handling -*****************************************************************************} - -{$i file.inc} - -{***************************************************************************** - Typed File Handling -*****************************************************************************} - -{$i typefile.inc} - -{***************************************************************************** - Text File Handling -*****************************************************************************} - -{$i text.inc} - -{***************************************************************************** - Directory Handling -*****************************************************************************} - -procedure mkdir(const s : string);[IOCheck]; -var - buffer : array[0..255] of char; - j: Integer; - temp : string; -begin - { We must check the Ctrl-C before IOChecking of course! } - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - { Clear CTRL-C signal } - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - If InOutRes <> 0 then exit; - temp:=s; - for j:=1 to length(temp) do - if temp[j] = '\' then temp[j] := '/'; - move(temp[1],buffer,length(temp)); - buffer[length(temp)]:=#0; - asm - move.l a6,d6 - { we must load the parameters BEFORE setting up the } - { OS call with a6 } - lea buffer,a0 - move.l a0,d1 - move.l _DosBase,a6 - jsr _LVOCreateDir(a6) - tst.l d0 - bne @noerror - jsr _LVOIoErr(a6) - move.w d0,errno - bra @end -@noerror: - { Now we must unlock the directory } - { d0 = lock returned by create dir } - move.l d0,d1 - jsr _LVOUnlock(a6) -@end: - { restore base pointer } - move.l d6,a6 - end; - If errno <> 0 then - Error2InOut; -end; - - -procedure rmdir(const s : string);[IOCheck]; -var - buffer : array[0..255] of char; - j : Integer; - temp : string; -begin - { We must check the Ctrl-C before IOChecking of course! } - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - { Clear CTRL-C signal } - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - If InOutRes <> 0 then exit; - temp:=s; - for j:=1 to length(temp) do - if temp[j] = '\' then temp[j] := '/'; - move(temp[1],buffer,length(temp)); - buffer[length(temp)]:=#0; - do_erase(buffer); -end; - - - -procedure chdir(const s : string);[IOCheck]; -var - buffer : array[0..255] of char; - alock : longint; - FIB :pFileInfoBlock; - j: integer; - temp : string; -begin - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - { Clear CTRL-C signal } - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - If InOutRes <> 0 then exit; - temp:=s; - for j:=1 to length(temp) do - if temp[j] = '\' then temp[j] := '/'; - { Return parent directory } - if s = '..' then - Begin - getdir(0,temp); - j:=length(temp); - { Look through the previous paths } - while (temp[j] <> '/') AND (temp[j] <> ':') AND (j > 0 ) do - dec(j); - if j > 0 then - temp:=copy(temp,1,j); - end; - alock := 0; - fib:=nil; - new(fib); - - move(temp[1],buffer,length(temp)); - buffer[length(temp)]:=#0; - { Changing the directory is a pretty complicated affair } - { 1) Obtain a lock on the directory } - { 2) CurrentDir the lock } - asm - lea buffer,a0 - move.l a0,d1 { pointer to buffer in d1 } - move.l d2,-(sp) { save d2 register } - move.l #-2,d2 { ACCESS_READ lock } - move.l a6,d6 { Save base pointer } - move.l _DosBase,a6 - jsr _LVOLock(a6){ Lock the directory } - move.l (sp)+,d2 { Restore d2 register } - tst.l d0 { zero = error! } - bne @noerror - jsr _LVOIoErr(a6) - move.w d0,errno - move.l d6,a6 { reset base pointer } - bra @End - @noerror: - move.l d6,a6 { reset base pointer } - move.l d0,alock { save the lock } - @End: - end; - If errno <> 0 then - Begin - Error2InOut; - exit; - end; - if (Examine(alock, fib^) = TRUE) AND (fib^.fib_DirEntryType > 0) then - Begin - alock := CurrentDir(alock); - if OrigDir = 0 then - Begin - OrigDir := alock; - alock := 0; - end; - end; - if alock <> 0 then - Unlock(alock); - if assigned(fib) then dispose(fib); -end; - - - - - Procedure GetCwd(var path: string); - var - lock: longint; - fib: PfileInfoBlock; - len : integer; - newlock : longint; - elen : integer; - Process : PProcess; - Begin - len := 0; - path := ''; - fib := nil; - { By using a pointer instead of a local variable} - { we are assured that the pointer is aligned on } - { a dword boundary. } - new(fib); - Process := FindTask(nil); - if (process^.pr_Task.tc_Node.ln_Type = NT_TASK) then - Begin - path:=''; - exit; - end; - lock := DupLock(process^.pr_CurrentDir); - if (Lock = 0) then - Begin - path:=''; - exit; - end; - - While (lock <> 0) and (Examine(lock,FIB^) = TRUE) do - Begin - elen := strlen(fib^.fib_FileName); - if (len + elen + 2 > 255) then - break; - newlock := ParentDir(lock); - if (len <> 0) then - Begin - if (newlock <> 0) then - path:='/'+path - else - path:=':'+path; - path:=strpas(fib^.fib_FileName)+path; - Inc(len); - end - else - Begin - path:=strpas(fib^.fib_Filename); - if (newlock = 0) then - path:=path+':'; - end; - - len := len + elen; - - UnLock(lock); - lock := newlock; - end; - if (lock <> 0) then - Begin - UnLock(lock); - path := ''; - end; - if assigned(fib) then dispose(fib); - end; - - -procedure getdir(drivenr : byte;var dir : string); -begin - if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then - Begin - { Clear CTRL-C signal } - SetSignal(0,SIGBREAKF_CTRL_C); - Halt(CTRL_C); - end; - GetCwd(dir); - If errno <> 0 then - Error2InOut; -end; - - -{***************************************************************************** - SystemUnit Initialization -*****************************************************************************} - -Procedure Startup; Assembler; -asm - move.l a6,d6 { save a6 } - - move.l (4),a6 { get ExecBase pointer } - move.l a6,_ExecBase - suba.l a1,a1 - jsr _LVOFindTask(a6) - move.l d0,a0 - { Check the stack value } - - { are we running from a CLI? } - - tst.l 172(a0) { 172 = pr_CLI } - bne @fromCLI - - { we do not support Workbench yet .. } - move.l d6,a6 { restore a6 } - move.l #1,d0 - jsr HALT_ERROR - -@fromCLI: - { Open the following libraries: } - { Intuition.library } - { dos.library } - - moveq.l #0,d0 - move.l intuitionname,a1 { directly since it is a pchar } - jsr _LVOOpenLibrary(a6) - move.l d0,_IntuitionBase - beq @exitprg - - moveq.l #0,d0 - move.l utilityname,a1 { directly since it is a pchar } - jsr _LVOOpenLibrary(a6) - move.l d0,_UtilityBase - beq @exitprg - - moveq.l #0,d0 - move.l dosname,a1 { directly since it is a pchar } - jsr _LVOOpenLibrary(a6) - move.l d0,_DOSBase - beq @exitprg - - { Find standard input and output } - { for CLI } -@OpenFiles: - move.l _DOSBase,a6 - jsr _LVOInput(a6) { get standard in } - move.l d0, StdInputHandle { save standard Input handle } -{ move.l d0,d1 }{ set up for next call } -{ jsr _LVOIsInteractive(a6)}{ is it interactive? } -{ move.l #_Input,a0 }{ get file record again } -{ move.b d0,INTERACTIVE(a0) }{ set flag } -{ beq StdInNotInteractive }{ skip this if not interactive } -{ move.l BUFFER(a0),a1 }{ get buffer address } -{ add.l #1,a1 }{ make end one byte further on } -{ move.l a1,MAX(a0) }{ set buffer size } -{ move.l a1,CURRENT(a0) }{ will need a read } - bra @OpenStdOutput -@StdInNotInteractive -{ jsr _p%FillBuffer } { fill the buffer } -@OpenStdOutput - jsr _LVOOutput(a6) { get ouput file handle } - move.l d0,StdOutputHandle { get file record } - bra @startupend -{ move.l d0,d1 } { set up for call } -{ jsr _LVOIsInteractive(a6) } { is it interactive? } -{ move.l #_Output,a0 } { get file record } -{ move.b d0,INTERACTIVE(a0)} { set flag } -@exitprg: - move.l d6,a6 { restore a6 } - move.l #219,d0 - jsr HALT_ERROR -@startupend: - move.l d6,a6 { restore a6 } -end; - - - -begin - errno:= 0; - FromHalt := FALSE; -{ Initial state is on -- in case of RunErrors before the i/o handles are } -{ ok. } - Initial:=TRUE; -{ Initialize ExitProc } - ExitProc:=Nil; - Startup; -{ to test stack depth } - loweststack:=maxlongint; -{ Setup heap } - InitHeap; -{ Setup stdin, stdout and stderr } - OpenStdIO(Input,fmInput,StdInputHandle); - OpenStdIO(Output,fmOutput,StdOutputHandle); - OpenStdIO(StdOut,fmOutput,StdOutputHandle); - { The Amiga does not seem to have a StdError } - { handle, therefore make the StdError handle } - { equal to the StdOutputHandle. } - StdErrorHandle := StdOutputHandle; - OpenStdIO(StdErr,fmOutput,StdErrorHandle); -{ Now Handles and function handlers are setup } -{ correctly. } - Initial:=FALSE; -{ Reset IO Error } - InOutRes:=0; -{ Startup } - { Only AmigaOS v2.04 or greater is supported } - If KickVersion < 36 then - Begin - WriteLn('v36 or greater of Kickstart required.'); - Halt(1); - end; - argc:=GetParamCount(args); - OrigDir := 0; - FileList := nil; -end. - - -{ - $Log$ - Revision 1.1 2000-07-13 06:30:29 michael - + Initial import - - Revision 1.15 2000/01/07 16:41:29 daniel - * copyright 2000 - - Revision 1.14 2000/01/07 16:32:22 daniel - * copyright 2000 added - - Revision 1.13 1999/09/10 15:40:32 peter - * fixed do_open flags to be > $100, becuase filemode can be upto 255 - - Revision 1.12 1999/01/18 10:05:47 pierre - + system_exit procedure added - - Revision 1.11 1998/12/28 15:50:42 peter - + stdout, which is needed when you write something in the system unit - to the screen. Like the runtime error - - Revision 1.10 1998/09/14 10:48:00 peter - * FPC_ names - * Heap manager is now system independent - - Revision 1.9 1998/08/17 12:34:22 carl - * chdir accepts .. characters - + added ctrl-c checking - + implemented sbrk - * exit code was never called if no error was found on exit! - * register was not saved in do_open - - Revision 1.8 1998/07/13 12:32:18 carl - * do_truncate works, some cleanup - - Revision 1.6 1998/07/02 12:37:52 carl - * IOCheck for chdir,rmdir and mkdir as in TP - - Revision 1.5 1998/07/01 14:30:56 carl - * forgot that includes are case sensitive - - Revision 1.4 1998/07/01 14:13:50 carl - * do_open bugfix - * correct conversion of Amiga error codes to TP error codes - * InoutRes word bugfix - * parameter counting fixed - * new stack checking implemented - + IOCheck for chdir,rmdir,getdir and rmdir - * do_filepos was wrong - + chdir correctly implemented - * getdir correctly implemented - - Revision 1.1.1.1 1998/03/25 11:18:47 root - * Restored version - - Revision 1.14 1998/03/21 04:20:09 carl - * correct ExecBase pointer (from Nils Sjoholm) - * correct OpenLibrary vector (from Nils Sjoholm) - - Revision 1.13 1998/03/14 21:34:32 carl - * forgot to save a6 in Startup routine - - Revision 1.12 1998/02/24 21:19:42 carl - *** empty log message *** - - Revision 1.11 1998/02/23 02:22:49 carl - * bugfix if linking problems - - Revision 1.9 1998/02/06 16:34:32 carl - + do_open is now standard with other platforms - - Revision 1.8 1998/02/02 15:01:45 carl - * fixed bug with opening library versions (from Nils Sjoholm) - - Revision 1.7 1998/01/31 19:35:19 carl - + added opening of utility.library - - Revision 1.6 1998/01/29 23:20:54 peter - - Removed Backslash convert - - Revision 1.5 1998/01/27 10:55:04 peter - * Amiga uses / not \, so change AllowSlash -> AllowBackSlash - - Revision 1.4 1998/01/25 21:53:20 peter - + Universal Handles support for StdIn/StdOut/StdErr - * Updated layout of sysamiga.pas - - Revision 1.3 1998/01/24 21:09:53 carl - + added missing input/output function pointers - - Revision 1.2 1998/01/24 14:08:25 carl - * RunError 217 --> RunError 219 (cannot open lib) - + Standard Handle names implemented - - Revision 1.1 1998/01/24 05:12:15 carl - + initial revision, some stuff still missing though. - (and as you might imagine ... untested :)) -} +{$i system.pp} diff --git a/rtl/amiga/system.pas b/rtl/amiga/system.pas new file mode 100644 index 0000000000..0660c302d8 --- /dev/null +++ b/rtl/amiga/system.pas @@ -0,0 +1,1915 @@ +{ + $Id$ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Carl Eric Codere + Some parts taken from + Marcel Timmermans - Modula 2 Compiler + Nils Sjoholm - Amiga porter + Matthew Dillon - Dice C (with his kind permission) + dillon@backplane.com + + 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 {$ifdef VER1_0}sysamiga{$else}{$ifdef VER0_99}sysamiga{$ELSE}system{$endif}{$ENDIF}; + +{--------------------------------------------------------------------} +{ LEFT TO DO: } +{--------------------------------------------------------------------} +{ o GetDir with different drive numbers } +{--------------------------------------------------------------------} + +{$I os.inc} + +{ AmigaOS uses character #10 as eoln only } +{$DEFINE SHORT_LINEBREAK} + + interface + + { used for single computations } + const BIAS4 = $7f-1; + + {$I systemh.inc} + + {$I heaph.inc} + +const + UnusedHandle : longint = -1; + StdInputHandle : longint = 0; + StdOutputHandle : longint = 0; + StdErrorHandle : longint = 0; + + _ExecBase:longint = $4; + _WorkbenchMsg : longint = 0; + + _IntuitionBase : pointer = nil; { intuition library pointer } + _DosBase : pointer = nil; { DOS library pointer } + _UtilityBase : pointer = nil; { utiity library pointer } + + { Required for crt unit } + function do_read(h,addr,len : longint) : longint; + function do_write(h,addr,len : longint) : longint; + + + + + + implementation + + const + + intuitionname : pchar = 'intuition.library'; + dosname : pchar = 'dos.library'; + utilityname : pchar = 'utility.library'; + argc : longint = 0; + { AmigaOS does not autoamtically deallocate memory on program termination } + { therefore we have to handle this manually. This is a list of allocated } + { pointers from the OS, we cannot use a linked list, because the linked } + { list itself uses the HEAP! } + pointerlist : array[1..8] of longint = + (0,0,0,0,0,0,0,0); + + + {$I exec.inc} + + TYPE + TDateStamp = packed record + ds_Days : Longint; { Number of days since Jan. 1, 1978 } + ds_Minute : Longint; { Number of minutes past midnight } + ds_Tick : Longint; { Number of ticks past minute } + end; + PDateStamp = ^TDateStamp; + + + PFileInfoBlock = ^TfileInfoBlock; + TFileInfoBlock = packed record + fib_DiskKey : Longint; + fib_DirEntryType : Longint; + { Type of Directory. If < 0, then a plain file. + If > 0 a directory } + fib_FileName : Array [0..107] of Char; + { Null terminated. Max 30 chars used for now } + fib_Protection : Longint; + { bit mask of protection, rwxd are 3-0. } + fib_EntryType : Longint; + fib_Size : Longint; { Number of bytes in file } + fib_NumBlocks : Longint; { Number of blocks in file } + fib_Date : TDateStamp; { Date file last changed } + fib_Comment : Array [0..79] of Char; + { Null terminated comment associated with file } + fib_Reserved : Array [0..35] of Char; + end; + + + TProcess = packed record + pr_Task : TTask; + pr_MsgPort : TMsgPort; { This is BPTR address from DOS functions } +{126} pr_Pad : Word; { Remaining variables on 4 byte boundaries } +{128} pr_SegList : Pointer; { Array of seg lists used by this process } +{132} pr_StackSize : Longint; { Size of process stack in bytes } +{136} pr_GlobVec : Pointer; { Global vector for this process (BCPL) } +{140} pr_TaskNum : Longint; { CLI task number of zero if not a CLI } +{144} pr_StackBase : BPTR; { Ptr to high memory end of process stack } +{148} pr_Result2 : Longint; { Value of secondary result from last call } +{152} pr_CurrentDir : BPTR; { Lock associated with current directory } +{156} pr_CIS : BPTR; { Current CLI Input Stream } +{160} pr_COS : BPTR; { Current CLI Output Stream } +{164} pr_ConsoleTask : Pointer; { Console handler process for current window} +{168} pr_FileSystemTask : Pointer; { File handler process for current drive } +{172} pr_CLI : BPTR; { pointer to ConsoleLineInterpreter } + pr_ReturnAddr : Pointer; { pointer to previous stack frame } + pr_PktWait : Pointer; { Function to be called when awaiting msg } + pr_WindowPtr : Pointer; { Window for error printing } + { following definitions are new with 2.0 } + pr_HomeDir : BPTR; { Home directory of executing program } + pr_Flags : Longint; { flags telling dos about process } + pr_ExitCode : Pointer; { code to call on exit of program OR NULL } + pr_ExitData : Longint; { Passed as an argument to pr_ExitCode. } + pr_Arguments : PChar; { Arguments passed to the process at start } + pr_LocalVars : TMinList; { Local environment variables } + pr_ShellPrivate : Longint; { for the use of the current shell } + pr_CES : BPTR; { Error stream - IF NULL, use pr_COS } + end; + PProcess = ^TProcess; + + { AmigaOS does not automatically close opened files on exit back to } + { the operating system, therefore as a precuation we close all files } + { manually on exit. } + PFileList = ^TFileList; + TFileList = record { no packed, must be correctly aligned } + Handle: longint; { Handle to file } + next: pfilelist; { Next file in list } + closed: boolean; { TRUE=file already closed } + end; + + + + + Const + CTRL_C = 20; { Error code on CTRL-C press } + SIGBREAKF_CTRL_C = $1000; { CTRL-C signal flags } + + _LVOFindTask = -294; + _LVOWaitPort = -384; + _LVOGetMsg = -372; + _LVOOpenLibrary = -552; + _LVOCloseLibrary = -414; + _LVOClose = -36; + _LVOOpen = -30; + _LVOIoErr = -132; + _LVOSeek = -66; + _LVODeleteFile = -72; + _LVORename = -78; + _LVOWrite = -48; + _LVORead = -42; + _LVOCreateDir = -120; + _LVOSetCurrentDirName = -558; + _LVOGetCurrentDirName = -564; + _LVOInput = -54; + _LVOOutput = -60; + _LVOUnLock = -90; + _LVOLock = -84; + _LVOCurrentDir = -126; + + _LVONameFromLock = -402; + _LVONameFromFH = -408; + _LVOGetProgramName = -576; + _LVOGetProgramDir = -600; + _LVODupLock = -96; + _LVOExamine = -102; + _LVOParentDir = -210; + _LVOSetFileSize = -456; + _LVOSetSignal = -306; + _LVOAllocVec = -684; + _LVOFreeVec = -690; + + + { Errors from IoErr(), etc. } + ERROR_NO_FREE_STORE = 103; + ERROR_TASK_TABLE_FULL = 105; + ERROR_BAD_TEMPLATE = 114; + ERROR_BAD_NUMBER = 115; + ERROR_REQUIRED_ARG_MISSING = 116; + ERROR_KEY_NEEDS_ARG = 117; + ERROR_TOO_MANY_ARGS = 118; + ERROR_UNMATCHED_QUOTES = 119; + ERROR_LINE_TOO_LONG = 120; + ERROR_FILE_NOT_OBJECT = 121; + ERROR_INVALID_RESIDENT_LIBRARY = 122; + ERROR_NO_DEFAULT_DIR = 201; + ERROR_OBJECT_IN_USE = 202; + ERROR_OBJECT_EXISTS = 203; + ERROR_DIR_NOT_FOUND = 204; + ERROR_OBJECT_NOT_FOUND = 205; + ERROR_BAD_STREAM_NAME = 206; + ERROR_OBJECT_TOO_LARGE = 207; + ERROR_ACTION_NOT_KNOWN = 209; + ERROR_INVALID_COMPONENT_NAME = 210; + ERROR_INVALID_LOCK = 211; + ERROR_OBJECT_WRONG_TYPE = 212; + ERROR_DISK_NOT_VALIDATED = 213; + ERROR_DISK_WRITE_PROTECTED = 214; + ERROR_RENAME_ACROSS_DEVICES = 215; + ERROR_DIRECTORY_NOT_EMPTY = 216; + ERROR_TOO_MANY_LEVELS = 217; + ERROR_DEVICE_NOT_MOUNTED = 218; + ERROR_SEEK_ERROR = 219; + ERROR_COMMENT_TOO_BIG = 220; + ERROR_DISK_FULL = 221; + ERROR_DELETE_PROTECTED = 222; + ERROR_WRITE_PROTECTED = 223; + ERROR_READ_PROTECTED = 224; + ERROR_NOT_A_DOS_DISK = 225; + ERROR_NO_DISK = 226; + ERROR_NO_MORE_ENTRIES = 232; + { added for 1.4 } + ERROR_IS_SOFT_LINK = 233; + ERROR_OBJECT_LINKED = 234; + ERROR_BAD_HUNK = 235; + ERROR_NOT_IMPLEMENTED = 236; + ERROR_RECORD_NOT_LOCKED = 240; + ERROR_LOCK_COLLISION = 241; + ERROR_LOCK_TIMEOUT = 242; + ERROR_UNLOCK_ERROR = 243; + + + + var + Initial: boolean; { Have successfully opened Std I/O } + errno : word; { AmigaOS IO Error number } + FileList : pFileList; { Linked list of opened files } + {old_exit: Pointer; not needed anymore } + FromHalt : boolean; + OrigDir : Longint; { Current lock on original startup directory } + + {$I system.inc} + {$I lowmath.inc} + + + + + { ************************ AMIGAOS STUB ROUTINES ************************* } + + procedure DateStamp(var ds : tDateStamp); + begin + asm + MOVE.L A6,-(A7) + MOVE.L ds,d1 + { LAST THING TO SETUP SHOULD BE A6, otherwise you can } + { not accept local variable, nor any parameters! :) } + MOVE.L _DOSBase,A6 + JSR -192(A6) + MOVE.L (A7)+,A6 + end; + end; + + + + { UNLOCK the BPTR pointed to in L } + Procedure Unlock(alock: longint); + Begin + asm + move.l alock,d1 + move.l a6,d6 { save base pointer } + move.l _DosBase,a6 + jsr _LVOUnlock(a6) + move.l d6,a6 { restore base pointer } + end; + end; + + { Change to the directory pointed to in the lock } + Function CurrentDir(alock : longint) : longint; + Begin + asm + move.l alock,d1 + move.l a6,d6 { save base pointer } + move.l _DosBase,a6 + jsr _LVOCurrentDir(a6) + move.l d6,a6 { restore base pointer } + move.l d0,@Result + end; + end; + + { Duplicate a lock } + Function DupLock(alock: longint): Longint; + Begin + asm + move.l alock,d1 + move.l a6,d6 { save base pointer } + move.l _DosBase,a6 + jsr _LVODupLock(a6) + move.l d6,a6 { restore base pointer } + move.l d0,@Result + end; + end; + + { Returns a lock on the directory was loaded from } + Function GetProgramLock: longint; + Begin + asm + move.l a6,d6 { save base pointer } + move.l _DosBase,a6 + jsr _LVOGetProgramDir(a6) + move.l d6,a6 { restore base pointer } + move.l d0,@Result + end; + end; + + + + Function Examine(alock :longint; var fib: TFileInfoBlock) : Boolean; + Begin + asm + move.l d2,-(sp) + move.l fib,d2 { pointer to FIB } + move.l alock,d1 + move.l a6,d6 { save base pointer } + move.l _DosBase,a6 + jsr _LVOExamine(a6) + move.l d6,a6 { restore base pointer } + tst.l d0 + bne @success + bra @end + @success: + move.b #1,d0 + @end: + move.b d0,@Result + move.l (sp)+,d2 + end; + end; + + { Returns the parent directory of a lock } + Function ParentDir(alock : longint): longint; + Begin + asm + move.l alock,d1 + move.l a6,d6 { save base pointer } + move.l _DosBase,a6 + jsr _LVOParentDir(a6) + move.l d6,a6 { restore base pointer } + move.l d0,@Result + end; + end; + + + Function FindTask(p : PChar): PProcess; + Begin + asm + move.l a6,d6 { Save base pointer } + move.l p,d0 + move.l d0,a1 + move.l _ExecBase,a6 + jsr _LVOFindTask(a6) + move.l d6,a6 { Restore base pointer } + move.l d0,@Result + end; + end; + + +{$S-} + Procedure stack_check; assembler; + { Check for local variable allocation } + { On Entry -> d0 : size of local stack we are trying to allocate } + asm + XDEF STACKCHECK + move.l sp,d1 { get value of stack pointer } + + { We must add some security, because Writing the RunError strings } + { requires a LOT of stack space (at least 1030 bytes!) } + add.l #2048,d0 + sub.l d0,d1 { sp - stack_size } + + move.l _ExecBase,a0 + move.l 276(A0),A0 { ExecBase.thisTask } + { if allocated stack_pointer - splower <= 0 then stack_ovf } + cmp.l 58(A0),D1 { Task.SpLower } + bgt @Ok + move.l #202,d0 + jsr HALT_ERROR { stack overflow } + @Ok: + end; + + + { This routine from EXEC determines if the Ctrl-C key has } + { been used since the last call to I/O routines. } + { Use to halt the program. } + { Returns the state of the old signals. } + Function SetSignal(newSignal: longint; SignalMask: longint): longint; + Begin + asm + move.l newSignal,d0 + move.l SignalMask,d1 + move.l a6,d6 { save Base pointer into scratch register } + move.l _ExecBase,a6 + jsr _LVOSetSignal(a6) + move.l d6,a6 + move.l d0,@Result + end; + end; + + + Function AllocVec(bytesize: longint; attributes: longint):longint; + Begin + asm + move.l bytesize,d0 + move.l attributes,d1 + move.l a6,d6 { save Base pointer into scratch register } + move.l _ExecBase,a6 + jsr _LVOAllocVec(a6) + move.l d6,a6 + move.l d0,@Result + end; + end; + + + Procedure FreeVec(p: longint); + Begin + asm + move.l p,a1 + move.l a6,d6 { save Base pointer into scratch register } + move.l _ExecBase,a6 + jsr _LVOFreeVec(a6) + move.l d6,a6 + end; + end; + + + { Converts an AMIGAOS error code to a TP compatible error code } + Procedure Error2InOut; + Begin + case errno of + ERROR_BAD_NUMBER, + ERROR_ACTION_NOT_KNOWN, + ERROR_NOT_IMPLEMENTED : InOutRes := 1; + + ERROR_OBJECT_NOT_FOUND : InOutRes := 2; + ERROR_DIR_NOT_FOUND : InOutRes := 3; + + ERROR_DISK_WRITE_PROTECTED : InOutRes := 150; + + ERROR_OBJECT_WRONG_TYPE : InOutRes := 151; + + ERROR_OBJECT_EXISTS, + ERROR_DELETE_PROTECTED, + ERROR_WRITE_PROTECTED, + ERROR_READ_PROTECTED, + ERROR_OBJECT_IN_USE, + ERROR_DIRECTORY_NOT_EMPTY : InOutRes := 5; + + ERROR_NO_MORE_ENTRIES : InOutRes := 18; + + ERROR_RENAME_ACROSS_DEVICES : InOutRes := 17; + + ERROR_DISK_FULL : InOutRes := 101; + + ERROR_INVALID_RESIDENT_LIBRARY : InoutRes := 153; + ERROR_BAD_HUNK : InOutRes := 153; + + ERROR_NOT_A_DOS_DISK : InOutRes := 157; + + ERROR_NO_DISK, + ERROR_DISK_NOT_VALIDATED, + ERROR_DEVICE_NOT_MOUNTED : InOutRes := 152; + + ERROR_SEEK_ERROR : InOutRes := 156; + + ERROR_LOCK_COLLISION, + ERROR_LOCK_TIMEOUT, + ERROR_UNLOCK_ERROR, + ERROR_INVALID_LOCK, + ERROR_INVALID_COMPONENT_NAME, + ERROR_BAD_STREAM_NAME, + ERROR_FILE_NOT_OBJECT : InOutRes := 6; + else + InOutres := errno; + end; + errno:=0; + end; + + + procedure CloseLibrary(lib : pointer); + { Close the library pointed to in lib } + Begin + asm + MOVE.L A6,-(A7) + MOVE.L lib,a1 + MOVE.L _ExecBase,A6 + JSR _LVOCloseLibrary(A6) + MOVE.L (A7)+,A6 + end; + end; + + + Function KickVersion: word; assembler; + asm + move.l _ExecBase, a0 { Get Exec Base } + move.w 20(a0), d0 { Return version - version at this offset } + end; + + + { ************************ AMIGAOS SUPP ROUTINES ************************* } + +(* Procedure CloseList(p: pFileList);*) + (***********************************************************************) + (* PROCEDURE CloseList *) + (* Description: This routine each time the program is about to *) + (* terminate, it closes all opened file handles, as this is not *) + (* handled by the operating system. *) + (* p -> Start of linked list of opened files *) + (***********************************************************************) +(* var + hp: pFileList; + hp1: pFileList; + h: longint; + Begin + hp:=p; + while Assigned(hp) do + Begin + if NOT hp^.closed then + Begin + h:=hp^.handle; + if (h <> StdInputHandle) and (h <> StdOutputHandle) and (h <> StdErrorHandle) then + Begin + { directly close file here, it is faster then doing } + { it do_close. } + asm + move.l h,d1 + move.l a6,d6 { save a6 } + move.l _DOSBase,a6 + jsr _LVOClose(a6) + move.l d6,a6 { restore a6 } + end; + end; + end; + hp1:=hp; + hp:=hp^.next; + dispose(hp1); + end; + end;*) + + +(* Procedure AddToList(var p: pFileList; h: longint);*) + (***********************************************************************) + (* PROCEDURE AddToList *) + (* Description: Adds a node to the linked list of files. *) + (* *) + (* p -> Start of File list linked list, if not allocated allocates *) + (* it for you. *) + (* h -> handle of file to add *) + (***********************************************************************) +(* var + hp: pFileList; + hp1: pFileList; + Begin + if p = nil then + Begin + new(p); + p^.handle:=h; + p^.closed := FALSE; + p^.next := nil; + exit; + end; + hp:=p; + { Find last list in entry } + while assigned(hp) do + Begin + if hp^.next = nil then break; + hp:=hp^.next; + end; + { Found last list in entry then add it to the list } + new(hp1); + hp^.next:=hp1; + hp1^.next:=nil; + hp1^.handle:=h; + hp1^.closed:=FALSE; + end; + + + Procedure SetClosedList(var p: pFileList; h: longint); + { Set the file flag to closed if the file is being closed } + var + hp: pFileList; + Begin + hp:=p; + while assigned(hp) do + Begin + if hp^.handle = h then + Begin + hp^.closed:=TRUE; + break; + end; + hp:=hp^.next; + end; + end;*) + + +{***************************************************************************** + System Dependent Exit code +*****************************************************************************} + Procedure system_exit; + var + i: byte; + Begin + { We must remove the CTRL-C FALG here because halt } + { may call I/O routines, which in turn might call } + { halt, so a recursive stack crash } + IF (SetSignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 THEN + SetSignal(0,SIGBREAKF_CTRL_C); + { Close remaining opened files } +{ CloseList(FileList); } + if (OrigDir <> 0) then + Begin + Unlock(CurrentDir(OrigDir)); + OrigDir := 0; + end; + { Is this a normal exit - YES, close libs } + IF NOT FromHalt then + Begin + { close the libraries } + If _UtilityBase <> nil then + CloseLibrary(_UtilityBase); + If _DosBase <> nil then + CloseLibrary(_DosBase); + If _IntuitionBase <> nil then + CloseLibrary(_IntuitionBase); + _UtilityBase := nil; + _DosBase := nil; + _IntuitionBase := nil; + end; + { Dispose of extraneous allocated pointers } + for I:=1 to 8 do + Begin + if pointerlist[i] <> 0 then FreeVec(pointerlist[i]); + end; + { exitproc:=old_exit;obsolete } + end; + + + procedure halt(errnum : byte); + begin + { Indicate to the SYSTEM EXIT procedure that we are calling it } + { from halt, and that its library will be closed HERE and not } + { in the exit procedure. } + FromHalt:=TRUE; + { We must remove the CTRL-C FALG here because halt } + { may call I/O routines, which in turn might call } + { halt, so a recursive stack crash } + IF (SetSignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 THEN + SetSignal(0,SIGBREAKF_CTRL_C); + { WE can only FLUSH the stdio } + { if the handles have correctly } + { been set. } + { No exit procedures exist } + { if in initial state } + If NOT Initial then + Begin + do_exit; + flush(stderr); + end; + { close the libraries } + If _UtilityBase <> nil then + CloseLibrary(_UtilityBase); + If _DosBase <> nil then + CloseLibrary(_DosBase); + If _IntuitionBase <> nil then + CloseLibrary(_IntuitionBase); + _UtilityBase := nil; + _DosBase := nil; + _IntuitionBase := nil; + asm + clr.l d0 + move.b errnum,d0 + move.l STKPTR,sp + rts + end; + end; + + + + { ************************ PARAMCOUNT/PARAMSTR *************************** } + + function paramcount : longint; + Begin + paramcount := argc; + end; + + + function args : pointer; assembler; + asm + move.l __ARGS,d0 + end; + + Function GetParamCount(const p: pchar): longint; + var + i: word; + count: word; + Begin + i:=0; + count:=0; + while p[count] <> #0 do + Begin + if (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) then + Begin + i:=i+1; + while (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) do + count:=count+1; + end; + if p[count] = #0 then break; + count:=count+1; + end; + GetParamCount:=longint(i); + end; + + + Function GetParam(index: word; const p : pchar): string; + { On Entry: index = string index to correct parameter } + { On exit: = correct character index into pchar array } + { Returns correct index to command line argument } + var + count: word; + localindex: word; + l: byte; + temp: string; + Begin + temp:=''; + count := 0; + { first index is one } + localindex := 1; + l:=0; + While p[count] <> #0 do + Begin + if (p[count] <> ' ') and (p[count] <> #9) then + Begin + if localindex = index then + Begin + while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) and (l < 256) do + Begin + temp:=temp+p[count]; + l:=l+1; + count:=count+1; + end; + temp[0]:=char(l); + GetParam:=temp; + exit; + end; + { Point to next argument in list } + while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) do + Begin + count:=count+1; + end; + localindex:=localindex+1; + end; + if p[count] = #0 then break; + count:=count+1; + end; + GetParam:=temp; + end; + + + Function GetProgramDir : String; + var + s1: string; + alock: longint; + counter : byte; + Begin + FillChar(@s1,255,#0); + { GetLock of program directory } + asm + move.l a6,d6 { save a6 } + move.l _DOSBase,a6 + jsr _LVOGetProgramDir(a6) + move.l d6,a6 { restore a6 } + move.l d0,alock { save the lock } + end; + if alock <> 0 then + Begin + { Get the name from the lock! } + asm + movem.l d2/d3,-(sp) { save used registers } + move.l alock,d1 + lea s1,a0 { Get pointer to string! } + move.l a0,d2 + add.l #1,d2 { let us point past the length byte! } + move.l #255,d3 + move.l a6,d6 { save a6 } + move.l _DOSBase,a6 + jsr _LVONameFromLock(a6) + move.l d6,a6 { restore a6 } + movem.l (sp)+,d2/d3 + end; + { no check out the length of the string } + counter := 1; + while s1[counter] <> #0 do + Inc(counter); + s1[0] := char(counter-1); + GetProgramDir := s1; + end + else + GetProgramDir := ''; + end; + + + Function GetProgramName : string; + { Returns ONLY the program name } + { There seems to be a bug in v39 since if the program is not } + { called from its home directory the program name will also } + { contain the path! } + var + s1: string; + counter : byte; + Begin + FillChar(@s1,255,#0); + asm + move.l d2,-(sp) { Save used register } + lea s1,a0 { Get pointer to string! } + move.l a0,d1 + add.l #1,d1 { point to correct offset } + move.l #255,d2 + move.l a6,d6 { save a6 } + move.l _DOSBase,a6 + jsr _LVOGetProgramName(a6) + move.l d6,a6 { restore a6 } + move.l (sp)+,d2 { restore saved register } + end; + { no check out and assign the length of the string } + counter := 1; + while s1[counter] <> #0 do + Inc(counter); + s1[0] := char(counter-1); + { now remove any component path which should not be there } + for counter:=length(s1) downto 1 do + if (s1[counter] = '/') or (s1[counter] = ':') then break; + { readjust counterv to point to character } + if counter <> 1 then + Inc(counter); + GetProgramName:=copy(s1,counter,length(s1)); + end; + + + function paramstr(l : longint) : string; + var + p : pchar; + s1 : string; + begin + { -> Call AmigaOS GetProgramName } + if l = 0 then + Begin + s1 := GetProgramDir; + { If this is a root, then simply don't add '/' } + if s1[length(s1)] = ':' then + paramstr:=s1+GetProgramName + else + { add backslash directory } + paramstr:=s1+'/'+GetProgramName + end + else + if (l>0) and (l<=paramcount) then + begin + p:=args; + paramstr:=GetParam(word(l),p); + end + else paramstr:=''; + end; + + { ************************************************************************ } + + procedure randomize; + + var + hl : longint; + time : TDateStamp; + begin + DateStamp(time); + randseed:=time.ds_tick; + end; + +function getheapstart:pointer;assembler; +asm + lea.l HEAP,a0 + move.l a0,d0 +end; + + +function getheapsize:longint;assembler; +asm + move.l HEAP_SIZE,d0 +end ['D0']; + + { This routine is used to grow the heap. } + { But here we do a trick, we say that the } + { heap cannot be regrown! } + function sbrk( size: longint): longint; + var + { on exit -1 = if fails. } + p: longint; + i: byte; + Begin + p:=0; + { Is the pointer list full } + if pointerlist[8] <> 0 then + begin + { yes, then don't allocate and simply exit } + sbrk:=-1; + exit; + end; + { Allocate best available memory } + p:=AllocVec(size,0); + if p = 0 then + sbrk:=-1 + else + Begin + i:=1; + { add it to the list of allocated pointers } + { first find the last pointer in the list } + while (i < 8) and (pointerlist[i] <> 0) do + i:=i+1; + pointerlist[i]:=p; + sbrk:=p; + end; + end; + + + +{$I heap.inc} + + +{**************************************************************************** + Low Level File Routines + ****************************************************************************} + +procedure do_close(h : longint); +{ We cannot check for CTRL-C because this routine will be called } +{ on HALT to close all remaining opened files. Therefore no } +{ CTRL-C checking otherwise a recursive call might result! } +{$ifdef debug} +var + buffer: array[0..255] of char; +{$endif} +begin + { check if the file handle is in the list } + { if so the put its field to closed } +{ SetClosedList(FileList,h);} +{$ifdef debug} + asm + move.l h,d1 + move.l a6,d6 + move.l d2,-(sp) + move.l d3,-(sp) + lea buffer,a0 + move.l a0,d2 + move.l #255,d3 + move.l _DosBase,a6 + jsr _LVONameFromFH(a6) + move.l d6,a6 + move.l (sp)+,d3 + move.l (sp)+,d2 + end; + WriteLn(Buffer); +{$endif debug} + asm + move.l h,d1 + move.l a6,d6 { save a6 } + move.l _DOSBase,a6 + jsr _LVOClose(a6) + move.l d6,a6 { restore a6 } + end; +end; + + +function do_isdevice(handle:longint):boolean; +begin + if (handle=stdoutputhandle) or (handle=stdinputhandle) or + (handle=stderrorhandle) then + do_isdevice:=TRUE + else + do_isdevice:=FALSE; +end; + + + +procedure do_erase(p : pchar); +begin + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + asm + move.l a6,d6 { save a6 } + + move.l p,d1 + move.l _DOSBase,a6 + jsr _LVODeleteFile(a6) + tst.l d0 { zero = failure } + bne @noerror + + jsr _LVOIoErr(a6) + move.w d0,errno + + @noerror: + move.l d6,a6 { restore a6 } + end; + if errno <> 0 then + Error2InOut; +end; + + +procedure do_rename(p1,p2 : pchar); +begin + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + asm + move.l a6,d6 { save a6 } + move.l d2,-(sp) { save d2 } + + move.l p1,d1 + move.l p2,d2 + move.l _DOSBase,a6 + jsr _LVORename(a6) + move.l (sp)+,d2 { restore d2 } + tst.l d0 + bne @dosreend { if zero = error } + jsr _LVOIoErr(a6) + move.w d0,errno + @dosreend: + move.l d6,a6 { restore a6 } + end; + if errno <> 0 then + Error2InOut; +end; + + +function do_write(h,addr,len : longint) : longint; +begin + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + if len <= 0 then + Begin + do_write:=0; + exit; + end; + asm + move.l a6,d6 + + movem.l d2/d3,-(sp) + move.l h,d1 { we must of course set up the } + move.l addr,d2 { parameters BEFORE getting } + move.l len,d3 { _DOSBase } + move.l _DOSBase,a6 + jsr _LVOWrite(a6) + movem.l (sp)+,d2/d3 + + cmp.l #-1,d0 + bne @doswrend { if -1 = error } + jsr _LVOIoErr(a6) + move.w d0,errno + bra @doswrend2 + @doswrend: + { we must restore the base pointer before setting the result } + move.l d6,a6 + move.l d0,@RESULT + bra @end + @doswrend2: + move.l d6,a6 + @end: + end; + If errno <> 0 then + Error2InOut; +end; + + +function do_read(h,addr,len : longint) : longint; +begin + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + if len <= 0 then + Begin + do_read:=0; + exit; + end; + asm + move.l a6,d6 + + movem.l d2/d3,-(sp) + move.l h,d1 { we must set up aparamters BEFORE } + move.l addr,d2 { setting up a6 for the OS call } + move.l len,d3 + move.l _DOSBase,a6 + jsr _LVORead(a6) + movem.l (sp)+,d2/d3 + + cmp.l #-1,d0 + bne @doswrend { if -1 = error } + jsr _LVOIoErr(a6) + move.w d0,errno + bra @doswrend2 + @doswrend: + { to store a result for the function } + { we must of course first get back the} + { base pointer! } + move.l d6,a6 + move.l d0,@RESULT + bra @end + @doswrend2: + move.l d6,a6 + @end: + end; + If errno <> 0 then + Error2InOut; +end; + + +function do_filepos(handle : longint) : longint; +begin + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + { Clear CTRL-C signal } + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + asm + move.l a6,d6 + + move.l handle,d1 + move.l d2,-(sp) + move.l d3,-(sp) { save registers } + + clr.l d2 { offset 0 } + move.l #0,d3 { OFFSET_CURRENT } + move.l _DOSBase,a6 + jsr _LVOSeek(a6) + + move.l (sp)+,d3 { restore registers } + move.l (sp)+,d2 + cmp.l #-1,d0 { is there a file access error? } + bne @noerr + jsr _LVOIoErr(a6) + move.w d0,errno + bra @fposend + @noerr: + move.l d6,a6 { restore a6 } + move.l d0,@Result + bra @end + @fposend: + move.l d6,a6 { restore a6 } + @end: + end; + If errno <> 0 then + Error2InOut; +end; + + +procedure do_seek(handle,pos : longint); +begin + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + { Clear CTRL-C signal } + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + asm + move.l a6,d6 + + move.l handle,d1 + move.l d2,-(sp) + move.l d3,-(sp) { save registers } + + move.l pos,d2 + { -1 } + move.l #$ffffffff,d3 { OFFSET_BEGINNING } + move.l _DOSBase,a6 + jsr _LVOSeek(a6) + + move.l (sp)+,d3 { restore registers } + move.l (sp)+,d2 + cmp.l #-1,d0 { is there a file access error? } + bne @noerr + jsr _LVOIoErr(a6) + move.w d0,errno + bra @seekend + @noerr: + @seekend: + move.l d6,a6 { restore a6 } + end; + If errno <> 0 then + Error2InOut; +end; + + +function do_seekend(handle:longint):longint; +begin + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + { Clear CTRL-C signal } + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + asm + { seek from end of file } + move.l a6,d6 + + move.l handle,d1 + move.l d2,-(sp) + move.l d3,-(sp) { save registers } + + clr.l d2 + move.l #1,d3 { OFFSET_END } + move.l _DOSBase,a6 + jsr _LVOSeek(a6) + + move.l (sp)+,d3 { restore registers } + move.l (sp)+,d2 + cmp.l #-1,d0 { is there a file access error? } + bne @noerr + jsr _LVOIoErr(a6) + move.w d0,errno + bra @seekend + @noerr: + move.l d6,a6 { restore a6 } + move.l d0,@Result + bra @end + @seekend: + move.l d6,a6 { restore a6 } + @end: + end; + If Errno <> 0 then + Error2InOut; +end; + + +function do_filesize(handle : longint) : longint; +var + aktfilepos : longint; +begin + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + { Clear CTRL-C signal } + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + aktfilepos:=do_filepos(handle); + { We have to do this two times, because seek returns the } + { OLD position } + do_filesize:=do_seekend(handle); + do_filesize:=do_seekend(handle); + do_seek(handle,aktfilepos); +end; + + +procedure do_truncate (handle,pos:longint); +begin + { Point to the end of the file } + { with the new size } + asm + @noerr_one: { Seek a second time } + move.l a6,d6 { Save base pointer } + + move.l handle,d1 + move.l d2,-(sp) + move.l d3,-(sp) { save registers } + + move.l pos,d2 + move.l #-1,d3 { Setup correct move type } + move.l _DOSBase,a6 { from beginning of file } + jsr _LVOSetFileSize(a6) + + move.l (sp)+,d3 { restore registers } + move.l (sp)+,d2 + cmp.l #-1,d0 { is there a file access error? } + bne @noerr + jsr _LVOIoErr(a6) + move.w d0,errno { Global variable, so no need } + @noerr: { to restore base pointer now } + move.l d6,a6 { Restore base pointer } + end; + If Errno <> 0 then + Error2InOut; +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 $100) the file will be append + when (flags and $1000) the file will be truncate/rewritten + when (flags and $10000) there is no check for close (needed for textfiles) +} +var + i,j : longint; + oflags: longint; + path : string; + buffer : array[0..255] of char; + index : integer; + s : string; +begin + path:=strpas(p); + for index:=1 to length(path) do + if path[index]='\' then path[index]:='/'; + { remove any dot characters and replace by their current } + { directory equivalent. } + if pos('../',path) = 1 then + { look for parent directory } + Begin + delete(path,1,3); + getdir(0,s); + j:=length(s); + while (s[j] <> '/') AND (s[j] <> ':') AND (j > 0 ) do + dec(j); + if j > 0 then + s:=copy(s,1,j); + path:=s+path; + end + else + if pos('./',path) = 1 then + { look for current directory } + Begin + delete(path,1,2); + getdir(0,s); + if (s[length(s)] <> '/') and (s[length(s)] <> ':') then + s:=s+'/'; + path:=s+path; + end; + move(path[1],buffer,length(path)); + buffer[length(path)]:=#0; + { close first if opened } + if ((flags and $10000)=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:=UnusedHandle; +{ convert filemode to filerec modes } + { READ/WRITE on existing file } + { RESET/APPEND } + oflags := 1005; + case (flags and 3) of + 0 : begin + filerec(f).mode:=fminput; + end; + 1 : filerec(f).mode:=fmoutput; + 2 : filerec(f).mode:=fminout; + end; + { READ/WRITE mode, create file in all cases } + { REWRITE } + if (flags and $1000)<>0 then + begin + filerec(f).mode:=fmoutput; + oflags := 1006; + end + else + { READ/WRITE mode on existing file } + { APPEND } + if (flags and $100)<>0 then + begin + filerec(f).mode:=fmoutput; + oflags := 1005; + 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; + asm + move.l a6,d6 { save a6 } + move.l d2,-(sp) + lea buffer,a0 + move.l a0,d1 + move.l oflags,d2 { MODE_READWRITE } + move.l _DOSBase,a6 + jsr _LVOOpen(a6) + tst.l d0 + bne @noopenerror { on zero an error occured } + jsr _LVOIoErr(a6) + move.w d0,errno + bra @openend + @noopenerror: + move.l (sp)+,d2 + move.l d6,a6 { restore a6 } + move.l d0,i { we need the base pointer to access this variable } + bra @end + @openend: + move.l d6,a6 { restore a6 } + move.l (sp)+,d2 + @end: + end; +(* if Errno = 0 then*) + { No error, add file handle to linked list } + { this must be checked before the call to } + { Error2InIOut since it resets Errno to 0 } +(* AddToList(FileList,i);*) + If Errno <> 0 then + Error2InOut; + + filerec(f).handle:=i; + if (flags and $100)<>0 then + do_seekend(filerec(f).handle); + +end; + +{***************************************************************************** + UnTyped File Handling +*****************************************************************************} + +{$i file.inc} + +{***************************************************************************** + Typed File Handling +*****************************************************************************} + +{$i typefile.inc} + +{***************************************************************************** + Text File Handling +*****************************************************************************} + +{$i text.inc} + +{***************************************************************************** + Directory Handling +*****************************************************************************} + +procedure mkdir(const s : string);[IOCheck]; +var + buffer : array[0..255] of char; + j: Integer; + temp : string; +begin + { We must check the Ctrl-C before IOChecking of course! } + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + { Clear CTRL-C signal } + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + If InOutRes <> 0 then exit; + temp:=s; + for j:=1 to length(temp) do + if temp[j] = '\' then temp[j] := '/'; + move(temp[1],buffer,length(temp)); + buffer[length(temp)]:=#0; + asm + move.l a6,d6 + { we must load the parameters BEFORE setting up the } + { OS call with a6 } + lea buffer,a0 + move.l a0,d1 + move.l _DosBase,a6 + jsr _LVOCreateDir(a6) + tst.l d0 + bne @noerror + jsr _LVOIoErr(a6) + move.w d0,errno + bra @end +@noerror: + { Now we must unlock the directory } + { d0 = lock returned by create dir } + move.l d0,d1 + jsr _LVOUnlock(a6) +@end: + { restore base pointer } + move.l d6,a6 + end; + If errno <> 0 then + Error2InOut; +end; + + +procedure rmdir(const s : string);[IOCheck]; +var + buffer : array[0..255] of char; + j : Integer; + temp : string; +begin + { We must check the Ctrl-C before IOChecking of course! } + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + { Clear CTRL-C signal } + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + If InOutRes <> 0 then exit; + temp:=s; + for j:=1 to length(temp) do + if temp[j] = '\' then temp[j] := '/'; + move(temp[1],buffer,length(temp)); + buffer[length(temp)]:=#0; + do_erase(buffer); +end; + + + +procedure chdir(const s : string);[IOCheck]; +var + buffer : array[0..255] of char; + alock : longint; + FIB :pFileInfoBlock; + j: integer; + temp : string; +begin + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + { Clear CTRL-C signal } + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + If InOutRes <> 0 then exit; + temp:=s; + for j:=1 to length(temp) do + if temp[j] = '\' then temp[j] := '/'; + { Return parent directory } + if s = '..' then + Begin + getdir(0,temp); + j:=length(temp); + { Look through the previous paths } + while (temp[j] <> '/') AND (temp[j] <> ':') AND (j > 0 ) do + dec(j); + if j > 0 then + temp:=copy(temp,1,j); + end; + alock := 0; + fib:=nil; + new(fib); + + move(temp[1],buffer,length(temp)); + buffer[length(temp)]:=#0; + { Changing the directory is a pretty complicated affair } + { 1) Obtain a lock on the directory } + { 2) CurrentDir the lock } + asm + lea buffer,a0 + move.l a0,d1 { pointer to buffer in d1 } + move.l d2,-(sp) { save d2 register } + move.l #-2,d2 { ACCESS_READ lock } + move.l a6,d6 { Save base pointer } + move.l _DosBase,a6 + jsr _LVOLock(a6){ Lock the directory } + move.l (sp)+,d2 { Restore d2 register } + tst.l d0 { zero = error! } + bne @noerror + jsr _LVOIoErr(a6) + move.w d0,errno + move.l d6,a6 { reset base pointer } + bra @End + @noerror: + move.l d6,a6 { reset base pointer } + move.l d0,alock { save the lock } + @End: + end; + If errno <> 0 then + Begin + Error2InOut; + exit; + end; + if (Examine(alock, fib^) = TRUE) AND (fib^.fib_DirEntryType > 0) then + Begin + alock := CurrentDir(alock); + if OrigDir = 0 then + Begin + OrigDir := alock; + alock := 0; + end; + end; + if alock <> 0 then + Unlock(alock); + if assigned(fib) then dispose(fib); +end; + + + + + Procedure GetCwd(var path: string); + var + lock: longint; + fib: PfileInfoBlock; + len : integer; + newlock : longint; + elen : integer; + Process : PProcess; + Begin + len := 0; + path := ''; + fib := nil; + { By using a pointer instead of a local variable} + { we are assured that the pointer is aligned on } + { a dword boundary. } + new(fib); + Process := FindTask(nil); + if (process^.pr_Task.tc_Node.ln_Type = NT_TASK) then + Begin + path:=''; + exit; + end; + lock := DupLock(process^.pr_CurrentDir); + if (Lock = 0) then + Begin + path:=''; + exit; + end; + + While (lock <> 0) and (Examine(lock,FIB^) = TRUE) do + Begin + elen := strlen(fib^.fib_FileName); + if (len + elen + 2 > 255) then + break; + newlock := ParentDir(lock); + if (len <> 0) then + Begin + if (newlock <> 0) then + path:='/'+path + else + path:=':'+path; + path:=strpas(fib^.fib_FileName)+path; + Inc(len); + end + else + Begin + path:=strpas(fib^.fib_Filename); + if (newlock = 0) then + path:=path+':'; + end; + + len := len + elen; + + UnLock(lock); + lock := newlock; + end; + if (lock <> 0) then + Begin + UnLock(lock); + path := ''; + end; + if assigned(fib) then dispose(fib); + end; + + +procedure getdir(drivenr : byte;var dir : string); +begin + if (Setsignal(0,0) AND SIGBREAKF_CTRL_C) <> 0 then + Begin + { Clear CTRL-C signal } + SetSignal(0,SIGBREAKF_CTRL_C); + Halt(CTRL_C); + end; + GetCwd(dir); + If errno <> 0 then + Error2InOut; +end; + + +{***************************************************************************** + SystemUnit Initialization +*****************************************************************************} + +Procedure Startup; Assembler; +asm + move.l a6,d6 { save a6 } + + move.l (4),a6 { get ExecBase pointer } + move.l a6,_ExecBase + suba.l a1,a1 + jsr _LVOFindTask(a6) + move.l d0,a0 + { Check the stack value } + + { are we running from a CLI? } + + tst.l 172(a0) { 172 = pr_CLI } + bne @fromCLI + + { we do not support Workbench yet .. } + move.l d6,a6 { restore a6 } + move.l #1,d0 + jsr HALT_ERROR + +@fromCLI: + { Open the following libraries: } + { Intuition.library } + { dos.library } + + moveq.l #0,d0 + move.l intuitionname,a1 { directly since it is a pchar } + jsr _LVOOpenLibrary(a6) + move.l d0,_IntuitionBase + beq @exitprg + + moveq.l #0,d0 + move.l utilityname,a1 { directly since it is a pchar } + jsr _LVOOpenLibrary(a6) + move.l d0,_UtilityBase + beq @exitprg + + moveq.l #0,d0 + move.l dosname,a1 { directly since it is a pchar } + jsr _LVOOpenLibrary(a6) + move.l d0,_DOSBase + beq @exitprg + + { Find standard input and output } + { for CLI } +@OpenFiles: + move.l _DOSBase,a6 + jsr _LVOInput(a6) { get standard in } + move.l d0, StdInputHandle { save standard Input handle } +{ move.l d0,d1 }{ set up for next call } +{ jsr _LVOIsInteractive(a6)}{ is it interactive? } +{ move.l #_Input,a0 }{ get file record again } +{ move.b d0,INTERACTIVE(a0) }{ set flag } +{ beq StdInNotInteractive }{ skip this if not interactive } +{ move.l BUFFER(a0),a1 }{ get buffer address } +{ add.l #1,a1 }{ make end one byte further on } +{ move.l a1,MAX(a0) }{ set buffer size } +{ move.l a1,CURRENT(a0) }{ will need a read } + bra @OpenStdOutput +@StdInNotInteractive +{ jsr _p%FillBuffer } { fill the buffer } +@OpenStdOutput + jsr _LVOOutput(a6) { get ouput file handle } + move.l d0,StdOutputHandle { get file record } + bra @startupend +{ move.l d0,d1 } { set up for call } +{ jsr _LVOIsInteractive(a6) } { is it interactive? } +{ move.l #_Output,a0 } { get file record } +{ move.b d0,INTERACTIVE(a0)} { set flag } +@exitprg: + move.l d6,a6 { restore a6 } + move.l #219,d0 + jsr HALT_ERROR +@startupend: + move.l d6,a6 { restore a6 } +end; + + + +begin + errno:= 0; + FromHalt := FALSE; +{ Initial state is on -- in case of RunErrors before the i/o handles are } +{ ok. } + Initial:=TRUE; +{ Initialize ExitProc } + ExitProc:=Nil; + Startup; +{ to test stack depth } + loweststack:=maxlongint; +{ Setup heap } + InitHeap; +{ Setup stdin, stdout and stderr } + OpenStdIO(Input,fmInput,StdInputHandle); + OpenStdIO(Output,fmOutput,StdOutputHandle); + OpenStdIO(StdOut,fmOutput,StdOutputHandle); + { The Amiga does not seem to have a StdError } + { handle, therefore make the StdError handle } + { equal to the StdOutputHandle. } + StdErrorHandle := StdOutputHandle; + OpenStdIO(StdErr,fmOutput,StdErrorHandle); +{ Now Handles and function handlers are setup } +{ correctly. } + Initial:=FALSE; +{ Reset IO Error } + InOutRes:=0; +{ Startup } + { Only AmigaOS v2.04 or greater is supported } + If KickVersion < 36 then + Begin + WriteLn('v36 or greater of Kickstart required.'); + Halt(1); + end; + argc:=GetParamCount(args); + OrigDir := 0; + FileList := nil; +end. + + +{ + $Log$ + Revision 1.1 2001-03-16 20:01:47 hajny + + system unit name change + + Revision 1.1 2000/07/13 06:30:29 michael + + Initial import + + Revision 1.15 2000/01/07 16:41:29 daniel + * copyright 2000 + + Revision 1.14 2000/01/07 16:32:22 daniel + * copyright 2000 added + + Revision 1.13 1999/09/10 15:40:32 peter + * fixed do_open flags to be > $100, becuase filemode can be upto 255 + + Revision 1.12 1999/01/18 10:05:47 pierre + + system_exit procedure added + + Revision 1.11 1998/12/28 15:50:42 peter + + stdout, which is needed when you write something in the system unit + to the screen. Like the runtime error + + Revision 1.10 1998/09/14 10:48:00 peter + * FPC_ names + * Heap manager is now system independent + + Revision 1.9 1998/08/17 12:34:22 carl + * chdir accepts .. characters + + added ctrl-c checking + + implemented sbrk + * exit code was never called if no error was found on exit! + * register was not saved in do_open + + Revision 1.8 1998/07/13 12:32:18 carl + * do_truncate works, some cleanup + + Revision 1.6 1998/07/02 12:37:52 carl + * IOCheck for chdir,rmdir and mkdir as in TP + + Revision 1.5 1998/07/01 14:30:56 carl + * forgot that includes are case sensitive + + Revision 1.4 1998/07/01 14:13:50 carl + * do_open bugfix + * correct conversion of Amiga error codes to TP error codes + * InoutRes word bugfix + * parameter counting fixed + * new stack checking implemented + + IOCheck for chdir,rmdir,getdir and rmdir + * do_filepos was wrong + + chdir correctly implemented + * getdir correctly implemented + + Revision 1.1.1.1 1998/03/25 11:18:47 root + * Restored version + + Revision 1.14 1998/03/21 04:20:09 carl + * correct ExecBase pointer (from Nils Sjoholm) + * correct OpenLibrary vector (from Nils Sjoholm) + + Revision 1.13 1998/03/14 21:34:32 carl + * forgot to save a6 in Startup routine + + Revision 1.12 1998/02/24 21:19:42 carl + *** empty log message *** + + Revision 1.11 1998/02/23 02:22:49 carl + * bugfix if linking problems + + Revision 1.9 1998/02/06 16:34:32 carl + + do_open is now standard with other platforms + + Revision 1.8 1998/02/02 15:01:45 carl + * fixed bug with opening library versions (from Nils Sjoholm) + + Revision 1.7 1998/01/31 19:35:19 carl + + added opening of utility.library + + Revision 1.6 1998/01/29 23:20:54 peter + - Removed Backslash convert + + Revision 1.5 1998/01/27 10:55:04 peter + * Amiga uses / not \, so change AllowSlash -> AllowBackSlash + + Revision 1.4 1998/01/25 21:53:20 peter + + Universal Handles support for StdIn/StdOut/StdErr + * Updated layout of sysamiga.pas + + Revision 1.3 1998/01/24 21:09:53 carl + + added missing input/output function pointers + + Revision 1.2 1998/01/24 14:08:25 carl + * RunError 217 --> RunError 219 (cannot open lib) + + Standard Handle names implemented + + Revision 1.1 1998/01/24 05:12:15 carl + + initial revision, some stuff still missing though. + (and as you might imagine ... untested :)) +} diff --git a/rtl/atari/sysatari.pas b/rtl/atari/sysatari.pas index 4a3236e9ab..4d342eaddd 100644 --- a/rtl/atari/sysatari.pas +++ b/rtl/atari/sysatari.pas @@ -1,804 +1 @@ -{ - $Id$ - This file is part of the Free Pascal run time library. - Copyright (c) 1999-2000 by Carl Eric Codere - member of the Free Pascal development team - - 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. - - **********************************************************************} -{$define ATARI} -unit sysatari; - -{--------------------------------------------------------------------} -{ LEFT TO DO: } -{--------------------------------------------------------------------} -{ o SBrk } -{ o Implement truncate } -{ o Implement paramstr(0) } -{--------------------------------------------------------------------} - - -{$I os.inc} - - interface - - { used for single computations } - const BIAS4 = $7f-1; - - {$I systemh.inc} - - {$I heaph.inc} - -const - UnusedHandle = $ffff; - StdInputHandle = 0; - StdOutputHandle = 1; - StdErrorHandle = $ffff; - - - - implementation - - {$I system.inc} - {$I lowmath.inc} - - - const - argc : longint = 0; - - - var - errno : integer; - -{$S-} - procedure Stack_Check; assembler; - { Check for local variable allocation } - { On Entry -> d0 : size of local stack we are trying to allocate } - asm - XDEF STACKCHECK - move.l sp,d1 { get value of stack pointer } - sub.l d0,d1 { sp - stack_size } - sub.l #2048,d1 - cmp.l __BREAK,d1 - bgt @st1nosweat - move.l #202,d0 - jsr HALT_ERROR - @st1nosweat: - end; - - - Procedure Error2InOut; - Begin - if (errno <= -2) and (errno >= -11) then - InOutRes:=150-errno { 150+errno } - else - Begin - case errno of - -32 : InOutRes:=1; - -33 : InOutRes:=2; - -34 : InOutRes:=3; - -35 : InOutRes:=4; - -36 : InOutRes:=5; - -37 : InOutRes:=8; - -39 : InOutRes:=8; - -40 : InOutRes:=9; - -46 : InOutRes:=15; - -67..-64 : InOutRes:=153; - -15 : InOutRes:=151; - -13 : InOutRes:=150; - else - InOutres := word(errno); - end; - end; - errno:=0; - end; - - - - procedure halt(errnum : byte); - - begin - do_exit; - flush(stderr); - asm - clr.l d0 - move.b errnum,d0 - move.w d0,-(sp) - move.w #$4c,-(sp) - trap #1 - end; - end; - - - function args : pointer; assembler; - asm - move.l __ARGS,d0 - end; - - - - - Function GetParamCount(const p: pchar): longint; - var - i: word; - count: word; - Begin - i:=0; - count:=0; - while p[count] <> #0 do - Begin - if (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) then - Begin - i:=i+1; - while (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) do - count:=count+1; - end; - if p[count] = #0 then break; - count:=count+1; - end; - GetParamCount:=longint(i); - end; - - - Function GetParam(index: word; const p : pchar): string; - { On Entry: index = string index to correct parameter } - { On exit: = correct character index into pchar array } - { Returns correct index to command line argument } - var - count: word; - localindex: word; - l: byte; - temp: string; - Begin - temp:=''; - count := 0; - { first index is one } - localindex := 1; - l:=0; - While p[count] <> #0 do - Begin - if (p[count] <> ' ') and (p[count] <> #9) then - Begin - if localindex = index then - Begin - while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) and (l < 256) do - Begin - temp:=temp+p[count]; - l:=l+1; - count:=count+1; - end; - temp[0]:=char(l); - GetParam:=temp; - exit; - end; - { Point to next argument in list } - while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) do - Begin - count:=count+1; - end; - localindex:=localindex+1; - end; - if p[count] = #0 then break; - count:=count+1; - end; - GetParam:=temp; - end; - - - function paramstr(l : longint) : string; - var - p : pchar; - s1 : string; - begin - if l = 0 then - Begin - s1 := ''; - end - else - if (l>0) and (l<=paramcount) then - begin - p:=args; - paramstr:=GetParam(word(l),p); - end - else paramstr:=''; - end; - - function paramcount : longint; - Begin - paramcount := argc; - end; - - - - - procedure randomize; - - var - hl : longint; - - begin - asm - movem.l d2/d3/a2/a3, -(sp) { save OS registers } - move.w #17,-(sp) - trap #14 { call xbios - random number } - add.l #2,sp - movem.l (sp)+,d2/d3/a2/a3 - move.l d0,hl { result in d0 } - end; - randseed:=hl; - end; - -function getheapstart:pointer;assembler; -asm - lea.l HEAP,a0 - move.l a0,d0 -end; - - -function getheapsize:longint;assembler; -asm - move.l HEAP_SIZE,d0 -end ['D0']; - - { This routine is used to grow the heap. } - { But here we do a trick, we say that the } - { heap cannot be regrown! } - function sbrk( size: longint): longint; - { on exit -1 = if fails. } - Begin - sbrk:=-1; - end; - -{$I heap.inc} - - -{**************************************************************************** - Low Level File Routines - ****************************************************************************} - -procedure AllowSlash(p:pchar); -var - i : longint; -begin -{ allow slash as backslash } - for i:=0 to strlen(p) do - if p[i]='/' then p[i]:='\'; -end; - - -procedure do_close(h : longint); -begin - asm - movem.l d2/d3/a2/a3,-(sp) - move.l h,d0 - move.w d0,-(sp) - move.w #$3e,-(sp) - trap #1 - add.l #4,sp { restore stack ... } - movem.l (sp)+,d2/d3/a2/a3 - end; -end; - - -procedure do_erase(p : pchar); -begin - AllowSlash(p); - asm - move.l d2,d6 { save d2 } - movem.l d3/a2/a3,-(sp) { save regs } - move.l p,-(sp) - move.w #$41,-(sp) - trap #1 - add.l #6,sp - move.l d6,d2 { restore d2 } - movem.l (sp)+,d3/a2/a3 - tst.w d0 - beq @doserend - move.w d0,errno - @doserend: - end; - if errno <> 0 then - Error2InOut; -end; - - -procedure do_rename(p1,p2 : pchar); -begin - AllowSlash(p1); - AllowSlash(p2); - asm - move.l d2,d6 { save d2 } - movem.l d3/a2/a3,-(sp) - move.l p1,-(sp) - move.l p2,-(sp) - clr.w -(sp) - move.w #$56,-(sp) - trap #1 - lea 12(sp),sp - move.l d6,d2 { restore d2 } - movem.l (sp)+,d3/a2/a3 - tst.w d0 - beq @dosreend - move.w d0,errno { error ... } - @dosreend: - end; - if errno <> 0 then - Error2InOut; -end; - -function do_isdevice(handle:word):boolean; -begin - if (handle=stdoutputhandle) or (handle=stdinputhandle) or - (handle=stderrorhandle) then - do_isdevice:=FALSE - else - do_isdevice:=TRUE; -end; - - -function do_write(h,addr,len : longint) : longint; -begin - asm - move.l d2,d6 { save d2 } - movem.l d3/a2/a3,-(sp) - move.l addr,-(sp) - move.l len,-(sp) - move.l h,d0 - move.w d0,-(sp) - move.w #$40,-(sp) - trap #1 - lea 12(sp),sp - move.l d6,d2 { restore d2 } - movem.l (sp)+,d3/a2/a3 - tst.l d0 - bpl @doswrend - move.w d0,errno { error ... } - @doswrend: - move.l d0,@RESULT - end; - if errno <> 0 then - Error2InOut; -end; - - -function do_read(h,addr,len : longint) : longint; -begin - asm - move.l d2,d6 { save d2 } - movem.l d3/a2/a3,-(sp) - move.l addr,-(sp) - move.l len,-(sp) - move.l h,d0 - move.w d0,-(sp) - move.w #$3f,-(sp) - trap #1 - lea 12(sp),sp - move.l d6,d2 { restore d2 } - movem.l (sp)+,d3/a2/a3 - tst.l d0 - bpl @dosrdend - move.w d0,errno { error ... } - @dosrdend: - move.l d0,@Result - end; - if errno <> 0 then - Error2InOut; -end; - - -function do_filepos(handle : longint) : longint; -begin - asm - move.l d2,d6 { save d2 } - movem.l d3/a2/a3,-(sp) - move.w #1,-(sp) { seek from current position } - move.l handle,d0 - move.w d0,-(sp) - move.l #0,-(sp) { with a seek offset of zero } - move.w #$42,-(sp) - trap #1 - lea 10(sp),sp - move.l d6,d2 { restore d2 } - movem.l (sp)+,d3/a2/a3 - move.l d0,@Result - end; -end; - - -procedure do_seek(handle,pos : longint); -begin - asm - move.l d2,d6 { save d2 } - movem.l d3/a2/a3,-(sp) - move.w #0,-(sp) { seek from start of file } - move.l handle,d0 - move.w d0,-(sp) - move.l pos,-(sp) - move.w #$42,-(sp) - trap #1 - lea 10(sp),sp - move.l d6,d2 { restore d2 } - movem.l (sp)+,d3/a2/a3 - end; -end; - - -function do_seekend(handle:longint):longint; -var - t: longint; -begin - asm - move.l d2,d6 { save d2 } - movem.l d3/a2/a3,-(sp) - move.w #2,-(sp) { seek from end of file } - move.l handle,d0 - move.w d0,-(sp) - move.l #0,-(sp) { with an offset of 0 from end } - move.w #$42,-(sp) - trap #1 - lea 10(sp),sp - move.l d6,d2 { restore d2 } - movem.l (sp)+,d3/a2/a3 - move.l d0,t - end; - do_seekend:=t; -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 - do_seek(handle,pos); - {!!!!!!!!!!!!} -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 $100) the file will be append - when (flags and $1000) the file will be truncate/rewritten - when (flags and $10000) there is no check for close (needed for textfiles) -} -var - i : word; - oflags: longint; -begin - AllowSlash(p); - { close first if opened } - if ((flags and $10000)=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:=UnusedHandle; - oflags:=$02; { read/write mode } -{ convert filemode to filerec modes } - case (flags and 3) of - 0 : begin - filerec(f).mode:=fminput; - oflags:=$00; { read mode only } - end; - 1 : filerec(f).mode:=fmoutput; - 2 : filerec(f).mode:=fminout; - end; - if (flags and $1000)<>0 then - begin - filerec(f).mode:=fmoutput; - oflags:=$04; { read/write with create } - end - else - if (flags and $100)<>0 then - begin - filerec(f).mode:=fmoutput; - oflags:=$02; { read/write } - 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; - asm - movem.l d2/d3/a2/a3,-(sp) { save used registers } - - cmp.l #4,oflags { check if rewrite mode ... } - bne @opencont2 - { rewrite mode - create new file } - move.w #0,-(sp) - move.l p,-(sp) - move.w #$3c,-(sp) - trap #1 - add.l #8,sp { restore stack of os call } - bra @end - { reset - open existing files } - @opencont2: - move.l oflags,d0 { use flag as source ... } - @opencont1: - move.w d0,-(sp) - move.l p,-(sp) - move.w #$3d,-(sp) - trap #1 - add.l #8,sp { restore stack of os call } - @end: - movem.l (sp)+,d2/d3/a2/a3 - - tst.w d0 - bpl @opennoerr { if positive return values then ok } - cmp.w #-1,d0 { if handle is -1 CON: } - beq @opennoerr - cmp.w #-2,d0 { if handle is -2 AUX: } - beq @opennoerr - cmp.w #-3,d0 { if handle is -3 PRN: } - beq @opennoerr - move.w d0,errno { otherwise normal error } - @opennoerr: - move.w d0,i { get handle as SIGNED VALUE... } - end; - if errno <> 0 then - Error2InOut; - filerec(f).handle:=i; - if (flags and $100)<>0 then - do_seekend(filerec(f).handle); -end; - -{***************************************************************************** - UnTyped File Handling -*****************************************************************************} - -{$i file.inc} - -{***************************************************************************** - Typed File Handling -*****************************************************************************} - -{$i typefile.inc} - -{***************************************************************************** - Text File Handling -*****************************************************************************} - -{$i text.inc} - -{***************************************************************************** - Directory Handling -*****************************************************************************} - -procedure DosDir(func:byte;const s:string); -var - buffer : array[0..255] of char; - c : word; -begin - move(s[1],buffer,length(s)); - buffer[length(s)]:=#0; - AllowSlash(pchar(@buffer)); - c:=word(func); - asm - move.l d2,d6 { save d2 } - movem.l d3/a2/a3,-(sp) - pea buffer - move.w c,-(sp) - trap #1 - add.l #6,sp - move.l d6,d2 { restore d2 } - movem.l (sp)+,d3/a2/a3 - tst.w d0 - beq @dosdirend - move.w d0,errno - @dosdirend: - end; - if errno <> 0 then - Error2InOut; -end; - - -procedure mkdir(const s : string);[IOCheck]; -begin - If InOutRes <> 0 then exit; - DosDir($39,s); -end; - - -procedure rmdir(const s : string);[IOCheck]; -begin - If InOutRes <> 0 then exit; - DosDir($3a,s); -end; - - -procedure chdir(const s : string);[IOCheck]; -begin - If InOutRes <> 0 then exit; - DosDir($3b,s); -end; - - -procedure getdir(drivenr : byte;var dir : string); -var - temp : array[0..255] of char; - i : longint; - j: byte; - drv: word; -begin - drv:=word(drivenr); - asm - move.l d2,d6 { save d2 } - movem.l d3/a2/a3,-(sp) - - { Get dir from drivenr : 0=default, 1=A etc... } - move.w drv,-(sp) - - { put (previously saved) offset in si } -{ move.l temp,-(sp)} - pea temp - - { call attos function 47H : Get dir } - move.w #$47,-(sp) - - { make the call } - trap #1 - add.l #8,sp - - move.l d6,d2 { restore d2 } - movem.l (sp)+,d3/a2/a3 - end; - { conversion to pascal string } - i:=0; - while (temp[i]<>#0) do - begin - if temp[i]='/' then - temp[i]:='\'; - dir[i+3]:=temp[i]; - inc(i); - end; - dir[2]:=':'; - dir[3]:='\'; - dir[0]:=char(i+2); -{ upcase the string (FPC Pascal function) } - dir:=upcase(dir); - if drivenr<>0 then { Drive was supplied. We know it } - dir[1]:=chr(65+drivenr-1) - else - begin - asm - move.l d2,d6 { save d2 } - movem.l d3/a2/a3,-(sp) - move.w #$19,-(sp) - trap #1 - add.l #2,sp - move.w d0,drv - move.l d6,d2 { restore d2 } - movem.l (sp)+,d3/a2/a3 - end; - dir[1]:=chr(byte(drv)+ord('A')); - end; -end; - - -{***************************************************************************** - System Dependent Exit code -*****************************************************************************} -Procedure system_exit; -begin -end; - -{***************************************************************************** - SystemUnit Initialization -*****************************************************************************} - - -begin -{ Initialize ExitProc } - ExitProc:=Nil; -{ to test stack depth } - loweststack:=maxlongint; -{ Setup heap } - InitHeap; -{ Setup stdin, stdout and stderr } - OpenStdIO(Input,fmInput,StdInputHandle); - OpenStdIO(Output,fmOutput,StdOutputHandle); - OpenStdIO(StdOut,fmOutput,StdOutputHandle); - OpenStdIO(StdErr,fmOutput,StdErrorHandle); -{ Reset IO Error } - InOutRes:=0; - errno := 0; -{ Setup command line arguments } - argc:=GetParamCount(args); -end. - -{ - $Log$ - Revision 1.2 2000-07-14 10:30:58 michael - + - - Revision 1.1 2000/07/13 06:30:30 michael - + Initial import - - Revision 1.14 2000/01/07 16:41:29 daniel - * copyright 2000 - - Revision 1.13 2000/01/07 16:32:23 daniel - * copyright 2000 added - - Revision 1.12 1999/09/10 15:40:33 peter - * fixed do_open flags to be > $100, becuase filemode can be upto 255 - - Revision 1.11 1999/01/18 10:05:48 pierre - + system_exit procedure added - - Revision 1.10 1998/12/28 15:50:43 peter - + stdout, which is needed when you write something in the system unit - to the screen. Like the runtime error - - Revision 1.9 1998/09/14 10:48:02 peter - * FPC_ names - * Heap manager is now system independent - - Revision 1.8 1998/07/15 12:11:59 carl - * hmmm... can't remember! :(... - - Revision 1.5 1998/07/13 12:34:13 carl - + Error2InoutRes implemented - * do_read was doing a wrong os call! - * do_open was not pushing the right values - * DosDir was pushing the wrong params on the stack - * do_close would never works, was pushing a longint instead of word - - Revision 1.4 1998/07/02 12:39:27 carl - * IOCheck for mkdir,chdir and rmdir, just like in TP - - Revision 1.3 1998/07/01 14:40:20 carl - + new stack checking implemented - + IOCheck for chdir , getdir , mkdir and rmdir - - Revision 1.1.1.1 1998/03/25 11:18:47 root - * Restored version - - Revision 1.8 1998/02/23 02:27:39 carl - * make it link correctly - - Revision 1.7 1998/02/06 16:33:02 carl - * oops... commited wrong file - + do_open is now standard with other platforms - - Revision 1.5 1998/01/31 19:32:51 carl - - removed incorrect $define - - Revision 1.4 1998/01/27 10:55:45 peter - * Word Handles from -1 -> $ffff - - Revision 1.3 1998/01/25 22:44:14 peter - * Using uniform layout - -} +{$i system.pp} diff --git a/rtl/atari/system.pas b/rtl/atari/system.pas new file mode 100644 index 0000000000..ccdd6050a2 --- /dev/null +++ b/rtl/atari/system.pas @@ -0,0 +1,815 @@ +{ + $Id$ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Carl Eric Codere + member of the Free Pascal development team + + 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. + + **********************************************************************} +{$define ATARI} +unit {$ifdef VER1_0}sysatari{$else}{$ifdef VER0_99}sysatari{$ELSE}system{$endif}{$ENDIF}; + +{--------------------------------------------------------------------} +{ LEFT TO DO: } +{--------------------------------------------------------------------} +{ o SBrk } +{ o Implement truncate } +{ o Implement paramstr(0) } +{--------------------------------------------------------------------} + + +{$I os.inc} + + interface + + { used for single computations } + const BIAS4 = $7f-1; + + {$I systemh.inc} + + {$I heaph.inc} + +const + UnusedHandle = $ffff; + StdInputHandle = 0; + StdOutputHandle = 1; + StdErrorHandle = $ffff; + + + + implementation + + {$I system.inc} + {$I lowmath.inc} + + + const + argc : longint = 0; + + + var + errno : integer; + +{$S-} + procedure Stack_Check; assembler; + { Check for local variable allocation } + { On Entry -> d0 : size of local stack we are trying to allocate } + asm + XDEF STACKCHECK + move.l sp,d1 { get value of stack pointer } + sub.l d0,d1 { sp - stack_size } + sub.l #2048,d1 + cmp.l __BREAK,d1 + bgt @st1nosweat + move.l #202,d0 + jsr HALT_ERROR + @st1nosweat: + end; + + + Procedure Error2InOut; + Begin + if (errno <= -2) and (errno >= -11) then + InOutRes:=150-errno { 150+errno } + else + Begin + case errno of + -32 : InOutRes:=1; + -33 : InOutRes:=2; + -34 : InOutRes:=3; + -35 : InOutRes:=4; + -36 : InOutRes:=5; + -37 : InOutRes:=8; + -39 : InOutRes:=8; + -40 : InOutRes:=9; + -46 : InOutRes:=15; + -67..-64 : InOutRes:=153; + -15 : InOutRes:=151; + -13 : InOutRes:=150; + else + InOutres := word(errno); + end; + end; + errno:=0; + end; + + + + procedure halt(errnum : byte); + + begin + do_exit; + flush(stderr); + asm + clr.l d0 + move.b errnum,d0 + move.w d0,-(sp) + move.w #$4c,-(sp) + trap #1 + end; + end; + + + function args : pointer; assembler; + asm + move.l __ARGS,d0 + end; + + + + + Function GetParamCount(const p: pchar): longint; + var + i: word; + count: word; + Begin + i:=0; + count:=0; + while p[count] <> #0 do + Begin + if (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) then + Begin + i:=i+1; + while (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) do + count:=count+1; + end; + if p[count] = #0 then break; + count:=count+1; + end; + GetParamCount:=longint(i); + end; + + + Function GetParam(index: word; const p : pchar): string; + { On Entry: index = string index to correct parameter } + { On exit: = correct character index into pchar array } + { Returns correct index to command line argument } + var + count: word; + localindex: word; + l: byte; + temp: string; + Begin + temp:=''; + count := 0; + { first index is one } + localindex := 1; + l:=0; + While p[count] <> #0 do + Begin + if (p[count] <> ' ') and (p[count] <> #9) then + Begin + if localindex = index then + Begin + while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) and (l < 256) do + Begin + temp:=temp+p[count]; + l:=l+1; + count:=count+1; + end; + temp[0]:=char(l); + GetParam:=temp; + exit; + end; + { Point to next argument in list } + while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) do + Begin + count:=count+1; + end; + localindex:=localindex+1; + end; + if p[count] = #0 then break; + count:=count+1; + end; + GetParam:=temp; + end; + + + function paramstr(l : longint) : string; + var + p : pchar; + s1 : string; + begin + if l = 0 then + Begin + s1 := ''; + end + else + if (l>0) and (l<=paramcount) then + begin + p:=args; + paramstr:=GetParam(word(l),p); + end + else paramstr:=''; + end; + + function paramcount : longint; + Begin + paramcount := argc; + end; + + + + + procedure randomize; + + var + hl : longint; + + begin + asm + movem.l d2/d3/a2/a3, -(sp) { save OS registers } + move.w #17,-(sp) + trap #14 { call xbios - random number } + add.l #2,sp + movem.l (sp)+,d2/d3/a2/a3 + move.l d0,hl { result in d0 } + end; + randseed:=hl; + end; + +function getheapstart:pointer;assembler; +asm + lea.l HEAP,a0 + move.l a0,d0 +end; + + +function getheapsize:longint;assembler; +asm + move.l HEAP_SIZE,d0 +end ['D0']; + + { This routine is used to grow the heap. } + { But here we do a trick, we say that the } + { heap cannot be regrown! } + function sbrk( size: longint): longint; + { on exit -1 = if fails. } + Begin + sbrk:=-1; + end; + +{$I heap.inc} + + +{**************************************************************************** + Low Level File Routines + ****************************************************************************} + +procedure AllowSlash(p:pchar); +var + i : longint; +begin +{ allow slash as backslash } + for i:=0 to strlen(p) do + if p[i]='/' then p[i]:='\'; +end; + + +procedure do_close(h : longint); +begin + asm + movem.l d2/d3/a2/a3,-(sp) + move.l h,d0 + move.w d0,-(sp) + move.w #$3e,-(sp) + trap #1 + add.l #4,sp { restore stack ... } + movem.l (sp)+,d2/d3/a2/a3 + end; +end; + + +procedure do_erase(p : pchar); +begin + AllowSlash(p); + asm + move.l d2,d6 { save d2 } + movem.l d3/a2/a3,-(sp) { save regs } + move.l p,-(sp) + move.w #$41,-(sp) + trap #1 + add.l #6,sp + move.l d6,d2 { restore d2 } + movem.l (sp)+,d3/a2/a3 + tst.w d0 + beq @doserend + move.w d0,errno + @doserend: + end; + if errno <> 0 then + Error2InOut; +end; + + +procedure do_rename(p1,p2 : pchar); +begin + AllowSlash(p1); + AllowSlash(p2); + asm + move.l d2,d6 { save d2 } + movem.l d3/a2/a3,-(sp) + move.l p1,-(sp) + move.l p2,-(sp) + clr.w -(sp) + move.w #$56,-(sp) + trap #1 + lea 12(sp),sp + move.l d6,d2 { restore d2 } + movem.l (sp)+,d3/a2/a3 + tst.w d0 + beq @dosreend + move.w d0,errno { error ... } + @dosreend: + end; + if errno <> 0 then + Error2InOut; +end; + +function do_isdevice(handle:word):boolean; +begin + if (handle=stdoutputhandle) or (handle=stdinputhandle) or + (handle=stderrorhandle) then + do_isdevice:=FALSE + else + do_isdevice:=TRUE; +end; + + +function do_write(h,addr,len : longint) : longint; +begin + asm + move.l d2,d6 { save d2 } + movem.l d3/a2/a3,-(sp) + move.l addr,-(sp) + move.l len,-(sp) + move.l h,d0 + move.w d0,-(sp) + move.w #$40,-(sp) + trap #1 + lea 12(sp),sp + move.l d6,d2 { restore d2 } + movem.l (sp)+,d3/a2/a3 + tst.l d0 + bpl @doswrend + move.w d0,errno { error ... } + @doswrend: + move.l d0,@RESULT + end; + if errno <> 0 then + Error2InOut; +end; + + +function do_read(h,addr,len : longint) : longint; +begin + asm + move.l d2,d6 { save d2 } + movem.l d3/a2/a3,-(sp) + move.l addr,-(sp) + move.l len,-(sp) + move.l h,d0 + move.w d0,-(sp) + move.w #$3f,-(sp) + trap #1 + lea 12(sp),sp + move.l d6,d2 { restore d2 } + movem.l (sp)+,d3/a2/a3 + tst.l d0 + bpl @dosrdend + move.w d0,errno { error ... } + @dosrdend: + move.l d0,@Result + end; + if errno <> 0 then + Error2InOut; +end; + + +function do_filepos(handle : longint) : longint; +begin + asm + move.l d2,d6 { save d2 } + movem.l d3/a2/a3,-(sp) + move.w #1,-(sp) { seek from current position } + move.l handle,d0 + move.w d0,-(sp) + move.l #0,-(sp) { with a seek offset of zero } + move.w #$42,-(sp) + trap #1 + lea 10(sp),sp + move.l d6,d2 { restore d2 } + movem.l (sp)+,d3/a2/a3 + move.l d0,@Result + end; +end; + + +procedure do_seek(handle,pos : longint); +begin + asm + move.l d2,d6 { save d2 } + movem.l d3/a2/a3,-(sp) + move.w #0,-(sp) { seek from start of file } + move.l handle,d0 + move.w d0,-(sp) + move.l pos,-(sp) + move.w #$42,-(sp) + trap #1 + lea 10(sp),sp + move.l d6,d2 { restore d2 } + movem.l (sp)+,d3/a2/a3 + end; +end; + + +function do_seekend(handle:longint):longint; +var + t: longint; +begin + asm + move.l d2,d6 { save d2 } + movem.l d3/a2/a3,-(sp) + move.w #2,-(sp) { seek from end of file } + move.l handle,d0 + move.w d0,-(sp) + move.l #0,-(sp) { with an offset of 0 from end } + move.w #$42,-(sp) + trap #1 + lea 10(sp),sp + move.l d6,d2 { restore d2 } + movem.l (sp)+,d3/a2/a3 + move.l d0,t + end; + do_seekend:=t; +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 + do_seek(handle,pos); + {!!!!!!!!!!!!} +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 $100) the file will be append + when (flags and $1000) the file will be truncate/rewritten + when (flags and $10000) there is no check for close (needed for textfiles) +} +var + i : word; + oflags: longint; +begin + AllowSlash(p); + { close first if opened } + if ((flags and $10000)=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:=UnusedHandle; + oflags:=$02; { read/write mode } +{ convert filemode to filerec modes } + case (flags and 3) of + 0 : begin + filerec(f).mode:=fminput; + oflags:=$00; { read mode only } + end; + 1 : filerec(f).mode:=fmoutput; + 2 : filerec(f).mode:=fminout; + end; + if (flags and $1000)<>0 then + begin + filerec(f).mode:=fmoutput; + oflags:=$04; { read/write with create } + end + else + if (flags and $100)<>0 then + begin + filerec(f).mode:=fmoutput; + oflags:=$02; { read/write } + 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; + asm + movem.l d2/d3/a2/a3,-(sp) { save used registers } + + cmp.l #4,oflags { check if rewrite mode ... } + bne @opencont2 + { rewrite mode - create new file } + move.w #0,-(sp) + move.l p,-(sp) + move.w #$3c,-(sp) + trap #1 + add.l #8,sp { restore stack of os call } + bra @end + { reset - open existing files } + @opencont2: + move.l oflags,d0 { use flag as source ... } + @opencont1: + move.w d0,-(sp) + move.l p,-(sp) + move.w #$3d,-(sp) + trap #1 + add.l #8,sp { restore stack of os call } + @end: + movem.l (sp)+,d2/d3/a2/a3 + + tst.w d0 + bpl @opennoerr { if positive return values then ok } + cmp.w #-1,d0 { if handle is -1 CON: } + beq @opennoerr + cmp.w #-2,d0 { if handle is -2 AUX: } + beq @opennoerr + cmp.w #-3,d0 { if handle is -3 PRN: } + beq @opennoerr + move.w d0,errno { otherwise normal error } + @opennoerr: + move.w d0,i { get handle as SIGNED VALUE... } + end; + if errno <> 0 then + Error2InOut; + filerec(f).handle:=i; + if (flags and $100)<>0 then + do_seekend(filerec(f).handle); +end; + +{***************************************************************************** + UnTyped File Handling +*****************************************************************************} + +{$i file.inc} + +{***************************************************************************** + Typed File Handling +*****************************************************************************} + +{$i typefile.inc} + +{***************************************************************************** + Text File Handling +*****************************************************************************} + +{$i text.inc} + +{***************************************************************************** + Directory Handling +*****************************************************************************} + +procedure DosDir(func:byte;const s:string); +var + buffer : array[0..255] of char; + c : word; +begin + move(s[1],buffer,length(s)); + buffer[length(s)]:=#0; + AllowSlash(pchar(@buffer)); + c:=word(func); + asm + move.l d2,d6 { save d2 } + movem.l d3/a2/a3,-(sp) + pea buffer + move.w c,-(sp) + trap #1 + add.l #6,sp + move.l d6,d2 { restore d2 } + movem.l (sp)+,d3/a2/a3 + tst.w d0 + beq @dosdirend + move.w d0,errno + @dosdirend: + end; + if errno <> 0 then + Error2InOut; +end; + + +procedure mkdir(const s : string);[IOCheck]; +begin + If InOutRes <> 0 then exit; + DosDir($39,s); +end; + + +procedure rmdir(const s : string);[IOCheck]; +begin + If InOutRes <> 0 then exit; + DosDir($3a,s); +end; + + +procedure chdir(const s : string);[IOCheck]; +begin + If InOutRes <> 0 then exit; + DosDir($3b,s); +end; + + +function GetDirIO (DriveNr: byte; var Dir: ShortString): word; + [public, alias: 'FPC_GETDIRIO']; +var + temp : array[0..255] of char; + i : longint; + j: byte; + drv: word; +begin + GetDirIO := 0; + drv:=word(drivenr); + asm + move.l d2,d6 { save d2 } + movem.l d3/a2/a3,-(sp) + + { Get dir from drivenr : 0=default, 1=A etc... } + move.w drv,-(sp) + + { put (previously saved) offset in si } +{ move.l temp,-(sp)} + pea temp + + { call attos function 47H : Get dir } + move.w #$47,-(sp) + + { make the call } + trap #1 + add.l #8,sp + + move.l d6,d2 { restore d2 } + movem.l (sp)+,d3/a2/a3 + end; + { conversion to pascal string } + i:=0; + while (temp[i]<>#0) do + begin + if temp[i]='/' then + temp[i]:='\'; + dir[i+3]:=temp[i]; + inc(i); + end; + dir[2]:=':'; + dir[3]:='\'; + dir[0]:=char(i+2); +{ upcase the string (FPC Pascal function) } + dir:=upcase(dir); + if drivenr<>0 then { Drive was supplied. We know it } + dir[1]:=chr(65+drivenr-1) + else + begin + asm + move.l d2,d6 { save d2 } + movem.l d3/a2/a3,-(sp) + move.w #$19,-(sp) + trap #1 + add.l #2,sp + move.w d0,drv + move.l d6,d2 { restore d2 } + movem.l (sp)+,d3/a2/a3 + end; + dir[1]:=chr(byte(drv)+ord('A')); + end; +end; + +procedure GetDir (DriveNr: byte; var Dir: ShortString); + +begin + InOutRes := GetDirIO (DriveNr, Dir); +end; + + +{***************************************************************************** + System Dependent Exit code +*****************************************************************************} +Procedure system_exit; +begin +end; + +{***************************************************************************** + SystemUnit Initialization +*****************************************************************************} + + +begin +{ Initialize ExitProc } + ExitProc:=Nil; +{ to test stack depth } + loweststack:=maxlongint; +{ Setup heap } + InitHeap; +{ Setup stdin, stdout and stderr } + OpenStdIO(Input,fmInput,StdInputHandle); + OpenStdIO(Output,fmOutput,StdOutputHandle); + OpenStdIO(StdOut,fmOutput,StdOutputHandle); + OpenStdIO(StdErr,fmOutput,StdErrorHandle); +{ Reset IO Error } + InOutRes:=0; + errno := 0; +{ Setup command line arguments } + argc:=GetParamCount(args); +end. + +{ + $Log$ + Revision 1.1 2001-03-16 20:01:47 hajny + + system unit name change + + Revision 1.2 2000/07/14 10:30:58 michael + + + + Revision 1.1 2000/07/13 06:30:30 michael + + Initial import + + Revision 1.14 2000/01/07 16:41:29 daniel + * copyright 2000 + + Revision 1.13 2000/01/07 16:32:23 daniel + * copyright 2000 added + + Revision 1.12 1999/09/10 15:40:33 peter + * fixed do_open flags to be > $100, becuase filemode can be upto 255 + + Revision 1.11 1999/01/18 10:05:48 pierre + + system_exit procedure added + + Revision 1.10 1998/12/28 15:50:43 peter + + stdout, which is needed when you write something in the system unit + to the screen. Like the runtime error + + Revision 1.9 1998/09/14 10:48:02 peter + * FPC_ names + * Heap manager is now system independent + + Revision 1.8 1998/07/15 12:11:59 carl + * hmmm... can't remember! :(... + + Revision 1.5 1998/07/13 12:34:13 carl + + Error2InoutRes implemented + * do_read was doing a wrong os call! + * do_open was not pushing the right values + * DosDir was pushing the wrong params on the stack + * do_close would never works, was pushing a longint instead of word + + Revision 1.4 1998/07/02 12:39:27 carl + * IOCheck for mkdir,chdir and rmdir, just like in TP + + Revision 1.3 1998/07/01 14:40:20 carl + + new stack checking implemented + + IOCheck for chdir , getdir , mkdir and rmdir + + Revision 1.1.1.1 1998/03/25 11:18:47 root + * Restored version + + Revision 1.8 1998/02/23 02:27:39 carl + * make it link correctly + + Revision 1.7 1998/02/06 16:33:02 carl + * oops... commited wrong file + + do_open is now standard with other platforms + + Revision 1.5 1998/01/31 19:32:51 carl + - removed incorrect $define + + Revision 1.4 1998/01/27 10:55:45 peter + * Word Handles from -1 -> $ffff + + Revision 1.3 1998/01/25 22:44:14 peter + * Using uniform layout + +} diff --git a/rtl/palmos/system.pp b/rtl/palmos/system.pp new file mode 100644 index 0000000000..188bcdf5f4 --- /dev/null +++ b/rtl/palmos/system.pp @@ -0,0 +1,103 @@ +{ + $Id$ + + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Florian Klaempfl + member of the Free Pascal development team + + 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. + + **********************************************************************} + +{$define PALMOS} +{$ASMMODE DIRECT} +unit system; + +{$I os.inc} + + Interface + + Type + { type and constant declartions doesn't hurt } + LongInt = $80000000..$7fffffff; + Integer = -32768..32767; + ShortInt = -128..127; + Byte = 0..255; + Word = 0..65535; + + { !!!! + DWord = Cardinal; + LongWord = Cardinal; + } + + { The Cardinal data type isn't currently implemented for the m68k } + DWord = LongInt; + LongWord = LongInt; + + { Zero - terminated strings } + PChar = ^Char; + PPChar = ^PChar; + + { procedure type } + TProcedure = Procedure; + + const + { max. values for longint and int } + MaxLongint = High(LongInt); + MaxInt = High(Integer); + + { Must be determined at startup for both } + Test68000 : byte = 0; + Test68881 : byte = 0; + + { Palm specific data types } + type + Ptr = ^Char; + + var + ExitCode : DWord; + { this variables are passed to PilotMain by the PalmOS } + cmd : Word; + cmdPBP : Ptr; + launchFlags : Word; + + implementation + + { mimic the C start code } + function PilotMain(_cmd : Word;_cmdPBP : Ptr;_launchFlags : Word) : DWord;cdecl;public; + + begin + cmd:=_cmd; + cmdPBP:=_cmdPBP; + launchFlags:=_launchFlags; + asm + bsr PASCALMAIN + end; + PilotMain:=ExitCode; + end; + +{***************************************************************************** + System Dependent Exit code +*****************************************************************************} +Procedure system_exit; +begin +end; + +begin + ExitCode:=0; +end. + +{ + $Log$ + Revision 1.1 2001-03-16 20:01:48 hajny + + system unit name change + + Revision 1.2 2000/07/13 11:33:54 michael + + removed logs + +}