system.pp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2004 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. System.pp for Netware libc environment
  11. **********************************************************************}
  12. { no stack check in system }
  13. {$S-}
  14. unit system;
  15. interface
  16. {$define netware}
  17. {$define netware_libc}
  18. {$define StdErrToConsole}
  19. {$define autoHeapRelease}
  20. {$define IOpossix}
  21. {$define DisableArrayOfConst}
  22. {$ifdef SYSTEMDEBUG}
  23. {$define SYSTEMEXCEPTIONDEBUG}
  24. {$endif SYSTEMDEBUG}
  25. {$ifdef cpui386}
  26. {$define Set_i386_Exception_handler}
  27. {$endif cpui386}
  28. { include system-independent routine headers }
  29. {$I systemh.inc}
  30. type THandle = DWord;
  31. {Platform specific information}
  32. const
  33. LineEnding = #13#10;
  34. LFNSupport : boolean = false;
  35. DirectorySeparator = '/';
  36. DriveSeparator = ':';
  37. PathSeparator = ';';
  38. { FileNameCaseSensitive is defined separately below!!! }
  39. maxExitCode = $ffff;
  40. { include heap support headers }
  41. {$I heaph.inc}
  42. CONST
  43. { Default filehandles }
  44. UnusedHandle : THandle = -1;
  45. StdInputHandle : THandle = 0;
  46. StdOutputHandle : THandle = 0;
  47. StdErrorHandle : THandle = 0;
  48. FileNameCaseSensitive : boolean = false;
  49. sLineBreak = LineEnding;
  50. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  51. type
  52. TNWCheckFunction = procedure (var code : longint);
  53. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  54. TDLL_Entry_Hook = procedure (dllparam : longint);
  55. VAR
  56. ArgC : INTEGER;
  57. ArgV : ppchar;
  58. NetwareCheckFunction: TNWCheckFunction;
  59. NWLoggerScreen : pointer = nil;
  60. const
  61. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  62. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  63. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  64. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  65. NetwareUnloadProc : pointer = nil; {like exitProc but for nlm unload only}
  66. envp : ppchar = nil;
  67. type
  68. //TSysCloseAllRemainingSemaphores = procedure;
  69. TSysReleaseThreadVars = procedure;
  70. TSysSetThreadDataAreaPtr = function (newPtr:pointer):pointer;
  71. procedure NWSysSetThreadFunctions (atv:TSysReleaseThreadVars;
  72. rtv:TSysReleaseThreadVars;
  73. stdata:TSysSetThreadDataAreaPtr);
  74. procedure ConsolePrintf (s :shortstring);
  75. procedure ConsolePrintf (FormatStr : PCHAR; Param : LONGINT);
  76. procedure ConsolePrintf (FormatStr : PCHAR; Param : pchar);
  77. procedure ConsolePrintf (FormatStr : PCHAR; P1,P2 : LONGINT);
  78. procedure ConsolePrintf (FormatStr : PCHAR; P1,P2,P3 : LONGINT);
  79. procedure ConsolePrintf (FormatStr : PCHAR);
  80. procedure __EnterDebugger; cdecl;
  81. function NWGetCodeStart : pointer; // needed for Lineinfo
  82. function NWGetCodeLength : dword;
  83. function NWGetDataStart : pointer;
  84. function NWGetDataLength : dword;
  85. implementation
  86. { Indicate that stack checking is taken care by OS}
  87. {$DEFINE NO_GENERIC_STACK_CHECK}
  88. { include system independent routines }
  89. {$I system.inc}
  90. { some declarations for Netware API calls }
  91. { I nwlibc.inc}
  92. {$I errno.inc}
  93. {$define INCLUDED_FROM_SYSTEM}
  94. {$I libc.pp}
  95. var
  96. {$ifdef autoHeapRelease}
  97. HeapListAllocResourceTag,
  98. {$endif}
  99. HeapAllocResourceTag : rtag_t;
  100. NLMHandle : pointer;
  101. ReleaseThreadVars : TSysReleaseThreadVars = nil;
  102. AllocateThreadVars: TSysReleaseThreadVars = nil;
  103. SetThreadDataAreaPtr : TSysSetThreadDataAreaPtr = nil;
  104. TerminatingThreadID : dword = 0;
  105. procedure NWSysSetThreadFunctions (atv:TSysReleaseThreadVars;
  106. rtv:TSysReleaseThreadVars;
  107. stdata:TSysSetThreadDataAreaPtr);
  108. begin
  109. AllocateThreadVars := atv;
  110. ReleaseThreadVars := rtv;
  111. SetThreadDataAreaPtr := stdata;
  112. end;
  113. procedure PASCALMAIN;external name 'PASCALMAIN';
  114. procedure fpc_do_exit;external name 'FPC_DO_EXIT';
  115. {*****************************************************************************
  116. System Dependent Exit code
  117. *****************************************************************************}
  118. {$ifdef autoHeapRelease}
  119. procedure FreeSbrkMem; forward;
  120. {$endif}
  121. var SigTermHandlerActive : boolean;
  122. Procedure system_exit;
  123. begin
  124. if TerminatingThreadID <> 0 then
  125. if TerminatingThreadID <> ThreadId then
  126. if TerminatingThreadID <> dword(pthread_self) then
  127. begin
  128. {$ifdef DEBUG_MT}
  129. ConsolePrintf ('Terminating Thread %x because halt was called while Thread %x terminates nlm'#13#10,dword(pthread_self),TerminatingThreadId);
  130. {$endif}
  131. pthread_exit (nil);
  132. // only for the case ExitThread fails
  133. while true do
  134. NXThreadYield;
  135. end;
  136. if assigned (ReleaseThreadVars) then ReleaseThreadVars;
  137. {$ifdef autoHeapRelease}
  138. FreeSbrkMem; { free memory allocated by heapmanager }
  139. {$endif}
  140. if not SigTermHandlerActive then
  141. begin
  142. if Erroraddr <> nil then { otherwise we dont see runtime-errors }
  143. SetScreenMode (0);
  144. _exit (ExitCode);
  145. end;
  146. end;
  147. {*****************************************************************************
  148. Stack check code
  149. *****************************************************************************}
  150. const StackErr : boolean = false;
  151. procedure int_stackcheck(stack_size:Cardinal);[saveregisters,public,alias:'FPC_STACKCHECK'];
  152. {
  153. called when trying to get local stack if the compiler directive $S
  154. is set this function must preserve all registers
  155. With a 5k byte safe area used to write to StdIo and some libc
  156. functions without crossing the stack boundary
  157. }
  158. begin
  159. if StackErr then exit; // avoid recursive calls
  160. if stackavail > stack_size + 5120 then exit; // we really need that much, at least on nw6.5
  161. StackErr := true;
  162. HandleError (202);
  163. end;
  164. {*****************************************************************************
  165. ParamStr/Randomize
  166. *****************************************************************************}
  167. { number of args }
  168. function paramcount : longint;
  169. begin
  170. paramcount := argc - 1;
  171. end;
  172. { argument number l }
  173. function paramstr(l : longint) : string;
  174. begin
  175. if (l>=0) and (l+1<=argc) then
  176. begin
  177. paramstr:=strpas(argv[l]);
  178. if l = 0 then // fix nlm path
  179. begin
  180. for l := 1 to length (paramstr) do
  181. if paramstr[l] = '\' then paramstr[l] := '/';
  182. end;
  183. end else
  184. paramstr:='';
  185. end;
  186. { set randseed to a new pseudo random value }
  187. procedure randomize;
  188. begin
  189. randseed := time (NIL);
  190. end;
  191. {*****************************************************************************
  192. Heap Management
  193. *****************************************************************************}
  194. var
  195. int_heap : pointer;external name 'HEAP';
  196. int_heapsize : longint;external name 'HEAPSIZE';
  197. { first address of heap }
  198. function getheapstart:pointer;
  199. begin
  200. getheapstart := int_heap;
  201. end;
  202. { current length of heap }
  203. function getheapsize:longint;
  204. begin
  205. getheapsize := int_heapsize;
  206. end;
  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. HeapSbrkReleased : boolean = false;
  214. { function to allocate size bytes more for the program }
  215. { must return the first address of new data space or nil if fail }
  216. { for netware all allocated blocks are saved to free them at }
  217. { exit (to avoid message "Module did not release xx resources") }
  218. Function SysOSAlloc(size : longint):pointer;
  219. var P2 : POINTER;
  220. i : longint;
  221. Slept : longint;
  222. begin
  223. if HeapSbrkReleased then
  224. begin
  225. ConsolePrintf ('Error: SysOSFree called after all heap memory was released'#13#10);
  226. exit(nil);
  227. end;
  228. SysOSAlloc := _Alloc (size,HeapAllocResourceTag);
  229. if SysOSAlloc <> nil then begin
  230. if HeapSbrkBlockList = nil then
  231. begin
  232. Pointer (HeapSbrkBlockList) := _Alloc (sizeof (HeapSbrkBlockList^),HeapListAllocResourceTag);
  233. if HeapSbrkBlockList = nil then
  234. begin
  235. _free (SysOSAlloc);
  236. SysOSAlloc := nil;
  237. exit;
  238. end;
  239. fillchar (HeapSbrkBlockList^,sizeof(HeapSbrkBlockList^),0);
  240. HeapSbrkAllocated := HeapInitialMaxBlocks;
  241. end;
  242. if (HeapSbrkLastUsed > 0) then
  243. for i := 1 to HeapSbrkLastUsed do
  244. if (HeapSbrkBlockList^[i] = nil) then
  245. begin // reuse free slot
  246. HeapSbrkBlockList^[i] := SysOSAlloc;
  247. exit;
  248. end;
  249. if (HeapSbrkLastUsed = HeapSbrkAllocated) then
  250. begin { grow }
  251. slept := 0;
  252. p2 := _ReallocSleepOK (HeapSbrkBlockList, (HeapSbrkAllocated + HeapInitialMaxBlocks) * sizeof(pointer),HeapListAllocResourceTag,Slept);
  253. if p2 = nil then // should we better terminate with error ?
  254. begin
  255. _free (SysOSAlloc);
  256. SysOSAlloc := nil;
  257. exit;
  258. end;
  259. HeapSbrkBlockList := p2;
  260. inc (HeapSbrkAllocated, HeapInitialMaxBlocks);
  261. end;
  262. inc (HeapSbrkLastUsed);
  263. HeapSbrkBlockList^[HeapSbrkLastUsed] := SysOSAlloc;
  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. HeapSbrkReleased := true;
  280. {ReturnResourceTag(HeapAllocResourceTag,1);
  281. ReturnResourceTag(HeapListAllocResourceTag,1); not in netware.imp, seems to be not needed}
  282. end;
  283. {*****************************************************************************
  284. OS Memory allocation / deallocation
  285. ****************************************************************************}
  286. {$define HAS_SYSOSFREE}
  287. procedure SysOSFree(p: pointer; size: ptrint);
  288. var i : longint;
  289. begin
  290. if HeapSbrkReleased then
  291. begin
  292. ConsolePrintf ('Error: SysOSFree called after all heap memory was released'#13#10);
  293. end else
  294. if (HeapSbrkLastUsed > 0) then
  295. for i := 1 to HeapSbrkLastUsed do
  296. if (HeapSbrkBlockList^[i] = p) then
  297. begin
  298. _free (p);
  299. HeapSbrkBlockList^[i] := nil;
  300. exit;
  301. end;
  302. HandleError (204); // invalid pointer operation
  303. end;
  304. {$else autoHeapRelease}
  305. {$define HAS_SYSOSFREE}
  306. procedure SysOSFree(p: pointer; size: ptrint);
  307. begin
  308. _free (p);
  309. end;
  310. function SysOSAlloc(size: ptrint): pointer;
  311. begin
  312. SysOSAlloc := _Alloc(size,HeapAllocResourceTag);
  313. end;
  314. {$endif autoHeapRelease}
  315. { include standard heap management }
  316. {$I heap.inc}
  317. {****************************************************************************
  318. Low level File Routines
  319. All these functions can set InOutRes on errors
  320. ****************************************************************************}
  321. PROCEDURE NW2PASErr (Err : LONGINT);
  322. BEGIN
  323. if Err = 0 then { Else it will go through all the cases }
  324. exit;
  325. case Err of
  326. Sys_ENFILE,
  327. Sys_EMFILE : Inoutres:=4;
  328. Sys_ENOENT : Inoutres:=2;
  329. Sys_EBADF : Inoutres:=6;
  330. Sys_ENOMEM,
  331. Sys_EFAULT : Inoutres:=217;
  332. Sys_EINVAL : Inoutres:=218;
  333. Sys_EPIPE,
  334. Sys_EINTR,
  335. Sys_EIO,
  336. Sys_EAGAIN,
  337. Sys_ENOSPC : Inoutres:=101;
  338. Sys_ENAMETOOLONG,
  339. Sys_ELOOP,
  340. Sys_ENOTDIR : Inoutres:=3;
  341. Sys_EROFS,
  342. Sys_EEXIST,
  343. Sys_EACCES : Inoutres:=5;
  344. Sys_EBUSY : Inoutres:=162
  345. else begin
  346. Writeln (stderr,'NW2PASErr: unknown error ',err);
  347. libc_perror('NW2PASErr');
  348. Inoutres := Err;
  349. end;
  350. end;
  351. END;
  352. procedure Errno2Inoutres;
  353. begin
  354. NW2PASErr (___errno^);
  355. end;
  356. procedure SetFileError (VAR Err : LONGINT);
  357. begin
  358. if Err >= 0 then
  359. InOutRes := 0
  360. else begin
  361. // libc_perror ('SetFileError');
  362. Err := ___errno^;
  363. NW2PASErr (Err);
  364. Err := 0;
  365. end;
  366. end;
  367. { close a file from the handle value }
  368. procedure do_close(handle : thandle);
  369. VAR res : LONGINT;
  370. begin
  371. {$ifdef IOpossix}
  372. res := FpClose (handle);
  373. {$else}
  374. res := _fclose (_TFILE(handle));
  375. {$endif}
  376. IF res <> 0 THEN
  377. SetFileError (res)
  378. ELSE
  379. InOutRes := 0;
  380. end;
  381. procedure do_erase(p : pchar);
  382. VAR res : LONGINT;
  383. begin
  384. res := unlink (p);
  385. IF Res < 0 THEN
  386. SetFileError (res)
  387. ELSE
  388. InOutRes := 0;
  389. end;
  390. procedure do_rename(p1,p2 : pchar);
  391. VAR res : LONGINT;
  392. begin
  393. res := rename (p1,p2);
  394. IF Res < 0 THEN
  395. SetFileError (res)
  396. ELSE
  397. InOutRes := 0
  398. end;
  399. function do_write(h:thandle;addr:pointer;len : longint) : longint;
  400. var res : LONGINT;
  401. begin
  402. {$ifdef IOpossix}
  403. res := Fpwrite (h,addr,len);
  404. {$else}
  405. res := _fwrite (addr,1,len,_TFILE(h));
  406. {$endif}
  407. if res > 0 then
  408. InOutRes := 0
  409. else
  410. SetFileError (res);
  411. do_write := res;
  412. NXThreadYield;
  413. end;
  414. function do_read(h:thandle;addr:pointer;len : longint) : longint;
  415. VAR res : LONGINT;
  416. begin
  417. {$ifdef IOpossix}
  418. res := Fpread (h,addr,len);
  419. {$else}
  420. res := _fread (addr,1,len,_TFILE(h));
  421. {$endif}
  422. IF res > 0 THEN
  423. InOutRes := 0
  424. ELSE
  425. SetFileError (res);
  426. do_read := res;
  427. NXThreadYield;
  428. end;
  429. function do_filepos(handle : thandle) : longint;
  430. var res : LONGINT;
  431. begin
  432. InOutRes:=1;
  433. {$ifdef IOpossix}
  434. res := Fptell (handle);
  435. {$else}
  436. res := _ftell (_TFILE(handle));
  437. {$endif}
  438. if res < 0 THEN
  439. SetFileError (res)
  440. else
  441. InOutRes := 0;
  442. do_filepos := res;
  443. end;
  444. procedure do_seek(handle:thandle;pos : longint);
  445. VAR res : LONGINT;
  446. begin
  447. {$ifdef IOpossix}
  448. res := Fplseek (handle,pos, SEEK_SET);
  449. {$else}
  450. res := _fseek (_TFILE(handle),pos, SEEK_SET);
  451. {$endif}
  452. IF res >= 0 THEN
  453. InOutRes := 0
  454. ELSE
  455. SetFileError (res);
  456. end;
  457. function do_seekend(handle:thandle):longint;
  458. VAR res : LONGINT;
  459. begin
  460. {$ifdef IOpossix}
  461. res := Fplseek (handle,0, SEEK_END);
  462. {$else}
  463. res := _fseek (_TFILE(handle),0, SEEK_END);
  464. {$endif}
  465. IF res >= 0 THEN
  466. InOutRes := 0
  467. ELSE
  468. SetFileError (res);
  469. do_seekend := res;
  470. end;
  471. function do_filesize(handle : thandle) : longint;
  472. VAR res : LONGINT;
  473. statbuf : TStat;
  474. begin
  475. {$ifdef IOpossix}
  476. res := Fpfstat (handle, statbuf);
  477. {$else}
  478. res := _fstat (_fileno (_TFILE(handle)), statbuf); // was _filelength for clib
  479. {$endif}
  480. if res <> 0 then
  481. begin
  482. SetFileError (Res);
  483. do_filesize := -1;
  484. end else
  485. begin
  486. InOutRes := 0;
  487. do_filesize := statbuf.st_size;
  488. end;
  489. end;
  490. { truncate at a given position }
  491. procedure do_truncate (handle:thandle;pos:longint);
  492. VAR res : LONGINT;
  493. begin
  494. {$ifdef IOpossix}
  495. res := ftruncate (handle,pos);
  496. {$else}
  497. res := _ftruncate (_fileno (_TFILE(handle)),pos);
  498. {$endif}
  499. IF res <> 0 THEN
  500. SetFileError (res)
  501. ELSE
  502. InOutRes := 0;
  503. end;
  504. {$ifdef IOpossix}
  505. // mostly stolen from syslinux
  506. procedure do_open(var f;p:pchar;flags:longint);
  507. {
  508. filerec and textrec have both handle and mode as the first items so
  509. they could use the same routine for opening/creating.
  510. when (flags and $10) the file will be append
  511. when (flags and $100) the file will be truncate/rewritten
  512. when (flags and $1000) there is no check for close (needed for textfiles)
  513. }
  514. var
  515. oflags : longint;
  516. Begin
  517. { close first if opened }
  518. if ((flags and $10000)=0) then
  519. begin
  520. case FileRec(f).mode of
  521. fminput,fmoutput,fminout : Do_Close(FileRec(f).Handle);
  522. fmclosed : ;
  523. else
  524. begin
  525. inoutres:=102; {not assigned}
  526. exit;
  527. end;
  528. end;
  529. end;
  530. { reset file Handle }
  531. FileRec(f).Handle:=UnusedHandle;
  532. { We do the conversion of filemodes here, concentrated on 1 place }
  533. case (flags and 3) of
  534. 0 : begin
  535. oflags := O_RDONLY;
  536. filerec(f).mode := fminput;
  537. end;
  538. 1 : begin
  539. oflags := O_WRONLY;
  540. filerec(f).mode := fmoutput;
  541. end;
  542. 2 : begin
  543. oflags := O_RDWR;
  544. filerec(f).mode := fminout;
  545. end;
  546. end;
  547. if (flags and $1000)=$1000 then
  548. oflags:=oflags or (O_CREAT or O_TRUNC)
  549. else
  550. if (flags and $100)=$100 then
  551. oflags:=oflags or (O_APPEND);
  552. { empty name is special }
  553. if p[0]=#0 then
  554. begin
  555. case FileRec(f).mode of
  556. fminput :
  557. FileRec(f).Handle:=StdInputHandle;
  558. fminout, { this is set by rewrite }
  559. fmoutput :
  560. FileRec(f).Handle:=StdOutputHandle;
  561. fmappend :
  562. begin
  563. FileRec(f).Handle:=StdOutputHandle;
  564. FileRec(f).mode:=fmoutput; {fool fmappend}
  565. end;
  566. end;
  567. exit;
  568. end;
  569. { real open call }
  570. ___errno^ := 0;
  571. FileRec(f).Handle := open(p,oflags,438);
  572. { open somtimes returns > -1 but errno was set }
  573. if (___errno^ <> 0) or (longint(FileRec(f).Handle) < 0) then
  574. if (___errno^=Sys_EROFS) and ((OFlags and O_RDWR)<>0) then
  575. begin // i.e. for cd-rom
  576. Oflags:=Oflags and not(O_RDWR);
  577. FileRec(f).Handle := open(p,oflags,438);
  578. end;
  579. if (___errno^ <> 0) or (longint(FileRec(f).Handle) < 0) then
  580. Errno2Inoutres
  581. else
  582. InOutRes := 0;
  583. end;
  584. {$else}
  585. procedure do_open(var f;p:pchar;flags:longint);
  586. {
  587. filerec and textrec have both handle and mode as the first items so
  588. they could use the same routine for opening/creating.
  589. when (flags and $10) the file will be append
  590. when (flags and $100) the file will be truncate/rewritten
  591. when (flags and $1000) there is no check for close (needed for textfiles)
  592. }
  593. var
  594. oflags : string[10];
  595. Begin
  596. { close first if opened }
  597. if ((flags and $10000)=0) then
  598. begin
  599. case FileRec(f).mode of
  600. fminput,fmoutput,fminout : Do_Close(FileRec(f).Handle);
  601. fmclosed : ;
  602. else
  603. begin
  604. inoutres:=102; {not assigned}
  605. exit;
  606. end;
  607. end;
  608. end;
  609. { reset file Handle }
  610. FileRec(f).Handle:=UnusedHandle;
  611. { We do the conversion of filemodes here, concentrated on 1 place }
  612. case (flags and 3) of
  613. 0 : begin
  614. oflags := 'rb'#0;
  615. filerec(f).mode := fminput;
  616. end;
  617. 1 : begin
  618. if (flags and $1000)=$1000 then
  619. oflags := 'w+b' else
  620. oflags := 'wb';
  621. filerec(f).mode := fmoutput;
  622. end;
  623. 2 : begin
  624. if (flags and $1000)=$1000 then
  625. oflags := 'w+' else
  626. oflags := 'r+';
  627. filerec(f).mode := fminout;
  628. end;
  629. end;
  630. {if (flags and $1000)=$1000 then
  631. oflags:=oflags or (O_CREAT or O_TRUNC)
  632. else
  633. if (flags and $100)=$100 then
  634. oflags:=oflags or (O_APPEND);}
  635. { empty name is special }
  636. if p[0]=#0 then
  637. begin
  638. case FileRec(f).mode of
  639. fminput :
  640. FileRec(f).Handle:=StdInputHandle;
  641. fminout, { this is set by rewrite }
  642. fmoutput :
  643. FileRec(f).Handle:=StdOutputHandle;
  644. fmappend :
  645. begin
  646. FileRec(f).Handle:=StdOutputHandle;
  647. FileRec(f).mode:=fmoutput; {fool fmappend}
  648. end;
  649. end;
  650. exit;
  651. end;
  652. { real open call }
  653. FileRec(f).Handle := THandle (_fopen (p,@oflags[1]));//_open(p,oflags,438);
  654. //WriteLn ('_open (',p,') returned ',ErrNo, 'Handle: ',FileRec(f).Handle);
  655. // errno does not seem to be set on succsess ??
  656. {IF FileRec(f).Handle < 0 THEN
  657. if (ErrNo=Sys_EROFS) and ((OFlags and O_RDWR)<>0) then
  658. begin // i.e. for cd-rom
  659. Oflags:=Oflags and not(O_RDWR);
  660. FileRec(f).Handle := _open(p,oflags,438);
  661. end;}
  662. if FileRec(f).Handle = 0 then
  663. Errno2Inoutres
  664. else
  665. InOutRes := 0;
  666. End;
  667. {$endif}
  668. function do_isdevice(handle:THandle):boolean;
  669. begin
  670. {$ifdef IOpossix}
  671. do_isdevice := (Fpisatty (handle) > 0);
  672. {$else}
  673. do_isdevice := (isatty (_fileno(_TFILE(handle))) > 0);
  674. {$endif}
  675. end;
  676. {*****************************************************************************
  677. UnTyped File Handling
  678. *****************************************************************************}
  679. {$i file.inc}
  680. {*****************************************************************************
  681. Typed File Handling
  682. *****************************************************************************}
  683. {$i typefile.inc}
  684. {*****************************************************************************
  685. Text File Handling
  686. *****************************************************************************}
  687. {$i text.inc}
  688. {*****************************************************************************
  689. Directory Handling
  690. *****************************************************************************}
  691. procedure mkdir(const s : string);[IOCheck];
  692. var S2 : STRING;
  693. Res: LONGINT;
  694. BEGIN
  695. S2 := S;
  696. IF Length (S2) = 255 THEN DEC (BYTE(S2[0]));
  697. S2 := S2 + #0;
  698. Res := FpMkdir (@S2[1],S_IRWXU);
  699. if Res = 0 then
  700. InOutRes:=0
  701. else
  702. SetFileError (Res);
  703. end;
  704. procedure rmdir(const s : string);[IOCheck];
  705. VAR S2 : STRING;
  706. Res: LONGINT;
  707. BEGIN
  708. S2 := S;
  709. IF Length (S2) = 255 THEN DEC (BYTE(S2[0]));
  710. S2 := S2 + #0;
  711. Res := FpRmdir (@S2[1]);
  712. IF Res = 0 THEN
  713. InOutRes:=0
  714. ELSE
  715. SetFileError (Res);
  716. end;
  717. procedure chdir(const s : string);[IOCheck];
  718. VAR S2 : STRING;
  719. Res: LONGINT;
  720. begin
  721. S2 := S;
  722. IF Length (S2) = 255 THEN DEC (BYTE(S2[0]));
  723. S2 := S2 + #0;
  724. Res := FpChdir (@S2[1]);
  725. IF Res = 0 THEN
  726. InOutRes:=0
  727. ELSE
  728. SetFileError (Res);
  729. end;
  730. procedure getdir(drivenr : byte;var dir : shortstring);
  731. var P : array [0..255] of CHAR;
  732. i : LONGINT;
  733. begin
  734. P[0] := #0;
  735. getcwdpath(@P,nil,0); // getcwd does not return volume, getcwdpath does
  736. i := libc_strlen (P);
  737. if i > 0 then
  738. begin
  739. Move (P, dir[1], i);
  740. BYTE(dir[0]) := i;
  741. For i := 1 to length (dir) do
  742. if dir[i] = '\' then dir [i] := '/';
  743. // fix / after volume, the compiler needs that
  744. // normaly root of a volumes is SERVERNAME/SYS:, change that
  745. // to SERVERNAME/SYS:/
  746. i := pos (':',dir);
  747. if (i > 0) then
  748. if i = Length (dir) then dir := dir + '/' else
  749. if dir [i+1] <> '/' then insert ('/',dir,i+1);
  750. end else
  751. InOutRes := 1;
  752. end;
  753. {*****************************************************************************
  754. Thread Handling
  755. *****************************************************************************}
  756. procedure InitFPU;assembler;
  757. asm
  758. fninit
  759. fldcw fpucw
  760. end;
  761. { if return-value is <> 0, netware shows the message
  762. Unload Anyway ?
  763. To Disable unload at all, SetNLMDontUnloadFlag can be used on
  764. Netware >= 4.0 }
  765. function CheckFunction : longint; CDECL; [public,alias: '_NonAppCheckUnload'];
  766. var oldPtr : pointer;
  767. begin
  768. //ConsolePrintf ('CheckFunction'#13#10);
  769. if assigned (NetwareCheckFunction) then
  770. begin
  771. if assigned (SetThreadDataAreaPtr) then
  772. oldPtr := SetThreadDataAreaPtr (NIL); { nil means main thread }
  773. result := 0;
  774. NetwareCheckFunction (result);
  775. if assigned (SetThreadDataAreaPtr) then
  776. SetThreadDataAreaPtr (oldPtr);
  777. end else
  778. result := 0;
  779. end;
  780. procedure ConsolePrintf (s : shortstring);
  781. begin
  782. if length(s) > 254 then
  783. byte(s[0]) := 254;
  784. s := s + #0;
  785. ConsolePrintf (@s[1]);
  786. end;
  787. procedure ConsolePrintf (FormatStr : PCHAR);
  788. begin
  789. if NWLoggerScreen = nil then
  790. NWLoggerScreen := getnetwarelogger;
  791. if NWLoggerScreen <> nil then
  792. screenprintf (NWLoggerScreen,FormatStr);
  793. end;
  794. procedure ConsolePrintf (FormatStr : PCHAR; Param : LONGINT);
  795. begin
  796. if NWLoggerScreen = nil then
  797. NWLoggerScreen := getnetwarelogger;
  798. if NWLoggerScreen <> nil then
  799. screenprintf (NWLoggerScreen,FormatStr,Param);
  800. end;
  801. procedure ConsolePrintf (FormatStr : PCHAR; Param : pchar);
  802. begin
  803. ConsolePrintf (FormatStr,longint(Param));
  804. end;
  805. procedure ConsolePrintf (FormatStr : PCHAR; P1,P2 : LONGINT);
  806. begin
  807. if NWLoggerScreen = nil then
  808. NWLoggerScreen := getnetwarelogger;
  809. if NWLoggerScreen <> nil then
  810. screenprintf (NWLoggerScreen,FormatStr,P1,P2);
  811. end;
  812. procedure ConsolePrintf (FormatStr : PCHAR; P1,P2,P3 : LONGINT);
  813. begin
  814. if NWLoggerScreen = nil then
  815. NWLoggerScreen := getnetwarelogger;
  816. if NWLoggerScreen <> nil then
  817. screenprintf (NWLoggerScreen,FormatStr,P1,P2,P3);
  818. end;
  819. procedure __EnterDebugger;cdecl;external '!netware' name 'EnterDebugger';
  820. var NWUts : Tutsname;
  821. procedure getCodeAddresses;
  822. begin
  823. if Fpuname(NWUts) < 0 then
  824. FillChar(NWuts,sizeof(NWUts),0);
  825. end;
  826. function NWGetCodeStart : pointer;
  827. begin
  828. NWGetCodeStart := NWUts.codeoffset;
  829. NXThreadYield;
  830. end;
  831. function NWGetCodeLength : dword;
  832. begin
  833. NWGetCodeLength := NWUts.codelength;
  834. NXThreadYield;
  835. end;
  836. function NWGetDataStart : pointer;
  837. begin
  838. NWGetDataStart := NWUts.dataoffset;
  839. NXThreadYield;
  840. end;
  841. function NWGetDataLength : dword;
  842. begin
  843. NWGetDataLength := NWUts.datalength;
  844. NXThreadYield;
  845. end;
  846. {$ifdef StdErrToConsole}
  847. var ConsoleBuff : array [0..512] of char;
  848. Function ConsoleWrite(Var F: TextRec): Integer;
  849. var
  850. i : longint;
  851. Begin
  852. if F.BufPos>0 then
  853. begin
  854. if F.BufPos>sizeof(ConsoleBuff)-1 then
  855. i:=sizeof(ConsoleBuff)-1
  856. else
  857. i:=F.BufPos;
  858. Move(F.BufPtr^,ConsoleBuff,i);
  859. ConsoleBuff[i] := #0;
  860. screenprintf (NWLoggerScreen,@ConsoleBuff);
  861. end;
  862. F.BufPos:=0;
  863. ConsoleWrite := 0;
  864. NXThreadYield;
  865. End;
  866. Function ConsoleClose(Var F: TextRec): Integer;
  867. begin
  868. ConsoleClose:=0;
  869. end;
  870. Function ConsoleOpen(Var F: TextRec): Integer;
  871. Begin
  872. TextRec(F).InOutFunc:=@ConsoleWrite;
  873. TextRec(F).FlushFunc:=@ConsoleWrite;
  874. TextRec(F).CloseFunc:=@ConsoleClose;
  875. ConsoleOpen:=0;
  876. End;
  877. procedure AssignStdErrConsole(Var T: Text);
  878. begin
  879. Assign(T,'');
  880. TextRec(T).OpenFunc:=@ConsoleOpen;
  881. Rewrite(T);
  882. end;
  883. {$endif}
  884. { this will be called if the nlm is unloaded. It will NOT be
  885. called if the program exits i.e. with halt.
  886. Halt (or _exit) can not be called from this callback procedure }
  887. procedure TermSigHandler (Sig:longint); CDecl;
  888. var oldPtr : pointer;
  889. current_exit : procedure;
  890. begin
  891. { Threadvar Pointer will not be valid because the signal
  892. handler is called by netware with a differnt thread. To avoid
  893. problems in the exit routines, we set the data of the main thread
  894. here }
  895. if assigned (SetThreadDataAreaPtr) then
  896. oldPtr := SetThreadDataAreaPtr (NIL); { nil means main thread }
  897. TerminatingThreadID := dword(pthread_self);
  898. {we need to finalize winock to release threads
  899. waiting on a blocking socket call. If that thread
  900. calls halt, we have to avoid that unit finalization
  901. is called by that thread because we are doing it
  902. here
  903. like the old exitProc, mainly to allow winsock to release threads
  904. blocking in a winsock calls }
  905. while NetwareUnloadProc<>nil Do
  906. Begin
  907. InOutRes:=0;
  908. current_exit:=tProcedure(NetwareUnloadProc);
  909. NetwareUnloadProc:=nil;
  910. current_exit();
  911. NXThreadYield;
  912. //hadExitProc := true;
  913. End;
  914. SigTermHandlerActive := true; { to avoid that system_exit calls _exit }
  915. do_exit; { calls finalize units }
  916. if assigned (SetThreadDataAreaPtr) then
  917. SetThreadDataAreaPtr (oldPtr);
  918. end;
  919. procedure SysInitStdIO;
  920. begin
  921. { Setup stdin, stdout and stderr }
  922. {$ifdef IOpossix}
  923. StdInputHandle := THandle (fileno (___stdin^)); // GetStd** returns **FILE !
  924. StdOutputHandle:= THandle (fileno (___stdout^));
  925. StdErrorHandle := THandle (fileno (___stderr^));
  926. {$else}
  927. StdInputHandle := THandle (___stdin^); // GetStd** returns **FILE !
  928. StdOutputHandle:= THandle (___stdout^);
  929. StdErrorHandle := THandle (___stderr^);
  930. {$endif}
  931. OpenStdIO(Input,fmInput,StdInputHandle);
  932. OpenStdIO(Output,fmOutput,StdOutputHandle);
  933. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  934. {$ifdef StdErrToConsole}
  935. AssignStdErrConsole(StdErr);
  936. {$else}
  937. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  938. {$endif}
  939. end;
  940. // this is called by main.as, setup args and call PASCALMAIN
  941. procedure nlm_main (_ArgC : LONGINT; _ArgV : ppchar); cdecl; [public,alias: '_FPC_NLM_Entry'];
  942. BEGIN
  943. ArgC := _ArgC;
  944. ArgV := _ArgV;
  945. isLibrary := false;
  946. PASCALMAIN;
  947. do_exit; // currently not needed
  948. END;
  949. function _DLLMain (hInstDLL:pointer; fdwReason:dword; DLLParam:longint):longbool; cdecl;
  950. [public, alias : '_FPC_DLL_Entry'];
  951. var res : longbool;
  952. begin
  953. {$ifdef DEBUG_MT}
  954. ConsolePrintf ('_FPC_DLL_Entry called');
  955. {$endif}
  956. _DLLMain := false;
  957. isLibrary := true;
  958. case fdwReason of
  959. DLL_ACTUAL_DLLMAIN : _DLLMain := true;
  960. DLL_NLM_STARTUP : begin
  961. //__ConsolePrintf ('DLL_NLM_STARTUP');
  962. if assigned(Dll_Process_Attach_Hook) then
  963. begin
  964. res:=Dll_Process_Attach_Hook(DllParam);
  965. if not res then
  966. exit(false);
  967. end;
  968. PASCALMAIN;
  969. _DLLMain := true;
  970. end;
  971. DLL_NLM_SHUTDOWN : begin
  972. //__ConsolePrintf ('DLL_NLM_SHUTDOWN');
  973. TermSigHandler(0);
  974. _DLLMain := true;
  975. end;
  976. { standard DllMain() messages... }
  977. DLL_THREAD_ATTACH,
  978. DLL_PROCESS_ATTACH : begin
  979. //__ConsolePrintf ('DLL_PROCESS/THREAD_ATTACH');
  980. if assigned(AllocateThreadVars) then
  981. AllocateThreadVars;
  982. if assigned(Dll_Thread_Attach_Hook) then
  983. Dll_Thread_Attach_Hook(DllParam);
  984. _DLLMain := true;
  985. end;
  986. DLL_THREAD_DETACH,
  987. DLL_PROCESS_DETACH : begin
  988. //__ConsolePrintf ('DLL_PROCESS/THREAD_DETACH');
  989. if assigned(Dll_Thread_Detach_Hook) then
  990. Dll_Thread_Detach_Hook(DllParam);
  991. if assigned(ReleaseThreadVars) then
  992. ReleaseThreadVars;
  993. _DLLMain := true;
  994. end;
  995. end;
  996. end;
  997. {*****************************************************************************
  998. SystemUnit Initialization
  999. *****************************************************************************}
  1000. Begin
  1001. getCodeAddresses;
  1002. StackBottom := SPtr - StackLength;
  1003. SigTermHandlerActive := false;
  1004. NetwareCheckFunction := nil;
  1005. {$ifdef StdErrToConsole}
  1006. NWLoggerScreen := getnetwarelogger;
  1007. {$endif}
  1008. CheckFunction; // avoid check function to be removed by the linker
  1009. envp := ____environ^;
  1010. NLMHandle := getnlmhandle;
  1011. { allocate resource tags to see what kind of memory i forgot to release }
  1012. HeapAllocResourceTag :=
  1013. AllocateResourceTag(NLMHandle,'Heap Memory',AllocSignature);
  1014. {$ifdef autoHeapRelease}
  1015. HeapListAllocResourceTag :=
  1016. AllocateResourceTag(NLMHandle,'Heap Memory List',AllocSignature);
  1017. {$endif}
  1018. FpSignal (SIGTERM, @TermSigHandler);
  1019. { Setup heap }
  1020. InitHeap;
  1021. SysInitExceptions;
  1022. { Reset IO Error }
  1023. InOutRes:=0;
  1024. ThreadID := dword(pthread_self);
  1025. SysInitStdIO;
  1026. {Delphi Compatible}
  1027. IsConsole := TRUE;
  1028. ExitCode := 0;
  1029. {$ifdef HASVARIANT}
  1030. initvariantmanager;
  1031. {$endif HASVARIANT}
  1032. End.
  1033. {
  1034. $Log$
  1035. Revision 1.4 2004-09-26 19:23:34 armin
  1036. * exiting threads at nlm unload
  1037. * renamed some libc functions
  1038. Revision 1.3 2004/09/19 20:06:37 armin
  1039. * removed get/free video buf from video.pp
  1040. * implemented sockets
  1041. * basic library support
  1042. * threadvar memory leak removed
  1043. * fixes (ide now starts and editor is usable)
  1044. * support for lineinfo
  1045. Revision 1.2 2004/09/12 20:51:22 armin
  1046. * added keyboard and video
  1047. * a lot of fixes
  1048. Revision 1.1 2004/09/05 20:58:47 armin
  1049. * first rtl version for netwlibc
  1050. }