system.pp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  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. {$ifdef autoHeapRelease}
  195. const HeapInitialMaxBlocks = 32;
  196. type THeapSbrkBlockList = array [1.. HeapInitialMaxBlocks] of pointer;
  197. var HeapSbrkBlockList : ^THeapSbrkBlockList = nil;
  198. HeapSbrkLastUsed : dword = 0;
  199. HeapSbrkAllocated : dword = 0;
  200. HeapSbrkReleased : boolean = false;
  201. { function to allocate size bytes more for the program }
  202. { must return the first address of new data space or nil if fail }
  203. { for netware all allocated blocks are saved to free them at }
  204. { exit (to avoid message "Module did not release xx resources") }
  205. Function SysOSAlloc(size : longint):pointer;
  206. var P2 : POINTER;
  207. i : longint;
  208. Slept : longint;
  209. begin
  210. if HeapSbrkReleased then
  211. begin
  212. ConsolePrintf ('Error: SysOSFree called after all heap memory was released'#13#10);
  213. exit(nil);
  214. end;
  215. SysOSAlloc := _Alloc (size,HeapAllocResourceTag);
  216. if SysOSAlloc <> nil then begin
  217. if HeapSbrkBlockList = nil then
  218. begin
  219. Pointer (HeapSbrkBlockList) := _Alloc (sizeof (HeapSbrkBlockList^),HeapListAllocResourceTag);
  220. if HeapSbrkBlockList = nil then
  221. begin
  222. _free (SysOSAlloc);
  223. SysOSAlloc := nil;
  224. exit;
  225. end;
  226. fillchar (HeapSbrkBlockList^,sizeof(HeapSbrkBlockList^),0);
  227. HeapSbrkAllocated := HeapInitialMaxBlocks;
  228. end;
  229. if (HeapSbrkLastUsed > 0) then
  230. for i := 1 to HeapSbrkLastUsed do
  231. if (HeapSbrkBlockList^[i] = nil) then
  232. begin // reuse free slot
  233. HeapSbrkBlockList^[i] := SysOSAlloc;
  234. exit;
  235. end;
  236. if (HeapSbrkLastUsed = HeapSbrkAllocated) then
  237. begin { grow }
  238. slept := 0;
  239. p2 := _ReallocSleepOK (HeapSbrkBlockList, (HeapSbrkAllocated + HeapInitialMaxBlocks) * sizeof(pointer),HeapListAllocResourceTag,Slept);
  240. if p2 = nil then // should we better terminate with error ?
  241. begin
  242. _free (SysOSAlloc);
  243. SysOSAlloc := nil;
  244. exit;
  245. end;
  246. HeapSbrkBlockList := p2;
  247. inc (HeapSbrkAllocated, HeapInitialMaxBlocks);
  248. end;
  249. inc (HeapSbrkLastUsed);
  250. HeapSbrkBlockList^[HeapSbrkLastUsed] := SysOSAlloc;
  251. end;
  252. end;
  253. procedure FreeSbrkMem;
  254. var i : longint;
  255. begin
  256. if HeapSbrkBlockList <> nil then
  257. begin
  258. for i := 1 to HeapSbrkLastUsed do
  259. if (HeapSbrkBlockList^[i] <> nil) then
  260. _free (HeapSbrkBlockList^[i]);
  261. _free (HeapSbrkBlockList);
  262. HeapSbrkAllocated := 0;
  263. HeapSbrkLastUsed := 0;
  264. HeapSbrkBlockList := nil;
  265. end;
  266. HeapSbrkReleased := true;
  267. {ReturnResourceTag(HeapAllocResourceTag,1);
  268. ReturnResourceTag(HeapListAllocResourceTag,1); not in netware.imp, seems to be not needed}
  269. end;
  270. {*****************************************************************************
  271. OS Memory allocation / deallocation
  272. ****************************************************************************}
  273. {$define HAS_SYSOSFREE}
  274. procedure SysOSFree(p: pointer; size: ptrint);
  275. var i : longint;
  276. begin
  277. if HeapSbrkReleased then
  278. begin
  279. ConsolePrintf ('Error: SysOSFree called after all heap memory was released'#13#10);
  280. end else
  281. if (HeapSbrkLastUsed > 0) then
  282. for i := 1 to HeapSbrkLastUsed do
  283. if (HeapSbrkBlockList^[i] = p) then
  284. begin
  285. _free (p);
  286. HeapSbrkBlockList^[i] := nil;
  287. exit;
  288. end;
  289. HandleError (204); // invalid pointer operation
  290. end;
  291. {$else autoHeapRelease}
  292. {$define HAS_SYSOSFREE}
  293. procedure SysOSFree(p: pointer; size: ptrint);
  294. begin
  295. _free (p);
  296. end;
  297. function SysOSAlloc(size: ptrint): pointer;
  298. begin
  299. SysOSAlloc := _Alloc(size,HeapAllocResourceTag);
  300. end;
  301. {$endif autoHeapRelease}
  302. { include standard heap management }
  303. {$I heap.inc}
  304. {****************************************************************************
  305. Low level File Routines
  306. All these functions can set InOutRes on errors
  307. ****************************************************************************}
  308. PROCEDURE NW2PASErr (Err : LONGINT);
  309. BEGIN
  310. if Err = 0 then { Else it will go through all the cases }
  311. exit;
  312. case Err of
  313. Sys_ENFILE,
  314. Sys_EMFILE : Inoutres:=4;
  315. Sys_ENOENT : Inoutres:=2;
  316. Sys_EBADF : Inoutres:=6;
  317. Sys_ENOMEM,
  318. Sys_EFAULT : Inoutres:=217;
  319. Sys_EINVAL : Inoutres:=218;
  320. Sys_EPIPE,
  321. Sys_EINTR,
  322. Sys_EIO,
  323. Sys_EAGAIN,
  324. Sys_ENOSPC : Inoutres:=101;
  325. Sys_ENAMETOOLONG,
  326. Sys_ELOOP,
  327. Sys_ENOTDIR : Inoutres:=3;
  328. Sys_EROFS,
  329. Sys_EEXIST,
  330. Sys_EACCES : Inoutres:=5;
  331. Sys_EBUSY : Inoutres:=162
  332. else begin
  333. Writeln (stderr,'NW2PASErr: unknown error ',err);
  334. libc_perror('NW2PASErr');
  335. Inoutres := Err;
  336. end;
  337. end;
  338. END;
  339. procedure Errno2Inoutres;
  340. begin
  341. NW2PASErr (___errno^);
  342. end;
  343. procedure SetFileError (VAR Err : LONGINT);
  344. begin
  345. if Err >= 0 then
  346. InOutRes := 0
  347. else begin
  348. // libc_perror ('SetFileError');
  349. Err := ___errno^;
  350. NW2PASErr (Err);
  351. Err := 0;
  352. end;
  353. end;
  354. { close a file from the handle value }
  355. procedure do_close(handle : thandle);
  356. VAR res : LONGINT;
  357. begin
  358. {$ifdef IOpossix}
  359. res := FpClose (handle);
  360. {$else}
  361. res := _fclose (_TFILE(handle));
  362. {$endif}
  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. {$ifdef IOpossix}
  390. res := Fpwrite (h,addr,len);
  391. {$else}
  392. res := _fwrite (addr,1,len,_TFILE(h));
  393. {$endif}
  394. if res > 0 then
  395. InOutRes := 0
  396. else
  397. SetFileError (res);
  398. do_write := res;
  399. NXThreadYield;
  400. end;
  401. function do_read(h:thandle;addr:pointer;len : longint) : longint;
  402. VAR res : LONGINT;
  403. begin
  404. {$ifdef IOpossix}
  405. res := Fpread (h,addr,len);
  406. {$else}
  407. res := _fread (addr,1,len,_TFILE(h));
  408. {$endif}
  409. IF res > 0 THEN
  410. InOutRes := 0
  411. ELSE
  412. SetFileError (res);
  413. do_read := res;
  414. NXThreadYield;
  415. end;
  416. function do_filepos(handle : thandle) : longint;
  417. var res : LONGINT;
  418. begin
  419. InOutRes:=1;
  420. {$ifdef IOpossix}
  421. res := Fptell (handle);
  422. {$else}
  423. res := _ftell (_TFILE(handle));
  424. {$endif}
  425. if res < 0 THEN
  426. SetFileError (res)
  427. else
  428. InOutRes := 0;
  429. do_filepos := res;
  430. end;
  431. procedure do_seek(handle:thandle;pos : longint);
  432. VAR res : LONGINT;
  433. begin
  434. {$ifdef IOpossix}
  435. res := Fplseek (handle,pos, SEEK_SET);
  436. {$else}
  437. res := _fseek (_TFILE(handle),pos, SEEK_SET);
  438. {$endif}
  439. IF res >= 0 THEN
  440. InOutRes := 0
  441. ELSE
  442. SetFileError (res);
  443. end;
  444. function do_seekend(handle:thandle):longint;
  445. VAR res : LONGINT;
  446. begin
  447. {$ifdef IOpossix}
  448. res := Fplseek (handle,0, SEEK_END);
  449. {$else}
  450. res := _fseek (_TFILE(handle),0, SEEK_END);
  451. {$endif}
  452. IF res >= 0 THEN
  453. InOutRes := 0
  454. ELSE
  455. SetFileError (res);
  456. do_seekend := res;
  457. end;
  458. function do_filesize(handle : thandle) : longint;
  459. VAR res : LONGINT;
  460. statbuf : TStat;
  461. begin
  462. {$ifdef IOpossix}
  463. res := Fpfstat (handle, statbuf);
  464. {$else}
  465. res := _fstat (_fileno (_TFILE(handle)), statbuf); // was _filelength for clib
  466. {$endif}
  467. if res <> 0 then
  468. begin
  469. SetFileError (Res);
  470. do_filesize := -1;
  471. end else
  472. begin
  473. InOutRes := 0;
  474. do_filesize := statbuf.st_size;
  475. end;
  476. end;
  477. { truncate at a given position }
  478. procedure do_truncate (handle:thandle;pos:longint);
  479. VAR res : LONGINT;
  480. begin
  481. {$ifdef IOpossix}
  482. res := ftruncate (handle,pos);
  483. {$else}
  484. res := _ftruncate (_fileno (_TFILE(handle)),pos);
  485. {$endif}
  486. IF res <> 0 THEN
  487. SetFileError (res)
  488. ELSE
  489. InOutRes := 0;
  490. end;
  491. {$ifdef IOpossix}
  492. // mostly stolen from syslinux
  493. procedure do_open(var f;p:pchar;flags:longint);
  494. {
  495. filerec and textrec have both handle and mode as the first items so
  496. they could use the same routine for opening/creating.
  497. when (flags and $10) the file will be append
  498. when (flags and $100) the file will be truncate/rewritten
  499. when (flags and $1000) there is no check for close (needed for textfiles)
  500. }
  501. var
  502. oflags : longint;
  503. Begin
  504. { close first if opened }
  505. if ((flags and $10000)=0) then
  506. begin
  507. case FileRec(f).mode of
  508. fminput,fmoutput,fminout : Do_Close(FileRec(f).Handle);
  509. fmclosed : ;
  510. else
  511. begin
  512. inoutres:=102; {not assigned}
  513. exit;
  514. end;
  515. end;
  516. end;
  517. { reset file Handle }
  518. FileRec(f).Handle:=UnusedHandle;
  519. { We do the conversion of filemodes here, concentrated on 1 place }
  520. case (flags and 3) of
  521. 0 : begin
  522. oflags := O_RDONLY;
  523. filerec(f).mode := fminput;
  524. end;
  525. 1 : begin
  526. oflags := O_WRONLY;
  527. filerec(f).mode := fmoutput;
  528. end;
  529. 2 : begin
  530. oflags := O_RDWR;
  531. filerec(f).mode := fminout;
  532. end;
  533. end;
  534. if (flags and $1000)=$1000 then
  535. oflags:=oflags or (O_CREAT or O_TRUNC)
  536. else
  537. if (flags and $100)=$100 then
  538. oflags:=oflags or (O_APPEND);
  539. { empty name is special }
  540. if p[0]=#0 then
  541. begin
  542. case FileRec(f).mode of
  543. fminput :
  544. FileRec(f).Handle:=StdInputHandle;
  545. fminout, { this is set by rewrite }
  546. fmoutput :
  547. FileRec(f).Handle:=StdOutputHandle;
  548. fmappend :
  549. begin
  550. FileRec(f).Handle:=StdOutputHandle;
  551. FileRec(f).mode:=fmoutput; {fool fmappend}
  552. end;
  553. end;
  554. exit;
  555. end;
  556. { real open call }
  557. ___errno^ := 0;
  558. FileRec(f).Handle := open(p,oflags,438);
  559. { open somtimes returns > -1 but errno was set }
  560. if (___errno^ <> 0) or (longint(FileRec(f).Handle) < 0) then
  561. if (___errno^=Sys_EROFS) and ((OFlags and O_RDWR)<>0) then
  562. begin // i.e. for cd-rom
  563. Oflags:=Oflags and not(O_RDWR);
  564. FileRec(f).Handle := open(p,oflags,438);
  565. end;
  566. if (___errno^ <> 0) or (longint(FileRec(f).Handle) < 0) then
  567. Errno2Inoutres
  568. else
  569. InOutRes := 0;
  570. end;
  571. {$else}
  572. procedure do_open(var f;p:pchar;flags:longint);
  573. {
  574. filerec and textrec have both handle and mode as the first items so
  575. they could use the same routine for opening/creating.
  576. when (flags and $10) the file will be append
  577. when (flags and $100) the file will be truncate/rewritten
  578. when (flags and $1000) there is no check for close (needed for textfiles)
  579. }
  580. var
  581. oflags : string[10];
  582. Begin
  583. { close first if opened }
  584. if ((flags and $10000)=0) then
  585. begin
  586. case FileRec(f).mode of
  587. fminput,fmoutput,fminout : Do_Close(FileRec(f).Handle);
  588. fmclosed : ;
  589. else
  590. begin
  591. inoutres:=102; {not assigned}
  592. exit;
  593. end;
  594. end;
  595. end;
  596. { reset file Handle }
  597. FileRec(f).Handle:=UnusedHandle;
  598. { We do the conversion of filemodes here, concentrated on 1 place }
  599. case (flags and 3) of
  600. 0 : begin
  601. oflags := 'rb'#0;
  602. filerec(f).mode := fminput;
  603. end;
  604. 1 : begin
  605. if (flags and $1000)=$1000 then
  606. oflags := 'w+b' else
  607. oflags := 'wb';
  608. filerec(f).mode := fmoutput;
  609. end;
  610. 2 : begin
  611. if (flags and $1000)=$1000 then
  612. oflags := 'w+' else
  613. oflags := 'r+';
  614. filerec(f).mode := fminout;
  615. end;
  616. end;
  617. {if (flags and $1000)=$1000 then
  618. oflags:=oflags or (O_CREAT or O_TRUNC)
  619. else
  620. if (flags and $100)=$100 then
  621. oflags:=oflags or (O_APPEND);}
  622. { empty name is special }
  623. if p[0]=#0 then
  624. begin
  625. case FileRec(f).mode of
  626. fminput :
  627. FileRec(f).Handle:=StdInputHandle;
  628. fminout, { this is set by rewrite }
  629. fmoutput :
  630. FileRec(f).Handle:=StdOutputHandle;
  631. fmappend :
  632. begin
  633. FileRec(f).Handle:=StdOutputHandle;
  634. FileRec(f).mode:=fmoutput; {fool fmappend}
  635. end;
  636. end;
  637. exit;
  638. end;
  639. { real open call }
  640. FileRec(f).Handle := THandle (_fopen (p,@oflags[1]));//_open(p,oflags,438);
  641. //WriteLn ('_open (',p,') returned ',ErrNo, 'Handle: ',FileRec(f).Handle);
  642. // errno does not seem to be set on succsess ??
  643. {IF FileRec(f).Handle < 0 THEN
  644. if (ErrNo=Sys_EROFS) and ((OFlags and O_RDWR)<>0) then
  645. begin // i.e. for cd-rom
  646. Oflags:=Oflags and not(O_RDWR);
  647. FileRec(f).Handle := _open(p,oflags,438);
  648. end;}
  649. if FileRec(f).Handle = 0 then
  650. Errno2Inoutres
  651. else
  652. InOutRes := 0;
  653. End;
  654. {$endif}
  655. function do_isdevice(handle:THandle):boolean;
  656. begin
  657. {$ifdef IOpossix}
  658. do_isdevice := (Fpisatty (handle) > 0);
  659. {$else}
  660. do_isdevice := (isatty (_fileno(_TFILE(handle))) > 0);
  661. {$endif}
  662. end;
  663. {*****************************************************************************
  664. UnTyped File Handling
  665. *****************************************************************************}
  666. {$i file.inc}
  667. {*****************************************************************************
  668. Typed File Handling
  669. *****************************************************************************}
  670. {$i typefile.inc}
  671. {*****************************************************************************
  672. Text File Handling
  673. *****************************************************************************}
  674. {$i text.inc}
  675. {*****************************************************************************
  676. Directory Handling
  677. *****************************************************************************}
  678. procedure mkdir(const s : string);[IOCheck];
  679. var S2 : STRING;
  680. Res: LONGINT;
  681. BEGIN
  682. S2 := S;
  683. IF Length (S2) = 255 THEN DEC (BYTE(S2[0]));
  684. S2 := S2 + #0;
  685. Res := FpMkdir (@S2[1],S_IRWXU);
  686. if Res = 0 then
  687. InOutRes:=0
  688. else
  689. SetFileError (Res);
  690. end;
  691. procedure rmdir(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 := FpRmdir (@S2[1]);
  699. IF Res = 0 THEN
  700. InOutRes:=0
  701. ELSE
  702. SetFileError (Res);
  703. end;
  704. procedure chdir(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 := FpChdir (@S2[1]);
  712. IF Res = 0 THEN
  713. InOutRes:=0
  714. ELSE
  715. SetFileError (Res);
  716. end;
  717. procedure getdir(drivenr : byte;var dir : shortstring);
  718. var P : array [0..255] of CHAR;
  719. i : LONGINT;
  720. begin
  721. P[0] := #0;
  722. getcwdpath(@P,nil,0); // getcwd does not return volume, getcwdpath does
  723. i := libc_strlen (P);
  724. if i > 0 then
  725. begin
  726. Move (P, dir[1], i);
  727. BYTE(dir[0]) := i;
  728. For i := 1 to length (dir) do
  729. if dir[i] = '\' then dir [i] := '/';
  730. // fix / after volume, the compiler needs that
  731. // normaly root of a volumes is SERVERNAME/SYS:, change that
  732. // to SERVERNAME/SYS:/
  733. i := pos (':',dir);
  734. if (i > 0) then
  735. if i = Length (dir) then dir := dir + '/' else
  736. if dir [i+1] <> '/' then insert ('/',dir,i+1);
  737. end else
  738. InOutRes := 1;
  739. end;
  740. {*****************************************************************************
  741. Thread Handling
  742. *****************************************************************************}
  743. procedure InitFPU;assembler;
  744. asm
  745. fninit
  746. fldcw fpucw
  747. end;
  748. { if return-value is <> 0, netware shows the message
  749. Unload Anyway ?
  750. To Disable unload at all, SetNLMDontUnloadFlag can be used on
  751. Netware >= 4.0 }
  752. function CheckFunction : longint; CDECL; [public,alias: '_NonAppCheckUnload'];
  753. var oldPtr : pointer;
  754. begin
  755. //ConsolePrintf ('CheckFunction'#13#10);
  756. if assigned (NetwareCheckFunction) then
  757. begin
  758. if assigned (SetThreadDataAreaPtr) then
  759. oldPtr := SetThreadDataAreaPtr (NIL); { nil means main thread }
  760. result := 0;
  761. NetwareCheckFunction (result);
  762. if assigned (SetThreadDataAreaPtr) then
  763. SetThreadDataAreaPtr (oldPtr);
  764. end else
  765. result := 0;
  766. end;
  767. procedure ConsolePrintf (s : shortstring);
  768. begin
  769. if length(s) > 254 then
  770. byte(s[0]) := 254;
  771. s := s + #0;
  772. ConsolePrintf (@s[1]);
  773. end;
  774. procedure ConsolePrintf (FormatStr : PCHAR);
  775. begin
  776. if NWLoggerScreen = nil then
  777. NWLoggerScreen := getnetwarelogger;
  778. if NWLoggerScreen <> nil then
  779. screenprintf (NWLoggerScreen,FormatStr);
  780. end;
  781. procedure ConsolePrintf (FormatStr : PCHAR; Param : LONGINT);
  782. begin
  783. if NWLoggerScreen = nil then
  784. NWLoggerScreen := getnetwarelogger;
  785. if NWLoggerScreen <> nil then
  786. screenprintf (NWLoggerScreen,FormatStr,Param);
  787. end;
  788. procedure ConsolePrintf (FormatStr : PCHAR; Param : pchar);
  789. begin
  790. ConsolePrintf (FormatStr,longint(Param));
  791. end;
  792. procedure ConsolePrintf (FormatStr : PCHAR; P1,P2 : LONGINT);
  793. begin
  794. if NWLoggerScreen = nil then
  795. NWLoggerScreen := getnetwarelogger;
  796. if NWLoggerScreen <> nil then
  797. screenprintf (NWLoggerScreen,FormatStr,P1,P2);
  798. end;
  799. procedure ConsolePrintf (FormatStr : PCHAR; P1,P2,P3 : LONGINT);
  800. begin
  801. if NWLoggerScreen = nil then
  802. NWLoggerScreen := getnetwarelogger;
  803. if NWLoggerScreen <> nil then
  804. screenprintf (NWLoggerScreen,FormatStr,P1,P2,P3);
  805. end;
  806. procedure __EnterDebugger;cdecl;external '!netware' name 'EnterDebugger';
  807. var NWUts : Tutsname;
  808. procedure getCodeAddresses;
  809. begin
  810. if Fpuname(NWUts) < 0 then
  811. FillChar(NWuts,sizeof(NWUts),0);
  812. end;
  813. function NWGetCodeStart : pointer;
  814. begin
  815. NWGetCodeStart := NWUts.codeoffset;
  816. NXThreadYield;
  817. end;
  818. function NWGetCodeLength : dword;
  819. begin
  820. NWGetCodeLength := NWUts.codelength;
  821. NXThreadYield;
  822. end;
  823. function NWGetDataStart : pointer;
  824. begin
  825. NWGetDataStart := NWUts.dataoffset;
  826. NXThreadYield;
  827. end;
  828. function NWGetDataLength : dword;
  829. begin
  830. NWGetDataLength := NWUts.datalength;
  831. NXThreadYield;
  832. end;
  833. {$ifdef StdErrToConsole}
  834. var ConsoleBuff : array [0..512] of char;
  835. Function ConsoleWrite(Var F: TextRec): Integer;
  836. var
  837. i : longint;
  838. Begin
  839. if F.BufPos>0 then
  840. begin
  841. if F.BufPos>sizeof(ConsoleBuff)-1 then
  842. i:=sizeof(ConsoleBuff)-1
  843. else
  844. i:=F.BufPos;
  845. Move(F.BufPtr^,ConsoleBuff,i);
  846. ConsoleBuff[i] := #0;
  847. screenprintf (NWLoggerScreen,@ConsoleBuff);
  848. end;
  849. F.BufPos:=0;
  850. ConsoleWrite := 0;
  851. NXThreadYield;
  852. End;
  853. Function ConsoleClose(Var F: TextRec): Integer;
  854. begin
  855. ConsoleClose:=0;
  856. end;
  857. Function ConsoleOpen(Var F: TextRec): Integer;
  858. Begin
  859. TextRec(F).InOutFunc:=@ConsoleWrite;
  860. TextRec(F).FlushFunc:=@ConsoleWrite;
  861. TextRec(F).CloseFunc:=@ConsoleClose;
  862. ConsoleOpen:=0;
  863. End;
  864. procedure AssignStdErrConsole(Var T: Text);
  865. begin
  866. Assign(T,'');
  867. TextRec(T).OpenFunc:=@ConsoleOpen;
  868. Rewrite(T);
  869. end;
  870. {$endif}
  871. { this will be called if the nlm is unloaded. It will NOT be
  872. called if the program exits i.e. with halt.
  873. Halt (or _exit) can not be called from this callback procedure }
  874. procedure TermSigHandler (Sig:longint); CDecl;
  875. var oldPtr : pointer;
  876. current_exit : procedure;
  877. begin
  878. { Threadvar Pointer will not be valid because the signal
  879. handler is called by netware with a differnt thread. To avoid
  880. problems in the exit routines, we set the data of the main thread
  881. here }
  882. if assigned (SetThreadDataAreaPtr) then
  883. oldPtr := SetThreadDataAreaPtr (NIL); { nil means main thread }
  884. TerminatingThreadID := dword(pthread_self);
  885. {we need to finalize winock to release threads
  886. waiting on a blocking socket call. If that thread
  887. calls halt, we have to avoid that unit finalization
  888. is called by that thread because we are doing it
  889. here
  890. like the old exitProc, mainly to allow winsock to release threads
  891. blocking in a winsock calls }
  892. while NetwareUnloadProc<>nil Do
  893. Begin
  894. InOutRes:=0;
  895. current_exit:=tProcedure(NetwareUnloadProc);
  896. NetwareUnloadProc:=nil;
  897. current_exit();
  898. NXThreadYield;
  899. //hadExitProc := true;
  900. End;
  901. SigTermHandlerActive := true; { to avoid that system_exit calls _exit }
  902. do_exit; { calls finalize units }
  903. if assigned (SetThreadDataAreaPtr) then
  904. SetThreadDataAreaPtr (oldPtr);
  905. end;
  906. procedure SysInitStdIO;
  907. begin
  908. { Setup stdin, stdout and stderr }
  909. {$ifdef IOpossix}
  910. StdInputHandle := THandle (fileno (___stdin^)); // GetStd** returns **FILE !
  911. StdOutputHandle:= THandle (fileno (___stdout^));
  912. StdErrorHandle := THandle (fileno (___stderr^));
  913. {$else}
  914. StdInputHandle := THandle (___stdin^); // GetStd** returns **FILE !
  915. StdOutputHandle:= THandle (___stdout^);
  916. StdErrorHandle := THandle (___stderr^);
  917. {$endif}
  918. OpenStdIO(Input,fmInput,StdInputHandle);
  919. OpenStdIO(Output,fmOutput,StdOutputHandle);
  920. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  921. {$ifdef StdErrToConsole}
  922. AssignStdErrConsole(StdErr);
  923. {$else}
  924. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  925. {$endif}
  926. end;
  927. // this is called by main.as, setup args and call PASCALMAIN
  928. procedure nlm_main (_ArgC : LONGINT; _ArgV : ppchar); cdecl; [public,alias: '_FPC_NLM_Entry'];
  929. BEGIN
  930. ArgC := _ArgC;
  931. ArgV := _ArgV;
  932. isLibrary := false;
  933. PASCALMAIN;
  934. do_exit; // currently not needed
  935. END;
  936. function _DLLMain (hInstDLL:pointer; fdwReason:dword; DLLParam:longint):longbool; cdecl;
  937. [public, alias : '_FPC_DLL_Entry'];
  938. var res : longbool;
  939. begin
  940. {$ifdef DEBUG_MT}
  941. ConsolePrintf ('_FPC_DLL_Entry called');
  942. {$endif}
  943. _DLLMain := false;
  944. isLibrary := true;
  945. case fdwReason of
  946. DLL_ACTUAL_DLLMAIN : _DLLMain := true;
  947. DLL_NLM_STARTUP : begin
  948. //__ConsolePrintf ('DLL_NLM_STARTUP');
  949. if assigned(Dll_Process_Attach_Hook) then
  950. begin
  951. res:=Dll_Process_Attach_Hook(DllParam);
  952. if not res then
  953. exit(false);
  954. end;
  955. PASCALMAIN;
  956. _DLLMain := true;
  957. end;
  958. DLL_NLM_SHUTDOWN : begin
  959. //__ConsolePrintf ('DLL_NLM_SHUTDOWN');
  960. TermSigHandler(0);
  961. _DLLMain := true;
  962. end;
  963. { standard DllMain() messages... }
  964. DLL_THREAD_ATTACH,
  965. DLL_PROCESS_ATTACH : begin
  966. //__ConsolePrintf ('DLL_PROCESS/THREAD_ATTACH');
  967. if assigned(AllocateThreadVars) then
  968. AllocateThreadVars;
  969. if assigned(Dll_Thread_Attach_Hook) then
  970. Dll_Thread_Attach_Hook(DllParam);
  971. _DLLMain := true;
  972. end;
  973. DLL_THREAD_DETACH,
  974. DLL_PROCESS_DETACH : begin
  975. //__ConsolePrintf ('DLL_PROCESS/THREAD_DETACH');
  976. if assigned(Dll_Thread_Detach_Hook) then
  977. Dll_Thread_Detach_Hook(DllParam);
  978. if assigned(ReleaseThreadVars) then
  979. ReleaseThreadVars;
  980. _DLLMain := true;
  981. end;
  982. end;
  983. end;
  984. {*****************************************************************************
  985. SystemUnit Initialization
  986. *****************************************************************************}
  987. Begin
  988. getCodeAddresses;
  989. StackBottom := SPtr - StackLength;
  990. SigTermHandlerActive := false;
  991. NetwareCheckFunction := nil;
  992. {$ifdef StdErrToConsole}
  993. NWLoggerScreen := getnetwarelogger;
  994. {$endif}
  995. CheckFunction; // avoid check function to be removed by the linker
  996. envp := ____environ^;
  997. NLMHandle := getnlmhandle;
  998. { allocate resource tags to see what kind of memory i forgot to release }
  999. HeapAllocResourceTag :=
  1000. AllocateResourceTag(NLMHandle,'Heap Memory',AllocSignature);
  1001. {$ifdef autoHeapRelease}
  1002. HeapListAllocResourceTag :=
  1003. AllocateResourceTag(NLMHandle,'Heap Memory List',AllocSignature);
  1004. {$endif}
  1005. FpSignal (SIGTERM, @TermSigHandler);
  1006. { Setup heap }
  1007. InitHeap;
  1008. SysInitExceptions;
  1009. { Reset IO Error }
  1010. InOutRes:=0;
  1011. ThreadID := dword(pthread_self);
  1012. SysInitStdIO;
  1013. {Delphi Compatible}
  1014. IsConsole := TRUE;
  1015. ExitCode := 0;
  1016. {$ifdef HASVARIANT}
  1017. initvariantmanager;
  1018. {$endif HASVARIANT}
  1019. End.
  1020. {
  1021. $Log$
  1022. Revision 1.5 2004-10-25 15:38:59 peter
  1023. * compiler defined HEAP and HEAPSIZE removed
  1024. Revision 1.4 2004/09/26 19:23:34 armin
  1025. * exiting threads at nlm unload
  1026. * renamed some libc functions
  1027. Revision 1.3 2004/09/19 20:06:37 armin
  1028. * removed get/free video buf from video.pp
  1029. * implemented sockets
  1030. * basic library support
  1031. * threadvar memory leak removed
  1032. * fixes (ide now starts and editor is usable)
  1033. * support for lineinfo
  1034. Revision 1.2 2004/09/12 20:51:22 armin
  1035. * added keyboard and video
  1036. * a lot of fixes
  1037. Revision 1.1 2004/09/05 20:58:47 armin
  1038. * first rtl version for netwlibc
  1039. }