system.pp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  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. {$define StdErrToConsole}
  16. {$define useLongNamespaceByDefault}
  17. {$define autoHeapRelease}
  18. {$ifdef SYSTEMDEBUG}
  19. {$define SYSTEMEXCEPTIONDEBUG}
  20. {$endif SYSTEMDEBUG}
  21. {$ifdef cpui386}
  22. {$define Set_i386_Exception_handler}
  23. {$endif cpui386}
  24. { include system-independent routine headers }
  25. {$I systemh.inc}
  26. type THandle = DWord;
  27. {Platform specific information}
  28. const
  29. LineEnding = #13#10;
  30. LFNSupport : boolean = false;
  31. DirectorySeparator = '/';
  32. DriveSeparator = ':';
  33. PathSeparator = ';';
  34. { FileNameCaseSensitive is defined separately below!!! }
  35. { include heap support headers }
  36. {$I heaph.inc}
  37. CONST
  38. { Default filehandles }
  39. UnusedHandle : THandle = -1;
  40. StdInputHandle : THandle = 0;
  41. StdOutputHandle : THandle = 0;
  42. StdErrorHandle : THandle = 0;
  43. FileNameCaseSensitive : boolean = false;
  44. sLineBreak = LineEnding;
  45. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  46. TYPE
  47. TNWCheckFunction = procedure (var code : longint);
  48. VAR
  49. ArgC : INTEGER;
  50. ArgV : ppchar;
  51. NetwareCheckFunction : TNWCheckFunction;
  52. NetwareMainThreadGroupID: longint;
  53. NetwareCodeStartAddress : dword;
  54. CONST
  55. envp : ppchar = nil; {dummy to make heaptrc happy}
  56. PROCEDURE ConsolePrintf (FormatStr : PCHAR; Param : LONGINT); CDecl;
  57. PROCEDURE ConsolePrintf3 (FormatStr : PCHAR; P1,P2,P3 : LONGINT); CDecl;
  58. PROCEDURE ConsolePrintf (FormatStr : PCHAR); CDecl;
  59. type
  60. TSysCloseAllRemainingSemaphores = procedure;
  61. TSysReleaseThreadVars = procedure;
  62. TSysSetThreadDataAreaPtr = function (newPtr:pointer):pointer;
  63. procedure NWSysSetThreadFunctions (crs:TSysCloseAllRemainingSemaphores;
  64. rtv:TSysReleaseThreadVars;
  65. stdata:TSysSetThreadDataAreaPtr);
  66. implementation
  67. { Indicate that stack checking is taken care by OS}
  68. {$DEFINE NO_GENERIC_STACK_CHECK}
  69. { include system independent routines }
  70. {$I system.inc}
  71. { some declarations for Netware API calls }
  72. {$I nwsys.inc}
  73. {$I errno.inc}
  74. var
  75. CloseAllRemainingSemaphores : TSysCloseAllRemainingSemaphores = nil;
  76. ReleaseThreadVars : TSysReleaseThreadVars = nil;
  77. SetThreadDataAreaPtr : TSysSetThreadDataAreaPtr = nil;
  78. procedure NWSysSetThreadFunctions (crs:TSysCloseAllRemainingSemaphores;
  79. rtv:TSysReleaseThreadVars;
  80. stdata:TSysSetThreadDataAreaPtr);
  81. begin
  82. CloseAllRemainingSemaphores := crs;
  83. ReleaseThreadVars := rtv;
  84. SetThreadDataAreaPtr := stdata;
  85. end;
  86. procedure PASCALMAIN;external name 'PASCALMAIN';
  87. procedure fpc_do_exit;external name 'FPC_DO_EXIT';
  88. {*****************************************************************************
  89. Startup
  90. *****************************************************************************}
  91. function __GetBssStart : pointer; external name '__getBssStart';
  92. function __getUninitializedDataSize : longint; external name '__getUninitializedDataSize';
  93. //function __getDataStart : longint; external name '__getDataStart';
  94. function __GetTextStart : longint; external name '__getTextStart';
  95. PROCEDURE nlm_main (_ArgC : LONGINT; _ArgV : ppchar); CDECL; [public,alias: '_nlm_main'];
  96. BEGIN
  97. // Initialize BSS
  98. if __getUninitializedDataSize > 0 then
  99. fillchar (__getBssStart^,__getUninitializedDataSize,0);
  100. NetwareCodeStartAddress := __GetTextStart;
  101. ArgC := _ArgC;
  102. ArgV := _ArgV;
  103. fpc_threadvar_relocate_proc := nil;
  104. PASCALMAIN;
  105. END;
  106. {*****************************************************************************
  107. System Dependent Exit code
  108. *****************************************************************************}
  109. {$ifdef autoHeapRelease}
  110. procedure FreeSbrkMem; forward;
  111. {$endif}
  112. var SigTermHandlerActive : boolean;
  113. Procedure system_exit;
  114. begin
  115. if assigned (CloseAllRemainingSemaphores) then CloseAllRemainingSemaphores;
  116. if assigned (ReleaseThreadVars) then ReleaseThreadVars;
  117. {$ifdef autoHeapRelease}
  118. FreeSbrkMem; { free memory allocated by heapmanager }
  119. {$endif}
  120. if not SigTermHandlerActive then
  121. begin
  122. if ExitCode <> 0 Then { otherwise we dont see runtime-errors }
  123. _SetAutoScreenDestructionMode (false);
  124. _exit (ExitCode);
  125. end;
  126. end;
  127. {*****************************************************************************
  128. Stack check code
  129. *****************************************************************************}
  130. const StackErr : boolean = false;
  131. procedure int_stackcheck(stack_size:Cardinal);[saveregisters,public,alias:'FPC_STACKCHECK'];
  132. {
  133. called when trying to get local stack if the compiler directive $S
  134. is set this function must preserve all registers
  135. With a 2048 byte safe area used to write to StdIo without crossing
  136. the stack boundary
  137. }
  138. begin
  139. if StackErr then exit; // avoid recursive calls
  140. if _stackavail > stack_size + 2048 THEN EXIT;
  141. StackErr := true;
  142. HandleError (202);
  143. end;
  144. {*****************************************************************************
  145. ParamStr/Randomize
  146. *****************************************************************************}
  147. { number of args }
  148. function paramcount : longint;
  149. begin
  150. paramcount := argc - 1;
  151. end;
  152. { argument number l }
  153. function paramstr(l : longint) : string;
  154. begin
  155. if (l>=0) and (l+1<=argc) then
  156. begin
  157. paramstr:=strpas(argv[l]);
  158. if l = 0 then // fix nlm path
  159. begin
  160. for l := 1 to length (paramstr) do
  161. if paramstr[l] = '\' then paramstr[l] := '/';
  162. end;
  163. end else
  164. paramstr:='';
  165. end;
  166. { set randseed to a new pseudo random value }
  167. procedure randomize;
  168. begin
  169. randseed := _time (NIL);
  170. end;
  171. {*****************************************************************************
  172. Heap Management
  173. *****************************************************************************}
  174. var
  175. heap : longint;external name 'HEAP';
  176. intern_heapsize : longint;external name 'HEAPSIZE';
  177. { first address of heap }
  178. function getheapstart:pointer;
  179. assembler;
  180. asm
  181. leal HEAP,%eax
  182. end ['EAX'];
  183. { current length of heap }
  184. function getheapsize:longint;
  185. assembler;
  186. asm
  187. movl intern_HEAPSIZE,%eax
  188. end ['EAX'];
  189. {$ifdef autoHeapRelease}
  190. const HeapInitialMaxBlocks = 32;
  191. type THeapSbrkBlockList = array [1.. HeapInitialMaxBlocks] of pointer;
  192. var HeapSbrkBlockList : ^THeapSbrkBlockList = nil;
  193. HeapSbrkLastUsed : dword = 0;
  194. HeapSbrkAllocated : dword = 0;
  195. { function to allocate size bytes more for the program }
  196. { must return the first address of new data space or nil if fail }
  197. { for netware all allocated blocks are saved to free them at }
  198. { exit (to avoid message "Module did not release xx resources") }
  199. Function Sbrk(size : longint):pointer;
  200. var P2 : POINTER;
  201. i : longint;
  202. begin
  203. Sbrk := _malloc (size);
  204. if Sbrk <> nil then begin
  205. if HeapSbrkBlockList = nil then
  206. begin
  207. Pointer (HeapSbrkBlockList) := _malloc (sizeof (HeapSbrkBlockList^));
  208. if HeapSbrkBlockList = nil then
  209. begin
  210. _free (Sbrk);
  211. Sbrk := nil;
  212. exit;
  213. end;
  214. fillchar (HeapSbrkBlockList^,sizeof(HeapSbrkBlockList^),0);
  215. HeapSbrkAllocated := HeapInitialMaxBlocks;
  216. end;
  217. if (HeapSbrkLastUsed > 0) then
  218. for i := 1 to HeapSbrkLastUsed do
  219. if (HeapSbrkBlockList^[i] = nil) then
  220. begin // reuse free slot
  221. HeapSbrkBlockList^[i] := Sbrk;
  222. exit;
  223. end;
  224. if (HeapSbrkLastUsed = HeapSbrkAllocated) then
  225. begin { grow }
  226. p2 := _realloc (HeapSbrkBlockList, (HeapSbrkAllocated + HeapInitialMaxBlocks) * sizeof(pointer));
  227. if p2 = nil then // should we better terminate with error ?
  228. begin
  229. _free (Sbrk);
  230. Sbrk := nil;
  231. exit;
  232. end;
  233. HeapSbrkBlockList := p2;
  234. inc (HeapSbrkAllocated, HeapInitialMaxBlocks);
  235. end;
  236. inc (HeapSbrkLastUsed);
  237. HeapSbrkBlockList^[HeapSbrkLastUsed] := Sbrk;
  238. end;
  239. end;
  240. procedure FreeSbrkMem;
  241. var i : longint;
  242. begin
  243. if HeapSbrkBlockList <> nil then
  244. begin
  245. for i := 1 to HeapSbrkLastUsed do
  246. if (HeapSbrkBlockList^[i] <> nil) then
  247. _free (HeapSbrkBlockList^[i]);
  248. _free (HeapSbrkBlockList);
  249. HeapSbrkAllocated := 0;
  250. HeapSbrkLastUsed := 0;
  251. HeapSbrkBlockList := nil;
  252. end;
  253. end;
  254. {*****************************************************************************
  255. OS Memory allocation / deallocation
  256. ****************************************************************************}
  257. function SysOSAlloc(size: ptrint): pointer;
  258. begin
  259. result := sbrk(size);
  260. end;
  261. {$define HAS_SYSOSFREE}
  262. procedure SysOSFree(p: pointer; size: ptrint);
  263. var i : longint;
  264. begin
  265. //fpmunmap(p, size);
  266. if (HeapSbrkLastUsed > 0) then
  267. for i := 1 to HeapSbrkLastUsed do
  268. if (HeapSbrkBlockList^[i] = p) then
  269. begin
  270. _free (p);
  271. HeapSbrkBlockList^[i] := nil;
  272. exit;
  273. end;
  274. HandleError (204); // invalid pointer operation
  275. end;
  276. {$else autoHeapRelease}
  277. {$define HAS_SYSOSFREE}
  278. procedure SysOSFree(p: pointer; size: ptrint);
  279. begin
  280. _free (p);
  281. end;
  282. function SysOSAlloc(size: ptrint): pointer;
  283. begin
  284. SysOSAlloc := _malloc (size);
  285. end;
  286. {$endif autoHeapRelease}
  287. { include standard heap management }
  288. {$I heap.inc}
  289. {****************************************************************************
  290. Low level File Routines
  291. All these functions can set InOutRes on errors
  292. ****************************************************************************}
  293. PROCEDURE NW2PASErr (Err : LONGINT);
  294. BEGIN
  295. if Err = 0 then { Else it will go through all the cases }
  296. exit;
  297. case Err of
  298. Sys_ENFILE,
  299. Sys_EMFILE : Inoutres:=4;
  300. Sys_ENOENT : Inoutres:=2;
  301. Sys_EBADF : Inoutres:=6;
  302. Sys_ENOMEM,
  303. Sys_EFAULT : Inoutres:=217;
  304. Sys_EINVAL : Inoutres:=218;
  305. Sys_EPIPE,
  306. Sys_EINTR,
  307. Sys_EIO,
  308. Sys_EAGAIN,
  309. Sys_ENOSPC : Inoutres:=101;
  310. Sys_ENAMETOOLONG,
  311. Sys_ELOOP,
  312. Sys_ENOTDIR : Inoutres:=3;
  313. Sys_EROFS,
  314. Sys_EEXIST,
  315. Sys_EACCES : Inoutres:=5;
  316. Sys_EBUSY : Inoutres:=162;
  317. end;
  318. END;
  319. FUNCTION errno : LONGINT;
  320. BEGIN
  321. errno := __get_errno_ptr^;
  322. END;
  323. PROCEDURE Errno2Inoutres;
  324. BEGIN
  325. NW2PASErr (errno);
  326. END;
  327. PROCEDURE SetFileError (VAR Err : LONGINT);
  328. BEGIN
  329. IF Err >= 0 THEN
  330. InOutRes := 0
  331. ELSE
  332. BEGIN
  333. Err := errno;
  334. NW2PASErr (Err);
  335. Err := 0;
  336. END;
  337. END;
  338. { close a file from the handle value }
  339. procedure do_close(handle : thandle);
  340. VAR res : LONGINT;
  341. begin
  342. res := _close (handle);
  343. IF res <> 0 THEN
  344. SetFileError (res)
  345. ELSE
  346. InOutRes := 0;
  347. end;
  348. procedure do_erase(p : pchar);
  349. VAR res : LONGINT;
  350. begin
  351. res := _unlink (p);
  352. IF Res < 0 THEN
  353. SetFileError (res)
  354. ELSE
  355. InOutRes := 0;
  356. end;
  357. procedure do_rename(p1,p2 : pchar);
  358. VAR res : LONGINT;
  359. begin
  360. res := _rename (p1,p2);
  361. IF Res < 0 THEN
  362. SetFileError (res)
  363. ELSE
  364. InOutRes := 0
  365. end;
  366. function do_write(h:thandle;addr:pointer;len : longint) : longint;
  367. VAR res : LONGINT;
  368. begin
  369. res := _write (h,addr,len);
  370. IF res > 0 THEN
  371. InOutRes := 0
  372. ELSE
  373. SetFileError (res);
  374. do_write := res;
  375. end;
  376. function do_read(h:thandle;addr:pointer;len : longint) : longint;
  377. VAR res : LONGINT;
  378. begin
  379. res := _read (h,addr,len);
  380. IF res > 0 THEN
  381. InOutRes := 0
  382. ELSE
  383. SetFileError (res);
  384. do_read := res;
  385. end;
  386. function do_filepos(handle : thandle) : longint;
  387. VAR res : LONGINT;
  388. begin
  389. InOutRes:=1;
  390. res := _tell (handle);
  391. IF res < 0 THEN
  392. SetFileError (res)
  393. ELSE
  394. InOutRes := 0;
  395. do_filepos := res;
  396. end;
  397. CONST SEEK_SET = 0; // Seek from beginning of file.
  398. SEEK_CUR = 1; // Seek from current position.
  399. SEEK_END = 2; // Seek from end of file.
  400. procedure do_seek(handle:thandle;pos : longint);
  401. VAR res : LONGINT;
  402. begin
  403. res := _lseek (handle,pos, SEEK_SET);
  404. IF res >= 0 THEN
  405. InOutRes := 0
  406. ELSE
  407. SetFileError (res);
  408. end;
  409. function do_seekend(handle:thandle):longint;
  410. VAR res : LONGINT;
  411. begin
  412. res := _lseek (handle,0, SEEK_END);
  413. IF res >= 0 THEN
  414. InOutRes := 0
  415. ELSE
  416. SetFileError (res);
  417. do_seekend := res;
  418. end;
  419. function do_filesize(handle : thandle) : longint;
  420. VAR res : LONGINT;
  421. begin
  422. res := _filelength (handle);
  423. IF res < 0 THEN
  424. BEGIN
  425. SetFileError (Res);
  426. do_filesize := -1;
  427. END ELSE
  428. BEGIN
  429. InOutRes := 0;
  430. do_filesize := res;
  431. END;
  432. end;
  433. { truncate at a given position }
  434. procedure do_truncate (handle:thandle;pos:longint);
  435. VAR res : LONGINT;
  436. begin
  437. res := _chsize (handle,pos);
  438. IF res <> 0 THEN
  439. SetFileError (res)
  440. ELSE
  441. InOutRes := 0;
  442. end;
  443. // mostly stolen from syslinux
  444. procedure do_open(var f;p:pchar;flags:longint);
  445. {
  446. filerec and textrec have both handle and mode as the first items so
  447. they could use the same routine for opening/creating.
  448. when (flags and $10) the file will be append
  449. when (flags and $100) the file will be truncate/rewritten
  450. when (flags and $1000) there is no check for close (needed for textfiles)
  451. }
  452. var
  453. oflags : longint;
  454. Begin
  455. { close first if opened }
  456. if ((flags and $10000)=0) then
  457. begin
  458. case FileRec(f).mode of
  459. fminput,fmoutput,fminout : Do_Close(FileRec(f).Handle);
  460. fmclosed : ;
  461. else
  462. begin
  463. inoutres:=102; {not assigned}
  464. exit;
  465. end;
  466. end;
  467. end;
  468. { reset file Handle }
  469. FileRec(f).Handle:=UnusedHandle;
  470. { We do the conversion of filemodes here, concentrated on 1 place }
  471. case (flags and 3) of
  472. 0 : begin
  473. oflags := O_RDONLY;
  474. filerec(f).mode := fminput;
  475. end;
  476. 1 : begin
  477. oflags := O_WRONLY;
  478. filerec(f).mode := fmoutput;
  479. end;
  480. 2 : begin
  481. oflags := O_RDWR;
  482. filerec(f).mode := fminout;
  483. end;
  484. end;
  485. if (flags and $1000)=$1000 then
  486. oflags:=oflags or (O_CREAT or O_TRUNC)
  487. else
  488. if (flags and $100)=$100 then
  489. oflags:=oflags or (O_APPEND);
  490. { empty name is special }
  491. if p[0]=#0 then
  492. begin
  493. case FileRec(f).mode of
  494. fminput :
  495. FileRec(f).Handle:=StdInputHandle;
  496. fminout, { this is set by rewrite }
  497. fmoutput :
  498. FileRec(f).Handle:=StdOutputHandle;
  499. fmappend :
  500. begin
  501. FileRec(f).Handle:=StdOutputHandle;
  502. FileRec(f).mode:=fmoutput; {fool fmappend}
  503. end;
  504. end;
  505. exit;
  506. end;
  507. { real open call }
  508. FileRec(f).Handle := _open(p,oflags,438);
  509. //WriteLn ('_open (',p,') returned ',ErrNo, 'Handle: ',FileRec(f).Handle);
  510. // errno does not seem to be set on succsess ??
  511. IF FileRec(f).Handle < 0 THEN
  512. if (ErrNo=Sys_EROFS) and ((OFlags and O_RDWR)<>0) then
  513. begin // i.e. for cd-rom
  514. Oflags:=Oflags and not(O_RDWR);
  515. FileRec(f).Handle := _open(p,oflags,438);
  516. end;
  517. IF FileRec(f).Handle < 0 THEN
  518. Errno2Inoutres
  519. ELSE
  520. InOutRes := 0;
  521. End;
  522. function do_isdevice(handle:THandle):boolean;
  523. begin
  524. do_isdevice := (_isatty (handle) > 0);
  525. end;
  526. {*****************************************************************************
  527. UnTyped File Handling
  528. *****************************************************************************}
  529. {$i file.inc}
  530. {*****************************************************************************
  531. Typed File Handling
  532. *****************************************************************************}
  533. {$i typefile.inc}
  534. {*****************************************************************************
  535. Text File Handling
  536. *****************************************************************************}
  537. { should we consider #26 as the end of a file ? }
  538. {?? $DEFINE EOF_CTRLZ}
  539. {$i text.inc}
  540. {*****************************************************************************
  541. Directory Handling
  542. *****************************************************************************}
  543. procedure mkdir(const s : string);[IOCheck];
  544. VAR S2 : STRING;
  545. Res: LONGINT;
  546. BEGIN
  547. S2 := S;
  548. IF Length (S2) = 255 THEN DEC (BYTE(S2[0]));
  549. S2 := S2 + #0;
  550. Res := _mkdir (@S2[1]);
  551. IF Res = 0 THEN
  552. InOutRes:=0
  553. ELSE
  554. SetFileError (Res);
  555. END;
  556. procedure rmdir(const s : string);[IOCheck];
  557. VAR S2 : STRING;
  558. Res: LONGINT;
  559. BEGIN
  560. S2 := S;
  561. IF Length (S2) = 255 THEN DEC (BYTE(S2[0]));
  562. S2 := S2 + #0;
  563. Res := _rmdir (@S2[1]);
  564. IF Res = 0 THEN
  565. InOutRes:=0
  566. ELSE
  567. SetFileError (Res);
  568. end;
  569. procedure chdir(const s : string);[IOCheck];
  570. VAR S2 : STRING;
  571. Res: LONGINT;
  572. begin
  573. S2 := S;
  574. IF Length (S2) = 255 THEN DEC (BYTE(S2[0]));
  575. S2 := S2 + #0;
  576. Res := _chdir (@S2[1]);
  577. IF Res = 0 THEN
  578. InOutRes:=0
  579. ELSE
  580. SetFileError (Res);
  581. end;
  582. procedure getdir(drivenr : byte;var dir : shortstring);
  583. VAR P : ARRAY [0..255] OF CHAR;
  584. i : LONGINT;
  585. begin
  586. P[0] := #0;
  587. _getcwd (@P, SIZEOF (P));
  588. i := _strlen (P);
  589. if i > 0 then
  590. begin
  591. Move (P, dir[1], i);
  592. BYTE(dir[0]) := i;
  593. For i := 1 to length (dir) do
  594. if dir[i] = '\' then dir [i] := '/';
  595. // fix / after volume, the compiler needs that
  596. // normaly root of a volumes is SERVERNAME/SYS:, change that
  597. // to SERVERNAME/SYS:/
  598. i := pos (':',dir);
  599. if (i > 0) then
  600. if i = Length (dir) then dir := dir + '/' else
  601. if dir [i+1] <> '/' then insert ('/',dir,i+1);
  602. END ELSE
  603. InOutRes := 1;
  604. end;
  605. {*****************************************************************************
  606. Thread Handling
  607. *****************************************************************************}
  608. procedure InitFPU;assembler;
  609. asm
  610. fninit
  611. fldcw fpucw
  612. end;
  613. { if return-value is <> 0, netware shows the message
  614. Unload Anyway ?
  615. To Disable unload at all, SetNLMDontUnloadFlag can be used on
  616. Netware >= 4.0 }
  617. function CheckFunction : longint; CDECL; [public,alias: 'FPC_NW_CHECKFUNCTION'];
  618. var oldTG:longint;
  619. oldPtr: pointer;
  620. begin
  621. if assigned (NetwareCheckFunction) then
  622. begin
  623. { this function is called without clib context, to allow clib
  624. calls, we set the thread group id before calling the
  625. user-function }
  626. oldTG := _SetThreadGroupID (NetwareMainThreadGroupID);
  627. { to allow use of threadvars, we simply set the threadvar-memory
  628. from the main thread }
  629. if assigned (SetThreadDataAreaPtr) then
  630. oldPtr := SetThreadDataAreaPtr (NIL); { nil means main threadvars }
  631. result := 0;
  632. NetwareCheckFunction (result);
  633. if assigned (SetThreadDataAreaPtr) then
  634. SetThreadDataAreaPtr (oldPtr);
  635. _SetThreadGroupID (oldTG);
  636. end else
  637. result := 0;
  638. end;
  639. {$ifdef StdErrToConsole}
  640. var ConsoleBuff : array [0..512] of char;
  641. Function ConsoleWrite(Var F: TextRec): Integer;
  642. var
  643. i : longint;
  644. Begin
  645. if F.BufPos>0 then
  646. begin
  647. if F.BufPos>sizeof(ConsoleBuff)-1 then
  648. i:=sizeof(ConsoleBuff)-1
  649. else
  650. i:=F.BufPos;
  651. Move(F.BufPtr^,ConsoleBuff,i);
  652. ConsoleBuff[i] := #0;
  653. ConsolePrintf(@ConsoleBuff[0]);
  654. end;
  655. F.BufPos:=0;
  656. ConsoleWrite := 0;
  657. End;
  658. Function ConsoleClose(Var F: TextRec): Integer;
  659. begin
  660. ConsoleClose:=0;
  661. end;
  662. Function ConsoleOpen(Var F: TextRec): Integer;
  663. Begin
  664. TextRec(F).InOutFunc:=@ConsoleWrite;
  665. TextRec(F).FlushFunc:=@ConsoleWrite;
  666. TextRec(F).CloseFunc:=@ConsoleClose;
  667. ConsoleOpen:=0;
  668. End;
  669. procedure AssignStdErrConsole(Var T: Text);
  670. begin
  671. Assign(T,'');
  672. TextRec(T).OpenFunc:=@ConsoleOpen;
  673. Rewrite(T);
  674. end;
  675. {$endif}
  676. { this will be called if the nlm is unloaded. It will NOT be
  677. called if the program exits i.e. with halt.
  678. Halt (or _exit) can not be called from this callback procedure }
  679. procedure TermSigHandler (Sig:longint); CDecl;
  680. var oldTG : longint;
  681. oldPtr: pointer;
  682. begin
  683. oldTG := _SetThreadGroupID (NetwareMainThreadGroupID); { this is only needed for nw 3.11 }
  684. { _GetThreadDataAreaPtr will not be valid because the signal
  685. handler is called by netware with a differnt thread. To avoid
  686. problems in the exit routines, we set the data of the main thread
  687. here }
  688. if assigned (SetThreadDataAreaPtr) then
  689. oldPtr := SetThreadDataAreaPtr (NIL); { nil means main thread }
  690. SigTermHandlerActive := true; { to avoid that system_exit calls _exit }
  691. do_exit; { calls finalize units }
  692. if assigned (SetThreadDataAreaPtr) then
  693. SetThreadDataAreaPtr (oldPtr);
  694. _SetThreadGroupID (oldTG);
  695. end;
  696. procedure SysInitStdIO;
  697. begin
  698. { Setup stdin, stdout and stderr }
  699. StdInputHandle := _fileno (LONGINT (_GetStdIn^)); // GetStd** returns **FILE !
  700. StdOutputHandle:= _fileno (LONGINT (_GetStdOut^));
  701. StdErrorHandle := _fileno (LONGINT (_GetStdErr^));
  702. OpenStdIO(Input,fmInput,StdInputHandle);
  703. OpenStdIO(Output,fmOutput,StdOutputHandle);
  704. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  705. {$ifdef StdErrToConsole}
  706. AssignStdErrConsole(StdErr);
  707. {$else}
  708. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  709. {$endif}
  710. end;
  711. {*****************************************************************************
  712. SystemUnit Initialization
  713. *****************************************************************************}
  714. Begin
  715. StackBottom := SPtr - StackLength;
  716. SigTermHandlerActive := false;
  717. NetwareCheckFunction := nil;
  718. NetwareMainThreadGroupID := _GetThreadGroupID;
  719. _Signal (_SIGTERM, @TermSigHandler);
  720. {$ifdef useLongNamespaceByDefault}
  721. if _getenv ('FPC_DISABLE_LONG_NAMESPACE') = nil then
  722. begin
  723. if _SetCurrentNameSpace (NW_NS_LONG) <> 255 then
  724. begin
  725. if _SetTargetNamespace (NW_NS_LONG) <> 255 then
  726. LFNSupport := true
  727. else
  728. _SetCurrentNameSpace (NW_NS_DOS);
  729. end;
  730. end;
  731. {$endif useLongNamespaceByDefault}
  732. { Setup heap }
  733. InitHeap;
  734. SysInitExceptions;
  735. { Reset IO Error }
  736. InOutRes:=0;
  737. (* This should be changed to a real value during *)
  738. (* thread driver initialization if appropriate. *)
  739. ThreadID := 1;
  740. SysInitStdIO;
  741. {Delphi Compatible}
  742. IsLibrary := FALSE;
  743. IsConsole := TRUE;
  744. ExitCode := 0;
  745. {$ifdef HASVARIANT}
  746. initvariantmanager;
  747. {$endif HASVARIANT}
  748. End.
  749. {
  750. $Log$
  751. Revision 1.24 2004-08-01 20:02:48 armin
  752. * changed dir separator from \ to /
  753. * long namespace by default
  754. * dos.exec implemented
  755. * getenv ('PATH') is now supported
  756. * changed FExpand to global version
  757. * fixed heaplist growth error
  758. * support SysOSFree
  759. * stackcheck was without saveregisters
  760. * fpc can compile itself on netware
  761. Revision 1.23 2004/07/30 15:05:25 armin
  762. make netware rtl compilable under 1.9.5
  763. Revision 1.22 2004/06/17 16:16:14 peter
  764. * New heapmanager that releases memory back to the OS, donated
  765. by Micha Nelissen
  766. Revision 1.21 2004/01/20 23:11:20 hajny
  767. * ExecuteProcess fixes, ProcessID and ThreadID added
  768. Revision 1.20 2003/10/25 23:43:59 hajny
  769. * THandle in sysutils common using System.THandle
  770. Revision 1.19 2003/10/17 22:12:02 olle
  771. * changed i386 to cpui386
  772. Revision 1.18 2003/09/27 11:52:35 peter
  773. * sbrk returns pointer
  774. Revision 1.17 2003/03/25 18:17:54 armin
  775. * support for fcl, support for linking without debug info
  776. * renamed winsock2 to winsock for win32 compatinility
  777. * new sockets unit for netware
  778. * changes for compiler warnings
  779. Revision 1.16 2003/02/15 19:12:54 armin
  780. * changes for new threadvar support
  781. Revision 1.15 2002/10/13 09:28:45 florian
  782. + call to initvariantmanager inserted
  783. Revision 1.14 2002/09/07 16:01:21 peter
  784. * old logs removed and tabs fixed
  785. Revision 1.13 2002/07/01 16:29:05 peter
  786. * sLineBreak changed to normal constant like Kylix
  787. Revision 1.12 2002/04/15 18:47:34 carl
  788. + reinstate novell stack checking
  789. Revision 1.11 2002/04/12 17:40:11 carl
  790. + generic stack checking
  791. Revision 1.10 2002/04/01 15:20:08 armin
  792. + unload module no longer shows: Module did not release...
  793. + check-function will no longer be removed when smartlink is on
  794. Revision 1.9 2002/04/01 10:47:31 armin
  795. makefile.fpc for netware
  796. stderr to netware console
  797. free all memory (threadvars and heap) to avoid error message while unloading nlm
  798. Revision 1.8 2002/03/30 09:09:47 armin
  799. + support check-function for netware
  800. Revision 1.7 2002/03/17 17:57:33 armin
  801. + threads and winsock2 implemented
  802. }