system.pp 49 KB

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