system.pp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2005 by Florian Klaempfl and Pavel Ozerski
  4. and Yury Sidorov member of the Free Pascal development team.
  5. FPC Pascal system unit for the WinCE.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit System;
  13. interface
  14. {$ifdef SYSTEMDEBUG}
  15. {$define SYSTEMEXCEPTIONDEBUG}
  16. {$endif SYSTEMDEBUG}
  17. {$define WINCE_EXCEPTION_HANDLING}
  18. {$define DISABLE_NO_THREAD_MANAGER}
  19. {$define HAS_CMDLINE}
  20. {$define HAS_MEMORYMANAGER} // comment this line to switch from wincemm to fpcmm
  21. {$define HAS_WIDESTRINGMANAGER}
  22. { include system-independent routine headers }
  23. {$I systemh.inc}
  24. const
  25. LineEnding = #13#10;
  26. LFNSupport = true;
  27. DirectorySeparator = '\';
  28. DriveSeparator = ':';
  29. ExtensionSeparator = '.';
  30. PathSeparator = ';';
  31. AllowDirectorySeparators : set of char = ['\','/'];
  32. AllowDriveSeparators : set of char = [':'];
  33. { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
  34. maxExitCode = 65535;
  35. MaxPathLen = 260;
  36. AllFilesMask = '*';
  37. const
  38. { Default filehandles }
  39. UnusedHandle : THandle = THandle(-1);
  40. StdInputHandle : THandle = 0;
  41. StdOutputHandle : THandle = 0;
  42. StdErrorHandle : THandle = 0;
  43. FileNameCaseSensitive : boolean = false;
  44. FileNameCasePreserving: boolean = true;
  45. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  46. sLineBreak = LineEnding;
  47. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  48. var
  49. { WinCE Info }
  50. hprevinst,
  51. MainInstance,
  52. DLLreason,DLLparam:DWord;
  53. type
  54. TDLL_Entry_Hook = procedure (dllparam : longint);
  55. const
  56. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  57. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  58. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  59. { ANSI <-> Wide }
  60. function AnsiToWideBuf(AnsiBuf: PChar; AnsiBufLen: longint; WideBuf: PWideChar; WideBufLen: longint): longint;
  61. function WideToAnsiBuf(WideBuf: PWideChar; WideCharsLen: longint; AnsiBuf: PChar; AnsiBufLen: longint): longint;
  62. function PCharToPWideChar(str: PChar; strlen: longint = -1; outlen: PLongInt = nil): PWideChar;
  63. function StringToPWideChar(const s: AnsiString; outlen: PLongInt = nil): PWideChar;
  64. { Wrappers for some WinAPI calls }
  65. function CreateEvent(lpEventAttributes:pointer;bManualReset:longbool;bInitialState:longbool;lpName:pchar): THandle;
  66. function ResetEvent(h: THandle): LONGBOOL;
  67. function SetEvent(h: THandle): LONGBOOL;
  68. function GetCurrentProcessId:DWORD;
  69. function Win32GetCurrentThreadId:DWORD;
  70. function TlsAlloc : DWord;
  71. function TlsFree(dwTlsIndex : DWord) : LongBool;
  72. function GetFileAttributesW(p : pwidechar) : dword;
  73. cdecl; external KernelDLL name 'GetFileAttributesW';
  74. function DeleteFileW(p : pwidechar) : longint;
  75. cdecl; external KernelDLL name 'DeleteFileW';
  76. function MoveFileW(old,_new : pwidechar) : longint;
  77. cdecl; external KernelDLL name 'MoveFileW';
  78. function CreateFileW(lpFileName:pwidechar; dwDesiredAccess:DWORD; dwShareMode:DWORD;
  79. lpSecurityAttributes:pointer; dwCreationDisposition:DWORD;
  80. dwFlagsAndAttributes:DWORD; hTemplateFile:DWORD):longint;
  81. cdecl; external KernelDLL name 'CreateFileW';
  82. {$ifdef CPUARM}
  83. { the external directive isn't really necessary here because it is overridden by external (FK) }
  84. function addd(d1,d2 : double) : double; compilerproc;
  85. cdecl;external 'coredll' name '__addd';
  86. function subd(d1,d2 : double) : double; compilerproc;
  87. cdecl;external 'coredll' name '__subd';
  88. function muld(d1,d2 : double) : double; compilerproc;
  89. cdecl;external 'coredll' name '__muld';
  90. function divd(d1,d2 : double) : double; compilerproc;
  91. cdecl;external 'coredll' name '__divd';
  92. function eqd(d1,d2 : double) : boolean; compilerproc;
  93. cdecl;external 'coredll' name '__eqd';
  94. function ned(d1,d2 : double) : boolean; compilerproc;
  95. cdecl;external 'coredll' name '__ned';
  96. function ltd(d1,d2 : double) : boolean; compilerproc;
  97. cdecl;external 'coredll' name '__ltd';
  98. function gtd(d1,d2 : double) : boolean; compilerproc;
  99. cdecl;external 'coredll' name '__gtd';
  100. function ged(d1,d2 : double) : boolean; compilerproc;
  101. cdecl;external 'coredll' name '__ged';
  102. function led(d1,d2 : double) : boolean; compilerproc;
  103. cdecl;external 'coredll' name '__led';
  104. { ***************** single ******************** }
  105. function eqs(d1,d2 : single) : boolean; compilerproc;
  106. cdecl;external 'coredll' name '__eqs';
  107. function nes(d1,d2 : single) : boolean; compilerproc;
  108. cdecl;external 'coredll' name '__nes';
  109. function lts(d1,d2 : single) : boolean; compilerproc;
  110. cdecl;external 'coredll' name '__lts';
  111. function gts(d1,d2 : single) : boolean; compilerproc;
  112. cdecl;external 'coredll' name '__gts';
  113. function ges(d1,d2 : single) : boolean; compilerproc;
  114. cdecl;external 'coredll' name '__ges';
  115. function les(d1,d2 : single) : boolean; compilerproc;
  116. cdecl;external 'coredll' name '__les';
  117. function dtos(d : double) : single; compilerproc;
  118. cdecl;external 'coredll' name '__dtos';
  119. function stod(d : single) : double; compilerproc;
  120. cdecl;external 'coredll' name '__stod';
  121. function negs(d : single) : single; compilerproc;
  122. cdecl;external 'coredll' name '__negs';
  123. function negd(d : double) : double; compilerproc;
  124. cdecl;external 'coredll' name '__negd';
  125. function utod(i : dword) : double; compilerproc;
  126. cdecl;external 'coredll' name '__utod';
  127. function itod(i : longint) : double; compilerproc;
  128. cdecl;external 'coredll' name '__itod';
  129. function ui64tod(i : qword) : double; compilerproc;
  130. cdecl;external 'coredll' name '__u64tod';
  131. function i64tod(i : int64) : double; compilerproc;
  132. cdecl;external 'coredll' name '__i64tod';
  133. function utos(i : dword) : single; compilerproc;
  134. cdecl;external 'coredll' name '__utos';
  135. function itos(i : longint) : single; compilerproc;
  136. cdecl;external 'coredll' name '__itos';
  137. function ui64tos(i : qword) : single; compilerproc;
  138. cdecl;external 'coredll' name '__u64tos';
  139. function i64tos(i : int64) : single; compilerproc;
  140. cdecl;external 'coredll' name '__i64tos';
  141. function adds(s1,s2 : single) : single; compilerproc;
  142. function subs(s1,s2 : single) : single; compilerproc;
  143. function muls(s1,s2 : single) : single; compilerproc;
  144. function divs(s1,s2 : single) : single; compilerproc;
  145. {$endif CPUARM}
  146. function CmdLine: PChar;
  147. { C compatible arguments }
  148. function argc: longint;
  149. function argv: ppchar;
  150. implementation
  151. var
  152. SysInstance : Longint;public name '_FPC_SysInstance';
  153. function MessageBox(w1:longint;l1,l2:PWideChar;w2:longint):longint;
  154. cdecl; external 'coredll' name 'MessageBoxW';
  155. function CreateDirectoryW(name : pwidechar;sec : pointer) : longbool;
  156. cdecl; external KernelDLL name 'CreateDirectoryW';
  157. function RemoveDirectoryW(name:pwidechar):longbool;
  158. cdecl; external KernelDLL name 'RemoveDirectoryW';
  159. {*****************************************************************************}
  160. {$define FPC_SYSTEM_HAS_MOVE}
  161. procedure memmove(dest, src: pointer; count: longint);
  162. cdecl; external 'coredll' name 'memmove';
  163. procedure Move(const source;var dest;count:SizeInt);[public, alias: 'FPC_MOVE'];
  164. begin
  165. if count > 0 then
  166. memmove(@dest, @source, count);
  167. end;
  168. {$define FPC_SYSTEM_HAS_COMPAREBYTE}
  169. function memcmp(buf1, buf2: pointer; count: longint): longint;
  170. cdecl; external 'coredll' name 'memcmp';
  171. function CompareByte(Const buf1,buf2;len:SizeInt):SizeInt;
  172. begin
  173. CompareByte := memcmp(@buf1, @buf2, len);
  174. end;
  175. {$ifdef CPUARM}
  176. {$define FPC_SYSTEM_HAS_INT}
  177. function floor(d : double) : double;
  178. cdecl;external 'coredll' name 'floor';
  179. function ceil(d : double) : double;
  180. cdecl;external 'coredll' name 'ceil';
  181. function fpc_int_real(d: ValReal): ValReal;compilerproc;
  182. begin
  183. if d > 0 then
  184. fpc_int_real:=floor(d)
  185. else
  186. fpc_int_real:=ceil(d);
  187. end;
  188. {$define FPC_SYSTEM_HAS_TRUNC}
  189. function __dtoi64(d: double) : int64; cdecl; external 'coredll';
  190. function fpc_trunc_real(d : ValReal) : int64; assembler; nostackframe; compilerproc;
  191. asm
  192. b __dtoi64
  193. end;
  194. {$define FPC_SYSTEM_HAS_ABS}
  195. function fabs(d: double): double; cdecl; external 'coredll';
  196. function fpc_abs_real(d : ValReal) : ValReal; assembler; nostackframe; compilerproc;
  197. asm
  198. b fabs
  199. end;
  200. {$define FPC_SYSTEM_HAS_SQRT}
  201. function coresqrt(d: double): double; cdecl; external 'coredll' name 'sqrt';
  202. function fpc_sqrt_real(d : ValReal) : ValReal; assembler; nostackframe; compilerproc;
  203. asm
  204. b coresqrt
  205. end;
  206. function adds(s1,s2 : single) : single;
  207. begin
  208. adds := addd(s1, s2);
  209. end;
  210. function subs(s1,s2 : single) : single;
  211. begin
  212. subs := subd(s1, s2);
  213. end;
  214. function muls(s1,s2 : single) : single;
  215. begin
  216. muls := muld(s1, s2);
  217. end;
  218. function divs(s1,s2 : single) : single;
  219. begin
  220. divs := divd(s1, s2);
  221. end;
  222. {$endif CPUARM}
  223. {*****************************************************************************}
  224. { include system independent routines }
  225. {$I system.inc}
  226. {*****************************************************************************
  227. ANSI <-> Wide
  228. *****************************************************************************}
  229. const
  230. { MultiByteToWideChar }
  231. MB_PRECOMPOSED = 1;
  232. MB_COMPOSITE = 2;
  233. MB_ERR_INVALID_CHARS = 8;
  234. MB_USEGLYPHCHARS = 4;
  235. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  236. cdecl; external 'coredll' name 'MultiByteToWideChar';
  237. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  238. cdecl; external 'coredll' name 'WideCharToMultiByte';
  239. function GetACP:UINT; cdecl; external 'coredll' name 'GetACP';
  240. { Returns number of characters stored to WideBuf, including null-terminator. }
  241. function AnsiToWideBuf(AnsiBuf: PChar; AnsiBufLen: longint; WideBuf: PWideChar; WideBufLen: longint): longint;
  242. begin
  243. Result := MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, AnsiBuf, AnsiBufLen, WideBuf, WideBufLen div SizeOf(WideChar));
  244. if ((AnsiBufLen <> -1) or (Result = 0)) and (WideBuf <> nil) then
  245. begin
  246. if (Result + 1)*SizeOf(WideChar) > WideBufLen then
  247. begin
  248. Result := 0;
  249. if WideBufLen < SizeOf(WideChar) then
  250. exit;
  251. end;
  252. WideBuf[Result] := #0;
  253. end;
  254. if (AnsiBufLen <> -1) and ((Result <> 0) or (AnsiBufLen = 0)) then
  255. Inc(Result);
  256. end;
  257. { Returns number of characters stored to AnsiBuf, including null-terminator. }
  258. function WideToAnsiBuf(WideBuf: PWideChar; WideCharsLen: longint; AnsiBuf: PChar; AnsiBufLen: longint): longint;
  259. begin
  260. Result := WideCharToMultiByte(CP_ACP, 0, WideBuf, WideCharsLen, AnsiBuf, AnsiBufLen, nil, nil);
  261. if ((WideCharsLen <> -1) or (Result = 0)) and (AnsiBuf <> nil) then
  262. begin
  263. if Result + 1 > AnsiBufLen then
  264. begin
  265. Result := 0;
  266. if AnsiBufLen < 1 then
  267. exit;
  268. end;
  269. AnsiBuf[Result] := #0;
  270. end;
  271. if (WideCharsLen <> -1) and ((Result <> 0) or (WideCharsLen = 0)) then
  272. Inc(Result);
  273. end;
  274. { Returns dynamic memory block, which contains wide string. This memory should be freed using FreeMem. }
  275. { outlen will contain number of wide characters stored to result buffer, including null-terminator. }
  276. function PCharToPWideChar(str: PChar; strlen: longint = -1; outlen: PLongInt = nil): PWideChar;
  277. var
  278. len: longint;
  279. begin
  280. while True do begin
  281. if strlen <> -1 then
  282. len:=strlen + 1
  283. else
  284. len:=AnsiToWideBuf(str, -1, nil, 0);
  285. if len > 0 then
  286. begin
  287. len:=len*SizeOf(WideChar);
  288. GetMem(Result, len);
  289. len:=AnsiToWideBuf(str, strlen, Result, len);
  290. if (len = 0) and (strlen <> -1) then
  291. begin
  292. FreeMem(Result);
  293. strlen:=-1;
  294. continue;
  295. end;
  296. end
  297. else begin
  298. GetMem(Result, SizeOf(WideChar));
  299. len:=1;
  300. Result^:=#0;
  301. end;
  302. break;
  303. end;
  304. if outlen <> nil then
  305. outlen^:=len;
  306. end;
  307. { Returns dynamic memory block, which contains wide string. This memory should be freed using FreeMem. }
  308. { outlen will contain number of wide characters stored to result buffer, including null-terminator. }
  309. function StringToPWideChar(const s: AnsiString; outlen: PLongInt = nil): PWideChar;
  310. var
  311. len, wlen: longint;
  312. begin
  313. len:=Length(s);
  314. wlen:=(len + 1)*SizeOf(WideChar);
  315. GetMem(Result, wlen);
  316. wlen:=AnsiToWideBuf(PChar(s), len, Result, wlen)*SizeOf(WideChar);
  317. if wlen = 0 then
  318. begin
  319. wlen:=AnsiToWideBuf(PChar(s), len, nil, 0)*SizeOf(WideChar);
  320. if wlen > 0 then
  321. begin
  322. ReAllocMem(Result, wlen);
  323. wlen:=AnsiToWideBuf(PChar(s), len, Result, wlen)*SizeOf(WideChar);
  324. end
  325. else
  326. begin
  327. Result^:=#0;
  328. wlen:=SizeOf(WideChar);
  329. end;
  330. end;
  331. if outlen <> nil then
  332. outlen^:=wlen div SizeOf(WideChar);
  333. end;
  334. {*****************************************************************************
  335. WinAPI wrappers implementation
  336. *****************************************************************************}
  337. const
  338. {$ifdef CPUARM}
  339. UserKData = $FFFFC800;
  340. {$else CPUARM}
  341. UserKData = $00005800;
  342. {$endif CPUARM}
  343. SYSHANDLE_OFFSET = $004;
  344. SYS_HANDLE_BASE = 64;
  345. SH_CURTHREAD = 1;
  346. SH_CURPROC = 2;
  347. type
  348. PHandle = ^THandle;
  349. const
  350. EVENT_PULSE = 1;
  351. EVENT_RESET = 2;
  352. EVENT_SET = 3;
  353. function CreateEventW(lpEventAttributes:pointer;bManualReset:longbool;bInitialState:longbool;lpName:PWideChar): THandle;
  354. cdecl; external KernelDLL name 'CreateEventW';
  355. function CreateEvent(lpEventAttributes:pointer;bManualReset:longbool;bInitialState:longbool;lpName:pchar): THandle;
  356. var
  357. buf: array[0..MaxPathLen] of WideChar;
  358. begin
  359. if lpName=nil then
  360. CreateEvent := CreateEventW(lpEventAttributes, bManualReset, bInitialState, nil)
  361. else begin
  362. AnsiToWideBuf(lpName, -1, buf, SizeOf(buf));
  363. CreateEvent := CreateEventW(lpEventAttributes, bManualReset, bInitialState, buf);
  364. end;
  365. end;
  366. function EventModify(h: THandle; func: DWORD): LONGBOOL;
  367. cdecl; external KernelDLL name 'EventModify';
  368. function TlsCall(p1, p2: DWORD): DWORD;
  369. cdecl; external KernelDLL name 'TlsCall';
  370. function ResetEvent(h: THandle): LONGBOOL;
  371. begin
  372. ResetEvent := EventModify(h,EVENT_RESET);
  373. end;
  374. function SetEvent(h: THandle): LONGBOOL;
  375. begin
  376. SetEvent := EventModify(h,EVENT_SET);
  377. end;
  378. function GetCurrentProcessId:DWORD;
  379. var
  380. p: PHandle;
  381. begin
  382. p:=PHandle(UserKData+SYSHANDLE_OFFSET + SH_CURPROC*SizeOf(THandle));
  383. GetCurrentProcessId := p^;
  384. end;
  385. function Win32GetCurrentThreadId:DWORD;
  386. var
  387. p: PHandle;
  388. begin
  389. p:=PHandle(UserKData+SYSHANDLE_OFFSET + SH_CURTHREAD*SizeOf(THandle));
  390. Win32GetCurrentThreadId := p^;
  391. end;
  392. const
  393. TLS_FUNCALLOC = 0;
  394. TLS_FUNCFREE = 1;
  395. function TlsAlloc : DWord;
  396. begin
  397. TlsAlloc := TlsCall(TLS_FUNCALLOC, 0);
  398. end;
  399. function TlsFree(dwTlsIndex : DWord) : LongBool;
  400. begin
  401. TlsFree := LongBool(TlsCall(TLS_FUNCFREE, dwTlsIndex));
  402. end;
  403. {*****************************************************************************
  404. Parameter Handling
  405. *****************************************************************************}
  406. function GetCommandLine : pwidechar;
  407. cdecl; external KernelDLL name 'GetCommandLineW';
  408. var
  409. ModuleName : array[0..255] of char;
  410. function GetCommandFile:pchar;
  411. var
  412. buf: array[0..MaxPathLen] of WideChar;
  413. begin
  414. if ModuleName[0] = #0 then begin
  415. GetModuleFileName(0, @buf, SizeOf(buf));
  416. WideToAnsiBuf(buf, -1, @ModuleName, SizeOf(ModuleName));
  417. end;
  418. GetCommandFile:=@ModuleName;
  419. end;
  420. var
  421. Fargc: longint;
  422. Fargv: ppchar;
  423. FCmdLine: PChar;
  424. procedure setup_arguments;
  425. var
  426. arglen,
  427. count : longint;
  428. argstart,
  429. pc,arg : pchar;
  430. quote : char;
  431. argvlen : longint;
  432. procedure allocarg(idx,len:longint);
  433. var
  434. oldargvlen : longint;
  435. begin
  436. if idx>=argvlen then
  437. begin
  438. oldargvlen:=argvlen;
  439. argvlen:=(idx+8) and (not 7);
  440. sysreallocmem(Fargv,argvlen*sizeof(pointer));
  441. fillchar(Fargv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
  442. end;
  443. { use realloc to reuse already existing memory }
  444. { always allocate, even if length is zero, since }
  445. { the arg. is still present! }
  446. sysreallocmem(Fargv[idx],len+1);
  447. end;
  448. begin
  449. { create commandline, it starts with the executed filename which is argv[0] }
  450. { WinCE passes the command NOT via the args, but via getmodulefilename}
  451. if FCmdLine <> nil then exit;
  452. argvlen:=0;
  453. pc:=getcommandfile;
  454. Arglen:=0;
  455. while pc[Arglen] <> #0 do
  456. Inc(Arglen);
  457. allocarg(0,arglen);
  458. move(pc^,Fargv[0]^,arglen+1);
  459. { Setup FCmdLine variable }
  460. arg:=PChar(GetCommandLine);
  461. count:=WideToAnsiBuf(PWideChar(arg), -1, nil, 0);
  462. FCmdLine:=SysGetMem(arglen + count + 3);
  463. FCmdLine^:='"';
  464. move(pc^, (FCmdLine + 1)^, arglen);
  465. (FCmdLine + arglen + 1)^:='"';
  466. (FCmdLine + arglen + 2)^:=' ';
  467. WideToAnsiBuf(PWideChar(arg), -1, FCmdLine + arglen + 3, count);
  468. { process arguments }
  469. count:=0;
  470. pc:=FCmdLine;
  471. {$IfDef SYSTEM_DEBUG_STARTUP}
  472. Writeln(stderr,'WinCE GetCommandLine is #',pc,'#');
  473. {$EndIf }
  474. while pc^<>#0 do
  475. begin
  476. { skip leading spaces }
  477. while pc^ in [#1..#32] do
  478. inc(pc);
  479. if pc^=#0 then
  480. break;
  481. { calc argument length }
  482. quote:=' ';
  483. argstart:=pc;
  484. arglen:=0;
  485. while (pc^<>#0) do
  486. begin
  487. case pc^ of
  488. #1..#32 :
  489. begin
  490. if quote<>' ' then
  491. inc(arglen)
  492. else
  493. break;
  494. end;
  495. '"' :
  496. begin
  497. if quote<>'''' then
  498. begin
  499. if pchar(pc+1)^<>'"' then
  500. begin
  501. if quote='"' then
  502. quote:=' '
  503. else
  504. quote:='"';
  505. end
  506. else
  507. inc(pc);
  508. end
  509. else
  510. inc(arglen);
  511. end;
  512. '''' :
  513. begin
  514. if quote<>'"' then
  515. begin
  516. if pchar(pc+1)^<>'''' then
  517. begin
  518. if quote='''' then
  519. quote:=' '
  520. else
  521. quote:='''';
  522. end
  523. else
  524. inc(pc);
  525. end
  526. else
  527. inc(arglen);
  528. end;
  529. else
  530. inc(arglen);
  531. end;
  532. inc(pc);
  533. end;
  534. { copy argument }
  535. { Don't copy the first one, it is already there.}
  536. If Count<>0 then
  537. begin
  538. allocarg(count,arglen);
  539. quote:=' ';
  540. pc:=argstart;
  541. arg:=Fargv[count];
  542. while (pc^<>#0) do
  543. begin
  544. case pc^ of
  545. #1..#32 :
  546. begin
  547. if quote<>' ' then
  548. begin
  549. arg^:=pc^;
  550. inc(arg);
  551. end
  552. else
  553. break;
  554. end;
  555. '"' :
  556. begin
  557. if quote<>'''' then
  558. begin
  559. if pchar(pc+1)^<>'"' then
  560. begin
  561. if quote='"' then
  562. quote:=' '
  563. else
  564. quote:='"';
  565. end
  566. else
  567. inc(pc);
  568. end
  569. else
  570. begin
  571. arg^:=pc^;
  572. inc(arg);
  573. end;
  574. end;
  575. '''' :
  576. begin
  577. if quote<>'"' then
  578. begin
  579. if pchar(pc+1)^<>'''' then
  580. begin
  581. if quote='''' then
  582. quote:=' '
  583. else
  584. quote:='''';
  585. end
  586. else
  587. inc(pc);
  588. end
  589. else
  590. begin
  591. arg^:=pc^;
  592. inc(arg);
  593. end;
  594. end;
  595. else
  596. begin
  597. arg^:=pc^;
  598. inc(arg);
  599. end;
  600. end;
  601. inc(pc);
  602. end;
  603. arg^:=#0;
  604. end;
  605. {$IfDef SYSTEM_DEBUG_STARTUP}
  606. Writeln(stderr,'dos arg ',count,' #',arglen,'#',Fargv[count],'#');
  607. {$EndIf SYSTEM_DEBUG_STARTUP}
  608. inc(count);
  609. end;
  610. { get argc and create an nil entry }
  611. Fargc:=count;
  612. allocarg(argc,0);
  613. { free unused memory }
  614. sysreallocmem(Fargv,(argc+1)*sizeof(pointer));
  615. end;
  616. function CmdLine: PChar;
  617. begin
  618. setup_arguments;
  619. Result:=FCmdLine;
  620. end;
  621. function argc: longint;
  622. begin
  623. setup_arguments;
  624. Result:=Fargc;
  625. end;
  626. function argv: ppchar;
  627. begin
  628. setup_arguments;
  629. Result:=Fargv;
  630. end;
  631. function paramcount : longint;
  632. begin
  633. paramcount := argc - 1;
  634. end;
  635. function paramstr(l : longint) : string;
  636. begin
  637. setup_arguments;
  638. if (l>=0) and (l<Fargc) then
  639. paramstr:=strpas(Fargv[l])
  640. else
  641. paramstr:='';
  642. end;
  643. procedure randomize;
  644. begin
  645. randseed:=GetTickCount;
  646. end;
  647. {*****************************************************************************
  648. System Dependent Exit code
  649. *****************************************************************************}
  650. procedure PascalMain;external name 'PASCALMAIN';
  651. procedure ExitThread(Exitcode : longint); cdecl; external 'coredll';
  652. Procedure system_exit;
  653. begin
  654. if IsLibrary then
  655. exit;
  656. if not IsConsole then
  657. begin
  658. Close(stderr);
  659. Close(stdout);
  660. Close(erroutput);
  661. Close(Input);
  662. Close(Output);
  663. end;
  664. ExitThread(exitcode);
  665. end;
  666. {$ifdef cpu386}
  667. var
  668. { value of the stack segment
  669. to check if the call stack can be written on exceptions }
  670. _SS : Cardinal;
  671. {$endif cpu386}
  672. function Dll_entry : longbool;[public, alias : '_FPC_DLL_Entry'];
  673. begin
  674. IsLibrary:=true;
  675. Dll_entry:=false;
  676. case DLLreason of
  677. DLL_PROCESS_ATTACH :
  678. begin
  679. PASCALMAIN;
  680. Dll_entry:=true;
  681. end;
  682. DLL_THREAD_ATTACH :
  683. begin
  684. { Allocate Threadvars ?!}
  685. if assigned(Dll_Thread_Attach_Hook) then
  686. Dll_Thread_Attach_Hook(DllParam);
  687. end;
  688. DLL_THREAD_DETACH :
  689. begin
  690. if assigned(Dll_Thread_Detach_Hook) then
  691. Dll_Thread_Detach_Hook(DllParam);
  692. { Release Threadvars ?!}
  693. end;
  694. DLL_PROCESS_DETACH :
  695. begin
  696. Lib_Exit;
  697. if assigned(Dll_Process_Detach_Hook) then
  698. Dll_Process_Detach_Hook(DllParam);
  699. end;
  700. end;
  701. end;
  702. {$ifdef WINCE_EXCEPTION_HANDLING}
  703. //
  704. // Hardware exception handling
  705. //
  706. {
  707. Error code definitions for the WinCE API functions
  708. Values are 32 bit values layed out as follows:
  709. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  710. 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
  711. +---+-+-+-----------------------+-------------------------------+
  712. |Sev|C|R| Facility | Code |
  713. +---+-+-+-----------------------+-------------------------------+
  714. where
  715. Sev - is the severity code
  716. 00 - Success
  717. 01 - Informational
  718. 10 - Warning
  719. 11 - Error
  720. C - is the Customer code flag
  721. R - is a reserved bit
  722. Facility - is the facility code
  723. Code - is the facility's status code
  724. }
  725. const
  726. SEVERITY_SUCCESS = $00000000;
  727. SEVERITY_INFORMATIONAL = $40000000;
  728. SEVERITY_WARNING = $80000000;
  729. SEVERITY_ERROR = $C0000000;
  730. const
  731. STATUS_SEGMENT_NOTIFICATION = $40000005;
  732. DBG_TERMINATE_THREAD = $40010003;
  733. DBG_TERMINATE_PROCESS = $40010004;
  734. DBG_CONTROL_C = $40010005;
  735. DBG_CONTROL_BREAK = $40010008;
  736. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  737. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  738. STATUS_BREAKPOINT = $80000003;
  739. STATUS_SINGLE_STEP = $80000004;
  740. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  741. STATUS_ACCESS_VIOLATION = $C0000005;
  742. STATUS_IN_PAGE_ERROR = $C0000006;
  743. STATUS_INVALID_HANDLE = $C0000008;
  744. STATUS_NO_MEMORY = $C0000017;
  745. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  746. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  747. STATUS_INVALID_DISPOSITION = $C0000026;
  748. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  749. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  750. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  751. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  752. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  753. STATUS_FLOAT_OVERFLOW = $C0000091;
  754. STATUS_FLOAT_STACK_CHECK = $C0000092;
  755. STATUS_FLOAT_UNDERFLOW = $C0000093;
  756. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  757. STATUS_INTEGER_OVERFLOW = $C0000095;
  758. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  759. STATUS_STACK_OVERFLOW = $C00000FD;
  760. STATUS_CONTROL_C_EXIT = $C000013A;
  761. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  762. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  763. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  764. const
  765. ExceptionContinueExecution = 0;
  766. ExceptionContinueSearch = 1;
  767. ExceptionNestedException = 2;
  768. ExceptionCollidedUnwind = 3;
  769. ExceptionExecuteHandler = 4;
  770. MaxExceptionLevel = 16;
  771. exceptLevel : Byte = 0;
  772. {$ifdef CPUARM}
  773. const
  774. CONTEXT_ARM = $0000040;
  775. CONTEXT_CONTROL = CONTEXT_ARM or $00000001;
  776. CONTEXT_INTEGER = CONTEXT_ARM or $00000002;
  777. CONTEXT_SEGMENTS = CONTEXT_ARM or $00000004;
  778. CONTEXT_FLOATING_POINT = CONTEXT_ARM or $00000008;
  779. CONTEXT_DEBUG_REGISTERS = CONTEXT_ARM or $00000010;
  780. CONTEXT_EXTENDED_REGISTERS = CONTEXT_ARM or $00000020;
  781. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  782. NUM_VFP_REGS = 32;
  783. NUM_EXTRA_CONTROL_REGS = 8;
  784. type
  785. PContext = ^TContext;
  786. TContext = record
  787. ContextFlags : LongWord;
  788. // This section is specified/returned if the ContextFlags word contains
  789. // the flag CONTEXT_INTEGER.
  790. R0 : LongWord;
  791. R1 : LongWord;
  792. R2 : LongWord;
  793. R3 : LongWord;
  794. R4 : LongWord;
  795. R5 : LongWord;
  796. R6 : LongWord;
  797. R7 : LongWord;
  798. R8 : LongWord;
  799. R9 : LongWord;
  800. R10 : LongWord;
  801. R11 : LongWord;
  802. R12 : LongWord;
  803. // This section is specified/returned if the ContextFlags word contains
  804. // the flag CONTEXT_CONTROL.
  805. Sp : LongWord;
  806. Lr : LongWord;
  807. Pc : LongWord;
  808. Psr : LongWord;
  809. Fpscr : LongWord;
  810. FpExc : LongWord;
  811. // Floating point registers
  812. S : array[0..(NUM_VFP_REGS + 1)-1] of LongWord;
  813. FpExtra : array[0..(NUM_EXTRA_CONTROL_REGS)-1] of LongWord;
  814. end;
  815. {$endif CPUARM}
  816. {$ifdef CPUI386}
  817. const
  818. CONTEXT_X86 = $00010000;
  819. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  820. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  821. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  822. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  823. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  824. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  825. MAXIMUM_SUPPORTED_EXTENSION = 512;
  826. type
  827. PFloatingSaveArea = ^TFloatingSaveArea;
  828. TFloatingSaveArea = packed record
  829. ControlWord : Cardinal;
  830. StatusWord : Cardinal;
  831. TagWord : Cardinal;
  832. ErrorOffset : Cardinal;
  833. ErrorSelector : Cardinal;
  834. DataOffset : Cardinal;
  835. DataSelector : Cardinal;
  836. RegisterArea : array[0..79] of Byte;
  837. Cr0NpxState : Cardinal;
  838. end;
  839. PContext = ^TContext;
  840. TContext = packed record
  841. //
  842. // The flags values within this flag control the contents of
  843. // a CONTEXT record.
  844. //
  845. ContextFlags : Cardinal;
  846. //
  847. // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
  848. // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
  849. // included in CONTEXT_FULL.
  850. //
  851. Dr0, Dr1, Dr2,
  852. Dr3, Dr6, Dr7 : Cardinal;
  853. //
  854. // This section is specified/returned if the
  855. // ContextFlags word contains the flag CONTEXT_FLOATING_POINT.
  856. //
  857. FloatSave : TFloatingSaveArea;
  858. //
  859. // This section is specified/returned if the
  860. // ContextFlags word contains the flag CONTEXT_SEGMENTS.
  861. //
  862. SegGs, SegFs,
  863. SegEs, SegDs : Cardinal;
  864. //
  865. // This section is specified/returned if the
  866. // ContextFlags word contains the flag CONTEXT_INTEGER.
  867. //
  868. Edi, Esi, Ebx,
  869. Edx, Ecx, Eax : Cardinal;
  870. //
  871. // This section is specified/returned if the
  872. // ContextFlags word contains the flag CONTEXT_CONTROL.
  873. //
  874. Ebp : Cardinal;
  875. Eip : Cardinal;
  876. SegCs : Cardinal;
  877. EFlags, Esp, SegSs : Cardinal;
  878. //
  879. // This section is specified/returned if the ContextFlags word
  880. // contains the flag CONTEXT_EXTENDED_REGISTERS.
  881. // The format and contexts are processor specific
  882. //
  883. ExtendedRegisters : array[0..MAXIMUM_SUPPORTED_EXTENSION-1] of Byte;
  884. end;
  885. {$endif CPUI386}
  886. type
  887. PExceptionPointers = ^TExceptionPointers;
  888. TExceptionPointers = packed record
  889. ExceptionRecord : PExceptionRecord;
  890. ContextRecord : PContext;
  891. end;
  892. {$ifdef CPUI386}
  893. {**************************** i386 Exception handling *****************************************}
  894. function GetCurrentProcess:DWORD;
  895. begin
  896. GetCurrentProcess := SH_CURPROC+SYS_HANDLE_BASE;
  897. end;
  898. function ReadProcessMemory(process : dword;address : pointer;dest : pointer;size : dword;bytesread : pdword) : longbool;
  899. cdecl; external 'coredll' name 'ReadProcessMemory';
  900. function is_prefetch(p : pointer) : boolean;
  901. var
  902. a : array[0..15] of byte;
  903. doagain : boolean;
  904. instrlo,instrhi,opcode : byte;
  905. i : longint;
  906. begin
  907. result:=false;
  908. { read memory savely without causing another exeception }
  909. if not(ReadProcessMemory(GetCurrentProcess,p,@a,sizeof(a),nil)) then
  910. exit;
  911. i:=0;
  912. doagain:=true;
  913. while doagain and (i<15) do
  914. begin
  915. opcode:=a[i];
  916. instrlo:=opcode and $f;
  917. instrhi:=opcode and $f0;
  918. case instrhi of
  919. { prefix? }
  920. $20,$30:
  921. doagain:=(instrlo and 7)=6;
  922. $60:
  923. doagain:=(instrlo and $c)=4;
  924. $f0:
  925. doagain:=instrlo in [0,2,3];
  926. $0:
  927. begin
  928. result:=(instrlo=$f) and (a[i+1] in [$d,$18]);
  929. exit;
  930. end;
  931. else
  932. doagain:=false;
  933. end;
  934. inc(i);
  935. end;
  936. end;
  937. var
  938. exceptEip : array[0..MaxExceptionLevel-1] of Longint;
  939. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  940. resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
  941. {$ifdef SYSTEMEXCEPTIONDEBUG}
  942. procedure DebugHandleErrorAddrFrame(error, addr, frame : longint);
  943. begin
  944. if IsConsole then
  945. begin
  946. write(stderr,'HandleErrorAddrFrame(error=',error);
  947. write(stderr,',addr=',hexstr(addr,8));
  948. writeln(stderr,',frame=',hexstr(frame,8),')');
  949. end;
  950. HandleErrorAddrFrame(error,addr,frame);
  951. end;
  952. {$endif SYSTEMEXCEPTIONDEBUG}
  953. procedure JumpToHandleErrorFrame;
  954. var
  955. eip, ebp, error : Longint;
  956. begin
  957. // save ebp
  958. asm
  959. movl (%ebp),%eax
  960. movl %eax,ebp
  961. end;
  962. if (exceptLevel > 0) then
  963. dec(exceptLevel);
  964. eip:=exceptEip[exceptLevel];
  965. error:=exceptError[exceptLevel];
  966. {$ifdef SYSTEMEXCEPTIONDEBUG}
  967. if IsConsole then
  968. writeln(stderr,'In JumpToHandleErrorFrame error=',error);
  969. {$endif SYSTEMEXCEPTIONDEBUG}
  970. if resetFPU[exceptLevel] then
  971. SysResetFPU;
  972. { build a fake stack }
  973. asm
  974. {$ifdef REGCALL}
  975. movl ebp,%ecx
  976. movl eip,%edx
  977. movl error,%eax
  978. pushl eip
  979. movl ebp,%ebp // Change frame pointer
  980. {$else}
  981. movl ebp,%eax
  982. pushl %eax
  983. movl eip,%eax
  984. pushl %eax
  985. movl error,%eax
  986. pushl %eax
  987. movl eip,%eax
  988. pushl %eax
  989. movl ebp,%ebp // Change frame pointer
  990. {$endif}
  991. {$ifdef SYSTEMEXCEPTIONDEBUG}
  992. jmpl DebugHandleErrorAddrFrame
  993. {$else not SYSTEMEXCEPTIONDEBUG}
  994. jmpl HandleErrorAddrFrame
  995. {$endif SYSTEMEXCEPTIONDEBUG}
  996. end;
  997. end;
  998. function i386_exception_handler(ExceptionRecord: PExceptionRecord;
  999. EstablisherFrame: pointer; ContextRecord: PContext;
  1000. DispatcherContext: pointer): longint; cdecl;
  1001. var
  1002. res: longint;
  1003. must_reset_fpu: boolean;
  1004. begin
  1005. res := ExceptionContinueSearch;
  1006. if ContextRecord^.SegSs=_SS then begin
  1007. must_reset_fpu := true;
  1008. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1009. if IsConsole then Writeln(stderr,'Exception ',
  1010. hexstr(excep^.ExceptionRecord^.ExceptionCode, 8));
  1011. {$endif SYSTEMEXCEPTIONDEBUG}
  1012. case cardinal(ExceptionRecord^.ExceptionCode) of
  1013. STATUS_INTEGER_DIVIDE_BY_ZERO,
  1014. STATUS_FLOAT_DIVIDE_BY_ZERO :
  1015. res := 200;
  1016. STATUS_ARRAY_BOUNDS_EXCEEDED :
  1017. begin
  1018. res := 201;
  1019. must_reset_fpu := false;
  1020. end;
  1021. STATUS_STACK_OVERFLOW :
  1022. begin
  1023. res := 202;
  1024. must_reset_fpu := false;
  1025. end;
  1026. STATUS_FLOAT_OVERFLOW :
  1027. res := 205;
  1028. STATUS_FLOAT_DENORMAL_OPERAND,
  1029. STATUS_FLOAT_UNDERFLOW :
  1030. res := 206;
  1031. {excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  1032. STATUS_FLOAT_INEXACT_RESULT,
  1033. STATUS_FLOAT_INVALID_OPERATION,
  1034. STATUS_FLOAT_STACK_CHECK :
  1035. res := 207;
  1036. STATUS_INTEGER_OVERFLOW :
  1037. begin
  1038. res := 215;
  1039. must_reset_fpu := false;
  1040. end;
  1041. STATUS_ILLEGAL_INSTRUCTION:
  1042. res := 216;
  1043. STATUS_ACCESS_VIOLATION:
  1044. { Athlon prefetch bug? }
  1045. if is_prefetch(pointer(ContextRecord^.Eip)) then
  1046. begin
  1047. { if yes, then retry }
  1048. ExceptionRecord^.ExceptionCode := 0;
  1049. res:=ExceptionContinueExecution;
  1050. end
  1051. else
  1052. res := 216;
  1053. STATUS_CONTROL_C_EXIT:
  1054. res := 217;
  1055. STATUS_PRIVILEGED_INSTRUCTION:
  1056. begin
  1057. res := 218;
  1058. must_reset_fpu := false;
  1059. end;
  1060. else
  1061. begin
  1062. if ((ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  1063. res := 217
  1064. else
  1065. res := 255;
  1066. end;
  1067. end;
  1068. if (res >= 200) and (exceptLevel < MaxExceptionLevel) then begin
  1069. exceptEip[exceptLevel] := ContextRecord^.Eip;
  1070. exceptError[exceptLevel] := res;
  1071. resetFPU[exceptLevel] := must_reset_fpu;
  1072. inc(exceptLevel);
  1073. ContextRecord^.Eip := Longint(@JumpToHandleErrorFrame);
  1074. ExceptionRecord^.ExceptionCode := 0;
  1075. res := ExceptionContinueExecution;
  1076. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1077. if IsConsole then begin
  1078. writeln(stderr,'Exception Continue Exception set at ',
  1079. hexstr(exceptEip[exceptLevel],8));
  1080. writeln(stderr,'Eip changed to ',
  1081. hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', error);
  1082. end;
  1083. {$endif SYSTEMEXCEPTIONDEBUG}
  1084. end;
  1085. end;
  1086. i386_exception_handler := res;
  1087. end;
  1088. {$endif CPUI386}
  1089. {$ifdef CPUARM}
  1090. {**************************** ARM Exception handling *****************************************}
  1091. var
  1092. exceptPC : array[0..MaxExceptionLevel-1] of Longint;
  1093. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  1094. procedure JumpToHandleErrorFrame;
  1095. var
  1096. _pc, _fp, _error : Longint;
  1097. begin
  1098. // get original fp
  1099. asm
  1100. ldr r0,[r11,#-12]
  1101. str r0,_fp
  1102. end;
  1103. if (exceptLevel > 0) then
  1104. dec(exceptLevel);
  1105. _pc:=exceptPC[exceptLevel];
  1106. _error:=exceptError[exceptLevel];
  1107. asm
  1108. ldr r0,_error
  1109. ldr r1,_pc
  1110. ldr r2,_fp
  1111. mov r11,r2 // Change frame pointer
  1112. b HandleErrorAddrFrame
  1113. end;
  1114. end;
  1115. function ARM_ExceptionHandler(ExceptionRecord: PExceptionRecord;
  1116. EstablisherFrame: pointer; ContextRecord: PContext;
  1117. DispatcherContext: pointer): longint; [public, alias : '_ARM_ExceptionHandler'];
  1118. var
  1119. res: longint;
  1120. begin
  1121. res := ExceptionContinueSearch;
  1122. case cardinal(ExceptionRecord^.ExceptionCode) of
  1123. STATUS_INTEGER_DIVIDE_BY_ZERO,
  1124. STATUS_FLOAT_DIVIDE_BY_ZERO :
  1125. res := 200;
  1126. STATUS_ARRAY_BOUNDS_EXCEEDED :
  1127. res := 201;
  1128. STATUS_STACK_OVERFLOW :
  1129. res := 202;
  1130. STATUS_FLOAT_OVERFLOW :
  1131. res := 205;
  1132. STATUS_FLOAT_DENORMAL_OPERAND,
  1133. STATUS_FLOAT_UNDERFLOW :
  1134. res := 206;
  1135. STATUS_FLOAT_INEXACT_RESULT,
  1136. STATUS_FLOAT_INVALID_OPERATION,
  1137. STATUS_FLOAT_STACK_CHECK :
  1138. res := 207;
  1139. STATUS_INTEGER_OVERFLOW :
  1140. res := 215;
  1141. STATUS_ILLEGAL_INSTRUCTION:
  1142. res := 216;
  1143. STATUS_ACCESS_VIOLATION:
  1144. res := 216;
  1145. STATUS_DATATYPE_MISALIGNMENT:
  1146. res := 214;
  1147. STATUS_CONTROL_C_EXIT:
  1148. res := 217;
  1149. STATUS_PRIVILEGED_INSTRUCTION:
  1150. res := 218;
  1151. else
  1152. begin
  1153. if ((cardinal(ExceptionRecord^.ExceptionCode) and SEVERITY_ERROR) = SEVERITY_ERROR) then
  1154. res := 217
  1155. else
  1156. res := 255;
  1157. end;
  1158. end;
  1159. if (res <> ExceptionContinueSearch) and (exceptLevel < MaxExceptionLevel) then begin
  1160. exceptPC[exceptLevel] := ContextRecord^.PC;
  1161. exceptError[exceptLevel] := res;
  1162. inc(exceptLevel);
  1163. ContextRecord^.PC := Longint(@JumpToHandleErrorFrame);
  1164. ExceptionRecord^.ExceptionCode := 0;
  1165. res := ExceptionContinueExecution;
  1166. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1167. if IsConsole then begin
  1168. writeln(stderr,'Exception Continue Exception set at ',
  1169. hexstr(exceptEip[exceptLevel],8));
  1170. writeln(stderr,'Eip changed to ',
  1171. hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', error);
  1172. end;
  1173. {$endif SYSTEMEXCEPTIONDEBUG}
  1174. end;
  1175. ARM_ExceptionHandler := res;
  1176. end;
  1177. {$endif CPUARM}
  1178. {$endif WINCE_EXCEPTION_HANDLING}
  1179. procedure Exe_entry;[public, alias : '_FPC_EXE_Entry'];
  1180. begin
  1181. IsLibrary:=false;
  1182. {$ifdef CPUARM}
  1183. asm
  1184. mov fp,#0
  1185. bl PASCALMAIN;
  1186. end;
  1187. {$endif CPUARM}
  1188. {$ifdef CPUI386}
  1189. asm
  1190. {$ifdef WINCE_EXCEPTION_HANDLING}
  1191. pushl i386_exception_handler
  1192. pushl %fs:(0)
  1193. mov %esp,%fs:(0)
  1194. {$endif WINCE_EXCEPTION_HANDLING}
  1195. pushl %ebp
  1196. xorl %eax,%eax
  1197. movw %ss,%ax
  1198. movl %eax,_SS
  1199. xorl %ebp,%ebp
  1200. call PASCALMAIN
  1201. popl %ebp
  1202. {$ifdef WINCE_EXCEPTION_HANDLING}
  1203. popl %fs:(0)
  1204. addl $4, %esp
  1205. {$endif WINCE_EXCEPTION_HANDLING}
  1206. end;
  1207. {$endif CPUI386}
  1208. end;
  1209. procedure _FPC_mainCRTStartup;public name '_mainCRTStartup';
  1210. begin
  1211. IsConsole:=True;
  1212. Exe_entry;
  1213. end;
  1214. procedure _FPC_WinMainCRTStartup;public name '_WinMainCRTStartup';
  1215. begin
  1216. IsConsole:=False;
  1217. Exe_entry;
  1218. end;
  1219. procedure _FPC_DLLMainCRTStartup(_hinstance,_dllreason,_dllparam:longint);public name '_DLLMainCRTStartup';
  1220. begin
  1221. IsConsole:=true;
  1222. sysinstance:=_hinstance;
  1223. dllreason:=_dllreason;
  1224. dllparam:=_dllparam;
  1225. DLL_Entry;
  1226. end;
  1227. procedure _FPC_DLLWinMainCRTStartup(_hinstance,_dllreason,_dllparam:longint);public name '_DLLWinMainCRTStartup';
  1228. begin
  1229. IsConsole:=false;
  1230. sysinstance:=_hinstance;
  1231. dllreason:=_dllreason;
  1232. dllparam:=_dllparam;
  1233. DLL_Entry;
  1234. end;
  1235. {****************************************************************************
  1236. OS dependend widestrings
  1237. ****************************************************************************}
  1238. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD; cdecl; external KernelDLL name 'CharUpperBuffW';
  1239. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD; cdecl; external KernelDLL name 'CharLowerBuffW';
  1240. procedure WinCEWide2AnsiMove(source:pwidechar;var dest:RawByteString;cp:TSystemCodePage;len:SizeInt);
  1241. var
  1242. destlen: SizeInt;
  1243. begin
  1244. // retrieve length including trailing #0
  1245. // not anymore, because this must also be usable for single characters
  1246. destlen:=WideCharToMultiByte(cp, 0, source, len, nil, 0, nil, nil);
  1247. // this will null-terminate
  1248. setlength(dest, destlen);
  1249. if destlen>0 then
  1250. begin
  1251. WideCharToMultiByte(cp, 0, source, len, @dest[1], destlen, nil, nil);
  1252. PAnsiRec(pointer(dest)-AnsiFirstOff)^.CodePage:=cp;
  1253. end;
  1254. end;
  1255. procedure WinCEAnsi2WideMove(source:pchar;cp:TSystemCodePage;var dest:widestring;len:SizeInt);
  1256. var
  1257. destlen: SizeInt;
  1258. dwFlags: DWORD;
  1259. begin
  1260. if cp=CP_UTF8 then
  1261. dwFlags:=0
  1262. else
  1263. dwFlags:=MB_PRECOMPOSED;
  1264. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  1265. // this will null-terminate
  1266. setlength(dest, destlen);
  1267. if destlen>0 then
  1268. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  1269. end;
  1270. function WinCEWideUpper(const s : WideString) : WideString;
  1271. begin
  1272. result:=s;
  1273. UniqueString(result);
  1274. if length(result)>0 then
  1275. CharUpperBuff(LPWSTR(result),length(result));
  1276. end;
  1277. function WinCEWideLower(const s : WideString) : WideString;
  1278. begin
  1279. result:=s;
  1280. UniqueString(result);
  1281. if length(result)>0 then
  1282. CharLowerBuff(LPWSTR(result),length(result));
  1283. end;
  1284. procedure WinCEUnicode2AnsiMove(source:punicodechar;var dest:RawByteString;cp:TSystemCodePage;len:SizeInt);
  1285. var
  1286. destlen: SizeInt;
  1287. begin
  1288. // retrieve length including trailing #0
  1289. // not anymore, because this must also be usable for single characters
  1290. destlen:=WideCharToMultiByte(cp, 0, source, len, nil, 0, nil, nil);
  1291. // this will null-terminate
  1292. setlength(dest, destlen);
  1293. if destlen>0 then
  1294. begin
  1295. WideCharToMultiByte(cp, 0, source, len, @dest[1], destlen, nil, nil);
  1296. PAnsiRec(pointer(dest)-AnsiFirstOff)^.CodePage:=cp;
  1297. end;
  1298. end;
  1299. procedure WinCEAnsi2UnicodeMove(source:pchar;cp : TSystemCodePage;var dest:UnicodeString;len:SizeInt);
  1300. var
  1301. destlen: SizeInt;
  1302. dwflags: DWORD;
  1303. begin
  1304. if cp=CP_UTF8 then
  1305. dwFlags:=0
  1306. else
  1307. dwFlags:=MB_PRECOMPOSED;
  1308. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  1309. // this will null-terminate
  1310. setlength(dest, destlen);
  1311. if destlen>0 then
  1312. begin
  1313. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  1314. PUnicodeRec(pointer(dest)-UnicodeFirstOff)^.CodePage:=CP_UTF16;
  1315. end;
  1316. end;
  1317. function WinCEUnicodeUpper(const s : UnicodeString) : UnicodeString;
  1318. begin
  1319. Result:=WinCEWideUpper(s);
  1320. end;
  1321. function WinCEUnicodeLower(const s : UnicodeString) : UnicodeString;
  1322. begin
  1323. Result:=WinCEWideLower(s);
  1324. end;
  1325. function WinCEGetStandardCodePage(const stdcp: TStandardCodePageEnum): TSystemCodePage;
  1326. begin
  1327. case stdcp of
  1328. scpAnsi: Result := GetACP;
  1329. scpConsoleInput: Result := GetACP;
  1330. scpConsoleOutput: Result := GetACP;
  1331. { all of WinCE's file APIs are based on UTF8 -> prevent data loss when using
  1332. single byte strings }
  1333. scpFileSystemSingleByte: Result := CP_UTF8;
  1334. end;
  1335. end;
  1336. { there is a similiar procedure in sysutils which inits the fields which
  1337. are only relevant for the sysutils units }
  1338. procedure InitWinCEWidestrings;
  1339. begin
  1340. widestringmanager.Wide2AnsiMoveProc:=@WinCEWide2AnsiMove;
  1341. widestringmanager.Ansi2WideMoveProc:=@WinCEAnsi2WideMove;
  1342. widestringmanager.UpperWideStringProc:=@WinCEWideUpper;
  1343. widestringmanager.LowerWideStringProc:=@WinCEWideLower;
  1344. { Unicode }
  1345. widestringmanager.Unicode2AnsiMoveProc:=@WinCEUnicode2AnsiMove;
  1346. widestringmanager.Ansi2UnicodeMoveProc:=@WinCEAnsi2UnicodeMove;
  1347. widestringmanager.UpperUnicodeStringProc:=@WinCEUnicodeUpper;
  1348. widestringmanager.LowerUnicodeStringProc:=@WinCEUnicodeLower;
  1349. { Codepage }
  1350. widestringmanager.GetStandardCodePageProc:=@WinCEGetStandardCodePage;
  1351. DefaultSystemCodePage:=GetACP;
  1352. DefaultFileSystemCodePage:=WinCEGetStandardCodePage(scpFileSystemSingleByte);
  1353. DefaultRTLFileSystemCodePage:=DefaultFileSystemCodePage;
  1354. DefaultUnicodeCodePage:=CP_UTF16;
  1355. end;
  1356. {$IFDEF HAS_MEMORYMANAGER}
  1357. {****************************************************************************
  1358. Memory manager
  1359. ****************************************************************************}
  1360. function malloc(Size : ptruint) : Pointer; cdecl; external 'coredll';
  1361. procedure free(P : pointer); cdecl; external 'coredll';
  1362. function realloc(P : Pointer; Size : ptruint) : pointer; cdecl; external 'coredll';
  1363. function _msize(P : pointer): ptruint; cdecl; external 'coredll';
  1364. function SysGetMem (Size : ptruint) : Pointer;
  1365. begin
  1366. Result:=malloc(Size);
  1367. end;
  1368. Function SysFreeMem (P : pointer) : ptruint;
  1369. begin
  1370. free(P);
  1371. Result:=0;
  1372. end;
  1373. Function SysFreeMemSize(p:pointer;Size:ptruint):ptruint;
  1374. begin
  1375. Result:=0;
  1376. if (size > 0) and (p <> nil) then
  1377. Result:=SysFreeMem(P);
  1378. end;
  1379. Function SysAllocMem(Size : ptruint) : Pointer;
  1380. begin
  1381. Result:=SysGetMem(Size);
  1382. if Result <> nil then
  1383. FillChar(Result^, Size, 0);
  1384. end;
  1385. Function SysReAllocMem (var p:pointer;Size:ptruint):Pointer;
  1386. begin
  1387. Result:=realloc(p, Size);
  1388. p:=Result;
  1389. end;
  1390. function SysTryResizeMem(var p:pointer;size : ptruint):boolean;
  1391. var
  1392. res: pointer;
  1393. begin
  1394. res:=realloc(p, Size);
  1395. Result:=(res <> nil) or (Size = 0);
  1396. if Result then
  1397. p:=res;
  1398. end;
  1399. function SysMemSize(P : pointer): ptruint;
  1400. begin
  1401. Result:=_msize(P);
  1402. end;
  1403. function SysGetHeapStatus:THeapStatus;
  1404. begin
  1405. fillchar(Result,sizeof(Result),0);
  1406. end;
  1407. function SysGetFPCHeapStatus:TFPCHeapStatus;
  1408. begin
  1409. fillchar(Result,sizeof(Result),0);
  1410. end;
  1411. {$ENDIF HAS_MEMORYMANAGER}
  1412. {****************************************************************************
  1413. Error Message writing using messageboxes
  1414. ****************************************************************************}
  1415. const
  1416. ErrorBufferLength = 1024;
  1417. var
  1418. ErrorBuf : array[0..ErrorBufferLength] of char;
  1419. ErrorBufW : array[0..ErrorBufferLength] of widechar;
  1420. ErrorLen : longint;
  1421. procedure ErrorWrite(Var F: TextRec);
  1422. {
  1423. An error message should always end with #13#10#13#10
  1424. }
  1425. var
  1426. i : longint;
  1427. Begin
  1428. while F.BufPos>0 do
  1429. begin
  1430. begin
  1431. if F.BufPos+ErrorLen>ErrorBufferLength then
  1432. i:=ErrorBufferLength-ErrorLen
  1433. else
  1434. i:=F.BufPos;
  1435. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  1436. inc(ErrorLen,i);
  1437. ErrorBuf[ErrorLen]:=#0;
  1438. end;
  1439. if ErrorLen=ErrorBufferLength then
  1440. begin
  1441. AnsiToWideBuf(@ErrorBuf, -1, @ErrorBufW, SizeOf(ErrorBufW));
  1442. MessageBox(0,@ErrorBufW,'Error',$10010); { MB_SETFOREGROUND or ICON_ERROR }
  1443. ErrorLen:=0;
  1444. end;
  1445. Dec(F.BufPos,i);
  1446. end;
  1447. End;
  1448. procedure ErrorClose(Var F: TextRec);
  1449. begin
  1450. if ErrorLen>0 then
  1451. begin
  1452. AnsiToWideBuf(@ErrorBuf, -1, @ErrorBufW, SizeOf(ErrorBufW));
  1453. MessageBox(0,@ErrorBufW,'Error',$10010); { MB_SETFOREGROUND or ICON_ERROR }
  1454. ErrorLen:=0;
  1455. end;
  1456. ErrorLen:=0;
  1457. end;
  1458. procedure ErrorOpen(Var F: TextRec);
  1459. Begin
  1460. TextRec(F).InOutFunc:=@ErrorWrite;
  1461. TextRec(F).FlushFunc:=@ErrorWrite;
  1462. TextRec(F).CloseFunc:=@ErrorClose;
  1463. ErrorLen:=0;
  1464. End;
  1465. procedure AssignError(Var T: Text);
  1466. begin
  1467. Assign(T,'');
  1468. TextRec(T).OpenFunc:=@ErrorOpen;
  1469. Rewrite(T);
  1470. end;
  1471. function _getstdfilex(fd: integer): pointer; cdecl; external 'coredll';
  1472. function _fileno(fd: pointer): THandle; cdecl; external 'coredll';
  1473. procedure SysInitStdIO;
  1474. begin
  1475. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  1476. displayed in and messagebox }
  1477. if not IsConsole then
  1478. begin
  1479. AssignError(stderr);
  1480. AssignError(stdout);
  1481. Assign(Output,'');
  1482. Assign(Input,'');
  1483. Assign(ErrOutput,'');
  1484. end
  1485. else
  1486. begin
  1487. StdInputHandle:=_fileno(_getstdfilex(0));
  1488. StdOutputHandle:=_fileno(_getstdfilex(1));
  1489. StdErrorHandle:=_fileno(_getstdfilex(2));
  1490. OpenStdIO(Input,fmInput,StdInputHandle);
  1491. OpenStdIO(Output,fmOutput,StdOutputHandle);
  1492. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  1493. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  1494. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  1495. end;
  1496. end;
  1497. (* ProcessID cached to avoid repeated calls to GetCurrentProcess. *)
  1498. var
  1499. ProcessID: SizeUInt;
  1500. function GetProcessID: SizeUInt;
  1501. begin
  1502. GetProcessID := ProcessID;
  1503. end;
  1504. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  1505. begin
  1506. result := stklen;
  1507. end;
  1508. procedure SysCleanup;
  1509. var
  1510. i: integer;
  1511. begin
  1512. if FCmdLine = nil then
  1513. exit;
  1514. SysFreeMem(FCmdLine);
  1515. for i:=0 to Fargc do
  1516. sysfreemem(Fargv[i]);
  1517. sysfreemem(Fargv);
  1518. end;
  1519. initialization
  1520. SysResetFPU;
  1521. if not(IsLibrary) then
  1522. SysInitFPU;
  1523. StackLength := CheckInitialStkLen(InitialStkLen);
  1524. StackBottom := Sptr - StackLength;
  1525. { some misc stuff }
  1526. hprevinst:=0;
  1527. if not IsLibrary then
  1528. SysInstance:=GetModuleHandle(nil);
  1529. MainInstance:=SysInstance;
  1530. {$IFNDEF HAS_MEMORYMANAGER}
  1531. { Setup Heap }
  1532. InitHeap;
  1533. {$ENDIF HAS_MEMORYMANAGER}
  1534. SysInitExceptions;
  1535. initunicodestringmanager;
  1536. InitWinCEWidestrings;
  1537. if not IsLibrary then
  1538. begin
  1539. SysInitStdIO;
  1540. end;
  1541. { Reset IO Error }
  1542. InOutRes:=0;
  1543. ProcessID := GetCurrentProcessID;
  1544. { threading }
  1545. InitSystemThreads;
  1546. DispCallByIDProc:=@DoDispCallByIDError;
  1547. finalization
  1548. SysCleanup;
  1549. end.