system.pp 28 KB

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