system.pp 24 KB

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