sysamiga.pas 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1993,97 by the Free Pascal development team.
  5. Some parts taken from
  6. Marcel Timmermans - Modula 2 Compiler
  7. Nils Sjoholm - Amiga porter
  8. See the file COPYING.FPC, included in this distribution,
  9. for details about the copyright.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. **********************************************************************}
  14. unit sysamiga;
  15. { Things left to do : }
  16. { - Fix randomize }
  17. { - Fix Truncate!! }
  18. {$I os.inc}
  19. { AmigaOS uses character #10 as eoln only }
  20. {$DEFINE SHORT_LINEBREAK}
  21. interface
  22. { used for single computations }
  23. const BIAS4 = $7f-1;
  24. {$I systemh.inc}
  25. {$I heaph.inc}
  26. const
  27. UnusedHandle : longint = -1;
  28. StdInputHandle : longint = 0;
  29. StdOutputHandle : longint = 0;
  30. StdErrorHandle : longint = 0;
  31. argc : longint = 0;
  32. _ExecBase:longint = $4;
  33. _WorkbenchMsg : longint = 0;
  34. intuitionname : pchar = 'intuition.library';
  35. dosname : pchar = 'dos.library';
  36. utilityname : pchar = 'utility.library';
  37. _IntuitionBase : pointer = nil; { intuition library pointer }
  38. _DosBase : pointer = nil; { DOS library pointer }
  39. _UtilityBase : pointer = nil; { utiity library pointer }
  40. var
  41. OrigDir : Longint;
  42. implementation
  43. {$I exec.inc}
  44. TYPE
  45. TDateStamp = packed record
  46. ds_Days : Longint; { Number of days since Jan. 1, 1978 }
  47. ds_Minute : Longint; { Number of minutes past midnight }
  48. ds_Tick : Longint; { Number of ticks past minute }
  49. end;
  50. PDateStamp = ^TDateStamp;
  51. PFileInfoBlock = ^TfileInfoBlock;
  52. TFileInfoBlock = packed record
  53. fib_DiskKey : Longint;
  54. fib_DirEntryType : Longint;
  55. { Type of Directory. If < 0, then a plain file.
  56. If > 0 a directory }
  57. fib_FileName : Array [0..107] of Char;
  58. { Null terminated. Max 30 chars used for now }
  59. fib_Protection : Longint;
  60. { bit mask of protection, rwxd are 3-0. }
  61. fib_EntryType : Longint;
  62. fib_Size : Longint; { Number of bytes in file }
  63. fib_NumBlocks : Longint; { Number of blocks in file }
  64. fib_Date : TDateStamp; { Date file last changed }
  65. fib_Comment : Array [0..79] of Char;
  66. { Null terminated comment associated with file }
  67. fib_Reserved : Array [0..35] of Char;
  68. end;
  69. TProcess = packed record
  70. pr_Task : TTask;
  71. pr_MsgPort : TMsgPort; { This is BPTR address from DOS functions }
  72. {126} pr_Pad : Word; { Remaining variables on 4 byte boundaries }
  73. {128} pr_SegList : Pointer; { Array of seg lists used by this process }
  74. {132} pr_StackSize : Longint; { Size of process stack in bytes }
  75. {136} pr_GlobVec : Pointer; { Global vector for this process (BCPL) }
  76. {140} pr_TaskNum : Longint; { CLI task number of zero if not a CLI }
  77. {144} pr_StackBase : BPTR; { Ptr to high memory end of process stack }
  78. {148} pr_Result2 : Longint; { Value of secondary result from last call }
  79. {152} pr_CurrentDir : BPTR; { Lock associated with current directory }
  80. {156} pr_CIS : BPTR; { Current CLI Input Stream }
  81. {160} pr_COS : BPTR; { Current CLI Output Stream }
  82. {164} pr_ConsoleTask : Pointer; { Console handler process for current window}
  83. {168} pr_FileSystemTask : Pointer; { File handler process for current drive }
  84. {172} pr_CLI : BPTR; { pointer to ConsoleLineInterpreter }
  85. pr_ReturnAddr : Pointer; { pointer to previous stack frame }
  86. pr_PktWait : Pointer; { Function to be called when awaiting msg }
  87. pr_WindowPtr : Pointer; { Window for error printing }
  88. { following definitions are new with 2.0 }
  89. pr_HomeDir : BPTR; { Home directory of executing program }
  90. pr_Flags : Longint; { flags telling dos about process }
  91. pr_ExitCode : Pointer; { code to call on exit of program OR NULL }
  92. pr_ExitData : Longint; { Passed as an argument to pr_ExitCode. }
  93. pr_Arguments : PChar; { Arguments passed to the process at start }
  94. pr_LocalVars : TMinList; { Local environment variables }
  95. pr_ShellPrivate : Longint; { for the use of the current shell }
  96. pr_CES : BPTR; { Error stream - IF NULL, use pr_COS }
  97. end;
  98. PProcess = ^TProcess;
  99. Const
  100. _LVOFindTask = -294;
  101. _LVOWaitPort = -384;
  102. _LVOGetMsg = -372;
  103. _LVOOpenLibrary = -552;
  104. _LVOCloseLibrary = -414;
  105. _LVOClose = -36;
  106. _LVOOpen = -30;
  107. _LVOIoErr = -132;
  108. _LVOSeek = -66;
  109. _LVODeleteFile = -72;
  110. _LVORename = -78;
  111. _LVOWrite = -48;
  112. _LVORead = -42;
  113. _LVOCreateDir = -120;
  114. _LVOSetCurrentDirName = -558;
  115. _LVOGetCurrentDirName = -564;
  116. _LVOInput = -54;
  117. _LVOOutput = -60;
  118. _LVOUnLock = -90;
  119. _LVOLock = -84;
  120. _LVOCurrentDir = -126;
  121. _LVONameFromLock = -402;
  122. _LVONameFromFH = -408;
  123. _LVOGetProgramName = -576;
  124. _LVOGetProgramDir = -600;
  125. _LVODupLock = -96;
  126. _LVOExamine = -102;
  127. _LVOParentDir = -210;
  128. { Errors from IoErr(), etc. }
  129. ERROR_NO_FREE_STORE = 103;
  130. ERROR_TASK_TABLE_FULL = 105;
  131. ERROR_BAD_TEMPLATE = 114;
  132. ERROR_BAD_NUMBER = 115;
  133. ERROR_REQUIRED_ARG_MISSING = 116;
  134. ERROR_KEY_NEEDS_ARG = 117;
  135. ERROR_TOO_MANY_ARGS = 118;
  136. ERROR_UNMATCHED_QUOTES = 119;
  137. ERROR_LINE_TOO_LONG = 120;
  138. ERROR_FILE_NOT_OBJECT = 121;
  139. ERROR_INVALID_RESIDENT_LIBRARY = 122;
  140. ERROR_NO_DEFAULT_DIR = 201;
  141. ERROR_OBJECT_IN_USE = 202;
  142. ERROR_OBJECT_EXISTS = 203;
  143. ERROR_DIR_NOT_FOUND = 204;
  144. ERROR_OBJECT_NOT_FOUND = 205;
  145. ERROR_BAD_STREAM_NAME = 206;
  146. ERROR_OBJECT_TOO_LARGE = 207;
  147. ERROR_ACTION_NOT_KNOWN = 209;
  148. ERROR_INVALID_COMPONENT_NAME = 210;
  149. ERROR_INVALID_LOCK = 211;
  150. ERROR_OBJECT_WRONG_TYPE = 212;
  151. ERROR_DISK_NOT_VALIDATED = 213;
  152. ERROR_DISK_WRITE_PROTECTED = 214;
  153. ERROR_RENAME_ACROSS_DEVICES = 215;
  154. ERROR_DIRECTORY_NOT_EMPTY = 216;
  155. ERROR_TOO_MANY_LEVELS = 217;
  156. ERROR_DEVICE_NOT_MOUNTED = 218;
  157. ERROR_SEEK_ERROR = 219;
  158. ERROR_COMMENT_TOO_BIG = 220;
  159. ERROR_DISK_FULL = 221;
  160. ERROR_DELETE_PROTECTED = 222;
  161. ERROR_WRITE_PROTECTED = 223;
  162. ERROR_READ_PROTECTED = 224;
  163. ERROR_NOT_A_DOS_DISK = 225;
  164. ERROR_NO_DISK = 226;
  165. ERROR_NO_MORE_ENTRIES = 232;
  166. { added for 1.4 }
  167. ERROR_IS_SOFT_LINK = 233;
  168. ERROR_OBJECT_LINKED = 234;
  169. ERROR_BAD_HUNK = 235;
  170. ERROR_NOT_IMPLEMENTED = 236;
  171. ERROR_RECORD_NOT_LOCKED = 240;
  172. ERROR_LOCK_COLLISION = 241;
  173. ERROR_LOCK_TIMEOUT = 242;
  174. ERROR_UNLOCK_ERROR = 243;
  175. var
  176. Initial: boolean;
  177. errno : word;
  178. {$I system.inc}
  179. {$I lowmath.inc}
  180. { ************************ AMIGAOS STUB ROUTINES ************************* }
  181. { UNLOCK the BPTR pointed to in L }
  182. Procedure Unlock(alock: longint);
  183. Begin
  184. asm
  185. move.l alock,d1
  186. move.l a6,d6 { save base pointer }
  187. move.l _DosBase,a6
  188. jsr _LVOUnlock(a6)
  189. move.l d6,a6 { restore base pointer }
  190. end;
  191. end;
  192. { Change to the directory pointed to in the lock }
  193. Function CurrentDir(alock : longint) : longint;
  194. Begin
  195. asm
  196. move.l alock,d1
  197. move.l a6,d6 { save base pointer }
  198. move.l _DosBase,a6
  199. jsr _LVOCurrentDir(a6)
  200. move.l d6,a6 { restore base pointer }
  201. move.l d0,@Result
  202. end;
  203. end;
  204. { Duplicate a lock }
  205. Function DupLock(alock: longint): Longint;
  206. Begin
  207. asm
  208. move.l alock,d1
  209. move.l a6,d6 { save base pointer }
  210. move.l _DosBase,a6
  211. jsr _LVODupLock(a6)
  212. move.l d6,a6 { restore base pointer }
  213. move.l d0,@Result
  214. end;
  215. end;
  216. { Returns a lock on the directory was loaded from }
  217. Function GetProgramLock: longint;
  218. Begin
  219. asm
  220. move.l a6,d6 { save base pointer }
  221. move.l _DosBase,a6
  222. jsr _LVOGetProgramDir(a6)
  223. move.l d6,a6 { restore base pointer }
  224. move.l d0,@Result
  225. end;
  226. end;
  227. Function Examine(alock :longint; var fib: TFileInfoBlock) : Boolean;
  228. Begin
  229. asm
  230. move.l d2,-(sp)
  231. move.l fib,d2 { pointer to FIB }
  232. move.l alock,d1
  233. move.l a6,d6 { save base pointer }
  234. move.l _DosBase,a6
  235. jsr _LVOExamine(a6)
  236. move.l d6,a6 { restore base pointer }
  237. tst.l d0
  238. bne @success
  239. bra @end
  240. @success:
  241. move.b #1,d0
  242. @end:
  243. move.b d0,@Result
  244. move.l (sp)+,d2
  245. end;
  246. end;
  247. { Returns the parent directory of a lock }
  248. Function ParentDir(alock : longint): longint;
  249. Begin
  250. asm
  251. move.l alock,d1
  252. move.l a6,d6 { save base pointer }
  253. move.l _DosBase,a6
  254. jsr _LVOParentDir(a6)
  255. move.l d6,a6 { restore base pointer }
  256. move.l d0,@Result
  257. end;
  258. end;
  259. Function FindTask(p : PChar): PProcess;
  260. Begin
  261. asm
  262. move.l a6,d6 { Save base pointer }
  263. move.l p,d0
  264. move.l d0,a1
  265. move.l _ExecBase,a6
  266. jsr _LVOFindTask(a6)
  267. move.l d6,a6 { Restore base pointer }
  268. move.l d0,@Result
  269. end;
  270. end;
  271. {$S-}
  272. Procedure stack_check; assembler;
  273. { Check for local variable allocation }
  274. { On Entry -> d0 : size of local stack we are trying to allocate }
  275. asm
  276. XDEF STACKCHECK
  277. move.l sp,d1 { get value of stack pointer }
  278. { We must add some security, because Writing the RunError strings }
  279. { requires a LOT of stack space (at least 1030 bytes!) }
  280. add.l #2048,d0
  281. sub.l d0,d1 { sp - stack_size }
  282. move.l _ExecBase,a0
  283. move.l 276(A0),A0 { ExecBase.thisTask }
  284. { if allocated stack_pointer - splower <= 0 then stack_ovf }
  285. cmp.l 58(A0),D1 { Task.SpLower }
  286. bgt @Ok
  287. move.l #202,d0
  288. jsr HALT_ERROR { stack overflow }
  289. @Ok:
  290. end;
  291. { Converts an AMIGAOS error code to a TP compatible error code }
  292. Procedure Error2InOut;
  293. Begin
  294. case errno of
  295. ERROR_BAD_NUMBER,
  296. ERROR_ACTION_NOT_KNOWN,
  297. ERROR_NOT_IMPLEMENTED : InOutRes := 1;
  298. ERROR_OBJECT_NOT_FOUND : InOutRes := 2;
  299. ERROR_DIR_NOT_FOUND : InOutRes := 3;
  300. ERROR_DISK_WRITE_PROTECTED : InOutRes := 150;
  301. ERROR_OBJECT_WRONG_TYPE : InOutRes := 151;
  302. ERROR_OBJECT_EXISTS,
  303. ERROR_DELETE_PROTECTED,
  304. ERROR_WRITE_PROTECTED,
  305. ERROR_READ_PROTECTED,
  306. ERROR_OBJECT_IN_USE,
  307. ERROR_DIRECTORY_NOT_EMPTY : InOutRes := 5;
  308. ERROR_NO_MORE_ENTRIES : InOutRes := 18;
  309. ERROR_RENAME_ACROSS_DEVICES : InOutRes := 17;
  310. ERROR_DISK_FULL : InOutRes := 101;
  311. ERROR_INVALID_RESIDENT_LIBRARY : InoutRes := 153;
  312. ERROR_BAD_HUNK : InOutRes := 153;
  313. ERROR_NOT_A_DOS_DISK : InOutRes := 157;
  314. ERROR_NO_DISK,
  315. ERROR_DISK_NOT_VALIDATED,
  316. ERROR_DEVICE_NOT_MOUNTED : InOutRes := 152;
  317. ERROR_SEEK_ERROR : InOutRes := 156;
  318. ERROR_LOCK_COLLISION,
  319. ERROR_LOCK_TIMEOUT,
  320. ERROR_UNLOCK_ERROR,
  321. ERROR_INVALID_LOCK,
  322. ERROR_INVALID_COMPONENT_NAME,
  323. ERROR_BAD_STREAM_NAME,
  324. ERROR_FILE_NOT_OBJECT : InOutRes := 6;
  325. else
  326. InOutres := errno;
  327. end;
  328. errno:=0;
  329. end;
  330. procedure CloseLibrary(lib : pointer);
  331. { Close the library pointed to in lib }
  332. Begin
  333. asm
  334. MOVE.L A6,-(A7)
  335. MOVE.L lib,a1
  336. MOVE.L _ExecBase,A6
  337. JSR _LVOCloseLibrary(A6)
  338. MOVE.L (A7)+,A6
  339. end;
  340. end;
  341. Function KickVersion: word; assembler;
  342. asm
  343. move.l _ExecBase, a0 { Get Exec Base }
  344. move.w 20(a0), d0 { Return version - version at this offset }
  345. end;
  346. procedure halt(errnum : byte);
  347. begin
  348. { WE can only FLUSH the stdio }
  349. { if the handles have correctly }
  350. { been set. }
  351. { No exit procedures exist }
  352. { if in initial state }
  353. If NOT Initial then
  354. Begin
  355. do_exit;
  356. flush(stderr);
  357. end;
  358. if (OrigDir <> 0) then
  359. Begin
  360. Unlock(CurrentDir(OrigDir));
  361. OrigDir := 0;
  362. end;
  363. { close the libraries }
  364. If _UtilityBase <> nil then
  365. Begin
  366. CloseLibrary(_UtilityBase);
  367. end;
  368. If _DosBase <> nil then
  369. Begin
  370. CloseLibrary(_DosBase);
  371. end;
  372. If _IntuitionBase <> nil then
  373. Begin
  374. CloseLibrary(_IntuitionBase);
  375. end;
  376. asm
  377. clr.l d0
  378. move.b errnum,d0
  379. move.l STKPTR,sp
  380. rts
  381. end;
  382. end;
  383. { ************************ PARAMCOUNT/PARAMSTR *************************** }
  384. function paramcount : longint;
  385. Begin
  386. paramcount := argc;
  387. end;
  388. function args : pointer; assembler;
  389. asm
  390. move.l __ARGS,d0
  391. end;
  392. Function GetParamCount(const p: pchar): longint;
  393. var
  394. i: word;
  395. count: word;
  396. Begin
  397. i:=0;
  398. count:=0;
  399. while p[count] <> #0 do
  400. Begin
  401. if (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) then
  402. Begin
  403. i:=i+1;
  404. while (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) do
  405. count:=count+1;
  406. end;
  407. if p[count] = #0 then break;
  408. count:=count+1;
  409. end;
  410. GetParamCount:=longint(i);
  411. end;
  412. Function GetParam(index: word; const p : pchar): string;
  413. { On Entry: index = string index to correct parameter }
  414. { On exit: = correct character index into pchar array }
  415. { Returns correct index to command line argument }
  416. var
  417. count: word;
  418. localindex: word;
  419. l: byte;
  420. temp: string;
  421. Begin
  422. temp:='';
  423. count := 0;
  424. { first index is one }
  425. localindex := 1;
  426. l:=0;
  427. While p[count] <> #0 do
  428. Begin
  429. if (p[count] <> ' ') and (p[count] <> #9) then
  430. Begin
  431. if localindex = index then
  432. Begin
  433. while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) and (l < 256) do
  434. Begin
  435. temp:=temp+p[count];
  436. l:=l+1;
  437. count:=count+1;
  438. end;
  439. temp[0]:=char(l);
  440. GetParam:=temp;
  441. exit;
  442. end;
  443. { Point to next argument in list }
  444. while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) do
  445. Begin
  446. count:=count+1;
  447. end;
  448. localindex:=localindex+1;
  449. end;
  450. if p[count] = #0 then break;
  451. count:=count+1;
  452. end;
  453. GetParam:=temp;
  454. end;
  455. Function GetProgramDir : String;
  456. var
  457. s1: string;
  458. alock: longint;
  459. counter : byte;
  460. Begin
  461. FillChar(@s1,255,#0);
  462. { GetLock of program directory }
  463. asm
  464. move.l a6,d6 { save a6 }
  465. move.l _DOSBase,a6
  466. jsr _LVOGetProgramDir(a6)
  467. move.l d6,a6 { restore a6 }
  468. move.l d0,alock { save the lock }
  469. end;
  470. if alock <> 0 then
  471. Begin
  472. { Get the name from the lock! }
  473. asm
  474. movem.l d2/d3,-(sp) { save used registers }
  475. move.l alock,d1
  476. lea s1,a0 { Get pointer to string! }
  477. move.l a0,d2
  478. add.l #1,d2 { let us point past the length byte! }
  479. move.l #255,d3
  480. move.l a6,d6 { save a6 }
  481. move.l _DOSBase,a6
  482. jsr _LVONameFromLock(a6)
  483. move.l d6,a6 { restore a6 }
  484. movem.l (sp)+,d2/d3
  485. end;
  486. { no check out the length of the string }
  487. counter := 1;
  488. while s1[counter] <> #0 do
  489. Inc(counter);
  490. s1[0] := char(counter-1);
  491. GetProgramDir := s1;
  492. end
  493. else
  494. GetProgramDir := '';
  495. end;
  496. Function GetProgramName : string;
  497. { Returns ONLY the program name }
  498. { There seems to be a bug in v39 since if the program is not }
  499. { called from its home directory the program name will also }
  500. { contain the path! }
  501. var
  502. s1: string;
  503. counter : byte;
  504. Begin
  505. FillChar(@s1,255,#0);
  506. asm
  507. move.l d2,-(sp) { Save used register }
  508. lea s1,a0 { Get pointer to string! }
  509. move.l a0,d1
  510. add.l #1,d1 { point to correct offset }
  511. move.l #255,d2
  512. move.l a6,d6 { save a6 }
  513. move.l _DOSBase,a6
  514. jsr _LVOGetProgramName(a6)
  515. move.l d6,a6 { restore a6 }
  516. move.l (sp)+,d2 { restore saved register }
  517. end;
  518. { no check out and assign the length of the string }
  519. counter := 1;
  520. while s1[counter] <> #0 do
  521. Inc(counter);
  522. s1[0] := char(counter-1);
  523. { now remove any component path which should not be there }
  524. for counter:=length(s1) downto 1 do
  525. if (s1[counter] = '/') or (s1[counter] = ':') then break;
  526. { readjust counterv to point to character }
  527. if counter <> 1 then
  528. Inc(counter);
  529. GetProgramName:=copy(s1,counter,length(s1));
  530. end;
  531. function paramstr(l : longint) : string;
  532. var
  533. p : pchar;
  534. s1 : string;
  535. begin
  536. { -> Call AmigaOS GetProgramName }
  537. if l = 0 then
  538. Begin
  539. s1 := GetProgramDir;
  540. { If this is a root, then simply don't add '/' }
  541. if s1[length(s1)] = ':' then
  542. paramstr:=s1+GetProgramName
  543. else
  544. { add backslash directory }
  545. paramstr:=s1+'/'+GetProgramName
  546. end
  547. else
  548. if (l>0) and (l<=paramcount) then
  549. begin
  550. p:=args;
  551. paramstr:=GetParam(word(l),p);
  552. end
  553. else paramstr:='';
  554. end;
  555. { ************************************************************************ }
  556. procedure randomize;
  557. var
  558. hl : longint;
  559. begin
  560. asm
  561. { !!!!!!! }
  562. end;
  563. randseed:=hl;
  564. end;
  565. { This routine is used to grow the heap. }
  566. { But here we do a trick, we say that the }
  567. { heap cannot be regrown! }
  568. function sbrk( size: longint): longint;
  569. { on exit -1 = if fails. }
  570. Begin
  571. sbrk:=-1;
  572. end;
  573. {$I heap.inc}
  574. {****************************************************************************
  575. Low Level File Routines
  576. ****************************************************************************}
  577. procedure do_close(h : longint);
  578. begin
  579. asm
  580. move.l h,d1
  581. move.l a6,d6 { save a6 }
  582. move.l _DOSBase,a6
  583. jsr _LVOClose(a6)
  584. move.l d6,a6 { restore a6 }
  585. end;
  586. end;
  587. procedure do_erase(p : pchar);
  588. begin
  589. asm
  590. move.l a6,d6 { save a6 }
  591. move.l p,d1
  592. move.l _DOSBase,a6
  593. jsr _LVODeleteFile(a6)
  594. tst.l d0 { zero = failure }
  595. bne @noerror
  596. jsr _LVOIoErr(a6)
  597. move.w d0,errno
  598. @noerror:
  599. move.l d6,a6 { restore a6 }
  600. end;
  601. if errno <> 0 then
  602. Error2InOut;
  603. end;
  604. procedure do_rename(p1,p2 : pchar);
  605. begin
  606. asm
  607. move.l a6,d6 { save a6 }
  608. move.l d2,-(sp) { save d2 }
  609. move.l p1,d1
  610. move.l p2,d2
  611. move.l _DOSBase,a6
  612. jsr _LVORename(a6)
  613. move.l (sp)+,d2 { restore d2 }
  614. tst.l d0
  615. bne @dosreend { if zero = error }
  616. jsr _LVOIoErr(a6)
  617. move.w d0,errno
  618. @dosreend:
  619. move.l d6,a6 { restore a6 }
  620. end;
  621. if errno <> 0 then
  622. Error2InOut;
  623. end;
  624. function do_write(h,addr,len : longint) : longint;
  625. begin
  626. if len <= 0 then
  627. Begin
  628. do_write:=0;
  629. exit;
  630. end;
  631. asm
  632. move.l a6,d6
  633. movem.l d2/d3,-(sp)
  634. move.l h,d1 { we must of course set up the }
  635. move.l addr,d2 { parameters BEFORE getting }
  636. move.l len,d3 { _DOSBase }
  637. move.l _DOSBase,a6
  638. jsr _LVOWrite(a6)
  639. movem.l (sp)+,d2/d3
  640. cmp.l #-1,d0
  641. bne @doswrend { if -1 = error }
  642. jsr _LVOIoErr(a6)
  643. move.w d0,errno
  644. bra @doswrend2
  645. @doswrend:
  646. { we must restore the base pointer before setting the result }
  647. move.l d6,a6
  648. move.l d0,@RESULT
  649. bra @end
  650. @doswrend2:
  651. move.l d6,a6
  652. @end:
  653. end;
  654. If errno <> 0 then
  655. Error2InOut;
  656. end;
  657. function do_read(h,addr,len : longint) : longint;
  658. begin
  659. if len <= 0 then
  660. Begin
  661. do_read:=0;
  662. exit;
  663. end;
  664. asm
  665. move.l a6,d6
  666. movem.l d2/d3,-(sp)
  667. move.l h,d1 { we must set up aparamters BEFORE }
  668. move.l addr,d2 { setting up a6 for the OS call }
  669. move.l len,d3
  670. move.l _DOSBase,a6
  671. jsr _LVORead(a6)
  672. movem.l (sp)+,d2/d3
  673. cmp.l #-1,d0
  674. bne @doswrend { if -1 = error }
  675. jsr _LVOIoErr(a6)
  676. move.w d0,errno
  677. bra @doswrend2
  678. @doswrend:
  679. { to store a result for the function }
  680. { we must of course first get back the}
  681. { base pointer! }
  682. move.l d6,a6
  683. move.l d0,@RESULT
  684. bra @end
  685. @doswrend2:
  686. move.l d6,a6
  687. @end:
  688. end;
  689. If errno <> 0 then
  690. Error2InOut;
  691. end;
  692. function do_filepos(handle : longint) : longint;
  693. begin
  694. asm
  695. move.l a6,d6
  696. move.l handle,d1
  697. move.l d2,-(sp)
  698. move.l d3,-(sp) { save registers }
  699. clr.l d2 { offset 0 }
  700. move.l #0,d3 { OFFSET_CURRENT }
  701. move.l _DOSBase,a6
  702. jsr _LVOSeek(a6)
  703. move.l (sp)+,d3 { restore registers }
  704. move.l (sp)+,d2
  705. cmp.l #-1,d0 { is there a file access error? }
  706. bne @noerr
  707. jsr _LVOIoErr(a6)
  708. move.w d0,errno
  709. bra @fposend
  710. @noerr:
  711. move.l d6,a6 { restore a6 }
  712. move.l d0,@Result
  713. bra @end
  714. @fposend:
  715. move.l d6,a6 { restore a6 }
  716. @end:
  717. end;
  718. If errno <> 0 then
  719. Error2InOut;
  720. end;
  721. procedure do_seek(handle,pos : longint);
  722. begin
  723. asm
  724. move.l a6,d6
  725. move.l handle,d1
  726. move.l d2,-(sp)
  727. move.l d3,-(sp) { save registers }
  728. move.l pos,d2
  729. { -1 }
  730. move.l #$ffffffff,d3 { OFFSET_BEGINNING }
  731. move.l _DOSBase,a6
  732. jsr _LVOSeek(a6)
  733. move.l (sp)+,d3 { restore registers }
  734. move.l (sp)+,d2
  735. cmp.l #-1,d0 { is there a file access error? }
  736. bne @noerr
  737. jsr _LVOIoErr(a6)
  738. move.w d0,errno
  739. bra @seekend
  740. @noerr:
  741. @seekend:
  742. move.l d6,a6 { restore a6 }
  743. end;
  744. If errno <> 0 then
  745. Error2InOut;
  746. end;
  747. function do_seekend(handle:longint):longint;
  748. begin
  749. asm
  750. { seek from end of file }
  751. move.l a6,d6
  752. move.l handle,d1
  753. move.l d2,-(sp)
  754. move.l d3,-(sp) { save registers }
  755. clr.l d2
  756. move.l #1,d3 { OFFSET_END }
  757. move.l _DOSBase,a6
  758. jsr _LVOSeek(a6)
  759. move.l (sp)+,d3 { restore registers }
  760. move.l (sp)+,d2
  761. cmp.l #-1,d0 { is there a file access error? }
  762. bne @noerr
  763. jsr _LVOIoErr(a6)
  764. move.w d0,errno
  765. bra @seekend
  766. @noerr:
  767. move.l d6,a6 { restore a6 }
  768. move.l d0,@Result
  769. bra @end
  770. @seekend:
  771. move.l d6,a6 { restore a6 }
  772. @end:
  773. end;
  774. If Errno <> 0 then
  775. Error2InOut;
  776. end;
  777. function do_filesize(handle : longint) : longint;
  778. var
  779. aktfilepos : longint;
  780. begin
  781. aktfilepos:=do_filepos(handle);
  782. { We have to do this two times, because seek returns the }
  783. { OLD position }
  784. do_filesize:=do_seekend(handle);
  785. do_filesize:=do_seekend(handle);
  786. do_seek(handle,aktfilepos);
  787. end;
  788. procedure do_truncate (handle,pos:longint);
  789. begin
  790. {!!!!!!!!!!!!}
  791. end;
  792. procedure do_open(var f;p:pchar;flags:longint);
  793. {
  794. filerec and textrec have both handle and mode as the first items so
  795. they could use the same routine for opening/creating.
  796. when (flags and $10) the file will be append
  797. when (flags and $100) the file will be truncate/rewritten
  798. when (flags and $1000) there is no check for close (needed for textfiles)
  799. }
  800. var
  801. i : longint;
  802. oflags: longint;
  803. begin
  804. { close first if opened }
  805. if ((flags and $1000)=0) then
  806. begin
  807. case filerec(f).mode of
  808. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  809. fmclosed : ;
  810. else
  811. begin
  812. inoutres:=102; {not assigned}
  813. exit;
  814. end;
  815. end;
  816. end;
  817. { reset file handle }
  818. filerec(f).handle:=UnusedHandle;
  819. { convert filemode to filerec modes }
  820. { READ/WRITE on existing file }
  821. { RESET/APPEND }
  822. oflags := 1005;
  823. case (flags and 3) of
  824. 0 : begin
  825. filerec(f).mode:=fminput;
  826. end;
  827. 1 : filerec(f).mode:=fmoutput;
  828. 2 : filerec(f).mode:=fminout;
  829. end;
  830. { READ/WRITE mode, create file in all cases }
  831. { REWRITE }
  832. if (flags and $100)<>0 then
  833. begin
  834. filerec(f).mode:=fmoutput;
  835. oflags := 1006;
  836. end
  837. else
  838. { READ/WRITE mode on existing file }
  839. { APPEND }
  840. if (flags and $10)<>0 then
  841. begin
  842. filerec(f).mode:=fmoutput;
  843. oflags := 1005;
  844. end;
  845. { empty name is special }
  846. if p[0]=#0 then
  847. begin
  848. case filerec(f).mode of
  849. fminput : filerec(f).handle:=StdInputHandle;
  850. fmappend,
  851. fmoutput : begin
  852. filerec(f).handle:=StdOutputHandle;
  853. filerec(f).mode:=fmoutput; {fool fmappend}
  854. end;
  855. end;
  856. exit;
  857. end;
  858. asm
  859. move.l a6,d6 { save a6 }
  860. move.l p,d1
  861. move.l oflags,d2 { MODE_READWRITE }
  862. move.l _DOSBase,a6
  863. jsr _LVOOpen(a6)
  864. tst.l d0
  865. bne @noopenerror { on zero an error occured }
  866. jsr _LVOIoErr(a6)
  867. move.w d0,errno
  868. bra @openend
  869. @noopenerror:
  870. move.l d6,a6 { restore a6 }
  871. move.l d0,i { we need the base pointer to access this variable }
  872. bra @end
  873. @openend:
  874. move.l d6,a6 { restore a6 }
  875. @end:
  876. end;
  877. If Errno <> 0 then
  878. Error2InOut;
  879. filerec(f).handle:=i;
  880. if (flags and $10)<>0 then
  881. do_seekend(filerec(f).handle);
  882. end;
  883. {*****************************************************************************
  884. UnTyped File Handling
  885. *****************************************************************************}
  886. {$i file.inc}
  887. {*****************************************************************************
  888. Typed File Handling
  889. *****************************************************************************}
  890. {$i typefile.inc}
  891. {*****************************************************************************
  892. Text File Handling
  893. *****************************************************************************}
  894. {$i text.inc}
  895. {*****************************************************************************
  896. Directory Handling
  897. *****************************************************************************}
  898. procedure mkdir(const s : string);[IOCheck];
  899. var
  900. buffer : array[0..255] of char;
  901. begin
  902. move(s[1],buffer,length(s));
  903. buffer[length(s)]:=#0;
  904. asm
  905. move.l a6,d6
  906. { we must load the parameters BEFORE setting up the }
  907. { OS call with a6 }
  908. lea buffer,a0
  909. move.l a0,d1
  910. move.l _DosBase,a6
  911. jsr _LVOCreateDir(a6)
  912. tst.l d0
  913. bne @noerror
  914. jsr _LVOIoErr(a6)
  915. move.w d0,errno
  916. bra @end
  917. @noerror:
  918. { Now we must unlock the directory }
  919. { d0 = lock returned by create dir }
  920. move.l d0,d1
  921. jsr _LVOUnlock(a6)
  922. @end:
  923. { restore base pointer }
  924. move.l d6,a6
  925. end;
  926. If errno <> 0 then
  927. Error2InOut;
  928. end;
  929. procedure rmdir(const s : string);[IOCheck];
  930. var
  931. buffer : array[0..255] of char;
  932. begin
  933. move(s[1],buffer,length(s));
  934. buffer[length(s)]:=#0;
  935. do_erase(buffer);
  936. end;
  937. procedure chdir(const s : string);[IOCheck];
  938. var
  939. buffer : array[0..255] of char;
  940. alock : longint;
  941. FIB :pFileInfoBlock;
  942. begin
  943. alock := 0;
  944. fib:=nil;
  945. new(fib);
  946. move(s[1],buffer,length(s));
  947. buffer[length(s)]:=#0;
  948. { Changing the directory is a pretty complicated affair }
  949. { 1) Obtain a lock on the directory }
  950. { 2) CurrentDir the lock }
  951. asm
  952. lea buffer,a0
  953. move.l a0,d1 { pointer to buffer in d1 }
  954. move.l d2,-(sp) { save d2 register }
  955. move.l #-2,d2 { ACCESS_READ lock }
  956. move.l a6,d6 { Save base pointer }
  957. move.l _DosBase,a6
  958. jsr _LVOLock(a6){ Lock the directory }
  959. move.l (sp)+,d2 { Restore d2 register }
  960. tst.l d0 { zero = error! }
  961. bne @noerror
  962. jsr _LVOIoErr(a6)
  963. move.w d0,errno
  964. move.l d6,a6 { reset base pointer }
  965. bra @End
  966. @noerror:
  967. move.l d6,a6 { reset base pointer }
  968. move.l d0,alock { save the lock }
  969. @End:
  970. end;
  971. If errno <> 0 then
  972. Begin
  973. Error2InOut;
  974. exit;
  975. end;
  976. if (Examine(alock, fib^) = TRUE) AND (fib^.fib_DirEntryType > 0) then
  977. Begin
  978. alock := CurrentDir(alock);
  979. if OrigDir = 0 then
  980. Begin
  981. OrigDir := alock;
  982. alock := 0;
  983. end;
  984. end;
  985. if alock <> 0 then
  986. Unlock(alock);
  987. if assigned(fib) then dispose(fib);
  988. end;
  989. Procedure GetCwd(var path: string);
  990. var
  991. lock: longint;
  992. fib: PfileInfoBlock;
  993. len : integer;
  994. newlock : longint;
  995. elen : integer;
  996. Process : PProcess;
  997. Begin
  998. len := 0;
  999. path := '';
  1000. fib := nil;
  1001. { By using a pointer instead of a local variable}
  1002. { we are assured that the pointer is aligned on }
  1003. { a dword boundary. }
  1004. new(fib);
  1005. Process := FindTask(nil);
  1006. if (process^.pr_Task.tc_Node.ln_Type = NT_TASK) then
  1007. Begin
  1008. path:='';
  1009. exit;
  1010. end;
  1011. lock := DupLock(process^.pr_CurrentDir);
  1012. if (Lock = 0) then
  1013. Begin
  1014. path:='';
  1015. exit;
  1016. end;
  1017. While (lock <> 0) and (Examine(lock,FIB^) = TRUE) do
  1018. Begin
  1019. elen := strlen(fib^.fib_FileName);
  1020. if (len + elen + 2 > 255) then
  1021. break;
  1022. newlock := ParentDir(lock);
  1023. if (len <> 0) then
  1024. Begin
  1025. if (newlock <> 0) then
  1026. path:='/'+path
  1027. else
  1028. path:=':'+path;
  1029. path:=strpas(fib^.fib_FileName)+path;
  1030. Inc(len);
  1031. end
  1032. else
  1033. Begin
  1034. path:=strpas(fib^.fib_Filename);
  1035. if (newlock = 0) then
  1036. path:=path+':';
  1037. end;
  1038. len := len + elen;
  1039. UnLock(lock);
  1040. lock := newlock;
  1041. end;
  1042. if (lock <> 0) then
  1043. Begin
  1044. UnLock(lock);
  1045. path := '';
  1046. end;
  1047. if assigned(fib) then dispose(fib);
  1048. end;
  1049. procedure getdir(drivenr : byte;var dir : string);[IOCheck];
  1050. begin
  1051. GetCwd(dir);
  1052. If errno <> 0 then
  1053. Error2InOut;
  1054. end;
  1055. {*****************************************************************************
  1056. SystemUnit Initialization
  1057. *****************************************************************************}
  1058. Procedure Startup; Assembler;
  1059. asm
  1060. move.l a6,d6 { save a6 }
  1061. move.l (4),a6 { get ExecBase pointer }
  1062. move.l a6,_ExecBase
  1063. suba.l a1,a1
  1064. jsr _LVOFindTask(a6)
  1065. move.l d0,a0
  1066. { Check the stack value }
  1067. { are we running from a CLI? }
  1068. tst.l 172(a0) { 172 = pr_CLI }
  1069. bne @fromCLI
  1070. { we do not support Workbench yet .. }
  1071. move.l d6,a6 { restore a6 }
  1072. move.l #1,d0
  1073. jsr HALT_ERROR
  1074. @fromCLI:
  1075. { Open the following libraries: }
  1076. { Intuition.library }
  1077. { dos.library }
  1078. moveq.l #0,d0
  1079. move.l intuitionname,a1 { directly since it is a pchar }
  1080. jsr _LVOOpenLibrary(a6)
  1081. move.l d0,_IntuitionBase
  1082. beq @exitprg
  1083. moveq.l #0,d0
  1084. move.l utilityname,a1 { directly since it is a pchar }
  1085. jsr _LVOOpenLibrary(a6)
  1086. move.l d0,_UtilityBase
  1087. beq @exitprg
  1088. moveq.l #0,d0
  1089. move.l dosname,a1 { directly since it is a pchar }
  1090. jsr _LVOOpenLibrary(a6)
  1091. move.l d0,_DOSBase
  1092. beq @exitprg
  1093. { Find standard input and output }
  1094. { for CLI }
  1095. @OpenFiles:
  1096. move.l _DOSBase,a6
  1097. jsr _LVOInput(a6) { get standard in }
  1098. move.l d0, StdInputHandle { save standard Input handle }
  1099. { move.l d0,d1 }{ set up for next call }
  1100. { jsr _LVOIsInteractive(a6)}{ is it interactive? }
  1101. { move.l #_Input,a0 }{ get file record again }
  1102. { move.b d0,INTERACTIVE(a0) }{ set flag }
  1103. { beq StdInNotInteractive }{ skip this if not interactive }
  1104. { move.l BUFFER(a0),a1 }{ get buffer address }
  1105. { add.l #1,a1 }{ make end one byte further on }
  1106. { move.l a1,MAX(a0) }{ set buffer size }
  1107. { move.l a1,CURRENT(a0) }{ will need a read }
  1108. bra @OpenStdOutput
  1109. @StdInNotInteractive
  1110. { jsr _p%FillBuffer } { fill the buffer }
  1111. @OpenStdOutput
  1112. jsr _LVOOutput(a6) { get ouput file handle }
  1113. move.l d0,StdOutputHandle { get file record }
  1114. bra @startupend
  1115. { move.l d0,d1 } { set up for call }
  1116. { jsr _LVOIsInteractive(a6) } { is it interactive? }
  1117. { move.l #_Output,a0 } { get file record }
  1118. { move.b d0,INTERACTIVE(a0)} { set flag }
  1119. @exitprg:
  1120. move.l d6,a6 { restore a6 }
  1121. move.l #219,d0
  1122. jsr HALT_ERROR
  1123. @startupend:
  1124. move.l d6,a6 { restore a6 }
  1125. end;
  1126. procedure OpenStdIO(var f:text;mode:word;hdl:longint);
  1127. begin
  1128. Assign(f,'');
  1129. TextRec(f).Handle:=hdl;
  1130. TextRec(f).Mode:=mode;
  1131. TextRec(f).InOutFunc:=@FileInOutFunc;
  1132. TextRec(f).FlushFunc:=@FileInOutFunc;
  1133. TextRec(f).Closefunc:=@fileclosefunc;
  1134. end;
  1135. begin
  1136. errno:= 0;
  1137. { Initial state is on -- in case of RunErrors before the i/o handles are }
  1138. { ok. }
  1139. Initial:=TRUE;
  1140. { Initialize ExitProc }
  1141. ExitProc:=Nil;
  1142. Startup;
  1143. { to test stack depth }
  1144. loweststack:=maxlongint;
  1145. { Setup heap }
  1146. InitHeap;
  1147. { Setup stdin, stdout and stderr }
  1148. OpenStdIO(Input,fmInput,StdInputHandle);
  1149. OpenStdIO(Output,fmOutput,StdOutputHandle);
  1150. { The Amiga does not seem to have a StdError }
  1151. { handle, therefore make the StdError handle }
  1152. { equal to the StdOutputHandle. }
  1153. StdErrorHandle := StdOutputHandle;
  1154. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  1155. { Now Handles and function handlers are setup }
  1156. { correctly. }
  1157. Initial:=FALSE;
  1158. { Reset IO Error }
  1159. InOutRes:=0;
  1160. { Startup }
  1161. { Only AmigaOS v2.04 or greater is supported }
  1162. If KickVersion < 36 then
  1163. Begin
  1164. WriteLn('v36 or greater of Kickstart required.');
  1165. Halt(1);
  1166. end;
  1167. argc:=GetParamCount(args);
  1168. OrigDir := 0;
  1169. end.
  1170. {
  1171. $Log$
  1172. Revision 1.5 1998-07-01 14:30:56 carl
  1173. * forgot that includes are case sensitive
  1174. Revision 1.4 1998/07/01 14:13:50 carl
  1175. * do_open bugfix
  1176. * correct conversion of Amiga error codes to TP error codes
  1177. * InoutRes word bugfix
  1178. * parameter counting fixed
  1179. * new stack checking implemented
  1180. + IOCheck for chdir,rmdir,getdir and rmdir
  1181. * do_filepos was wrong
  1182. + chdir correctly implemented
  1183. * getdir correctly implemented
  1184. Revision 1.1.1.1 1998/03/25 11:18:47 root
  1185. * Restored version
  1186. Revision 1.14 1998/03/21 04:20:09 carl
  1187. * correct ExecBase pointer (from Nils Sjoholm)
  1188. * correct OpenLibrary vector (from Nils Sjoholm)
  1189. Revision 1.13 1998/03/14 21:34:32 carl
  1190. * forgot to save a6 in Startup routine
  1191. Revision 1.12 1998/02/24 21:19:42 carl
  1192. *** empty log message ***
  1193. Revision 1.11 1998/02/23 02:22:49 carl
  1194. * bugfix if linking problems
  1195. Revision 1.9 1998/02/06 16:34:32 carl
  1196. + do_open is now standard with other platforms
  1197. Revision 1.8 1998/02/02 15:01:45 carl
  1198. * fixed bug with opening library versions (from Nils Sjoholm)
  1199. Revision 1.7 1998/01/31 19:35:19 carl
  1200. + added opening of utility.library
  1201. Revision 1.6 1998/01/29 23:20:54 peter
  1202. - Removed Backslash convert
  1203. Revision 1.5 1998/01/27 10:55:04 peter
  1204. * Amiga uses / not \, so change AllowSlash -> AllowBackSlash
  1205. Revision 1.4 1998/01/25 21:53:20 peter
  1206. + Universal Handles support for StdIn/StdOut/StdErr
  1207. * Updated layout of sysamiga.pas
  1208. Revision 1.3 1998/01/24 21:09:53 carl
  1209. + added missing input/output function pointers
  1210. Revision 1.2 1998/01/24 14:08:25 carl
  1211. * RunError 217 --> RunError 219 (cannot open lib)
  1212. + Standard Handle names implemented
  1213. Revision 1.1 1998/01/24 05:12:15 carl
  1214. + initial revision, some stuff still missing though.
  1215. (and as you might imagine ... untested :))
  1216. }