system.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by 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. { no stack check in system }
  12. {$S-}
  13. unit system;
  14. interface
  15. {$ifdef SYSTEMDEBUG}
  16. {$define SYSTEMEXCEPTIONDEBUG}
  17. {$endif SYSTEMDEBUG}
  18. {$ifdef i386}
  19. {$define Set_i386_Exception_handler}
  20. {$endif i386}
  21. { include system-independent routine headers }
  22. {$I systemh.inc}
  23. { include heap support headers }
  24. {Why the hell do i have to define that ???
  25. otherwise FPC_FREEMEM expects 2 parameters but the compiler only
  26. puhes the address}
  27. { DEFINE NEWMM}
  28. { I heaph.inc}
  29. {Platform specific information}
  30. const
  31. LineEnding = #13#10;
  32. LFNSupport = false; { ??? - that's how it was declared in dos.pp! }
  33. DirectorySeparator = '\';
  34. DriveSeparator = ':';
  35. PathSeparator = ';';
  36. { FileNameCaseSensitive is defined separately below!!! }
  37. type
  38. { the fields of this record are os dependent }
  39. { and they shouldn't be used in a program }
  40. { only the type TCriticalSection is important }
  41. TRTLCriticalSection = packed record
  42. SemaHandle : LONGINT;
  43. SemaIsOpen : BOOLEAN;
  44. end;
  45. { include threading stuff }
  46. {$i threadh.inc}
  47. { include heap support headers }
  48. {$I heaph.inc}
  49. CONST
  50. { Default filehandles }
  51. UnusedHandle : longint = -1;
  52. StdInputHandle : longint = 0;
  53. StdOutputHandle : longint = 0;
  54. StdErrorHandle : longint = 0;
  55. FileNameCaseSensitive : boolean = false;
  56. sLineBreak : STRING = LineEnding;
  57. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  58. TYPE
  59. TNWCheckFunction = procedure (var code : longint);
  60. VAR
  61. ArgC : INTEGER;
  62. ArgV : ppchar;
  63. NetwareCheckFunction : TNWCheckFunction;
  64. NetwareMainThreadGroupID: longint;
  65. CONST
  66. envp : ppchar = nil; {dummy to make heaptrc happy}
  67. PROCEDURE ConsolePrintf (FormatStr : PCHAR; Param : LONGINT); CDecl;
  68. PROCEDURE ConsolePrintf3 (FormatStr : PCHAR; P1,P2,P3 : LONGINT); CDecl;
  69. PROCEDURE ConsolePrintf (FormatStr : PCHAR); CDecl;
  70. implementation
  71. { ?? why does this not work ?? DEFINE FPC_SYSTEM_HAS_MOVE}
  72. {procedure move (const source; var dest; count : longint);
  73. begin
  74. _memcpy (@dest, @source, count);
  75. end;}
  76. { include system independent routines }
  77. {$I system.inc}
  78. { some declarations for Netware API calls }
  79. {$I nwsys.inc}
  80. {$I errno.inc}
  81. procedure setup_arguments;
  82. begin
  83. end;
  84. procedure setup_environment;
  85. begin
  86. end;
  87. procedure PASCALMAIN;external name 'PASCALMAIN';
  88. procedure fpc_do_exit;external name 'FPC_DO_EXIT';
  89. {*****************************************************************************
  90. Startup
  91. *****************************************************************************}
  92. PROCEDURE _nlm_main (_ArgC : LONGINT; _ArgV : ppchar); CDECL; [public,alias: '_nlm_main'];
  93. BEGIN
  94. ArgC := _ArgC;
  95. ArgV := _ArgV;
  96. PASCALMAIN;
  97. END;
  98. {$ifdef MT}
  99. PROCEDURE CloseAllRemainingSemaphores; FORWARD;
  100. {$endif}
  101. { if return-value is <> 0, netware shows the message
  102. Unload Anyway ?
  103. To Disable unload at all, SetNLMDontUnloadFlag can be used on
  104. Netware >= 4.0 }
  105. function CheckFunction : longint; CDECL; [public,alias: 'FPC_NW_CHECKFUNCTION'];
  106. var oldTG:longint;
  107. begin
  108. if @NetwareCheckFunction <> nil then
  109. begin
  110. { this function is called without clib context, to allow clib
  111. calls, we set the thread group id before calling the
  112. user-function }
  113. oldTG := _SetThreadGroupID (NetwareMainThreadGroupID);
  114. result := 0;
  115. NetwareCheckFunction (result);
  116. _SetThreadGroupID (oldTG);
  117. end else
  118. result := 0;
  119. end;
  120. {*****************************************************************************
  121. System Dependent Exit code
  122. *****************************************************************************}
  123. Procedure system_exit;
  124. begin
  125. {$ifdef MT}
  126. CloseAllRemainingSemaphores;
  127. {$endif}
  128. _exit (ExitCode);
  129. end;
  130. {*****************************************************************************
  131. Stack check code
  132. *****************************************************************************}
  133. procedure int_stackcheck(stack_size:longint);[public,alias:'FPC_STACKCHECK'];
  134. {
  135. called when trying to get local stack if the compiler directive $S
  136. is set this function must preserve esi !!!! because esi is set by
  137. the calling proc for methods it must preserve all registers !!
  138. With a 2048 byte safe area used to write to StdIo without crossing
  139. the stack boundary
  140. }
  141. begin
  142. IF _stackavail > stack_size + 2048 THEN EXIT;
  143. HandleError (202);
  144. end;
  145. {*****************************************************************************
  146. ParamStr/Randomize
  147. *****************************************************************************}
  148. { number of args }
  149. function paramcount : longint;
  150. begin
  151. paramcount := argc - 1;
  152. end;
  153. { argument number l }
  154. function paramstr(l : longint) : string;
  155. begin
  156. if (l>=0) and (l+1<=argc) then
  157. paramstr:=strpas(argv[l])
  158. else
  159. paramstr:='';
  160. end;
  161. { set randseed to a new pseudo random value }
  162. procedure randomize;
  163. begin
  164. randseed := _time (NIL);
  165. end;
  166. {*****************************************************************************
  167. Heap Management
  168. *****************************************************************************}
  169. { first address of heap }
  170. function getheapstart:pointer;
  171. assembler;
  172. asm
  173. leal HEAP,%eax
  174. end ['EAX'];
  175. { current length of heap }
  176. function getheapsize:longint;
  177. assembler;
  178. asm
  179. movl HEAPSIZE,%eax
  180. end ['EAX'];
  181. { function to allocate size bytes more for the program }
  182. { must return the first address of new data space or -1 if fail }
  183. FUNCTION Sbrk(size : longint):longint;
  184. VAR P : POINTER;
  185. BEGIN
  186. P := _malloc (size);
  187. IF P = NIL THEN
  188. Sbrk := -1
  189. ELSE
  190. Sbrk := LONGINT (P);
  191. END;
  192. { include standard heap management }
  193. {$I heap.inc}
  194. {****************************************************************************
  195. Low level File Routines
  196. All these functions can set InOutRes on errors
  197. ****************************************************************************}
  198. PROCEDURE NW2PASErr (Err : LONGINT);
  199. BEGIN
  200. if Err = 0 then { Else it will go through all the cases }
  201. exit;
  202. case Err of
  203. Sys_ENFILE,
  204. Sys_EMFILE : Inoutres:=4;
  205. Sys_ENOENT : Inoutres:=2;
  206. Sys_EBADF : Inoutres:=6;
  207. Sys_ENOMEM,
  208. Sys_EFAULT : Inoutres:=217;
  209. Sys_EINVAL : Inoutres:=218;
  210. Sys_EPIPE,
  211. Sys_EINTR,
  212. Sys_EIO,
  213. Sys_EAGAIN,
  214. Sys_ENOSPC : Inoutres:=101;
  215. Sys_ENAMETOOLONG,
  216. Sys_ELOOP,
  217. Sys_ENOTDIR : Inoutres:=3;
  218. Sys_EROFS,
  219. Sys_EEXIST,
  220. Sys_EACCES : Inoutres:=5;
  221. Sys_EBUSY : Inoutres:=162;
  222. end;
  223. END;
  224. FUNCTION errno : LONGINT;
  225. BEGIN
  226. errno := __get_errno_ptr^;
  227. END;
  228. PROCEDURE Errno2Inoutres;
  229. BEGIN
  230. NW2PASErr (errno);
  231. END;
  232. PROCEDURE SetFileError (VAR Err : LONGINT);
  233. BEGIN
  234. IF Err >= 0 THEN
  235. InOutRes := 0
  236. ELSE
  237. BEGIN
  238. Err := errno;
  239. NW2PASErr (Err);
  240. Err := 0;
  241. END;
  242. END;
  243. { close a file from the handle value }
  244. procedure do_close(handle : longint);
  245. VAR res : LONGINT;
  246. begin
  247. res := _close (handle);
  248. IF res <> 0 THEN
  249. SetFileError (res)
  250. ELSE
  251. InOutRes := 0;
  252. end;
  253. procedure do_erase(p : pchar);
  254. VAR res : LONGINT;
  255. begin
  256. res := _unlink (p);
  257. IF Res < 0 THEN
  258. SetFileError (res)
  259. ELSE
  260. InOutRes := 0;
  261. end;
  262. procedure do_rename(p1,p2 : pchar);
  263. VAR res : LONGINT;
  264. begin
  265. res := _rename (p1,p2);
  266. IF Res < 0 THEN
  267. SetFileError (res)
  268. ELSE
  269. InOutRes := 0
  270. end;
  271. function do_write(h,addr,len : longint) : longint;
  272. VAR res : LONGINT;
  273. begin
  274. res := _write (h,POINTER(addr),len);
  275. IF res > 0 THEN
  276. InOutRes := 0
  277. ELSE
  278. SetFileError (res);
  279. do_write := res;
  280. end;
  281. function do_read(h,addr,len : longint) : longint;
  282. VAR res : LONGINT;
  283. begin
  284. res := _read (h,POINTER(addr),len);
  285. IF res > 0 THEN
  286. InOutRes := 0
  287. ELSE
  288. SetFileError (res);
  289. do_read := res;
  290. end;
  291. function do_filepos(handle : longint) : longint;
  292. VAR res : LONGINT;
  293. begin
  294. InOutRes:=1;
  295. res := _tell (handle);
  296. IF res < 0 THEN
  297. SetFileError (res)
  298. ELSE
  299. InOutRes := 0;
  300. do_filepos := res;
  301. end;
  302. CONST SEEK_SET = 0; // Seek from beginning of file.
  303. SEEK_CUR = 1; // Seek from current position.
  304. SEEK_END = 2; // Seek from end of file.
  305. procedure do_seek(handle,pos : longint);
  306. VAR res : LONGINT;
  307. begin
  308. res := _lseek (handle,pos, SEEK_SET);
  309. IF res >= 0 THEN
  310. InOutRes := 0
  311. ELSE
  312. SetFileError (res);
  313. end;
  314. function do_seekend(handle:longint):longint;
  315. VAR res : LONGINT;
  316. begin
  317. res := _lseek (handle,0, SEEK_END);
  318. IF res >= 0 THEN
  319. InOutRes := 0
  320. ELSE
  321. SetFileError (res);
  322. do_seekend := res;
  323. end;
  324. function do_filesize(handle : longint) : longint;
  325. VAR res : LONGINT;
  326. begin
  327. res := _filelength (handle);
  328. IF res < 0 THEN
  329. BEGIN
  330. SetFileError (Res);
  331. do_filesize := -1;
  332. END ELSE
  333. BEGIN
  334. InOutRes := 0;
  335. do_filesize := res;
  336. END;
  337. end;
  338. { truncate at a given position }
  339. procedure do_truncate (handle,pos:longint);
  340. VAR res : LONGINT;
  341. begin
  342. res := _chsize (handle,pos);
  343. IF res <> 0 THEN
  344. SetFileError (res)
  345. ELSE
  346. InOutRes := 0;
  347. end;
  348. // mostly stolen from syslinux
  349. procedure do_open(var f;p:pchar;flags:longint);
  350. {
  351. filerec and textrec have both handle and mode as the first items so
  352. they could use the same routine for opening/creating.
  353. when (flags and $10) the file will be append
  354. when (flags and $100) the file will be truncate/rewritten
  355. when (flags and $1000) there is no check for close (needed for textfiles)
  356. }
  357. var
  358. oflags : longint;
  359. Begin
  360. { close first if opened }
  361. if ((flags and $10000)=0) then
  362. begin
  363. case FileRec(f).mode of
  364. fminput,fmoutput,fminout : Do_Close(FileRec(f).Handle);
  365. fmclosed : ;
  366. else
  367. begin
  368. inoutres:=102; {not assigned}
  369. exit;
  370. end;
  371. end;
  372. end;
  373. { reset file Handle }
  374. FileRec(f).Handle:=UnusedHandle;
  375. { We do the conversion of filemodes here, concentrated on 1 place }
  376. case (flags and 3) of
  377. 0 : begin
  378. oflags := O_RDONLY;
  379. filerec(f).mode := fminput;
  380. end;
  381. 1 : begin
  382. oflags := O_WRONLY;
  383. filerec(f).mode := fmoutput;
  384. end;
  385. 2 : begin
  386. oflags := O_RDWR;
  387. filerec(f).mode := fminout;
  388. end;
  389. end;
  390. if (flags and $1000)=$1000 then
  391. oflags:=oflags or (O_CREAT or O_TRUNC)
  392. else
  393. if (flags and $100)=$100 then
  394. oflags:=oflags or (O_APPEND);
  395. { empty name is special }
  396. if p[0]=#0 then
  397. begin
  398. case FileRec(f).mode of
  399. fminput :
  400. FileRec(f).Handle:=StdInputHandle;
  401. fminout, { this is set by rewrite }
  402. fmoutput :
  403. FileRec(f).Handle:=StdOutputHandle;
  404. fmappend :
  405. begin
  406. FileRec(f).Handle:=StdOutputHandle;
  407. FileRec(f).mode:=fmoutput; {fool fmappend}
  408. end;
  409. end;
  410. exit;
  411. end;
  412. { real open call }
  413. FileRec(f).Handle := _open(p,oflags,438);
  414. //WriteLn ('_open (',p,') liefert ',ErrNo, 'Handle: ',FileRec(f).Handle);
  415. // errno does not seem to be set on succsess ??
  416. IF FileRec(f).Handle < 0 THEN
  417. if (ErrNo=Sys_EROFS) and ((OFlags and O_RDWR)<>0) then
  418. begin // i.e. for cd-rom
  419. Oflags:=Oflags and not(O_RDWR);
  420. FileRec(f).Handle := _open(p,oflags,438);
  421. end;
  422. IF FileRec(f).Handle < 0 THEN
  423. Errno2Inoutres
  424. ELSE
  425. InOutRes := 0;
  426. End;
  427. function do_isdevice(handle:longint):boolean;
  428. begin
  429. do_isdevice := (_isatty (handle) > 0);
  430. end;
  431. {*****************************************************************************
  432. UnTyped File Handling
  433. *****************************************************************************}
  434. {$i file.inc}
  435. {*****************************************************************************
  436. Typed File Handling
  437. *****************************************************************************}
  438. {$i typefile.inc}
  439. {*****************************************************************************
  440. Text File Handling
  441. *****************************************************************************}
  442. { should we consider #26 as the end of a file ? }
  443. {?? $DEFINE EOF_CTRLZ}
  444. {$i text.inc}
  445. {*****************************************************************************
  446. Directory Handling
  447. *****************************************************************************}
  448. procedure mkdir(const s : string);[IOCheck];
  449. VAR S2 : STRING;
  450. Res: LONGINT;
  451. BEGIN
  452. S2 := S;
  453. IF Length (S2) = 255 THEN DEC (BYTE(S2[0]));
  454. S2 := S2 + #0;
  455. Res := _mkdir (@S2[1]);
  456. IF Res = 0 THEN
  457. InOutRes:=0
  458. ELSE
  459. SetFileError (Res);
  460. END;
  461. procedure rmdir(const s : string);[IOCheck];
  462. VAR S2 : STRING;
  463. Res: LONGINT;
  464. BEGIN
  465. S2 := S;
  466. IF Length (S2) = 255 THEN DEC (BYTE(S2[0]));
  467. S2 := S2 + #0;
  468. Res := _rmdir (@S2[1]);
  469. IF Res = 0 THEN
  470. InOutRes:=0
  471. ELSE
  472. SetFileError (Res);
  473. end;
  474. procedure chdir(const s : string);[IOCheck];
  475. VAR S2 : STRING;
  476. Res: LONGINT;
  477. begin
  478. S2 := S;
  479. IF Length (S2) = 255 THEN DEC (BYTE(S2[0]));
  480. S2 := S2 + #0;
  481. Res := _chdir (@S2[1]);
  482. IF Res = 0 THEN
  483. InOutRes:=0
  484. ELSE
  485. SetFileError (Res);
  486. end;
  487. procedure getdir(drivenr : byte;var dir : shortstring);
  488. VAR P : ARRAY [0..255] OF CHAR;
  489. Len: LONGINT;
  490. begin
  491. P[0] := #0;
  492. _getcwd (@P, SIZEOF (P));
  493. Len := _strlen (P);
  494. IF Len > 0 THEN
  495. BEGIN
  496. Move (P, dir[1], Len);
  497. BYTE(dir[0]) := Len;
  498. END ELSE
  499. InOutRes := 1;
  500. end;
  501. {*****************************************************************************
  502. Thread Handling
  503. *****************************************************************************}
  504. const
  505. fpucw : word = $1332;
  506. procedure InitFPU;assembler;
  507. asm
  508. fninit
  509. fldcw fpucw
  510. end;
  511. { include threading stuff, this is os dependend part }
  512. {$I thread.inc}
  513. {*****************************************************************************
  514. SystemUnit Initialization
  515. *****************************************************************************}
  516. Begin
  517. {$ifdef MT}
  518. { the exceptions use threadvars so do this _before_ initexceptions }
  519. AllocateThreadVars;
  520. {$endif MT}
  521. NetwareCheckFunction := nil;
  522. NetwareMainThreadGroupID := _GetThreadGroupID;
  523. { Setup heap }
  524. InitHeap;
  525. InitExceptions;
  526. { Setup stdin, stdout and stderr }
  527. StdInputHandle := _fileno (LONGINT (_GetStdIn^)); // GetStd** returns **FILE !
  528. StdOutputHandle:= _fileno (LONGINT (_GetStdOut^));
  529. StdErrorHandle := _fileno (LONGINT (_GetStdErr^));
  530. OpenStdIO(Input,fmInput,StdInputHandle);
  531. OpenStdIO(Output,fmOutput,StdOutputHandle);
  532. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  533. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  534. { Setup environment and arguments }
  535. Setup_Environment;
  536. Setup_Arguments;
  537. { Reset IO Error }
  538. InOutRes:=0;
  539. {Delphi Compatible}
  540. IsLibrary := FALSE;
  541. IsConsole := TRUE;
  542. End.
  543. {
  544. $Log$
  545. Revision 1.8 2002-03-30 09:09:47 armin
  546. + support check-function for netware
  547. Revision 1.7 2002/03/17 17:57:33 armin
  548. + threads and winsock2 implemented
  549. Revision 1.5 2001/06/18 14:26:16 jonas
  550. * move platform independent constant declarations after inclusion of
  551. systemh.inc
  552. Revision 1.4 2001/06/13 22:20:11 hajny
  553. + platform specific information
  554. Revision 1.3 2001/04/16 18:39:50 florian
  555. * updates from Armin commited
  556. Revision 1.2 2001/04/11 14:17:00 florian
  557. * added logs, fixed email address of Armin, it is
  558. [email protected]
  559. Revision 1.1 2001/04/11 14:14:12 florian
  560. * initial commit, thanks to Armin Diehl ([email protected])
  561. Revision 1.2 2000/07/13 11:33:56 michael
  562. + removed logs
  563. }