system.pas 19 KB

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