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