system.pp 27 KB

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