2
0

sysutils.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2016 by Free Pascal development team
  4. Sysutils unit for Atari
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit sysutils;
  12. interface
  13. {$MODE objfpc}
  14. {$MODESWITCH OUT}
  15. { force ansistrings }
  16. {$H+}
  17. {$modeswitch typehelpers}
  18. {$modeswitch advancedrecords}
  19. {$DEFINE OS_FILESETDATEBYNAME}
  20. {$DEFINE HAS_SLEEP}
  21. {$DEFINE HAS_OSERROR}
  22. {OS has only 1 byte version for ExecuteProcess}
  23. {$define executeprocuni}
  24. { used OS file system APIs use ansistring }
  25. {$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
  26. { OS has an ansistring/single byte environment variable API }
  27. {$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
  28. { Include platform independent interface part }
  29. {$i sysutilh.inc}
  30. { Platform dependent calls }
  31. implementation
  32. uses
  33. { dos,} sysconst;
  34. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  35. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  36. { Include platform independent implementation part }
  37. {$i sysutils.inc}
  38. {$i gemdos.inc}
  39. {****************************************************************************
  40. File Functions
  41. ****************************************************************************}
  42. {$I-}{ Required for correct usage of these routines }
  43. (****** non portable routines ******)
  44. function FileOpen(const FileName: rawbytestring; Mode: Integer): THandle;
  45. begin
  46. { Mode has some Share modes. Maybe something for MiNT? }
  47. { Lower three bits of Mode are actually TOS compatible }
  48. FileOpen:=gemdos_fopen(pchar(FileName), Mode and 3);
  49. if FileOpen < -1 then
  50. FileOpen:=-1;
  51. end;
  52. function FileGetDate(Handle: THandle) : Int64;
  53. var
  54. td: TDOSTIME;
  55. begin
  56. { Fdatime doesn't report errors... }
  57. gemdos_fdatime(@td,handle,0);
  58. result:=(td.date shl 16) or td.time;
  59. end;
  60. function FileSetDate(Handle: THandle; Age: Int64) : LongInt;
  61. var
  62. td: TDOSTIME;
  63. begin
  64. td.date:=(Age shr 16) and $ffff;
  65. td.time:=Age and $ffff;
  66. gemdos_fdatime(@td,handle,1);
  67. { Fdatime doesn't report errors... }
  68. result:=0;
  69. end;
  70. function FileSetDate(const FileName: RawByteString; Age: Int64) : LongInt;
  71. var
  72. f: THandle;
  73. begin
  74. FileSetDate:=-1;
  75. f:=FileOpen(FileName,fmOpenReadWrite);
  76. if f < 0 then
  77. exit;
  78. FileSetDate(f,Age);
  79. FileClose(f);
  80. end;
  81. function FileCreate(const FileName: RawByteString) : THandle;
  82. begin
  83. FileCreate:=gemdos_fcreate(pchar(FileName),0);
  84. if FileCreate < -1 then
  85. FileCreate:=-1;
  86. end;
  87. function FileCreate(const FileName: RawByteString; Rights: integer): THandle;
  88. begin
  89. { Rights are Un*x extension. Maybe something for MiNT? }
  90. FileCreate:=FileCreate(FileName);
  91. end;
  92. function FileCreate(const FileName: RawByteString; ShareMode: integer; Rights : integer): THandle;
  93. begin
  94. { Rights and ShareMode are Un*x extension. Maybe something for MiNT? }
  95. FileCreate:=FileCreate(FileName);
  96. end;
  97. function FileRead(Handle: THandle; out Buffer; Count: LongInt): LongInt;
  98. begin
  99. FileRead:=-1;
  100. if (Count<=0) then
  101. exit;
  102. FileRead:=gemdos_fread(handle, count, @buffer);
  103. if FileRead < -1 then
  104. FileRead:=-1;
  105. end;
  106. function FileWrite(Handle: THandle; const Buffer; Count: LongInt): LongInt;
  107. begin
  108. FileWrite:=-1;
  109. if (Count<=0) then
  110. exit;
  111. FileWrite:=gemdos_fwrite(handle, count, @buffer);
  112. if FileWrite < -1 then
  113. FileWrite:=-1;
  114. end;
  115. function FileSeek(Handle: THandle; FOffset, Origin: LongInt) : LongInt;
  116. var
  117. dosResult: longint;
  118. begin
  119. FileSeek:=-1;
  120. { TOS seek mode flags are actually compatible to DOS/TP }
  121. dosResult:=gemdos_fseek(FOffset, Handle, Origin);
  122. if dosResult < 0 then
  123. exit;
  124. FileSeek:=dosResult;
  125. end;
  126. function FileSeek(Handle: THandle; FOffset: Int64; Origin: Longint): Int64;
  127. begin
  128. FileSeek:=FileSeek(Handle,LongInt(FOffset),Origin);
  129. end;
  130. procedure FileClose(Handle: THandle);
  131. begin
  132. gemdos_fclose(handle);
  133. end;
  134. function FileTruncate(Handle: THandle; Size: Int64): Boolean;
  135. begin
  136. FileTruncate:=False;
  137. end;
  138. function DeleteFile(const FileName: RawByteString) : Boolean;
  139. begin
  140. DeleteFile:=gemdos_fdelete(pchar(FileName)) >= 0;
  141. end;
  142. function RenameFile(const OldName, NewName: RawByteString): Boolean;
  143. begin
  144. RenameFile:=gemdos_frename(0,pchar(oldname),pchar(newname)) >= 0;
  145. end;
  146. (****** end of non portable routines ******)
  147. function FileAge (const FileName : RawByteString): Int64;
  148. var
  149. f: THandle;
  150. begin
  151. FileAge:=-1;
  152. f:=FileOpen(FileName,fmOpenRead);
  153. if f < 0 then
  154. exit;
  155. FileAge:=FileGetDate(f);
  156. FileClose(f);
  157. end;
  158. function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;
  159. begin
  160. Result := False;
  161. end;
  162. function FileExists (const FileName : RawByteString; FollowLink : Boolean) : Boolean;
  163. var
  164. Attr: longint;
  165. begin
  166. FileExists:=false;
  167. Attr:=FileGetAttr(FileName);
  168. if Attr < 0 then
  169. exit;
  170. result:=(Attr and (faVolumeID or faDirectory)) = 0;
  171. end;
  172. type
  173. PInternalFindData = ^TInternalFindData;
  174. TInternalFindData = record
  175. dta_original: pointer;
  176. dta_search: TDTA;
  177. end;
  178. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  179. var
  180. dosResult: longint;
  181. IFD: PInternalFindData;
  182. begin
  183. result:=-1; { We emulate Linux/Unix behaviour, and return -1 on errors. }
  184. new(IFD);
  185. IFD^.dta_original:=gemdos_getdta;
  186. gemdos_setdta(@IFD^.dta_search);
  187. Rslt.FindHandle:=nil;
  188. dosResult:=gemdos_fsfirst(pchar(path), Attr and faAnyFile);
  189. if dosResult < 0 then
  190. begin
  191. InternalFindClose(IFD);
  192. exit;
  193. end;
  194. Rslt.FindHandle:=IFD;
  195. with IFD^.dta_search do
  196. begin
  197. Name:=d_fname;
  198. SetCodePage(Name,DefaultFileSystemCodePage,false);
  199. Rslt.Time:=(d_date shl 16) or d_time;
  200. Rslt.Size:=d_length;
  201. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  202. Rslt.Attr := 128 or d_attrib;
  203. end;
  204. result:=0;
  205. end;
  206. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  207. var
  208. dosResult: longint;
  209. IFD: PInternalFindData;
  210. begin
  211. result:=-1;
  212. IFD:=PInternalFindData(Rslt.FindHandle);
  213. if not assigned(IFD) then
  214. exit;
  215. dosResult:=gemdos_fsnext;
  216. if dosResult < 0 then
  217. exit;
  218. with IFD^.dta_search do
  219. begin
  220. Name:=d_fname;
  221. SetCodePage(Name,DefaultFileSystemCodePage,false);
  222. Rslt.Time:=(d_date shl 16) or d_time;
  223. Rslt.Size:=d_length;
  224. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  225. Rslt.Attr := 128 or d_attrib;
  226. end;
  227. result:=0;
  228. end;
  229. Procedure InternalFindClose(var Handle: Pointer);
  230. var
  231. IFD: PInternalFindData;
  232. begin
  233. IFD:=PInternalFindData(Handle);
  234. if not assigned(IFD) then
  235. exit;
  236. gemdos_setdta(IFD^.dta_original);
  237. dispose(IFD);
  238. IFD:=nil;
  239. end;
  240. (****** end of non portable routines ******)
  241. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  242. begin
  243. FileGetAttr:=gemdos_fattrib(pchar(FileName),0,0);
  244. end;
  245. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  246. begin
  247. FileSetAttr:=gemdos_fattrib(pchar(FileName),1,Attr and faAnyFile);
  248. if FileSetAttr < -1 then
  249. FileSetAttr:=-1
  250. else
  251. FileSetAttr:=0;
  252. end;
  253. {****************************************************************************
  254. Disk Functions
  255. ****************************************************************************}
  256. function DiskSize(Drive: Byte): Int64;
  257. var
  258. dosResult: longint;
  259. di: TDISKINFO;
  260. begin
  261. DiskSize := -1;
  262. dosResult:=gemdos_dfree(@di,drive);
  263. if dosResult < 0 then
  264. exit;
  265. DiskSize:=di.b_total * di.b_secsiz * di.b_clsiz;
  266. end;
  267. function DiskFree(Drive: Byte): Int64;
  268. var
  269. dosResult: longint;
  270. di: TDISKINFO;
  271. begin
  272. DiskFree := -1;
  273. dosResult:=gemdos_dfree(@di,drive);
  274. if dosResult < 0 then
  275. exit;
  276. DiskFree:=di.b_free * di.b_secsiz * di.b_clsiz;
  277. end;
  278. function DirectoryExists(const Directory: RawByteString; FollowLink : Boolean): Boolean;
  279. var
  280. Attr: longint;
  281. begin
  282. DirectoryExists:=false;
  283. Attr:=FileGetAttr(Directory);
  284. if Attr < 0 then
  285. exit;
  286. result:=(Attr and faDirectory) <> 0;
  287. end;
  288. {****************************************************************************
  289. Locale Functions
  290. ****************************************************************************}
  291. Procedure GetLocalTime(var SystemTime: TSystemTime);
  292. var
  293. TOSTime: Longint;
  294. begin
  295. LongRec(TOSTime).hi:=gemdos_tgetdate;
  296. LongRec(TOSTime).lo:=gemdos_tgettime;
  297. DateTimeToSystemTime(FileDateToDateTime(TOSTime),SystemTime);
  298. end;
  299. Procedure InitAnsi;
  300. Var
  301. i : longint;
  302. begin
  303. { Fill table entries 0 to 127 }
  304. for i := 0 to 96 do
  305. UpperCaseTable[i] := chr(i);
  306. for i := 97 to 122 do
  307. UpperCaseTable[i] := chr(i - 32);
  308. for i := 123 to 191 do
  309. UpperCaseTable[i] := chr(i);
  310. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  311. for i := 0 to 64 do
  312. LowerCaseTable[i] := chr(i);
  313. for i := 65 to 90 do
  314. LowerCaseTable[i] := chr(i + 32);
  315. for i := 91 to 191 do
  316. LowerCaseTable[i] := chr(i);
  317. Move (CPISO88591LCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  318. end;
  319. Procedure InitInternational;
  320. begin
  321. InitInternationalGeneric;
  322. InitAnsi;
  323. end;
  324. function SysErrorMessage(ErrorCode: Integer): String;
  325. begin
  326. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  327. end;
  328. function GetLastOSError: Integer;
  329. begin
  330. result:=-1;
  331. end;
  332. {****************************************************************************
  333. OS utility functions
  334. ****************************************************************************}
  335. function GetPathString: String;
  336. begin
  337. {writeln('Unimplemented GetPathString');}
  338. result := '';
  339. end;
  340. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  341. begin
  342. {writeln('Unimplemented GetEnvironmentVariable');}
  343. result:='';
  344. end;
  345. Function GetEnvironmentVariableCount : Integer;
  346. begin
  347. {writeln('Unimplemented GetEnvironmentVariableCount');}
  348. result:=0;
  349. end;
  350. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  351. begin
  352. {writeln('Unimplemented GetEnvironmentString');}
  353. result:='';
  354. end;
  355. function ExecuteProcess (const Path: RawByteString; const ComLine: RawByteString;Flags:TExecuteFlags=[]):
  356. integer;
  357. var
  358. tmpPath: RawByteString;
  359. pcmdline: ShortString;
  360. CommandLine: RawByteString;
  361. E: EOSError;
  362. begin
  363. tmpPath:=ToSingleByteFileSystemEncodedFileName(Path);
  364. pcmdline:=ToSingleByteFileSystemEncodedFileName(ComLine);
  365. { the zero offset for cmdline is actually correct here. pexec() expects
  366. pascal formatted string for cmdline, so length in first byte }
  367. result:=gemdos_pexec(0,PChar(tmpPath),@pcmdline[0],nil);
  368. if result < 0 then begin
  369. if ComLine = '' then
  370. CommandLine := Path
  371. else
  372. CommandLine := Path + ' ' + ComLine;
  373. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, result]);
  374. E.ErrorCode := result;
  375. raise E;
  376. end;
  377. end;
  378. function ExecuteProcess (const Path: RawByteString;
  379. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  380. var
  381. CommandLine: RawByteString;
  382. I: integer;
  383. begin
  384. Commandline := '';
  385. for I := 0 to High (ComLine) do
  386. if Pos (' ', ComLine [I]) <> 0 then
  387. CommandLine := CommandLine + ' ' + '"' + ToSingleByteFileSystemEncodedFileName(ComLine [I]) + '"'
  388. else
  389. CommandLine := CommandLine + ' ' + ToSingleByteFileSystemEncodedFileName(Comline [I]);
  390. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  391. end;
  392. procedure Sleep(Milliseconds: cardinal);
  393. begin
  394. {writeln('Unimplemented Sleep');}
  395. end;
  396. {****************************************************************************
  397. Initialization code
  398. ****************************************************************************}
  399. Initialization
  400. InitExceptions;
  401. InitInternational; { Initialize internationalization settings }
  402. OnBeep:=Nil; { No SysBeep() on Atari for now. }
  403. Finalization
  404. FreeTerminateProcs;
  405. DoneExceptions;
  406. end.