syswin32.pp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Florian Klaempfl and Pavel Ozerski
  5. member of the Free Pascal development team.
  6. FPC Pascal system unit for the Win32 API.
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit syswin32;
  14. interface
  15. {$ifdef i386}
  16. {$define Set_i386_Exception_handler}
  17. {$endif i386}
  18. { include system-independent routine headers }
  19. {$I systemh.inc}
  20. { include heap support headers }
  21. {$I heaph.inc}
  22. const
  23. { Default filehandles }
  24. UnusedHandle : longint = -1;
  25. StdInputHandle : longint = 0;
  26. StdOutputHandle : longint = 0;
  27. StdErrorHandle : longint = 0;
  28. FileNameCaseSensitive : boolean = true;
  29. type
  30. TStartupInfo=packed record
  31. cb : longint;
  32. lpReserved : Pointer;
  33. lpDesktop : Pointer;
  34. lpTitle : Pointer;
  35. dwX : longint;
  36. dwY : longint;
  37. dwXSize : longint;
  38. dwYSize : longint;
  39. dwXCountChars : longint;
  40. dwYCountChars : longint;
  41. dwFillAttribute : longint;
  42. dwFlags : longint;
  43. wShowWindow : Word;
  44. cbReserved2 : Word;
  45. lpReserved2 : Pointer;
  46. hStdInput : longint;
  47. hStdOutput : longint;
  48. hStdError : longint;
  49. end;
  50. var
  51. { C compatible arguments }
  52. argc : longint;
  53. argv : ppchar;
  54. { Win32 Info }
  55. startupinfo : tstartupinfo;
  56. hprevinst,
  57. HInstance,
  58. MainInstance,
  59. cmdshow : longint;
  60. IsLibrary,IsMultiThreaded,IsConsole : boolean;
  61. DLLreason,DLLparam:longint;
  62. Win32StackTop : Dword;
  63. { Thread count for DLL }
  64. const
  65. Thread_count : longint = 0;
  66. type
  67. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  68. TDLL_Entry_Hook = procedure (dllparam : longint);
  69. const
  70. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  71. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  72. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  73. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  74. implementation
  75. { include system independent routines }
  76. {$I system.inc}
  77. { some declarations for Win32 API calls }
  78. {$I win32.inc}
  79. CONST
  80. { These constants are used for conversion of error codes }
  81. { from win32 i/o errors to tp i/o errors }
  82. { errors 1 to 18 are the same as in Turbo Pascal }
  83. { DO NOT MODIFY UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING! }
  84. { The media is write protected. }
  85. ERROR_WRITE_PROTECT = 19;
  86. { The system cannot find the device specified. }
  87. ERROR_BAD_UNIT = 20;
  88. { The device is not ready. }
  89. ERROR_NOT_READY = 21;
  90. { The device does not recognize the command. }
  91. ERROR_BAD_COMMAND = 22;
  92. { Data error (cyclic redundancy check) }
  93. ERROR_CRC = 23;
  94. { The program issued a command but the }
  95. { command length is incorrect. }
  96. ERROR_BAD_LENGTH = 24;
  97. { The drive cannot locate a specific }
  98. { area or track on the disk. }
  99. ERROR_SEEK = 25;
  100. { The specified disk or diskette cannot be accessed. }
  101. ERROR_NOT_DOS_DISK = 26;
  102. { The drive cannot find the sector requested. }
  103. ERROR_SECTOR_NOT_FOUND = 27;
  104. { The printer is out of paper. }
  105. ERROR_OUT_OF_PAPER = 28;
  106. { The system cannot write to the specified device. }
  107. ERROR_WRITE_FAULT = 29;
  108. { The system cannot read from the specified device. }
  109. ERROR_READ_FAULT = 30;
  110. { A device attached to the system is not functioning.}
  111. ERROR_GEN_FAILURE = 31;
  112. { The process cannot access the file because }
  113. { it is being used by another process. }
  114. ERROR_SHARING_VIOLATION = 32;
  115. var
  116. errno : longint;
  117. {$ASMMODE ATT}
  118. { misc. functions }
  119. function GetLastError : DWORD;
  120. external 'kernel32' name 'GetLastError';
  121. { time and date functions }
  122. function GetTickCount : longint;
  123. external 'kernel32' name 'GetTickCount';
  124. { process functions }
  125. procedure ExitProcess(uExitCode : UINT);
  126. external 'kernel32' name 'ExitProcess';
  127. Procedure Errno2InOutRes;
  128. Begin
  129. { DO NOT MODIFY UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING }
  130. if (errno >= ERROR_WRITE_PROTECT) and (errno <= ERROR_GEN_FAILURE) THEN
  131. BEGIN
  132. { This is the offset to the Win32 to add to directly map }
  133. { to the DOS/TP compatible error codes when in this range }
  134. InOutRes := word(errno)+131;
  135. END
  136. else
  137. { This case is special }
  138. if errno=ERROR_SHARING_VIOLATION THEN
  139. BEGIN
  140. InOutRes :=5;
  141. END
  142. else
  143. { other error codes can directly be mapped }
  144. InOutRes := Word(errno);
  145. errno:=0;
  146. end;
  147. {$ifdef dummy}
  148. procedure int_stackcheck(stack_size:longint);[public,alias: 'STACKCHECK'];
  149. {
  150. called when trying to get local stack if the compiler directive $S
  151. is set this function must preserve esi !!!! because esi is set by
  152. the calling proc for methods it must preserve all registers !!
  153. With a 2048 byte safe area used to write to StdIo without crossing
  154. the stack boundary
  155. }
  156. begin
  157. asm
  158. pushl %eax
  159. pushl %ebx
  160. movl stack_size,%ebx
  161. addl $2048,%ebx
  162. movl %esp,%eax
  163. subl %ebx,%eax
  164. movl stacklimit,%ebx
  165. cmpl %eax,%ebx
  166. jae .L__short_on_stack
  167. popl %ebx
  168. popl %eax
  169. leave
  170. ret $4
  171. .L__short_on_stack:
  172. { can be usefull for error recovery !! }
  173. popl %ebx
  174. popl %eax
  175. end['EAX','EBX'];
  176. HandleError(202);
  177. end;
  178. {$endif dummy}
  179. procedure halt(errnum : byte);
  180. begin
  181. ExitCode:=errnum;
  182. do_exit;
  183. system_exit;
  184. end;
  185. function paramcount : longint;
  186. begin
  187. paramcount := argc - 1;
  188. end;
  189. { module functions }
  190. function GetModuleFileName(l1:longint;p:pointer;l2:longint):longint;
  191. external 'kernel32' name 'GetModuleFileNameA';
  192. function GetModuleHandle(p : pointer) : longint;
  193. external 'kernel32' name 'GetModuleHandleA';
  194. function GetCommandFile:pchar;forward;
  195. function paramstr(l : longint) : string;
  196. begin
  197. if (l>=0) and (l<argc) then
  198. paramstr:=strpas(argv[l])
  199. else
  200. paramstr:='';
  201. end;
  202. procedure randomize;
  203. begin
  204. randseed:=GetTickCount;
  205. end;
  206. {*****************************************************************************
  207. Heap Management
  208. *****************************************************************************}
  209. { memory functions }
  210. function GlobalAlloc(mode,size:longint):longint;
  211. external 'kernel32' name 'GlobalAlloc';
  212. function GlobalLock(handle:longint):pointer;
  213. external 'kernel32' name 'GlobalLock';
  214. {$ifdef SYSTEMDEBUG}
  215. function GlobalSize(h:longint):longint;
  216. external 'kernel32' name 'GlobalSize';
  217. {$endif}
  218. var
  219. heap : longint;external name 'HEAP';
  220. intern_heapsize : longint;external name 'HEAPSIZE';
  221. function getheapstart:pointer;assembler;
  222. asm
  223. leal HEAP,%eax
  224. end ['EAX'];
  225. function getheapsize:longint;assembler;
  226. asm
  227. movl intern_HEAPSIZE,%eax
  228. end ['EAX'];
  229. function Sbrk(size : longint):longint;
  230. var
  231. h,l : longint;
  232. begin
  233. h:=GlobalAlloc(258,size);
  234. l:=longint(GlobalLock(h));
  235. if l=0 then
  236. l:=-1;
  237. {$ifdef SYSTEMDEBUG}
  238. Writeln('new heap part at $',hexstr(l,8), ' size = ',GlobalSize(h));
  239. {$endif}
  240. sbrk:=l;
  241. end;
  242. { include standard heap management }
  243. {$I heap.inc}
  244. {*****************************************************************************
  245. Low Level File Routines
  246. *****************************************************************************}
  247. function WriteFile(fh:longint;buf:pointer;len:longint;var loaded:longint;
  248. overlap:pointer):longint;
  249. external 'kernel32' name 'WriteFile';
  250. function ReadFile(fh:longint;buf:pointer;len:longint;var loaded:longint;
  251. overlap:pointer):longint;
  252. external 'kernel32' name 'ReadFile';
  253. function CloseHandle(h : longint) : longint;
  254. external 'kernel32' name 'CloseHandle';
  255. function DeleteFile(p : pchar) : longint;
  256. external 'kernel32' name 'DeleteFileA';
  257. function MoveFile(old,_new : pchar) : longint;
  258. external 'kernel32' name 'MoveFileA';
  259. function SetFilePointer(l1,l2 : longint;l3 : pointer;l4 : longint) : longint;
  260. external 'kernel32' name 'SetFilePointer';
  261. function GetFileSize(h:longint;p:pointer) : longint;
  262. external 'kernel32' name 'GetFileSize';
  263. function CreateFile(name : pointer;access,sharing : longint;
  264. security : pointer;how,attr,template : longint) : longint;
  265. external 'kernel32' name 'CreateFileA';
  266. function SetEndOfFile(h : longint) : longbool;
  267. external 'kernel32' name 'SetEndOfFile';
  268. function GetFileType(Handle:DWORD):DWord;
  269. external 'kernel32' name 'GetFileType';
  270. procedure AllowSlash(p:pchar);
  271. var
  272. i : longint;
  273. begin
  274. { allow slash as backslash }
  275. for i:=0 to strlen(p) do
  276. if p[i]='/' then p[i]:='\';
  277. end;
  278. function do_isdevice(handle:longint):boolean;
  279. begin
  280. do_isdevice:=(getfiletype(handle)=2);
  281. end;
  282. procedure do_close(h : longint);
  283. begin
  284. if do_isdevice(h) then
  285. exit;
  286. CloseHandle(h);
  287. end;
  288. procedure do_erase(p : pchar);
  289. begin
  290. AllowSlash(p);
  291. if DeleteFile(p)=0 then
  292. Begin
  293. errno:=GetLastError;
  294. Errno2InoutRes;
  295. end;
  296. end;
  297. procedure do_rename(p1,p2 : pchar);
  298. begin
  299. AllowSlash(p1);
  300. AllowSlash(p2);
  301. if MoveFile(p1,p2)=0 then
  302. Begin
  303. errno:=GetLastError;
  304. Errno2InoutRes;
  305. end;
  306. end;
  307. function do_write(h,addr,len : longint) : longint;
  308. var
  309. size:longint;
  310. begin
  311. if writefile(h,pointer(addr),len,size,nil)=0 then
  312. Begin
  313. errno:=GetLastError;
  314. Errno2InoutRes;
  315. end;
  316. do_write:=size;
  317. end;
  318. function do_read(h,addr,len : longint) : longint;
  319. var
  320. _result:longint;
  321. begin
  322. if readfile(h,pointer(addr),len,_result,nil)=0 then
  323. Begin
  324. errno:=GetLastError;
  325. Errno2InoutRes;
  326. end;
  327. do_read:=_result;
  328. end;
  329. function do_filepos(handle : longint) : longint;
  330. var
  331. l:longint;
  332. begin
  333. l:=SetFilePointer(handle,0,nil,FILE_CURRENT);
  334. if l=-1 then
  335. begin
  336. l:=0;
  337. errno:=GetLastError;
  338. Errno2InoutRes;
  339. end;
  340. do_filepos:=l;
  341. end;
  342. procedure do_seek(handle,pos : longint);
  343. begin
  344. if SetFilePointer(handle,pos,nil,FILE_BEGIN)=-1 then
  345. Begin
  346. errno:=GetLastError;
  347. Errno2InoutRes;
  348. end;
  349. end;
  350. function do_seekend(handle:longint):longint;
  351. begin
  352. do_seekend:=SetFilePointer(handle,0,nil,FILE_END);
  353. if do_seekend=-1 then
  354. begin
  355. errno:=GetLastError;
  356. Errno2InoutRes;
  357. end;
  358. end;
  359. function do_filesize(handle : longint) : longint;
  360. var
  361. aktfilepos : longint;
  362. begin
  363. aktfilepos:=do_filepos(handle);
  364. do_filesize:=do_seekend(handle);
  365. do_seek(handle,aktfilepos);
  366. end;
  367. procedure do_truncate (handle,pos:longint);
  368. begin
  369. do_seek(handle,pos);
  370. if not(SetEndOfFile(handle)) then
  371. begin
  372. errno:=GetLastError;
  373. Errno2InoutRes;
  374. end;
  375. end;
  376. procedure do_open(var f;p : pchar;flags:longint);
  377. {
  378. filerec and textrec have both handle and mode as the first items so
  379. they could use the same routine for opening/creating.
  380. when (flags and $100) the file will be append
  381. when (flags and $1000) the file will be truncate/rewritten
  382. when (flags and $10000) there is no check for close (needed for textfiles)
  383. }
  384. Const
  385. file_Share_Read = $00000001;
  386. file_Share_Write = $00000002;
  387. fmShareCompat = $00000000;
  388. fmShareExclusive = $10;
  389. fmShareDenyWrite = $20;
  390. fmShareDenyRead = $30;
  391. fmShareDenyNone = $40;
  392. Var
  393. shflags,
  394. oflags,cd : longint;
  395. begin
  396. AllowSlash(p);
  397. { close first if opened }
  398. if ((flags and $10000)=0) then
  399. begin
  400. case filerec(f).mode of
  401. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  402. fmclosed : ;
  403. else
  404. begin
  405. {not assigned}
  406. inoutres:=102;
  407. exit;
  408. end;
  409. end;
  410. end;
  411. { reset file handle }
  412. filerec(f).handle:=UnusedHandle;
  413. { convert filesharing }
  414. shflags:=0;
  415. if ((filemode and fmshareExclusive) = fmshareExclusive) then
  416. { no sharing }
  417. else
  418. if (filemode = fmShareCompat) or ((filemode and fmshareDenyWrite) = fmshareDenyWrite) then
  419. shflags := file_Share_Read
  420. else
  421. if ((filemode and fmshareDenyRead) = fmshareDenyRead) then
  422. shflags := file_Share_Write
  423. else
  424. if ((filemode and fmshareDenyNone) = fmshareDenyNone) then
  425. shflags := file_Share_Read + file_Share_Write;
  426. { convert filemode to filerec modes }
  427. case (flags and 3) of
  428. 0 : begin
  429. filerec(f).mode:=fminput;
  430. oflags:=GENERIC_READ;
  431. end;
  432. 1 : begin
  433. filerec(f).mode:=fmoutput;
  434. oflags:=GENERIC_WRITE;
  435. end;
  436. 2 : begin
  437. filerec(f).mode:=fminout;
  438. oflags:=GENERIC_WRITE or GENERIC_READ;
  439. end;
  440. end;
  441. { standard is opening and existing file }
  442. cd:=OPEN_EXISTING;
  443. { create it ? }
  444. if (flags and $1000)<>0 then
  445. cd:=CREATE_ALWAYS
  446. { or append ? }
  447. else
  448. if (flags and $100)<>0 then
  449. cd:=OPEN_ALWAYS;
  450. { empty name is special }
  451. if p[0]=#0 then
  452. begin
  453. case filerec(f).mode of
  454. fminput : filerec(f).handle:=StdInputHandle;
  455. fmappend,
  456. fmoutput : begin
  457. filerec(f).handle:=StdOutputHandle;
  458. filerec(f).mode:=fmoutput; {fool fmappend}
  459. end;
  460. end;
  461. exit;
  462. end;
  463. filerec(f).handle:=CreateFile(p,oflags,shflags,nil,cd,FILE_ATTRIBUTE_NORMAL,0);
  464. { append mode }
  465. if (flags and $100)<>0 then
  466. begin
  467. do_seekend(filerec(f).handle);
  468. filerec(f).mode:=fmoutput; {fool fmappend}
  469. end;
  470. { get errors }
  471. { handle -1 is returned sometimes !! (PM) }
  472. if (filerec(f).handle=0) or (filerec(f).handle=-1) then
  473. begin
  474. errno:=GetLastError;
  475. Errno2InoutRes;
  476. end;
  477. end;
  478. {*****************************************************************************
  479. UnTyped File Handling
  480. *****************************************************************************}
  481. {$i file.inc}
  482. {*****************************************************************************
  483. Typed File Handling
  484. *****************************************************************************}
  485. {$i typefile.inc}
  486. {*****************************************************************************
  487. Text File Handling
  488. *****************************************************************************}
  489. {$DEFINE EOF_CTRLZ}
  490. {$i text.inc}
  491. {*****************************************************************************
  492. Directory Handling
  493. *****************************************************************************}
  494. function CreateDirectory(name : pointer;sec : pointer) : longint;
  495. external 'kernel32' name 'CreateDirectoryA';
  496. function RemoveDirectory(name:pointer):longint;
  497. external 'kernel32' name 'RemoveDirectoryA';
  498. function SetCurrentDirectory(name : pointer) : longint;
  499. external 'kernel32' name 'SetCurrentDirectoryA';
  500. function GetCurrentDirectory(bufsize : longint;name : pchar) : longint;
  501. external 'kernel32' name 'GetCurrentDirectoryA';
  502. type
  503. TDirFnType=function(name:pointer):word;
  504. procedure dirfn(afunc : TDirFnType;const s:string);
  505. var
  506. buffer : array[0..255] of char;
  507. begin
  508. move(s[1],buffer,length(s));
  509. buffer[length(s)]:=#0;
  510. AllowSlash(pchar(@buffer));
  511. if aFunc(@buffer)=0 then
  512. begin
  513. errno:=GetLastError;
  514. Errno2InoutRes;
  515. end;
  516. end;
  517. function CreateDirectoryTrunc(name:pointer):word;
  518. begin
  519. CreateDirectoryTrunc:=CreateDirectory(name,nil);
  520. end;
  521. procedure mkdir(const s:string);[IOCHECK];
  522. begin
  523. If InOutRes <> 0 then exit;
  524. dirfn(TDirFnType(@CreateDirectoryTrunc),s);
  525. end;
  526. procedure rmdir(const s:string);[IOCHECK];
  527. begin
  528. If InOutRes <> 0 then exit;
  529. dirfn(TDirFnType(@RemoveDirectory),s);
  530. end;
  531. procedure chdir(const s:string);[IOCHECK];
  532. begin
  533. If InOutRes <> 0 then exit;
  534. dirfn(TDirFnType(@SetCurrentDirectory),s);
  535. end;
  536. procedure getdir(drivenr:byte;var dir:shortstring);
  537. const
  538. Drive:array[0..3]of char=(#0,':',#0,#0);
  539. var
  540. defaultdrive:boolean;
  541. DirBuf,SaveBuf:array[0..259] of Char;
  542. begin
  543. defaultdrive:=drivenr=0;
  544. if not defaultdrive then
  545. begin
  546. byte(Drive[0]):=Drivenr+64;
  547. GetCurrentDirectory(SizeOf(SaveBuf),SaveBuf);
  548. SetCurrentDirectory(@Drive);
  549. end;
  550. GetCurrentDirectory(SizeOf(DirBuf),DirBuf);
  551. if not defaultdrive then
  552. SetCurrentDirectory(@SaveBuf);
  553. dir:=strpas(DirBuf);
  554. if not FileNameCaseSensitive then
  555. dir:=upcase(dir);
  556. end;
  557. {*****************************************************************************
  558. SystemUnit Initialization
  559. *****************************************************************************}
  560. { Startup }
  561. procedure GetStartupInfo(p : pointer);
  562. external 'kernel32' name 'GetStartupInfoA';
  563. function GetStdHandle(nStdHandle:DWORD):THANDLE;
  564. external 'kernel32' name 'GetStdHandle';
  565. { command line/enviroment functions }
  566. function GetCommandLine : pchar;
  567. external 'kernel32' name 'GetCommandLineA';
  568. var
  569. ModuleName : array[0..255] of char;
  570. function GetCommandFile:pchar;
  571. begin
  572. GetModuleFileName(0,@ModuleName,255);
  573. GetCommandFile:=@ModuleName;
  574. end;
  575. procedure setup_arguments;
  576. var
  577. arglen,
  578. count : longint;
  579. argstart,
  580. pc : pchar;
  581. quote : set of char;
  582. argsbuf : array[0..127] of pchar;
  583. begin
  584. { create commandline, it starts with the executed filename which is argv[0] }
  585. { Win32 passes the command NOT via the args, but via getmodulefilename}
  586. count:=0;
  587. pc:=getcommandfile;
  588. Arglen:=0;
  589. repeat
  590. Inc(Arglen);
  591. until (pc[Arglen]=#0);
  592. getmem(argsbuf[count],arglen+1);
  593. move(pc^,argsbuf[count]^,arglen);
  594. { Now skip the first one }
  595. pc:=GetCommandLine;
  596. repeat
  597. { skip leading spaces }
  598. while pc^ in [' ',#9,#13] do
  599. inc(pc);
  600. case pc^ of
  601. #0 : break;
  602. '"' : begin
  603. quote:=['"'];
  604. inc(pc);
  605. end;
  606. '''' : begin
  607. quote:=[''''];
  608. inc(pc);
  609. end;
  610. else
  611. quote:=[' ',#9,#13];
  612. end;
  613. { scan until the end of the argument }
  614. argstart:=pc;
  615. while (pc^<>#0) and not(pc^ in quote) do
  616. inc(pc);
  617. { Don't copy the first one, it is already there.}
  618. If Count<>0 then
  619. begin
  620. { reserve some memory }
  621. arglen:=pc-argstart;
  622. getmem(argsbuf[count],arglen+1);
  623. move(argstart^,argsbuf[count]^,arglen);
  624. argsbuf[count][arglen]:=#0;
  625. end;
  626. { skip quote }
  627. if pc^ in quote then
  628. inc(pc);
  629. inc(count);
  630. until false;
  631. { create argc }
  632. argc:=count;
  633. { create an nil entry }
  634. argsbuf[count]:=nil;
  635. inc(count);
  636. { create the argv }
  637. getmem(argv,count shl 2);
  638. move(argsbuf,argv^,count shl 2);
  639. { Setup cmdline variable }
  640. cmdline:=GetCommandLine;
  641. end;
  642. {*****************************************************************************
  643. System Dependent Exit code
  644. *****************************************************************************}
  645. Procedure system_exit;
  646. begin
  647. { don't call ExitProcess inside
  648. the DLL exit code !!
  649. This crashes Win95 at least PM }
  650. if IsLibrary then
  651. Exit;
  652. if not IsConsole then
  653. begin
  654. Close(stderr);
  655. Close(stdout);
  656. { what about Input and Output ?? PM }
  657. end;
  658. ExitProcess(ExitCode);
  659. end;
  660. {$ifdef dummy}
  661. Function SetUpStack : longint;
  662. { This routine does the following : }
  663. { returns the value of the initial SP - __stklen }
  664. begin
  665. asm
  666. pushl %ebx
  667. pushl %eax
  668. movl __stklen,%ebx
  669. movl %esp,%eax
  670. subl %ebx,%eax
  671. movl %eax,__RESULT
  672. popl %eax
  673. popl %ebx
  674. end;
  675. end;
  676. {$endif}
  677. procedure install_exception_handlers;forward;
  678. procedure PascalMain;external name 'PASCALMAIN';
  679. procedure fpc_do_exit;external name 'FPC_DO_EXIT';
  680. var
  681. { value of the stack segment
  682. to check if the call stack can be written on exceptions }
  683. _SS : longint;
  684. procedure Exe_entry;[public, alias : '_FPC_EXE_Entry'];
  685. begin
  686. IsLibrary:=false;
  687. { install the handlers for exe only ?
  688. or should we install them for DLL also ? (PM) }
  689. install_exception_handlers;
  690. { This strange construction is needed to solve the _SS problem
  691. with a smartlinked syswin32 (PFV) }
  692. asm
  693. pushl %ebp
  694. xorl %ebp,%ebp
  695. movl %esp,%eax
  696. movl %eax,Win32StackTop
  697. movw %ss,%bp
  698. movl %ebp,_SS
  699. xorl %ebp,%ebp
  700. call PASCALMAIN
  701. popl %ebp
  702. end;
  703. { if we pass here there was no error ! }
  704. system_exit;
  705. end;
  706. Const
  707. { DllEntryPoint }
  708. DLL_PROCESS_ATTACH = 1;
  709. DLL_THREAD_ATTACH = 2;
  710. DLL_PROCESS_DETACH = 0;
  711. DLL_THREAD_DETACH = 3;
  712. function Dll_entry : longbool;[public, alias : '_FPC_DLL_Entry'];
  713. var
  714. res : longbool;
  715. begin
  716. IsLibrary:=true;
  717. case DLLreason of
  718. DLL_PROCESS_ATTACH :
  719. begin
  720. asm
  721. movl %esp,%eax
  722. movl %eax,Win32StackTop
  723. xorl %edi,%edi
  724. movw %ss,%di
  725. movl %edi,_SS
  726. end;
  727. if assigned(Dll_Process_Attach_Hook) then
  728. begin
  729. res:=Dll_Process_Attach_Hook(DllParam);
  730. if not res then
  731. begin
  732. Dll_entry:=false;
  733. exit;
  734. end;
  735. end;
  736. PASCALMAIN;
  737. Dll_entry:=true;
  738. end;
  739. DLL_THREAD_ATTACH :
  740. begin
  741. inc(Thread_count);
  742. if assigned(Dll_Thread_Attach_Hook) then
  743. Dll_Thread_Attach_Hook(DllParam);
  744. Dll_entry:=true; { return value is ignored }
  745. end;
  746. DLL_THREAD_DETACH :
  747. begin
  748. dec(Thread_count);
  749. if assigned(Dll_Thread_Detach_Hook) then
  750. Dll_Thread_Detach_Hook(DllParam);
  751. Dll_entry:=true; { return value is ignored }
  752. end;
  753. DLL_PROCESS_DETACH :
  754. begin
  755. inc(Thread_count);
  756. Dll_entry:=true; { return value is ignored }
  757. FPC_DO_EXIT;
  758. if assigned(Dll_Process_Detach_Hook) then
  759. Dll_Process_Detach_Hook(DllParam);
  760. end;
  761. end;
  762. end;
  763. {$ifdef Set_i386_Exception_handler}
  764. const
  765. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  766. EXCEPTION_ACCESS_VIOLATION = $c0000005;
  767. EXCEPTION_BREAKPOINT = $80000003;
  768. EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
  769. EXCEPTION_SINGLE_STEP = $80000004;
  770. EXCEPTION_ARRAY_BOUNDS_EXCEEDED = $c000008c;
  771. EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d;
  772. EXCEPTION_FLT_DIVIDE_BY_ZERO = $c000008e;
  773. EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
  774. EXCEPTION_FLT_INVALID_OPERATION = $c0000090;
  775. EXCEPTION_FLT_OVERFLOW = $c0000091;
  776. EXCEPTION_FLT_STACK_CHECK = $c0000092;
  777. EXCEPTION_FLT_UNDERFLOW = $c0000093;
  778. EXCEPTION_INT_DIVIDE_BY_ZERO = $c0000094;
  779. EXCEPTION_INT_OVERFLOW = $c0000095;
  780. EXCEPTION_INVALID_HANDLE = $c0000008;
  781. EXCEPTION_PRIV_INSTRUCTION = $c0000096;
  782. EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
  783. EXCEPTION_NONCONTINUABLE = $1;
  784. EXCEPTION_STACK_OVERFLOW = $c00000fd;
  785. EXCEPTION_INVALID_DISPOSITION = $c0000026;
  786. ExceptionContinueExecution = 0;
  787. ExceptionContinueSearch = 1;
  788. type
  789. FLOATING_SAVE_AREA = record
  790. ControlWord : DWORD;
  791. StatusWord : DWORD;
  792. TagWord : DWORD;
  793. ErrorOffset : DWORD;
  794. ErrorSelector : DWORD;
  795. DataOffset : DWORD;
  796. DataSelector : DWORD;
  797. RegisterArea : array[0..79] of BYTE;
  798. Cr0NpxState : DWORD;
  799. end;
  800. _FLOATING_SAVE_AREA = FLOATING_SAVE_AREA;
  801. TFLOATINGSAVEAREA = FLOATING_SAVE_AREA;
  802. PFLOATINGSAVEAREA = ^FLOATING_SAVE_AREA;
  803. CONTEXT = record
  804. ContextFlags : DWORD;
  805. Dr0 : DWORD;
  806. Dr1 : DWORD;
  807. Dr2 : DWORD;
  808. Dr3 : DWORD;
  809. Dr6 : DWORD;
  810. Dr7 : DWORD;
  811. FloatSave : FLOATING_SAVE_AREA;
  812. SegGs : DWORD;
  813. SegFs : DWORD;
  814. SegEs : DWORD;
  815. SegDs : DWORD;
  816. Edi : DWORD;
  817. Esi : DWORD;
  818. Ebx : DWORD;
  819. Edx : DWORD;
  820. Ecx : DWORD;
  821. Eax : DWORD;
  822. Ebp : DWORD;
  823. Eip : DWORD;
  824. SegCs : DWORD;
  825. EFlags : DWORD;
  826. Esp : DWORD;
  827. SegSs : DWORD;
  828. end;
  829. LPCONTEXT = ^CONTEXT;
  830. _CONTEXT = CONTEXT;
  831. TCONTEXT = CONTEXT;
  832. PCONTEXT = ^CONTEXT;
  833. type pexception_record = ^exception_record;
  834. EXCEPTION_RECORD = record
  835. ExceptionCode : longint;
  836. ExceptionFlags : longint;
  837. ExceptionRecord : pexception_record;
  838. ExceptionAddress : pointer;
  839. NumberParameters : longint;
  840. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of pointer;
  841. end;
  842. PEXCEPTION_POINTERS = ^EXCEPTION_POINTERS;
  843. EXCEPTION_POINTERS = record
  844. ExceptionRecord : PEXCEPTION_RECORD ;
  845. ContextRecord : PCONTEXT ;
  846. end;
  847. { type of functions that should be used for exception handling }
  848. LPTOP_LEVEL_EXCEPTION_FILTER = function(excep :PEXCEPTION_POINTERS) : longint;
  849. function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : LPTOP_LEVEL_EXCEPTION_FILTER)
  850. : LPTOP_LEVEL_EXCEPTION_FILTER;
  851. external 'kernel32' name 'SetUnhandledExceptionFilter';
  852. function syswin32_i386_exception_handler(excep :PEXCEPTION_POINTERS) : longint;
  853. var frame : longint;
  854. begin
  855. { default : unhandled !}
  856. if excep^.ContextRecord^.SegSs=_SS then
  857. frame:=excep^.ContextRecord^.Ebp
  858. else
  859. frame:=0;
  860. syswin32_i386_exception_handler:=ExceptionContinueSearch;
  861. case excep^.ExceptionRecord^.ExceptionCode of
  862. EXCEPTION_ACCESS_VIOLATION :
  863. HandleErrorFrame(216,frame);
  864. { EXCEPTION_BREAKPOINT = $80000003;
  865. EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
  866. EXCEPTION_SINGLE_STEP = $80000004; }
  867. EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
  868. HandleErrorFrame(201,frame);
  869. { EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d; }
  870. EXCEPTION_FLT_DIVIDE_BY_ZERO :
  871. HandleErrorFrame(200,frame);
  872. {EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
  873. EXCEPTION_FLT_INVALID_OPERATION = $c0000090;}
  874. EXCEPTION_FLT_OVERFLOW :
  875. HandleErrorFrame(205,frame);
  876. EXCEPTION_FLT_STACK_CHECK :
  877. HandleErrorFrame(207,frame);
  878. { EXCEPTION_FLT_UNDERFLOW :
  879. HandleErrorFrame(206,frame); should be accepted as zero !! }
  880. EXCEPTION_INT_DIVIDE_BY_ZERO :
  881. HandleErrorFrame(200,frame);
  882. EXCEPTION_INT_OVERFLOW :
  883. HandleErrorFrame(215,frame);
  884. {EXCEPTION_INVALID_HANDLE = $c0000008;
  885. EXCEPTION_PRIV_INSTRUCTION = $c0000096;
  886. EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
  887. EXCEPTION_NONCONTINUABLE = $1;}
  888. EXCEPTION_STACK_OVERFLOW :
  889. HandleErrorFrame(202,frame);
  890. {EXCEPTION_INVALID_DISPOSITION = $c0000026;}
  891. end;
  892. end;
  893. procedure install_exception_handlers;
  894. begin
  895. SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
  896. end;
  897. {$else not i386 (Processor specific !!)}
  898. procedure install_exception_handlers;
  899. begin
  900. end;
  901. {$endif Set_i386_Exception_handler}
  902. {****************************************************************************
  903. Error Message writing using messageboxes
  904. ****************************************************************************}
  905. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  906. external 'user32' name 'MessageBoxA';
  907. const
  908. ErrorBufferLength = 1024;
  909. var
  910. ErrorBuf : array[0..ErrorBufferLength] of char;
  911. ErrorLen : longint;
  912. Function ErrorWrite(Var F: TextRec): Integer;
  913. {
  914. An error message should always end with #13#10#13#10
  915. }
  916. var
  917. p : pchar;
  918. i : longint;
  919. Begin
  920. if F.BufPos>0 then
  921. begin
  922. if F.BufPos+ErrorLen>ErrorBufferLength then
  923. i:=ErrorBufferLength-ErrorLen
  924. else
  925. i:=F.BufPos;
  926. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  927. inc(ErrorLen,i);
  928. ErrorBuf[ErrorLen]:=#0;
  929. end;
  930. if ErrorLen>3 then
  931. begin
  932. p:=@ErrorBuf[ErrorLen];
  933. for i:=1 to 4 do
  934. begin
  935. dec(p);
  936. if not(p^ in [#10,#13]) then
  937. break;
  938. end;
  939. end;
  940. if ErrorLen=ErrorBufferLength then
  941. i:=4;
  942. if (i=4) then
  943. begin
  944. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  945. ErrorLen:=0;
  946. end;
  947. F.BufPos:=0;
  948. ErrorWrite:=0;
  949. End;
  950. Function ErrorClose(Var F: TextRec): Integer;
  951. begin
  952. if ErrorLen>0 then
  953. begin
  954. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  955. ErrorLen:=0;
  956. end;
  957. ErrorLen:=0;
  958. ErrorClose:=0;
  959. end;
  960. Function ErrorOpen(Var F: TextRec): Integer;
  961. Begin
  962. TextRec(F).InOutFunc:=@ErrorWrite;
  963. TextRec(F).FlushFunc:=@ErrorWrite;
  964. TextRec(F).CloseFunc:=@ErrorClose;
  965. ErrorOpen:=0;
  966. End;
  967. procedure AssignError(Var T: Text);
  968. begin
  969. Assign(T,'');
  970. TextRec(T).OpenFunc:=@ErrorOpen;
  971. Rewrite(T);
  972. end;
  973. const
  974. Exe_entry_code : pointer = @Exe_entry;
  975. Dll_entry_code : pointer = @Dll_entry;
  976. begin
  977. { get some helpful informations }
  978. GetStartupInfo(@startupinfo);
  979. { some misc Win32 stuff }
  980. hprevinst:=0;
  981. if not IsLibrary then
  982. HInstance:=getmodulehandle(GetCommandFile);
  983. MainInstance:=HInstance;
  984. { No idea how to know this issue !! }
  985. IsMultithreaded:=false;
  986. cmdshow:=startupinfo.wshowwindow;
  987. { to test stack depth }
  988. loweststack:=maxlongint;
  989. { real test stack depth }
  990. { stacklimit := setupstack; }
  991. { Setup heap }
  992. InitHeap;
  993. InitExceptions;
  994. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  995. displayed in and messagebox }
  996. StdInputHandle:=longint(GetStdHandle(STD_INPUT_HANDLE));
  997. StdOutputHandle:=longint(GetStdHandle(STD_OUTPUT_HANDLE));
  998. StdErrorHandle:=longint(GetStdHandle(STD_ERROR_HANDLE));
  999. if not IsConsole then
  1000. begin
  1001. AssignError(stderr);
  1002. AssignError(stdout);
  1003. Assign(Output,'');
  1004. Assign(Input,'');
  1005. end
  1006. else
  1007. begin
  1008. OpenStdIO(Input,fmInput,StdInputHandle);
  1009. OpenStdIO(Output,fmOutput,StdOutputHandle);
  1010. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  1011. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  1012. end;
  1013. { Arguments }
  1014. setup_arguments;
  1015. { Reset IO Error }
  1016. InOutRes:=0;
  1017. { Reset internal error variable }
  1018. errno:=0;
  1019. end.
  1020. {
  1021. $Log$
  1022. Revision 1.57 2000-01-18 09:03:04 pierre
  1023. * DLL crash fixed : ExitProcess can not be called in DLL system_exit
  1024. Problem : Halt or RunError code inside DLL will return to caller !!
  1025. * Changed the "if h<4 then" into "if do_isdevice(h) then " in do_close
  1026. to avoid closing of standard files
  1027. Revision 1.56 2000/01/16 23:05:03 peter
  1028. * fixed typo
  1029. Revision 1.55 2000/01/16 22:25:38 peter
  1030. * check handle for file closing
  1031. Revision 1.54 2000/01/07 16:41:52 daniel
  1032. * copyright 2000
  1033. Revision 1.53 2000/01/07 16:32:34 daniel
  1034. * copyright 2000 added
  1035. Revision 1.52 2000/01/06 23:40:36 peter
  1036. * fixed exitprocess call, it's now in system_exit and uses exitcode
  1037. Revision 1.51 1999/12/01 22:57:31 peter
  1038. * cmdline support
  1039. Revision 1.50 1999/11/20 00:16:44 pierre
  1040. + DLL Hooks for the four callings added
  1041. Revision 1.49 1999/11/18 22:19:57 pierre
  1042. * bug fix for web bug703 and 704
  1043. Revision 1.48 1999/11/09 22:34:00 pierre
  1044. * Check ErrorBuf at exit
  1045. + Win32StackTop
  1046. Revision 1.47 1999/10/26 12:25:51 peter
  1047. * report stderr,stdout to message box for errors
  1048. * close input,output when GUI app is made
  1049. Revision 1.46 1999/10/22 14:47:19 peter
  1050. * allocate an extra byte for argv[0]
  1051. Revision 1.45 1999/10/03 19:39:05 peter
  1052. * fixed argv[0] length
  1053. Revision 1.44 1999/09/10 15:40:35 peter
  1054. * fixed do_open flags to be > $100, becuase filemode can be upto 255
  1055. Revision 1.43 1999/07/07 10:04:43 michael
  1056. + Small edit in paramstr
  1057. Revision 1.42 1999/07/07 09:43:16 michael
  1058. Better construction of commandline argv
  1059. Revision 1.41 1999/07/05 20:04:30 peter
  1060. * removed temp defines
  1061. Revision 1.40 1999/06/11 16:26:40 michael
  1062. + Fixed paramstr(0)
  1063. Revision 1.39 1999/05/17 21:52:47 florian
  1064. * most of the Object Pascal stuff moved to the system unit
  1065. Revision 1.38 1999/04/28 11:42:53 peter
  1066. + FileNameCaseSensetive boolean
  1067. Revision 1.37 1999/04/08 12:23:11 peter
  1068. * removed os.inc
  1069. Revision 1.36 1999/03/24 23:25:59 peter
  1070. * fixed file sharing
  1071. Revision 1.35 1999/03/12 00:07:48 pierre
  1072. + code for coff writer
  1073. Revision 1.34 1999/03/10 22:15:31 florian
  1074. + system.cmdline variable for go32v2 and win32 added
  1075. Revision 1.33 1999/01/18 10:05:57 pierre
  1076. + system_exit procedure added
  1077. Revision 1.32 1998/12/28 23:30:11 peter
  1078. * fixes for smartlinking
  1079. Revision 1.31 1998/12/28 15:50:51 peter
  1080. + stdout, which is needed when you write something in the system unit
  1081. to the screen. Like the runtime error
  1082. Revision 1.30 1998/12/21 14:28:23 pierre
  1083. * HandleError -> HandleErrorFrame to avoid problem in
  1084. assembler code in i386.inc
  1085. (call to overloaded function in assembler block !)
  1086. Revision 1.29 1998/12/15 22:43:14 peter
  1087. * removed temp symbols
  1088. Revision 1.28 1998/12/09 17:57:33 pierre
  1089. + exception handling by default
  1090. Revision 1.27 1998/12/01 14:00:08 pierre
  1091. + added conversion from exceptions into run time error
  1092. (only if syswin32 compiled with -ddebug for now !)
  1093. * added HandleErrorFrame(errno,frame)
  1094. where you specify the frame
  1095. needed for win32 exception handling
  1096. Revision 1.26 1998/11/30 13:13:41 pierre
  1097. * needs asw to link correctly wprt0 or wdllprt0 file
  1098. Revision 1.25 1998/11/30 09:16:58 pierre
  1099. + added the changes from Pavel Ozerski after several modifications
  1100. to be able to create DLLs
  1101. Revision 1.24 1998/11/16 15:48:54 peter
  1102. * fixed longbool returns for api calls
  1103. Revision 1.23 1998/11/16 14:14:58 pierre
  1104. * changed getdir(byte,string) to getdir(byte,shortstring)
  1105. Revision 1.22 1998/10/27 15:07:16 florian
  1106. + Is* flags added
  1107. + IsLibrary works also
  1108. Revision 1.21 1998/10/15 16:26:19 peter
  1109. + fpuinit
  1110. + end of backtrace indicator
  1111. Revision 1.20 1998/09/14 10:48:33 peter
  1112. * FPC_ names
  1113. * Heap manager is now system independent
  1114. Revision 1.19 1998/09/02 09:03:46 pierre
  1115. * do_open sometimes returns -1 as handle on fail
  1116. was not checked correctly
  1117. Revision 1.16 1998/08/24 14:45:22 pierre
  1118. * sbrk was wrong
  1119. heap growing now works for win32
  1120. Revision 1.15 1998/08/21 10:10:16 peter
  1121. * winheap turned off by default
  1122. Revision 1.14 1998/07/30 13:27:19 michael
  1123. + Added support for errorproc. Changed runerror to HandleError
  1124. Revision 1.13 1998/07/13 21:19:15 florian
  1125. * some problems with ansi string support fixed
  1126. Revision 1.12 1998/07/07 12:37:28 carl
  1127. * correct mapping of error codes for TP compatibility
  1128. + implemented stack checking in ifdef dummy
  1129. Revision 1.11 1998/07/02 12:33:18 carl
  1130. * IOCheck/InOutRes check for mkdir,rmdir and chdir like in TP
  1131. Revision 1.10 1998/07/01 15:30:02 peter
  1132. * better readln/writeln
  1133. Revision 1.9 1998/06/10 10:39:17 peter
  1134. * working w32 rtl
  1135. Revision 1.8 1998/06/08 23:07:47 peter
  1136. * dos interface is now 100% compatible
  1137. * fixed call PASCALMAIN which must be direct asm
  1138. Revision 1.7 1998/05/06 12:36:51 michael
  1139. + Removed log from before restored version.
  1140. Revision 1.6 1998/04/27 18:29:09 florian
  1141. + do_open implemented, the file-I/O should be now complete
  1142. Revision 1.5 1998/04/27 13:58:21 florian
  1143. + paramstr/paramcount implemented
  1144. Revision 1.4 1998/04/26 22:37:22 florian
  1145. * some small extensions
  1146. Revision 1.3 1998/04/26 21:49:57 florian
  1147. + more stuff added (??dir procedures etc.)
  1148. }