system.pp 28 KB

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