system.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Carl Eric Codere
  4. member of the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$define ATARI}
  12. unit system;
  13. {--------------------------------------------------------------------}
  14. { LEFT TO DO: }
  15. {--------------------------------------------------------------------}
  16. { o SBrk }
  17. { o Implement truncate }
  18. { o Implement paramstr(0) }
  19. {--------------------------------------------------------------------}
  20. {$I os.inc}
  21. interface
  22. {$I systemh.inc}
  23. type
  24. THandle = longint;
  25. {$I heaph.inc}
  26. {Platform specific information}
  27. const
  28. LineEnding = #10;
  29. LFNSupport = true;
  30. CtrlZMarksEOF: boolean = false; (* #26 not considered as end of file *)
  31. DirectorySeparator = '/';
  32. DriveSeparator = ':';
  33. ExtensionSeparator = '.';
  34. PathSeparator = ';';
  35. AllowDirectorySeparators : set of char = ['\','/'];
  36. AllowDriveSeparators : set of char = [':'];
  37. FileNameCaseSensitive = false;
  38. FileNameCasePreserving = false;
  39. maxExitCode = 255;
  40. MaxPathLen = 255;
  41. AllFilesMask = '*';
  42. sLineBreak: string [1] = LineEnding;
  43. { used for single computations }
  44. const BIAS4 = $7f-1;
  45. const
  46. UnusedHandle = $ffff;
  47. StdInputHandle = 0;
  48. StdOutputHandle = 1;
  49. StdErrorHandle = $ffff;
  50. implementation
  51. {$I system.inc}
  52. {$I lowmath.inc}
  53. function GetProcessID:SizeUInt;
  54. begin
  55. {$WARNING To be checked by platform maintainer}
  56. GetProcessID := 1;
  57. end;
  58. const
  59. argc : longint = 0;
  60. var
  61. errno : integer;
  62. {$S-}
  63. procedure Stack_Check; assembler;
  64. { Check for local variable allocation }
  65. { On Entry -> d0 : size of local stack we are trying to allocate }
  66. asm
  67. XDEF STACKCHECK
  68. move.l sp,d1 { get value of stack pointer }
  69. sub.l d0,d1 { sp - stack_size }
  70. sub.l #2048,d1
  71. cmp.l __BREAK,d1
  72. bgt @st1nosweat
  73. move.l #202,d0
  74. jsr HALT_ERROR
  75. @st1nosweat:
  76. end;
  77. Procedure Error2InOut;
  78. Begin
  79. if (errno <= -2) and (errno >= -11) then
  80. InOutRes:=150-errno { 150+errno }
  81. else
  82. Begin
  83. case errno of
  84. -32 : InOutRes:=1;
  85. -33 : InOutRes:=2;
  86. -34 : InOutRes:=3;
  87. -35 : InOutRes:=4;
  88. -36 : InOutRes:=5;
  89. -37 : InOutRes:=8;
  90. -39 : InOutRes:=8;
  91. -40 : InOutRes:=9;
  92. -46 : InOutRes:=15;
  93. -67..-64 : InOutRes:=153;
  94. -15 : InOutRes:=151;
  95. -13 : InOutRes:=150;
  96. else
  97. InOutres := word(errno);
  98. end;
  99. end;
  100. errno:=0;
  101. end;
  102. procedure halt(errnum : byte);
  103. begin
  104. do_exit;
  105. flush(stderr);
  106. asm
  107. clr.l d0
  108. move.b errnum,d0
  109. move.w d0,-(sp)
  110. move.w #$4c,-(sp)
  111. trap #1
  112. end;
  113. end;
  114. function args : pointer; assembler;
  115. asm
  116. move.l __ARGS,d0
  117. end;
  118. Function GetParamCount(const p: pchar): longint;
  119. var
  120. i: word;
  121. count: word;
  122. Begin
  123. i:=0;
  124. count:=0;
  125. while p[count] <> #0 do
  126. Begin
  127. if (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) then
  128. Begin
  129. i:=i+1;
  130. while (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) do
  131. count:=count+1;
  132. end;
  133. if p[count] = #0 then break;
  134. count:=count+1;
  135. end;
  136. GetParamCount:=longint(i);
  137. end;
  138. Function GetParam(index: word; const p : pchar): string;
  139. { On Entry: index = string index to correct parameter }
  140. { On exit: = correct character index into pchar array }
  141. { Returns correct index to command line argument }
  142. var
  143. count: word;
  144. localindex: word;
  145. l: byte;
  146. temp: string;
  147. Begin
  148. temp:='';
  149. count := 0;
  150. { first index is one }
  151. localindex := 1;
  152. l:=0;
  153. While p[count] <> #0 do
  154. Begin
  155. if (p[count] <> ' ') and (p[count] <> #9) then
  156. Begin
  157. if localindex = index then
  158. Begin
  159. while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) and (l < 256) do
  160. Begin
  161. temp:=temp+p[count];
  162. l:=l+1;
  163. count:=count+1;
  164. end;
  165. temp[0]:=char(l);
  166. GetParam:=temp;
  167. exit;
  168. end;
  169. { Point to next argument in list }
  170. while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) do
  171. Begin
  172. count:=count+1;
  173. end;
  174. localindex:=localindex+1;
  175. end;
  176. if p[count] = #0 then break;
  177. count:=count+1;
  178. end;
  179. GetParam:=temp;
  180. end;
  181. function paramstr(l : longint) : string;
  182. var
  183. p : pchar;
  184. s1 : string;
  185. begin
  186. if l = 0 then
  187. Begin
  188. s1 := '';
  189. end
  190. else
  191. if (l>0) and (l<=paramcount) then
  192. begin
  193. p:=args;
  194. paramstr:=GetParam(word(l),p);
  195. end
  196. else paramstr:='';
  197. end;
  198. function paramcount : longint;
  199. Begin
  200. paramcount := argc;
  201. end;
  202. procedure randomize;
  203. var
  204. hl : longint;
  205. begin
  206. asm
  207. movem.l d2/d3/a2/a3, -(sp) { save OS registers }
  208. move.w #17,-(sp)
  209. trap #14 { call xbios - random number }
  210. add.l #2,sp
  211. movem.l (sp)+,d2/d3/a2/a3
  212. move.l d0,hl { result in d0 }
  213. end;
  214. randseed:=hl;
  215. end;
  216. function getheapstart:pointer;assembler;
  217. asm
  218. lea.l HEAP,a0
  219. move.l a0,d0
  220. end;
  221. function getheapsize:longint;assembler;
  222. asm
  223. move.l HEAP_SIZE,d0
  224. end ['D0'];
  225. { This routine is used to grow the heap. }
  226. { But here we do a trick, we say that the }
  227. { heap cannot be regrown! }
  228. function sbrk( size: longint): pointer;
  229. { on exit nil = if fails. }
  230. Begin
  231. sbrk:=nil;
  232. end;
  233. {$I heap.inc}
  234. {****************************************************************************
  235. Low Level File Routines
  236. ****************************************************************************}
  237. procedure DoDirSeparators(p:pchar);
  238. var
  239. i : longint;
  240. begin
  241. { allow slash as backslash }
  242. for i:=0 to strlen(p) do
  243. if p[i] in AllowDirectorySeparators then p[i]:=DirectorySeparator;
  244. end;
  245. procedure do_close(h : longint);
  246. begin
  247. asm
  248. movem.l d2/d3/a2/a3,-(sp)
  249. move.l h,d0
  250. move.w d0,-(sp)
  251. move.w #$3e,-(sp)
  252. trap #1
  253. add.l #4,sp { restore stack ... }
  254. movem.l (sp)+,d2/d3/a2/a3
  255. end;
  256. end;
  257. procedure do_erase(p : pchar);
  258. begin
  259. DoDirSeparators(p);
  260. asm
  261. move.l d2,d6 { save d2 }
  262. movem.l d3/a2/a3,-(sp) { save regs }
  263. move.l p,-(sp)
  264. move.w #$41,-(sp)
  265. trap #1
  266. add.l #6,sp
  267. move.l d6,d2 { restore d2 }
  268. movem.l (sp)+,d3/a2/a3
  269. tst.w d0
  270. beq @doserend
  271. move.w d0,errno
  272. @doserend:
  273. end;
  274. if errno <> 0 then
  275. Error2InOut;
  276. end;
  277. procedure do_rename(p1,p2 : pchar);
  278. begin
  279. DoDirSeparators(p1);
  280. DoDirSeparators(p2);
  281. asm
  282. move.l d2,d6 { save d2 }
  283. movem.l d3/a2/a3,-(sp)
  284. move.l p1,-(sp)
  285. move.l p2,-(sp)
  286. clr.w -(sp)
  287. move.w #$56,-(sp)
  288. trap #1
  289. lea 12(sp),sp
  290. move.l d6,d2 { restore d2 }
  291. movem.l (sp)+,d3/a2/a3
  292. tst.w d0
  293. beq @dosreend
  294. move.w d0,errno { error ... }
  295. @dosreend:
  296. end;
  297. if errno <> 0 then
  298. Error2InOut;
  299. end;
  300. function do_isdevice(handle:word):boolean;
  301. begin
  302. if (handle=stdoutputhandle) or (handle=stdinputhandle) or
  303. (handle=stderrorhandle) then
  304. do_isdevice:=FALSE
  305. else
  306. do_isdevice:=TRUE;
  307. end;
  308. function do_write(h,addr,len : longint) : longint;
  309. begin
  310. asm
  311. move.l d2,d6 { save d2 }
  312. movem.l d3/a2/a3,-(sp)
  313. move.l addr,-(sp)
  314. move.l len,-(sp)
  315. move.l h,d0
  316. move.w d0,-(sp)
  317. move.w #$40,-(sp)
  318. trap #1
  319. lea 12(sp),sp
  320. move.l d6,d2 { restore d2 }
  321. movem.l (sp)+,d3/a2/a3
  322. tst.l d0
  323. bpl @doswrend
  324. move.w d0,errno { error ... }
  325. @doswrend:
  326. move.l d0,@RESULT
  327. end;
  328. if errno <> 0 then
  329. Error2InOut;
  330. end;
  331. function do_read(h,addr,len : longint) : longint;
  332. begin
  333. asm
  334. move.l d2,d6 { save d2 }
  335. movem.l d3/a2/a3,-(sp)
  336. move.l addr,-(sp)
  337. move.l len,-(sp)
  338. move.l h,d0
  339. move.w d0,-(sp)
  340. move.w #$3f,-(sp)
  341. trap #1
  342. lea 12(sp),sp
  343. move.l d6,d2 { restore d2 }
  344. movem.l (sp)+,d3/a2/a3
  345. tst.l d0
  346. bpl @dosrdend
  347. move.w d0,errno { error ... }
  348. @dosrdend:
  349. move.l d0,@Result
  350. end;
  351. if errno <> 0 then
  352. Error2InOut;
  353. end;
  354. function do_filepos(handle : longint) : longint;
  355. begin
  356. asm
  357. move.l d2,d6 { save d2 }
  358. movem.l d3/a2/a3,-(sp)
  359. move.w #1,-(sp) { seek from current position }
  360. move.l handle,d0
  361. move.w d0,-(sp)
  362. move.l #0,-(sp) { with a seek offset of zero }
  363. move.w #$42,-(sp)
  364. trap #1
  365. lea 10(sp),sp
  366. move.l d6,d2 { restore d2 }
  367. movem.l (sp)+,d3/a2/a3
  368. move.l d0,@Result
  369. end;
  370. end;
  371. procedure do_seek(handle,pos : longint);
  372. begin
  373. asm
  374. move.l d2,d6 { save d2 }
  375. movem.l d3/a2/a3,-(sp)
  376. move.w #0,-(sp) { seek from start of file }
  377. move.l handle,d0
  378. move.w d0,-(sp)
  379. move.l pos,-(sp)
  380. move.w #$42,-(sp)
  381. trap #1
  382. lea 10(sp),sp
  383. move.l d6,d2 { restore d2 }
  384. movem.l (sp)+,d3/a2/a3
  385. end;
  386. end;
  387. function do_seekend(handle:longint):longint;
  388. var
  389. t: longint;
  390. begin
  391. asm
  392. move.l d2,d6 { save d2 }
  393. movem.l d3/a2/a3,-(sp)
  394. move.w #2,-(sp) { seek from end of file }
  395. move.l handle,d0
  396. move.w d0,-(sp)
  397. move.l #0,-(sp) { with an offset of 0 from end }
  398. move.w #$42,-(sp)
  399. trap #1
  400. lea 10(sp),sp
  401. move.l d6,d2 { restore d2 }
  402. movem.l (sp)+,d3/a2/a3
  403. move.l d0,t
  404. end;
  405. do_seekend:=t;
  406. end;
  407. function do_filesize(handle : longint) : longint;
  408. var
  409. aktfilepos : longint;
  410. begin
  411. aktfilepos:=do_filepos(handle);
  412. do_filesize:=do_seekend(handle);
  413. do_seek(handle,aktfilepos);
  414. end;
  415. procedure do_truncate (handle,pos:longint);
  416. begin
  417. do_seek(handle,pos);
  418. {!!!!!!!!!!!!}
  419. end;
  420. procedure do_open(var f;p:pchar;flags:longint);
  421. {
  422. filerec and textrec have both handle and mode as the first items so
  423. they could use the same routine for opening/creating.
  424. when (flags and $100) the file will be append
  425. when (flags and $1000) the file will be truncate/rewritten
  426. when (flags and $10000) there is no check for close (needed for textfiles)
  427. }
  428. var
  429. i : word;
  430. oflags: longint;
  431. begin
  432. DoDirSeparators(p);
  433. { close first if opened }
  434. if ((flags and $10000)=0) then
  435. begin
  436. case filerec(f).mode of
  437. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  438. fmclosed : ;
  439. else
  440. begin
  441. inoutres:=102; {not assigned}
  442. exit;
  443. end;
  444. end;
  445. end;
  446. { reset file handle }
  447. filerec(f).handle:=UnusedHandle;
  448. oflags:=$02; { read/write mode }
  449. { convert filemode to filerec modes }
  450. case (flags and 3) of
  451. 0 : begin
  452. filerec(f).mode:=fminput;
  453. oflags:=$00; { read mode only }
  454. end;
  455. 1 : filerec(f).mode:=fmoutput;
  456. 2 : filerec(f).mode:=fminout;
  457. end;
  458. if (flags and $1000)<>0 then
  459. begin
  460. filerec(f).mode:=fmoutput;
  461. oflags:=$04; { read/write with create }
  462. end
  463. else
  464. if (flags and $100)<>0 then
  465. begin
  466. filerec(f).mode:=fmoutput;
  467. oflags:=$02; { read/write }
  468. end;
  469. { empty name is special }
  470. if p[0]=#0 then
  471. begin
  472. case filerec(f).mode of
  473. fminput : filerec(f).handle:=StdInputHandle;
  474. fmappend,
  475. fmoutput : begin
  476. filerec(f).handle:=StdOutputHandle;
  477. filerec(f).mode:=fmoutput; {fool fmappend}
  478. end;
  479. end;
  480. exit;
  481. end;
  482. asm
  483. movem.l d2/d3/a2/a3,-(sp) { save used registers }
  484. cmp.l #4,oflags { check if rewrite mode ... }
  485. bne @opencont2
  486. { rewrite mode - create new file }
  487. move.w #0,-(sp)
  488. move.l p,-(sp)
  489. move.w #$3c,-(sp)
  490. trap #1
  491. add.l #8,sp { restore stack of os call }
  492. bra @end
  493. { reset - open existing files }
  494. @opencont2:
  495. move.l oflags,d0 { use flag as source ... }
  496. @opencont1:
  497. move.w d0,-(sp)
  498. move.l p,-(sp)
  499. move.w #$3d,-(sp)
  500. trap #1
  501. add.l #8,sp { restore stack of os call }
  502. @end:
  503. movem.l (sp)+,d2/d3/a2/a3
  504. tst.w d0
  505. bpl @opennoerr { if positive return values then ok }
  506. cmp.w #-1,d0 { if handle is -1 CON: }
  507. beq @opennoerr
  508. cmp.w #-2,d0 { if handle is -2 AUX: }
  509. beq @opennoerr
  510. cmp.w #-3,d0 { if handle is -3 PRN: }
  511. beq @opennoerr
  512. move.w d0,errno { otherwise normal error }
  513. @opennoerr:
  514. move.w d0,i { get handle as SIGNED VALUE... }
  515. end;
  516. if errno <> 0 then
  517. Error2InOut;
  518. filerec(f).handle:=i;
  519. if ((flags and $100) <> 0) and
  520. (FileRec (F).Handle <> UnusedHandle) then
  521. do_seekend(filerec(f).handle);
  522. end;
  523. {*****************************************************************************
  524. UnTyped File Handling
  525. *****************************************************************************}
  526. {$i file.inc}
  527. {*****************************************************************************
  528. Typed File Handling
  529. *****************************************************************************}
  530. {$i typefile.inc}
  531. {*****************************************************************************
  532. Text File Handling
  533. *****************************************************************************}
  534. {$i text.inc}
  535. {*****************************************************************************
  536. Directory Handling
  537. *****************************************************************************}
  538. procedure DosDir(func:byte;const s:string);
  539. var
  540. buffer : array[0..255] of char;
  541. c : word;
  542. begin
  543. move(s[1],buffer,length(s));
  544. buffer[length(s)]:=#0;
  545. DoDirSeparators(pchar(@buffer));
  546. c:=word(func);
  547. asm
  548. move.l d2,d6 { save d2 }
  549. movem.l d3/a2/a3,-(sp)
  550. pea buffer
  551. move.w c,-(sp)
  552. trap #1
  553. add.l #6,sp
  554. move.l d6,d2 { restore d2 }
  555. movem.l (sp)+,d3/a2/a3
  556. tst.w d0
  557. beq @dosdirend
  558. move.w d0,errno
  559. @dosdirend:
  560. end;
  561. if errno <> 0 then
  562. Error2InOut;
  563. end;
  564. procedure mkdir(const s : string);[IOCheck];
  565. begin
  566. If InOutRes <> 0 then exit;
  567. DosDir($39,s);
  568. end;
  569. procedure rmdir(const s : string);[IOCheck];
  570. begin
  571. If InOutRes <> 0 then exit;
  572. DosDir($3a,s);
  573. end;
  574. procedure chdir(const s : string);[IOCheck];
  575. begin
  576. If InOutRes <> 0 then exit;
  577. DosDir($3b,s);
  578. end;
  579. function GetDirIO (DriveNr: byte; var Dir: ShortString): word;
  580. [public, alias: 'FPC_GETDIRIO'];
  581. var
  582. temp : array[0..255] of char;
  583. i : longint;
  584. j: byte;
  585. drv: word;
  586. begin
  587. GetDirIO := 0;
  588. drv:=word(drivenr);
  589. asm
  590. move.l d2,d6 { save d2 }
  591. movem.l d3/a2/a3,-(sp)
  592. { Get dir from drivenr : 0=default, 1=A etc... }
  593. move.w drv,-(sp)
  594. { put (previously saved) offset in si }
  595. { move.l temp,-(sp)}
  596. pea temp
  597. { call attos function 47H : Get dir }
  598. move.w #$47,-(sp)
  599. { make the call }
  600. trap #1
  601. add.l #8,sp
  602. move.l d6,d2 { restore d2 }
  603. movem.l (sp)+,d3/a2/a3
  604. end;
  605. { conversion to pascal string }
  606. i:=0;
  607. while (temp[i]<>#0) do
  608. begin
  609. if temp[i] in AllowDirectorySeparators then
  610. temp[i]:=DirectorySeparator;
  611. dir[i+3]:=temp[i];
  612. inc(i);
  613. end;
  614. dir[2]:=':';
  615. dir[3]:='\';
  616. dir[0]:=char(i+2);
  617. { upcase the string (FPC Pascal function) }
  618. dir:=upcase(dir);
  619. if drivenr<>0 then { Drive was supplied. We know it }
  620. dir[1]:=chr(65+drivenr-1)
  621. else
  622. begin
  623. asm
  624. move.l d2,d6 { save d2 }
  625. movem.l d3/a2/a3,-(sp)
  626. move.w #$19,-(sp)
  627. trap #1
  628. add.l #2,sp
  629. move.w d0,drv
  630. move.l d6,d2 { restore d2 }
  631. movem.l (sp)+,d3/a2/a3
  632. end;
  633. dir[1]:=chr(byte(drv)+ord('A'));
  634. end;
  635. end;
  636. procedure GetDir (DriveNr: byte; var Dir: ShortString);
  637. begin
  638. InOutRes := GetDirIO (DriveNr, Dir);
  639. end;
  640. {*****************************************************************************
  641. System Dependent Exit code
  642. *****************************************************************************}
  643. Procedure system_exit;
  644. begin
  645. end;
  646. {*****************************************************************************
  647. SystemUnit Initialization
  648. *****************************************************************************}
  649. function CheckInitialStkLen (StkLen: SizeUInt): SizeUInt;
  650. begin
  651. CheckInitialStkLen := StkLen;
  652. end;
  653. begin
  654. StackLength := CheckInitialStkLen (InitialStkLen);
  655. { Initialize ExitProc }
  656. ExitProc:=Nil;
  657. { Setup heap }
  658. InitHeap;
  659. {$ifdef HASWIDESTRING}
  660. InitUnicodeStringManager;
  661. {$endif HASWIDESTRING}
  662. { Setup stdin, stdout and stderr }
  663. OpenStdIO(Input,fmInput,StdInputHandle);
  664. OpenStdIO(Output,fmOutput,StdOutputHandle);
  665. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  666. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  667. { Reset IO Error }
  668. InOutRes:=0;
  669. (* This should be changed to a real value during *)
  670. (* thread driver initialization if appropriate. *)
  671. ThreadID := 1;
  672. errno := 0;
  673. { Setup command line arguments }
  674. argc:=GetParamCount(args);
  675. InitVariantManager;
  676. end.