system.pas 19 KB

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