system.pp 28 KB

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