system.pp 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754
  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. {$ifndef VER1_0}
  14. { $define MT}
  15. {$endif VER1_0}
  16. unit {$ifdef VER1_0}SysWin32{$else}System{$endif};
  17. interface
  18. {$ifdef SYSTEMDEBUG}
  19. {$define SYSTEMEXCEPTIONDEBUG}
  20. {$endif SYSTEMDEBUG}
  21. {$ifdef cpui386}
  22. {$define Set_i386_Exception_handler}
  23. {$endif cpui386}
  24. { include system-independent routine headers }
  25. {$I systemh.inc}
  26. {Platform specific information}
  27. type
  28. {$ifdef CPU64}
  29. THandle = QWord;
  30. {$else CPU64}
  31. THandle = DWord;
  32. {$endif CPU64}
  33. const
  34. LineEnding = #13#10;
  35. LFNSupport = true;
  36. DirectorySeparator = '\';
  37. DriveSeparator = ':';
  38. PathSeparator = ';';
  39. { FileNameCaseSensitive is defined separately below!!! }
  40. maxExitCode = 65535;
  41. type
  42. PEXCEPTION_FRAME = ^TEXCEPTION_FRAME;
  43. TEXCEPTION_FRAME = record
  44. next : PEXCEPTION_FRAME;
  45. handler : pointer;
  46. end;
  47. { include heap support headers }
  48. {$I heaph.inc}
  49. const
  50. { Default filehandles }
  51. UnusedHandle : THandle = -1;
  52. StdInputHandle : THandle = 0;
  53. StdOutputHandle : THandle = 0;
  54. StdErrorHandle : THandle = 0;
  55. FileNameCaseSensitive : boolean = true;
  56. sLineBreak = LineEnding;
  57. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  58. { Thread count for DLL }
  59. Thread_count : longint = 0;
  60. System_exception_frame : PEXCEPTION_FRAME =nil;
  61. type
  62. TStartupInfo=packed record
  63. cb : longint;
  64. lpReserved : Pointer;
  65. lpDesktop : Pointer;
  66. lpTitle : Pointer;
  67. dwX : longint;
  68. dwY : longint;
  69. dwXSize : longint;
  70. dwYSize : longint;
  71. dwXCountChars : longint;
  72. dwYCountChars : longint;
  73. dwFillAttribute : longint;
  74. dwFlags : longint;
  75. wShowWindow : Word;
  76. cbReserved2 : Word;
  77. lpReserved2 : Pointer;
  78. hStdInput : longint;
  79. hStdOutput : longint;
  80. hStdError : longint;
  81. end;
  82. var
  83. { C compatible arguments }
  84. argc : longint;
  85. argv : ppchar;
  86. { Win32 Info }
  87. startupinfo : tstartupinfo;
  88. hprevinst,
  89. HInstance,
  90. MainInstance,
  91. cmdshow : longint;
  92. DLLreason,DLLparam:longint;
  93. Win32StackTop : Dword;
  94. type
  95. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  96. TDLL_Entry_Hook = procedure (dllparam : longint);
  97. const
  98. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  99. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  100. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  101. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  102. type
  103. HMODULE = THandle;
  104. implementation
  105. { include system independent routines }
  106. {$I system.inc}
  107. { some declarations for Win32 API calls }
  108. {$I win32.inc}
  109. CONST
  110. { These constants are used for conversion of error codes }
  111. { from win32 i/o errors to tp i/o errors }
  112. { errors 1 to 18 are the same as in Turbo Pascal }
  113. { DO NOT MODIFY UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING! }
  114. { The media is write protected. }
  115. ERROR_WRITE_PROTECT = 19;
  116. { The system cannot find the device specified. }
  117. ERROR_BAD_UNIT = 20;
  118. { The device is not ready. }
  119. ERROR_NOT_READY = 21;
  120. { The device does not recognize the command. }
  121. ERROR_BAD_COMMAND = 22;
  122. { Data error (cyclic redundancy check) }
  123. ERROR_CRC = 23;
  124. { The program issued a command but the }
  125. { command length is incorrect. }
  126. ERROR_BAD_LENGTH = 24;
  127. { The drive cannot locate a specific }
  128. { area or track on the disk. }
  129. ERROR_SEEK = 25;
  130. { The specified disk or diskette cannot be accessed. }
  131. ERROR_NOT_DOS_DISK = 26;
  132. { The drive cannot find the sector requested. }
  133. ERROR_SECTOR_NOT_FOUND = 27;
  134. { The printer is out of paper. }
  135. ERROR_OUT_OF_PAPER = 28;
  136. { The system cannot write to the specified device. }
  137. ERROR_WRITE_FAULT = 29;
  138. { The system cannot read from the specified device. }
  139. ERROR_READ_FAULT = 30;
  140. { A device attached to the system is not functioning.}
  141. ERROR_GEN_FAILURE = 31;
  142. { The process cannot access the file because }
  143. { it is being used by another process. }
  144. ERROR_SHARING_VIOLATION = 32;
  145. { A pipe has been closed on the other end }
  146. { Removing that error allows eof to works as on other OSes }
  147. ERROR_BROKEN_PIPE = 109;
  148. ERROR_DIR_NOT_EMPTY = 145;
  149. ERROR_ALREADY_EXISTS = 183;
  150. {$IFDEF SUPPORT_THREADVAR}
  151. threadvar
  152. {$ELSE SUPPORT_THREADVAR}
  153. var
  154. {$ENDIF SUPPORT_THREADVAR}
  155. errno : longint;
  156. {$ASMMODE ATT}
  157. { misc. functions }
  158. function GetLastError : DWORD;
  159. stdcall;external 'kernel32' name 'GetLastError';
  160. { time and date functions }
  161. function GetTickCount : longint;
  162. stdcall;external 'kernel32' name 'GetTickCount';
  163. { process functions }
  164. procedure ExitProcess(uExitCode : UINT);
  165. stdcall;external 'kernel32' name 'ExitProcess';
  166. Procedure Errno2InOutRes;
  167. Begin
  168. { DO NOT MODIFY UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING }
  169. case Errno of
  170. ERROR_WRITE_PROTECT..ERROR_GEN_FAILURE :
  171. begin
  172. { This is the offset to the Win32 to add to directly map }
  173. { to the DOS/TP compatible error codes when in this range }
  174. InOutRes := word(errno)+131;
  175. end;
  176. ERROR_DIR_NOT_EMPTY,
  177. ERROR_ALREADY_EXISTS,
  178. ERROR_SHARING_VIOLATION :
  179. begin
  180. InOutRes :=5;
  181. end;
  182. else
  183. begin
  184. { other error codes can directly be mapped }
  185. InOutRes := Word(errno);
  186. end;
  187. end;
  188. errno:=0;
  189. end;
  190. function paramcount : longint;
  191. begin
  192. paramcount := argc - 1;
  193. end;
  194. { module functions }
  195. function GetModuleFileName(l1:longint;p:pointer;l2:longint):longint;
  196. stdcall;external 'kernel32' name 'GetModuleFileNameA';
  197. function GetModuleHandle(p : pointer) : longint;
  198. stdcall;external 'kernel32' name 'GetModuleHandleA';
  199. function GetCommandFile:pchar;forward;
  200. function paramstr(l : longint) : string;
  201. begin
  202. if (l>=0) and (l<argc) then
  203. paramstr:=strpas(argv[l])
  204. else
  205. paramstr:='';
  206. end;
  207. procedure randomize;
  208. begin
  209. randseed:=GetTickCount;
  210. end;
  211. {*****************************************************************************
  212. Heap Management
  213. *****************************************************************************}
  214. { memory functions }
  215. function GetProcessHeap : DWord;
  216. stdcall;external 'kernel32' name 'GetProcessHeap';
  217. function HeapAlloc(hHeap : DWord; dwFlags : DWord; dwBytes : DWord) : Longint;
  218. stdcall;external 'kernel32' name 'HeapAlloc';
  219. function HeapFree(hHeap : dword; dwFlags : dword; lpMem: pointer) : boolean;
  220. stdcall;external 'kernel32' name 'HeapFree';
  221. {$IFDEF SYSTEMDEBUG}
  222. function WinAPIHeapSize(hHeap : DWord; dwFlags : DWord; ptr : Pointer) : DWord;
  223. stdcall;external 'kernel32' name 'HeapSize';
  224. {$ENDIF}
  225. {*****************************************************************************
  226. OS Memory allocation / deallocation
  227. ****************************************************************************}
  228. function SysOSAlloc(size: ptrint): pointer;
  229. var
  230. l : longword;
  231. begin
  232. l := HeapAlloc(GetProcessHeap, 0, size);
  233. {$ifdef DUMPGROW}
  234. Writeln('new heap part at $',hexstr(l,8), ' size = ',WinAPIHeapSize(GetProcessHeap()));
  235. {$endif}
  236. SysOSAlloc := pointer(l);
  237. end;
  238. {$define HAS_SYSOSFREE}
  239. procedure SysOSFree(p: pointer; size: ptrint);
  240. begin
  241. HeapFree(GetProcessHeap, 0, p);
  242. end;
  243. { include standard heap management }
  244. {$I heap.inc}
  245. {*****************************************************************************
  246. Low Level File Routines
  247. *****************************************************************************}
  248. function WriteFile(fh:thandle;buf:pointer;len:longint;var loaded:longint;
  249. overlap:pointer):longint;
  250. stdcall;external 'kernel32' name 'WriteFile';
  251. function ReadFile(fh:thandle;buf:pointer;len:longint;var loaded:longint;
  252. overlap:pointer):longint;
  253. stdcall;external 'kernel32' name 'ReadFile';
  254. function CloseHandle(h : thandle) : longint;
  255. stdcall;external 'kernel32' name 'CloseHandle';
  256. function DeleteFile(p : pchar) : longint;
  257. stdcall;external 'kernel32' name 'DeleteFileA';
  258. function MoveFile(old,_new : pchar) : longint;
  259. stdcall;external 'kernel32' name 'MoveFileA';
  260. function SetFilePointer(l1,l2 : thandle;l3 : pointer;l4 : longint) : longint;
  261. stdcall;external 'kernel32' name 'SetFilePointer';
  262. function GetFileSize(h:thandle;p:pointer) : longint;
  263. stdcall;external 'kernel32' name 'GetFileSize';
  264. function CreateFile(lpFileName:pchar; dwDesiredAccess:DWORD; dwShareMode:DWORD;
  265. lpSecurityAttributes:PSECURITYATTRIBUTES; dwCreationDisposition:DWORD;
  266. dwFlagsAndAttributes:DWORD; hTemplateFile:DWORD):longint;
  267. stdcall;external 'kernel32' name 'CreateFileA';
  268. function SetEndOfFile(h : thandle) : longbool;
  269. stdcall;external 'kernel32' name 'SetEndOfFile';
  270. function GetFileType(Handle:thandle):DWord;
  271. stdcall;external 'kernel32' name 'GetFileType';
  272. function GetFileAttributes(p : pchar) : dword;
  273. stdcall;external 'kernel32' name 'GetFileAttributesA';
  274. procedure AllowSlash(p:pchar);
  275. var
  276. i : longint;
  277. begin
  278. { allow slash as backslash }
  279. for i:=0 to strlen(p) do
  280. if p[i]='/' then p[i]:='\';
  281. end;
  282. function do_isdevice(handle:thandle):boolean;
  283. begin
  284. do_isdevice:=(getfiletype(handle)=2);
  285. end;
  286. procedure do_close(h : thandle);
  287. begin
  288. if do_isdevice(h) then
  289. exit;
  290. CloseHandle(h);
  291. end;
  292. procedure do_erase(p : pchar);
  293. begin
  294. AllowSlash(p);
  295. if DeleteFile(p)=0 then
  296. Begin
  297. errno:=GetLastError;
  298. if errno=5 then
  299. begin
  300. if (GetFileAttributes(p)=FILE_ATTRIBUTE_DIRECTORY) then
  301. errno:=2;
  302. end;
  303. Errno2InoutRes;
  304. end;
  305. end;
  306. procedure do_rename(p1,p2 : pchar);
  307. begin
  308. AllowSlash(p1);
  309. AllowSlash(p2);
  310. if MoveFile(p1,p2)=0 then
  311. Begin
  312. errno:=GetLastError;
  313. Errno2InoutRes;
  314. end;
  315. end;
  316. function do_write(h:thandle;addr:pointer;len : longint) : longint;
  317. var
  318. size:longint;
  319. begin
  320. if writefile(h,addr,len,size,nil)=0 then
  321. Begin
  322. errno:=GetLastError;
  323. Errno2InoutRes;
  324. end;
  325. do_write:=size;
  326. end;
  327. function do_read(h:thandle;addr:pointer;len : longint) : longint;
  328. var
  329. _result:longint;
  330. begin
  331. if readfile(h,addr,len,_result,nil)=0 then
  332. Begin
  333. errno:=GetLastError;
  334. if errno=ERROR_BROKEN_PIPE then
  335. errno:=0
  336. else
  337. Errno2InoutRes;
  338. end;
  339. do_read:=_result;
  340. end;
  341. function do_filepos(handle : thandle) : longint;
  342. var
  343. l:longint;
  344. begin
  345. l:=SetFilePointer(handle,0,nil,FILE_CURRENT);
  346. if l=-1 then
  347. begin
  348. l:=0;
  349. errno:=GetLastError;
  350. Errno2InoutRes;
  351. end;
  352. do_filepos:=l;
  353. end;
  354. procedure do_seek(handle:thandle;pos : longint);
  355. begin
  356. if SetFilePointer(handle,pos,nil,FILE_BEGIN)=-1 then
  357. Begin
  358. errno:=GetLastError;
  359. Errno2InoutRes;
  360. end;
  361. end;
  362. function do_seekend(handle:thandle):longint;
  363. begin
  364. do_seekend:=SetFilePointer(handle,0,nil,FILE_END);
  365. if do_seekend=-1 then
  366. begin
  367. errno:=GetLastError;
  368. Errno2InoutRes;
  369. end;
  370. end;
  371. function do_filesize(handle : thandle) : longint;
  372. var
  373. aktfilepos : longint;
  374. begin
  375. aktfilepos:=do_filepos(handle);
  376. do_filesize:=do_seekend(handle);
  377. do_seek(handle,aktfilepos);
  378. end;
  379. procedure do_truncate (handle:thandle;pos:longint);
  380. begin
  381. do_seek(handle,pos);
  382. if not(SetEndOfFile(handle)) then
  383. begin
  384. errno:=GetLastError;
  385. Errno2InoutRes;
  386. end;
  387. end;
  388. procedure do_open(var f;p:pchar;flags:longint);
  389. {
  390. filerec and textrec have both handle and mode as the first items so
  391. they could use the same routine for opening/creating.
  392. when (flags and $100) the file will be append
  393. when (flags and $1000) the file will be truncate/rewritten
  394. when (flags and $10000) there is no check for close (needed for textfiles)
  395. }
  396. Const
  397. file_Share_Read = $00000001;
  398. file_Share_Write = $00000002;
  399. Var
  400. shflags,
  401. oflags,cd : longint;
  402. security : TSecurityAttributes;
  403. begin
  404. AllowSlash(p);
  405. { close first if opened }
  406. if ((flags and $10000)=0) then
  407. begin
  408. case filerec(f).mode of
  409. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  410. fmclosed : ;
  411. else
  412. begin
  413. {not assigned}
  414. inoutres:=102;
  415. exit;
  416. end;
  417. end;
  418. end;
  419. { reset file handle }
  420. filerec(f).handle:=UnusedHandle;
  421. { convert filesharing }
  422. shflags:=0;
  423. if ((filemode and fmshareExclusive) = fmshareExclusive) then
  424. { no sharing }
  425. else
  426. if (filemode = fmShareCompat) or ((filemode and fmshareDenyWrite) = fmshareDenyWrite) then
  427. shflags := file_Share_Read
  428. else
  429. if ((filemode and fmshareDenyRead) = fmshareDenyRead) then
  430. shflags := file_Share_Write
  431. else
  432. if ((filemode and fmshareDenyNone) = fmshareDenyNone) then
  433. shflags := file_Share_Read + file_Share_Write;
  434. { convert filemode to filerec modes }
  435. case (flags and 3) of
  436. 0 : begin
  437. filerec(f).mode:=fminput;
  438. oflags:=longint(GENERIC_READ);
  439. end;
  440. 1 : begin
  441. filerec(f).mode:=fmoutput;
  442. oflags:=longint(GENERIC_WRITE);
  443. end;
  444. 2 : begin
  445. filerec(f).mode:=fminout;
  446. oflags:=longint(GENERIC_WRITE or GENERIC_READ);
  447. end;
  448. end;
  449. { create it ? }
  450. if (flags and $1000)<>0 then
  451. cd:=CREATE_ALWAYS
  452. { or Append/Open ? }
  453. else
  454. cd:=OPEN_EXISTING;
  455. { empty name is special }
  456. if p[0]=#0 then
  457. begin
  458. case FileRec(f).mode of
  459. fminput :
  460. FileRec(f).Handle:=StdInputHandle;
  461. fminout, { this is set by rewrite }
  462. fmoutput :
  463. FileRec(f).Handle:=StdOutputHandle;
  464. fmappend :
  465. begin
  466. FileRec(f).Handle:=StdOutputHandle;
  467. FileRec(f).mode:=fmoutput; {fool fmappend}
  468. end;
  469. end;
  470. exit;
  471. end;
  472. security.nLength := Sizeof(TSecurityAttributes);
  473. security.bInheritHandle:=true;
  474. security.lpSecurityDescriptor:=nil;
  475. filerec(f).handle:=CreateFile(p,oflags,shflags,@security,cd,FILE_ATTRIBUTE_NORMAL,0);
  476. { append mode }
  477. if ((flags and $100)<>0) and
  478. (filerec(f).handle<>0) and
  479. (filerec(f).handle<>UnusedHandle) then
  480. begin
  481. do_seekend(filerec(f).handle);
  482. filerec(f).mode:=fmoutput; {fool fmappend}
  483. end;
  484. { get errors }
  485. { handle -1 is returned sometimes !! (PM) }
  486. if (filerec(f).handle=0) or (filerec(f).handle=UnusedHandle) then
  487. begin
  488. errno:=GetLastError;
  489. Errno2InoutRes;
  490. end;
  491. end;
  492. {*****************************************************************************
  493. UnTyped File Handling
  494. *****************************************************************************}
  495. {$i file.inc}
  496. {*****************************************************************************
  497. Typed File Handling
  498. *****************************************************************************}
  499. {$i typefile.inc}
  500. {*****************************************************************************
  501. Text File Handling
  502. *****************************************************************************}
  503. {$DEFINE EOF_CTRLZ}
  504. {$i text.inc}
  505. {*****************************************************************************
  506. Directory Handling
  507. *****************************************************************************}
  508. function CreateDirectory(name : pointer;sec : pointer) : longbool;
  509. stdcall;external 'kernel32' name 'CreateDirectoryA';
  510. function RemoveDirectory(name:pointer):longbool;
  511. stdcall;external 'kernel32' name 'RemoveDirectoryA';
  512. function SetCurrentDirectory(name : pointer) : longbool;
  513. stdcall;external 'kernel32' name 'SetCurrentDirectoryA';
  514. function GetCurrentDirectory(bufsize : longint;name : pchar) : longbool;
  515. stdcall;external 'kernel32' name 'GetCurrentDirectoryA';
  516. type
  517. TDirFnType=function(name:pointer):longbool;stdcall;
  518. procedure dirfn(afunc : TDirFnType;const s:string);
  519. var
  520. buffer : array[0..255] of char;
  521. begin
  522. move(s[1],buffer,length(s));
  523. buffer[length(s)]:=#0;
  524. AllowSlash(pchar(@buffer));
  525. if not aFunc(@buffer) then
  526. begin
  527. errno:=GetLastError;
  528. Errno2InoutRes;
  529. end;
  530. end;
  531. function CreateDirectoryTrunc(name:pointer):longbool;stdcall;
  532. begin
  533. CreateDirectoryTrunc:=CreateDirectory(name,nil);
  534. end;
  535. procedure mkdir(const s:string);[IOCHECK];
  536. begin
  537. If (s='') or (InOutRes <> 0) then
  538. exit;
  539. dirfn(TDirFnType(@CreateDirectoryTrunc),s);
  540. end;
  541. procedure rmdir(const s:string);[IOCHECK];
  542. begin
  543. if (s ='.') then
  544. InOutRes := 16;
  545. If (s='') or (InOutRes <> 0) then
  546. exit;
  547. dirfn(TDirFnType(@RemoveDirectory),s);
  548. end;
  549. procedure chdir(const s:string);[IOCHECK];
  550. begin
  551. If (s='') or (InOutRes <> 0) then
  552. exit;
  553. dirfn(TDirFnType(@SetCurrentDirectory),s);
  554. if Inoutres=2 then
  555. Inoutres:=3;
  556. end;
  557. procedure GetDir (DriveNr: byte; var Dir: ShortString);
  558. const
  559. Drive:array[0..3]of char=(#0,':',#0,#0);
  560. var
  561. defaultdrive:boolean;
  562. DirBuf,SaveBuf:array[0..259] of Char;
  563. begin
  564. defaultdrive:=drivenr=0;
  565. if not defaultdrive then
  566. begin
  567. byte(Drive[0]):=Drivenr+64;
  568. GetCurrentDirectory(SizeOf(SaveBuf),SaveBuf);
  569. if not SetCurrentDirectory(@Drive) then
  570. begin
  571. errno := word (GetLastError);
  572. Errno2InoutRes;
  573. Dir := char (DriveNr + 64) + ':\';
  574. SetCurrentDirectory(@SaveBuf);
  575. Exit;
  576. end;
  577. end;
  578. GetCurrentDirectory(SizeOf(DirBuf),DirBuf);
  579. if not defaultdrive then
  580. SetCurrentDirectory(@SaveBuf);
  581. dir:=strpas(DirBuf);
  582. if not FileNameCaseSensitive then
  583. dir:=upcase(dir);
  584. end;
  585. {*****************************************************************************
  586. SystemUnit Initialization
  587. *****************************************************************************}
  588. { Startup }
  589. procedure GetStartupInfo(p : pointer);
  590. stdcall;external 'kernel32' name 'GetStartupInfoA';
  591. function GetStdHandle(nStdHandle:DWORD):THANDLE;
  592. stdcall;external 'kernel32' name 'GetStdHandle';
  593. { command line/enviroment functions }
  594. function GetCommandLine : pchar;
  595. stdcall;external 'kernel32' name 'GetCommandLineA';
  596. function GetCurrentProcessId:DWORD;
  597. stdcall; external 'kernel32' name 'GetCurrentProcessId';
  598. function GetCurrentThreadId:DWORD;
  599. stdcall; external 'kernel32' name 'GetCurrentThreadId';
  600. var
  601. ModuleName : array[0..255] of char;
  602. function GetCommandFile:pchar;
  603. begin
  604. GetModuleFileName(0,@ModuleName,255);
  605. GetCommandFile:=@ModuleName;
  606. end;
  607. procedure setup_arguments;
  608. var
  609. arglen,
  610. count : longint;
  611. argstart,
  612. pc,arg : pchar;
  613. quote : char;
  614. argvlen : longint;
  615. procedure allocarg(idx,len:longint);
  616. begin
  617. if idx>=argvlen then
  618. begin
  619. argvlen:=(idx+8) and (not 7);
  620. sysreallocmem(argv,argvlen*sizeof(pointer));
  621. end;
  622. { use realloc to reuse already existing memory }
  623. { always allocate, even if length is zero, since }
  624. { the arg. is still present! }
  625. sysreallocmem(argv[idx],len+1);
  626. end;
  627. begin
  628. { create commandline, it starts with the executed filename which is argv[0] }
  629. { Win32 passes the command NOT via the args, but via getmodulefilename}
  630. count:=0;
  631. argv:=nil;
  632. argvlen:=0;
  633. pc:=getcommandfile;
  634. Arglen:=0;
  635. repeat
  636. Inc(Arglen);
  637. until (pc[Arglen]=#0);
  638. allocarg(count,arglen);
  639. move(pc^,argv[count]^,arglen);
  640. { Setup cmdline variable }
  641. cmdline:=GetCommandLine;
  642. { process arguments }
  643. pc:=cmdline;
  644. {$IfDef SYSTEM_DEBUG_STARTUP}
  645. Writeln(stderr,'Win32 GetCommandLine is #',pc,'#');
  646. {$EndIf }
  647. while pc^<>#0 do
  648. begin
  649. { skip leading spaces }
  650. while pc^ in [#1..#32] do
  651. inc(pc);
  652. if pc^=#0 then
  653. break;
  654. { calc argument length }
  655. quote:=' ';
  656. argstart:=pc;
  657. arglen:=0;
  658. while (pc^<>#0) do
  659. begin
  660. case pc^ of
  661. #1..#32 :
  662. begin
  663. if quote<>' ' then
  664. inc(arglen)
  665. else
  666. break;
  667. end;
  668. '"' :
  669. begin
  670. if quote<>'''' then
  671. begin
  672. if pchar(pc+1)^<>'"' then
  673. begin
  674. if quote='"' then
  675. quote:=' '
  676. else
  677. quote:='"';
  678. end
  679. else
  680. inc(pc);
  681. end
  682. else
  683. inc(arglen);
  684. end;
  685. '''' :
  686. begin
  687. if quote<>'"' then
  688. begin
  689. if pchar(pc+1)^<>'''' then
  690. begin
  691. if quote='''' then
  692. quote:=' '
  693. else
  694. quote:='''';
  695. end
  696. else
  697. inc(pc);
  698. end
  699. else
  700. inc(arglen);
  701. end;
  702. else
  703. inc(arglen);
  704. end;
  705. inc(pc);
  706. end;
  707. { copy argument }
  708. { Don't copy the first one, it is already there.}
  709. If Count<>0 then
  710. begin
  711. allocarg(count,arglen);
  712. quote:=' ';
  713. pc:=argstart;
  714. arg:=argv[count];
  715. while (pc^<>#0) do
  716. begin
  717. case pc^ of
  718. #1..#32 :
  719. begin
  720. if quote<>' ' then
  721. begin
  722. arg^:=pc^;
  723. inc(arg);
  724. end
  725. else
  726. break;
  727. end;
  728. '"' :
  729. begin
  730. if quote<>'''' then
  731. begin
  732. if pchar(pc+1)^<>'"' then
  733. begin
  734. if quote='"' then
  735. quote:=' '
  736. else
  737. quote:='"';
  738. end
  739. else
  740. inc(pc);
  741. end
  742. else
  743. begin
  744. arg^:=pc^;
  745. inc(arg);
  746. end;
  747. end;
  748. '''' :
  749. begin
  750. if quote<>'"' then
  751. begin
  752. if pchar(pc+1)^<>'''' then
  753. begin
  754. if quote='''' then
  755. quote:=' '
  756. else
  757. quote:='''';
  758. end
  759. else
  760. inc(pc);
  761. end
  762. else
  763. begin
  764. arg^:=pc^;
  765. inc(arg);
  766. end;
  767. end;
  768. else
  769. begin
  770. arg^:=pc^;
  771. inc(arg);
  772. end;
  773. end;
  774. inc(pc);
  775. end;
  776. arg^:=#0;
  777. end;
  778. {$IfDef SYSTEM_DEBUG_STARTUP}
  779. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  780. {$EndIf SYSTEM_DEBUG_STARTUP}
  781. inc(count);
  782. end;
  783. { get argc and create an nil entry }
  784. argc:=count;
  785. allocarg(argc,0);
  786. { free unused memory }
  787. sysreallocmem(argv,(argc+1)*sizeof(pointer));
  788. end;
  789. {*****************************************************************************
  790. System Dependent Exit code
  791. *****************************************************************************}
  792. procedure install_exception_handlers;forward;
  793. procedure remove_exception_handlers;forward;
  794. procedure PascalMain;stdcall;external name 'PASCALMAIN';
  795. procedure fpc_do_exit;stdcall;external name 'FPC_DO_EXIT';
  796. Procedure ExitDLL(Exitcode : longint); forward;
  797. procedure asm_exit(Exitcode : longint);external name 'asm_exit';
  798. Procedure system_exit;
  799. begin
  800. { don't call ExitProcess inside
  801. the DLL exit code !!
  802. This crashes Win95 at least PM }
  803. if IsLibrary then
  804. ExitDLL(ExitCode);
  805. if not IsConsole then
  806. begin
  807. Close(stderr);
  808. Close(stdout);
  809. { what about Input and Output ?? PM }
  810. end;
  811. remove_exception_handlers;
  812. { call exitprocess, with cleanup as required }
  813. asm_exit(exitcode);
  814. end;
  815. var
  816. { value of the stack segment
  817. to check if the call stack can be written on exceptions }
  818. _SS : Cardinal;
  819. procedure Exe_entry;[public, alias : '_FPC_EXE_Entry'];
  820. begin
  821. IsLibrary:=false;
  822. { install the handlers for exe only ?
  823. or should we install them for DLL also ? (PM) }
  824. install_exception_handlers;
  825. { This strange construction is needed to solve the _SS problem
  826. with a smartlinked syswin32 (PFV) }
  827. asm
  828. { allocate space for an exception frame }
  829. pushl $0
  830. pushl %fs:(0)
  831. { movl %esp,%fs:(0)
  832. but don't insert it as it doesn't
  833. point to anything yet
  834. this will be used in signals unit }
  835. movl %esp,%eax
  836. movl %eax,System_exception_frame
  837. pushl %ebp
  838. xorl %ebp,%ebp
  839. movl %esp,%eax
  840. movl %eax,Win32StackTop
  841. movw %ss,%bp
  842. movl %ebp,_SS
  843. call SysResetFPU
  844. xorl %ebp,%ebp
  845. call PASCALMAIN
  846. popl %ebp
  847. end;
  848. { if we pass here there was no error ! }
  849. system_exit;
  850. end;
  851. Const
  852. { DllEntryPoint }
  853. DLL_PROCESS_ATTACH = 1;
  854. DLL_THREAD_ATTACH = 2;
  855. DLL_PROCESS_DETACH = 0;
  856. DLL_THREAD_DETACH = 3;
  857. Var
  858. DLLBuf : Jmp_buf;
  859. Const
  860. DLLExitOK : boolean = true;
  861. function Dll_entry : longbool;[public, alias : '_FPC_DLL_Entry'];
  862. var
  863. res : longbool;
  864. begin
  865. IsLibrary:=true;
  866. Dll_entry:=false;
  867. case DLLreason of
  868. DLL_PROCESS_ATTACH :
  869. begin
  870. If SetJmp(DLLBuf) = 0 then
  871. begin
  872. if assigned(Dll_Process_Attach_Hook) then
  873. begin
  874. res:=Dll_Process_Attach_Hook(DllParam);
  875. if not res then
  876. exit(false);
  877. end;
  878. PASCALMAIN;
  879. Dll_entry:=true;
  880. end
  881. else
  882. Dll_entry:=DLLExitOK;
  883. end;
  884. DLL_THREAD_ATTACH :
  885. begin
  886. inc(Thread_count);
  887. {$warning Allocate Threadvars !}
  888. if assigned(Dll_Thread_Attach_Hook) then
  889. Dll_Thread_Attach_Hook(DllParam);
  890. Dll_entry:=true; { return value is ignored }
  891. end;
  892. DLL_THREAD_DETACH :
  893. begin
  894. dec(Thread_count);
  895. if assigned(Dll_Thread_Detach_Hook) then
  896. Dll_Thread_Detach_Hook(DllParam);
  897. {$warning Release Threadvars !}
  898. Dll_entry:=true; { return value is ignored }
  899. end;
  900. DLL_PROCESS_DETACH :
  901. begin
  902. Dll_entry:=true; { return value is ignored }
  903. If SetJmp(DLLBuf) = 0 then
  904. begin
  905. FPC_DO_EXIT;
  906. end;
  907. if assigned(Dll_Process_Detach_Hook) then
  908. Dll_Process_Detach_Hook(DllParam);
  909. end;
  910. end;
  911. end;
  912. Procedure ExitDLL(Exitcode : longint);
  913. begin
  914. DLLExitOK:=ExitCode=0;
  915. LongJmp(DLLBuf,1);
  916. end;
  917. function GetCurrentProcess : dword;
  918. stdcall;external 'kernel32' name 'GetCurrentProcess';
  919. function ReadProcessMemory(process : dword;address : pointer;dest : pointer;size : dword;bytesread : pdword) : longbool;
  920. stdcall;external 'kernel32' name 'ReadProcessMemory';
  921. function is_prefetch(p : pointer) : boolean;
  922. var
  923. a : array[0..15] of byte;
  924. doagain : boolean;
  925. instrlo,instrhi,opcode : byte;
  926. i : longint;
  927. begin
  928. result:=false;
  929. { read memory savely without causing another exeception }
  930. if not(ReadProcessMemory(GetCurrentProcess,p,@a,sizeof(a),nil)) then
  931. exit;
  932. i:=0;
  933. doagain:=true;
  934. while doagain and (i<15) do
  935. begin
  936. opcode:=a[i];
  937. instrlo:=opcode and $f;
  938. instrhi:=opcode and $f0;
  939. case instrhi of
  940. { prefix? }
  941. $20,$30:
  942. doagain:=(instrlo and 7)=6;
  943. $60:
  944. doagain:=(instrlo and $c)=4;
  945. $f0:
  946. doagain:=instrlo in [0,2,3];
  947. $0:
  948. begin
  949. result:=(instrlo=$f) and (a[i+1] in [$d,$18]);
  950. exit;
  951. end;
  952. else
  953. doagain:=false;
  954. end;
  955. inc(i);
  956. end;
  957. end;
  958. //
  959. // Hardware exception handling
  960. //
  961. {$ifdef Set_i386_Exception_handler}
  962. {
  963. Error code definitions for the Win32 API functions
  964. Values are 32 bit values layed out as follows:
  965. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  966. 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
  967. +---+-+-+-----------------------+-------------------------------+
  968. |Sev|C|R| Facility | Code |
  969. +---+-+-+-----------------------+-------------------------------+
  970. where
  971. Sev - is the severity code
  972. 00 - Success
  973. 01 - Informational
  974. 10 - Warning
  975. 11 - Error
  976. C - is the Customer code flag
  977. R - is a reserved bit
  978. Facility - is the facility code
  979. Code - is the facility's status code
  980. }
  981. const
  982. SEVERITY_SUCCESS = $00000000;
  983. SEVERITY_INFORMATIONAL = $40000000;
  984. SEVERITY_WARNING = $80000000;
  985. SEVERITY_ERROR = $C0000000;
  986. const
  987. STATUS_SEGMENT_NOTIFICATION = $40000005;
  988. DBG_TERMINATE_THREAD = $40010003;
  989. DBG_TERMINATE_PROCESS = $40010004;
  990. DBG_CONTROL_C = $40010005;
  991. DBG_CONTROL_BREAK = $40010008;
  992. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  993. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  994. STATUS_BREAKPOINT = $80000003;
  995. STATUS_SINGLE_STEP = $80000004;
  996. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  997. STATUS_ACCESS_VIOLATION = $C0000005;
  998. STATUS_IN_PAGE_ERROR = $C0000006;
  999. STATUS_INVALID_HANDLE = $C0000008;
  1000. STATUS_NO_MEMORY = $C0000017;
  1001. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  1002. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  1003. STATUS_INVALID_DISPOSITION = $C0000026;
  1004. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  1005. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  1006. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  1007. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  1008. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  1009. STATUS_FLOAT_OVERFLOW = $C0000091;
  1010. STATUS_FLOAT_STACK_CHECK = $C0000092;
  1011. STATUS_FLOAT_UNDERFLOW = $C0000093;
  1012. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  1013. STATUS_INTEGER_OVERFLOW = $C0000095;
  1014. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  1015. STATUS_STACK_OVERFLOW = $C00000FD;
  1016. STATUS_CONTROL_C_EXIT = $C000013A;
  1017. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  1018. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  1019. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  1020. EXCEPTION_EXECUTE_HANDLER = 1;
  1021. EXCEPTION_CONTINUE_EXECUTION = -1;
  1022. EXCEPTION_CONTINUE_SEARCH = 0;
  1023. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  1024. CONTEXT_X86 = $00010000;
  1025. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  1026. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  1027. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  1028. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  1029. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  1030. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  1031. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  1032. MAXIMUM_SUPPORTED_EXTENSION = 512;
  1033. type
  1034. PFloatingSaveArea = ^TFloatingSaveArea;
  1035. TFloatingSaveArea = packed record
  1036. ControlWord : Cardinal;
  1037. StatusWord : Cardinal;
  1038. TagWord : Cardinal;
  1039. ErrorOffset : Cardinal;
  1040. ErrorSelector : Cardinal;
  1041. DataOffset : Cardinal;
  1042. DataSelector : Cardinal;
  1043. RegisterArea : array[0..79] of Byte;
  1044. Cr0NpxState : Cardinal;
  1045. end;
  1046. PContext = ^TContext;
  1047. TContext = packed record
  1048. //
  1049. // The flags values within this flag control the contents of
  1050. // a CONTEXT record.
  1051. //
  1052. ContextFlags : Cardinal;
  1053. //
  1054. // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
  1055. // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
  1056. // included in CONTEXT_FULL.
  1057. //
  1058. Dr0, Dr1, Dr2,
  1059. Dr3, Dr6, Dr7 : Cardinal;
  1060. //
  1061. // This section is specified/returned if the
  1062. // ContextFlags word contains the flag CONTEXT_FLOATING_POINT.
  1063. //
  1064. FloatSave : TFloatingSaveArea;
  1065. //
  1066. // This section is specified/returned if the
  1067. // ContextFlags word contains the flag CONTEXT_SEGMENTS.
  1068. //
  1069. SegGs, SegFs,
  1070. SegEs, SegDs : Cardinal;
  1071. //
  1072. // This section is specified/returned if the
  1073. // ContextFlags word contains the flag CONTEXT_INTEGER.
  1074. //
  1075. Edi, Esi, Ebx,
  1076. Edx, Ecx, Eax : Cardinal;
  1077. //
  1078. // This section is specified/returned if the
  1079. // ContextFlags word contains the flag CONTEXT_CONTROL.
  1080. //
  1081. Ebp : Cardinal;
  1082. Eip : Cardinal;
  1083. SegCs : Cardinal;
  1084. EFlags, Esp, SegSs : Cardinal;
  1085. //
  1086. // This section is specified/returned if the ContextFlags word
  1087. // contains the flag CONTEXT_EXTENDED_REGISTERS.
  1088. // The format and contexts are processor specific
  1089. //
  1090. ExtendedRegisters : array[0..MAXIMUM_SUPPORTED_EXTENSION-1] of Byte;
  1091. end;
  1092. type
  1093. PExceptionRecord = ^TExceptionRecord;
  1094. TExceptionRecord = packed record
  1095. ExceptionCode : Longint;
  1096. ExceptionFlags : Longint;
  1097. ExceptionRecord : PExceptionRecord;
  1098. ExceptionAddress : Pointer;
  1099. NumberParameters : Longint;
  1100. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of Pointer;
  1101. end;
  1102. PExceptionPointers = ^TExceptionPointers;
  1103. TExceptionPointers = packed record
  1104. ExceptionRecord : PExceptionRecord;
  1105. ContextRecord : PContext;
  1106. end;
  1107. { type of functions that should be used for exception handling }
  1108. TTopLevelExceptionFilter = function (excep : PExceptionPointers) : Longint;stdcall;
  1109. function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : TTopLevelExceptionFilter) : TTopLevelExceptionFilter;
  1110. stdcall;external 'kernel32' name 'SetUnhandledExceptionFilter';
  1111. const
  1112. MaxExceptionLevel = 16;
  1113. exceptLevel : Byte = 0;
  1114. var
  1115. exceptEip : array[0..MaxExceptionLevel-1] of Longint;
  1116. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  1117. resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
  1118. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1119. procedure DebugHandleErrorAddrFrame(error, addr, frame : longint);
  1120. begin
  1121. if IsConsole then begin
  1122. write(stderr,'HandleErrorAddrFrame(error=',error);
  1123. write(stderr,',addr=',hexstr(addr,8));
  1124. writeln(stderr,',frame=',hexstr(frame,8),')');
  1125. end;
  1126. HandleErrorAddrFrame(error,addr,frame);
  1127. end;
  1128. {$endif SYSTEMEXCEPTIONDEBUG}
  1129. procedure JumpToHandleErrorFrame;
  1130. var
  1131. eip, ebp, error : Longint;
  1132. begin
  1133. // save ebp
  1134. asm
  1135. movl (%ebp),%eax
  1136. movl %eax,ebp
  1137. end;
  1138. if (exceptLevel > 0) then
  1139. dec(exceptLevel);
  1140. eip:=exceptEip[exceptLevel];
  1141. error:=exceptError[exceptLevel];
  1142. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1143. if IsConsole then
  1144. writeln(stderr,'In JumpToHandleErrorFrame error=',error);
  1145. {$endif SYSTEMEXCEPTIONDEBUG}
  1146. if resetFPU[exceptLevel] then asm
  1147. fninit
  1148. fldcw fpucw
  1149. end;
  1150. { build a fake stack }
  1151. asm
  1152. {$ifdef REGCALL}
  1153. movl ebp,%ecx
  1154. movl eip,%edx
  1155. movl error,%eax
  1156. pushl eip
  1157. movl ebp,%ebp // Change frame pointer
  1158. {$else}
  1159. movl ebp,%eax
  1160. pushl %eax
  1161. movl eip,%eax
  1162. pushl %eax
  1163. movl error,%eax
  1164. pushl %eax
  1165. movl eip,%eax
  1166. pushl %eax
  1167. movl ebp,%ebp // Change frame pointer
  1168. {$endif}
  1169. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1170. jmpl DebugHandleErrorAddrFrame
  1171. {$else not SYSTEMEXCEPTIONDEBUG}
  1172. jmpl HandleErrorAddrFrame
  1173. {$endif SYSTEMEXCEPTIONDEBUG}
  1174. end;
  1175. end;
  1176. function syswin32_i386_exception_handler(excep : PExceptionPointers) : Longint;stdcall;
  1177. var
  1178. frame,
  1179. res : longint;
  1180. function SysHandleErrorFrame(error, frame : Longint; must_reset_fpu : Boolean) : Longint;
  1181. begin
  1182. if (frame = 0) then
  1183. SysHandleErrorFrame:=EXCEPTION_CONTINUE_SEARCH
  1184. else begin
  1185. if (exceptLevel >= MaxExceptionLevel) then exit;
  1186. exceptEip[exceptLevel] := excep^.ContextRecord^.Eip;
  1187. exceptError[exceptLevel] := error;
  1188. resetFPU[exceptLevel] := must_reset_fpu;
  1189. inc(exceptLevel);
  1190. excep^.ContextRecord^.Eip := Longint(@JumpToHandleErrorFrame);
  1191. excep^.ExceptionRecord^.ExceptionCode := 0;
  1192. SysHandleErrorFrame := EXCEPTION_CONTINUE_EXECUTION;
  1193. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1194. if IsConsole then begin
  1195. writeln(stderr,'Exception Continue Exception set at ',
  1196. hexstr(exceptEip[exceptLevel],8));
  1197. writeln(stderr,'Eip changed to ',
  1198. hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', error);
  1199. end;
  1200. {$endif SYSTEMEXCEPTIONDEBUG}
  1201. end;
  1202. end;
  1203. begin
  1204. if excep^.ContextRecord^.SegSs=_SS then
  1205. frame := excep^.ContextRecord^.Ebp
  1206. else
  1207. frame := 0;
  1208. res := EXCEPTION_CONTINUE_SEARCH;
  1209. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1210. if IsConsole then Writeln(stderr,'Exception ',
  1211. hexstr(excep^.ExceptionRecord^.ExceptionCode, 8));
  1212. {$endif SYSTEMEXCEPTIONDEBUG}
  1213. case cardinal(excep^.ExceptionRecord^.ExceptionCode) of
  1214. STATUS_INTEGER_DIVIDE_BY_ZERO,
  1215. STATUS_FLOAT_DIVIDE_BY_ZERO :
  1216. res := SysHandleErrorFrame(200, frame, true);
  1217. STATUS_ARRAY_BOUNDS_EXCEEDED :
  1218. res := SysHandleErrorFrame(201, frame, false);
  1219. STATUS_STACK_OVERFLOW :
  1220. res := SysHandleErrorFrame(202, frame, false);
  1221. STATUS_FLOAT_OVERFLOW :
  1222. res := SysHandleErrorFrame(205, frame, true);
  1223. STATUS_FLOAT_DENORMAL_OPERAND,
  1224. STATUS_FLOAT_UNDERFLOW :
  1225. res := SysHandleErrorFrame(206, frame, true);
  1226. {excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  1227. STATUS_FLOAT_INEXACT_RESULT,
  1228. STATUS_FLOAT_INVALID_OPERATION,
  1229. STATUS_FLOAT_STACK_CHECK :
  1230. res := SysHandleErrorFrame(207, frame, true);
  1231. STATUS_INTEGER_OVERFLOW :
  1232. res := SysHandleErrorFrame(215, frame, false);
  1233. STATUS_ILLEGAL_INSTRUCTION:
  1234. res := SysHandleErrorFrame(216, frame, true);
  1235. STATUS_ACCESS_VIOLATION:
  1236. { Athlon prefetch bug? }
  1237. if is_prefetch(pointer(excep^.ContextRecord^.Eip)) then
  1238. begin
  1239. { if yes, then retry }
  1240. excep^.ExceptionRecord^.ExceptionCode := 0;
  1241. res:=EXCEPTION_CONTINUE_EXECUTION;
  1242. end
  1243. else
  1244. res := SysHandleErrorFrame(216, frame, true);
  1245. STATUS_CONTROL_C_EXIT:
  1246. res := SysHandleErrorFrame(217, frame, true);
  1247. STATUS_PRIVILEGED_INSTRUCTION:
  1248. res := SysHandleErrorFrame(218, frame, false);
  1249. else
  1250. begin
  1251. if ((excep^.ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  1252. res := SysHandleErrorFrame(217, frame, true)
  1253. else
  1254. res := SysHandleErrorFrame(255, frame, true);
  1255. end;
  1256. end;
  1257. syswin32_i386_exception_handler := res;
  1258. end;
  1259. procedure install_exception_handlers;
  1260. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1261. var
  1262. oldexceptaddr,
  1263. newexceptaddr : Longint;
  1264. {$endif SYSTEMEXCEPTIONDEBUG}
  1265. begin
  1266. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1267. asm
  1268. movl $0,%eax
  1269. movl %fs:(%eax),%eax
  1270. movl %eax,oldexceptaddr
  1271. end;
  1272. {$endif SYSTEMEXCEPTIONDEBUG}
  1273. SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
  1274. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1275. asm
  1276. movl $0,%eax
  1277. movl %fs:(%eax),%eax
  1278. movl %eax,newexceptaddr
  1279. end;
  1280. if IsConsole then
  1281. writeln(stderr,'Old exception ',hexstr(oldexceptaddr,8),
  1282. ' new exception ',hexstr(newexceptaddr,8));
  1283. {$endif SYSTEMEXCEPTIONDEBUG}
  1284. end;
  1285. procedure remove_exception_handlers;
  1286. begin
  1287. SetUnhandledExceptionFilter(nil);
  1288. end;
  1289. {$else not cpui386 (Processor specific !!)}
  1290. procedure install_exception_handlers;
  1291. begin
  1292. end;
  1293. procedure remove_exception_handlers;
  1294. begin
  1295. end;
  1296. {$endif Set_i386_Exception_handler}
  1297. {****************************************************************************
  1298. Error Message writing using messageboxes
  1299. ****************************************************************************}
  1300. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  1301. stdcall;external 'user32' name 'MessageBoxA';
  1302. const
  1303. ErrorBufferLength = 1024;
  1304. var
  1305. ErrorBuf : array[0..ErrorBufferLength] of char;
  1306. ErrorLen : longint;
  1307. Function ErrorWrite(Var F: TextRec): Integer;
  1308. {
  1309. An error message should always end with #13#10#13#10
  1310. }
  1311. var
  1312. p : pchar;
  1313. i : longint;
  1314. Begin
  1315. if F.BufPos>0 then
  1316. begin
  1317. if F.BufPos+ErrorLen>ErrorBufferLength then
  1318. i:=ErrorBufferLength-ErrorLen
  1319. else
  1320. i:=F.BufPos;
  1321. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  1322. inc(ErrorLen,i);
  1323. ErrorBuf[ErrorLen]:=#0;
  1324. end;
  1325. if ErrorLen>3 then
  1326. begin
  1327. p:=@ErrorBuf[ErrorLen];
  1328. for i:=1 to 4 do
  1329. begin
  1330. dec(p);
  1331. if not(p^ in [#10,#13]) then
  1332. break;
  1333. end;
  1334. end;
  1335. if ErrorLen=ErrorBufferLength then
  1336. i:=4;
  1337. if (i=4) then
  1338. begin
  1339. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  1340. ErrorLen:=0;
  1341. end;
  1342. F.BufPos:=0;
  1343. ErrorWrite:=0;
  1344. End;
  1345. Function ErrorClose(Var F: TextRec): Integer;
  1346. begin
  1347. if ErrorLen>0 then
  1348. begin
  1349. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  1350. ErrorLen:=0;
  1351. end;
  1352. ErrorLen:=0;
  1353. ErrorClose:=0;
  1354. end;
  1355. Function ErrorOpen(Var F: TextRec): Integer;
  1356. Begin
  1357. TextRec(F).InOutFunc:=@ErrorWrite;
  1358. TextRec(F).FlushFunc:=@ErrorWrite;
  1359. TextRec(F).CloseFunc:=@ErrorClose;
  1360. ErrorOpen:=0;
  1361. End;
  1362. procedure AssignError(Var T: Text);
  1363. begin
  1364. Assign(T,'');
  1365. TextRec(T).OpenFunc:=@ErrorOpen;
  1366. Rewrite(T);
  1367. end;
  1368. procedure SysInitStdIO;
  1369. begin
  1370. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  1371. displayed in and messagebox }
  1372. StdInputHandle:=longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  1373. StdOutputHandle:=longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  1374. StdErrorHandle:=longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  1375. if not IsConsole then
  1376. begin
  1377. AssignError(stderr);
  1378. AssignError(stdout);
  1379. Assign(Output,'');
  1380. Assign(Input,'');
  1381. Assign(ErrOutput,'');
  1382. end
  1383. else
  1384. begin
  1385. OpenStdIO(Input,fmInput,StdInputHandle);
  1386. OpenStdIO(Output,fmOutput,StdOutputHandle);
  1387. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  1388. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  1389. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  1390. end;
  1391. end;
  1392. (* ProcessID cached to avoid repeated calls to GetCurrentProcess. *)
  1393. var
  1394. ProcessID: SizeUInt;
  1395. function GetProcessID: SizeUInt;
  1396. begin
  1397. GetProcessID := ProcessID;
  1398. end;
  1399. const
  1400. Exe_entry_code : pointer = @Exe_entry;
  1401. Dll_entry_code : pointer = @Dll_entry;
  1402. begin
  1403. StackLength := InitialStkLen;
  1404. StackBottom := Sptr - StackLength;
  1405. { get some helpful informations }
  1406. GetStartupInfo(@startupinfo);
  1407. { some misc Win32 stuff }
  1408. hprevinst:=0;
  1409. if not IsLibrary then
  1410. HInstance:=getmodulehandle(GetCommandFile);
  1411. MainInstance:=HInstance;
  1412. cmdshow:=startupinfo.wshowwindow;
  1413. { Setup heap }
  1414. InitHeap;
  1415. SysInitExceptions;
  1416. SysInitStdIO;
  1417. { Arguments }
  1418. setup_arguments;
  1419. { Reset IO Error }
  1420. InOutRes:=0;
  1421. ProcessID := GetCurrentProcessID;
  1422. ThreadID := GetCurrentThreadID;
  1423. { Reset internal error variable }
  1424. errno:=0;
  1425. {$ifdef HASVARIANT}
  1426. initvariantmanager;
  1427. {$endif HASVARIANT}
  1428. end.
  1429. {
  1430. $Log$
  1431. Revision 1.65 2004-12-12 11:53:47 florian
  1432. * remove inline assembler for calling asm_exit
  1433. Revision 1.64 2004/12/05 14:36:38 hajny
  1434. + GetProcessID added
  1435. Revision 1.63 2004/11/04 09:32:31 peter
  1436. ErrOutput added
  1437. Revision 1.62 2004/10/25 15:38:59 peter
  1438. * compiler defined HEAP and HEAPSIZE removed
  1439. Revision 1.61 2004/09/03 19:27:25 olle
  1440. + added maxExitCode to all System.pp
  1441. * constrained error code to be below maxExitCode in RunError et. al.
  1442. Revision 1.60 2004/06/27 11:57:18 florian
  1443. * finally (hopefully) fixed sysalloc trouble
  1444. Revision 1.59 2004/06/26 15:05:14 florian
  1445. * fixed argument copying
  1446. Revision 1.58 2004/06/20 09:24:40 peter
  1447. fixed go32v2 compile
  1448. Revision 1.57 2004/06/17 16:16:14 peter
  1449. * New heapmanager that releases memory back to the OS, donated
  1450. by Micha Nelissen
  1451. Revision 1.56 2004/05/16 18:51:20 peter
  1452. * use thandle in do_*
  1453. Revision 1.55 2004/04/22 21:10:56 peter
  1454. * do_read/do_write addr argument changed to pointer
  1455. Revision 1.54 2004/02/15 21:37:18 hajny
  1456. * ProcessID initialization added
  1457. Revision 1.53 2004/02/02 17:01:47 florian
  1458. * workaround for AMD prefetch bug
  1459. Revision 1.52 2004/01/20 23:12:49 hajny
  1460. * ExecuteProcess fixes, ProcessID and ThreadID added
  1461. Revision 1.51 2003/12/17 21:56:33 peter
  1462. * win32 regcall patches
  1463. Revision 1.50 2003/12/04 20:52:41 peter
  1464. * stdcall for CreateFile
  1465. Revision 1.49 2003/11/24 23:08:37 michael
  1466. + Redefined Fileopen so it corresponds to ascdef.inc definition
  1467. Revision 1.48 2003/11/03 09:42:28 marco
  1468. * Peter's Cardinal<->Longint fixes patch
  1469. Revision 1.47 2003/10/17 22:15:10 olle
  1470. * changed i386 to cpui386
  1471. Revision 1.46 2003/10/16 15:43:13 peter
  1472. * THandle is platform dependent
  1473. Revision 1.45 2003/10/06 23:52:53 florian
  1474. * some data types cleaned up
  1475. Revision 1.44 2003/09/27 11:52:36 peter
  1476. * sbrk returns pointer
  1477. Revision 1.43 2003/09/26 07:30:34 michael
  1478. + Win32 Do_open crahs on append
  1479. Revision 1.42 2003/09/17 15:06:36 peter
  1480. * stdcall patch
  1481. Revision 1.41 2003/09/12 12:33:43 olle
  1482. * nice-ified
  1483. Revision 1.40 2003/01/01 20:56:57 florian
  1484. + added invalid instruction exception
  1485. Revision 1.39 2002/12/24 15:35:15 peter
  1486. * error code fixes
  1487. Revision 1.38 2002/12/07 13:58:45 carl
  1488. * fix warnings
  1489. Revision 1.37 2002/11/30 18:17:35 carl
  1490. + profiling support
  1491. Revision 1.36 2002/10/31 15:17:58 carl
  1492. * always allocate argument even if its empty (bugfix web bug 2202)
  1493. Revision 1.35 2002/10/14 20:40:22 florian
  1494. * InitFPU renamed to SysResetFPU
  1495. Revision 1.34 2002/10/14 19:39:17 peter
  1496. * threads unit added for thread support
  1497. Revision 1.33 2002/10/13 09:28:45 florian
  1498. + call to initvariantmanager inserted
  1499. Revision 1.32 2002/09/07 21:28:10 carl
  1500. - removed os_types
  1501. * fix range check errors
  1502. Revision 1.31 2002/09/07 16:01:29 peter
  1503. * old logs removed and tabs fixed
  1504. Revision 1.30 2002/08/26 13:49:18 pierre
  1505. * fix bug report 2086
  1506. Revision 1.29 2002/07/28 20:43:49 florian
  1507. * several fixes for linux/powerpc
  1508. * several fixes to MT
  1509. Revision 1.28 2002/07/01 16:29:05 peter
  1510. * sLineBreak changed to normal constant like Kylix
  1511. Revision 1.27 2002/06/04 09:25:14 pierre
  1512. * Rename HeapSize to WinAPIHeapSize to avoid conflict with general function
  1513. Revision 1.26 2002/04/12 17:45:13 carl
  1514. + generic stack checking
  1515. Revision 1.25 2002/03/11 19:10:33 peter
  1516. * Regenerated with updated fpcmake
  1517. Revision 1.24 2002/01/30 14:57:11 pierre
  1518. * fix compilation failure
  1519. Revision 1.23 2002/01/25 16:23:03 peter
  1520. * merged filesearch() fix
  1521. }