sysutils.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  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) : LongInt;
  53. var
  54. td: TDOSTIME;
  55. begin
  56. { Fdatime doesn't report errors... }
  57. gemdos_fdatime(@td,handle,0);
  58. LongRec(result).hi:=td.date;
  59. LongRec(result).lo:=td.time;
  60. end;
  61. function FileSetDate(Handle: THandle; Age: LongInt) : LongInt;
  62. var
  63. td: TDOSTIME;
  64. begin
  65. td.date:=LongRec(Age).hi;
  66. td.time:=LongRec(Age).lo;
  67. gemdos_fdatime(@td,handle,1);
  68. { Fdatime doesn't report errors... }
  69. result:=0;
  70. end;
  71. function FileSetDate(const FileName: RawByteString; Age: LongInt) : LongInt;
  72. var
  73. f: THandle;
  74. begin
  75. FileSetDate:=-1;
  76. f:=FileOpen(FileName,fmOpenReadWrite);
  77. if f < 0 then
  78. exit;
  79. FileSetDate(f,Age);
  80. FileClose(f);
  81. end;
  82. function FileCreate(const FileName: RawByteString) : THandle;
  83. begin
  84. FileCreate:=gemdos_fcreate(pchar(FileName),0);
  85. if FileCreate < -1 then
  86. FileCreate:=-1;
  87. end;
  88. function FileCreate(const FileName: RawByteString; Rights: integer): THandle;
  89. begin
  90. { Rights are Un*x extension. Maybe something for MiNT? }
  91. FileCreate:=FileCreate(FileName);
  92. end;
  93. function FileCreate(const FileName: RawByteString; ShareMode: integer; Rights : integer): THandle;
  94. begin
  95. { Rights and ShareMode are Un*x extension. Maybe something for MiNT? }
  96. FileCreate:=FileCreate(FileName);
  97. end;
  98. function FileRead(Handle: THandle; out Buffer; Count: LongInt): LongInt;
  99. begin
  100. FileRead:=-1;
  101. if (Count<=0) then
  102. exit;
  103. FileRead:=gemdos_fread(handle, count, @buffer);
  104. if FileRead < -1 then
  105. FileRead:=-1;
  106. end;
  107. function FileWrite(Handle: THandle; const Buffer; Count: LongInt): LongInt;
  108. begin
  109. FileWrite:=-1;
  110. if (Count<=0) then
  111. exit;
  112. FileWrite:=gemdos_fwrite(handle, count, @buffer);
  113. if FileWrite < -1 then
  114. FileWrite:=-1;
  115. end;
  116. function FileSeek(Handle: THandle; FOffset, Origin: LongInt) : LongInt;
  117. var
  118. dosResult: longint;
  119. begin
  120. FileSeek:=-1;
  121. { TOS seek mode flags are actually compatible to DOS/TP }
  122. dosResult:=gemdos_fseek(FOffset, Handle, Origin);
  123. if dosResult < 0 then
  124. exit;
  125. FileSeek:=dosResult;
  126. end;
  127. function FileSeek(Handle: THandle; FOffset: Int64; Origin: Longint): Int64;
  128. begin
  129. FileSeek:=FileSeek(Handle,LongInt(FOffset),Origin);
  130. end;
  131. procedure FileClose(Handle: THandle);
  132. begin
  133. gemdos_fclose(handle);
  134. end;
  135. function FileTruncate(Handle: THandle; Size: Int64): Boolean;
  136. begin
  137. FileTruncate:=False;
  138. end;
  139. function DeleteFile(const FileName: RawByteString) : Boolean;
  140. begin
  141. DeleteFile:=gemdos_fdelete(pchar(FileName)) >= 0;
  142. end;
  143. function RenameFile(const OldName, NewName: RawByteString): Boolean;
  144. begin
  145. RenameFile:=gemdos_frename(0,pchar(oldname),pchar(newname)) >= 0;
  146. end;
  147. (****** end of non portable routines ******)
  148. function FileAge (const FileName : RawByteString): Longint;
  149. var
  150. f: THandle;
  151. begin
  152. FileAge:=-1;
  153. f:=FileOpen(FileName,fmOpenRead);
  154. if f < 0 then
  155. exit;
  156. FileAge:=FileGetDate(f);
  157. FileClose(f);
  158. end;
  159. function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;
  160. begin
  161. Result := False;
  162. end;
  163. function FileExists (const FileName : RawByteString; FollowLink : Boolean) : Boolean;
  164. var
  165. Attr: longint;
  166. begin
  167. FileExists:=false;
  168. Attr:=FileGetAttr(FileName);
  169. if Attr < 0 then
  170. exit;
  171. result:=(Attr and (faVolumeID or faDirectory)) = 0;
  172. end;
  173. type
  174. PInternalFindData = ^TInternalFindData;
  175. TInternalFindData = record
  176. dta_original: pointer;
  177. dta_search: TDTA;
  178. end;
  179. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  180. var
  181. dosResult: longint;
  182. IFD: PInternalFindData;
  183. begin
  184. result:=-1; { We emulate Linux/Unix behaviour, and return -1 on errors. }
  185. new(IFD);
  186. IFD^.dta_original:=gemdos_getdta;
  187. gemdos_setdta(@IFD^.dta_search);
  188. Rslt.FindHandle:=nil;
  189. dosResult:=gemdos_fsfirst(pchar(path), Attr and faAnyFile);
  190. if dosResult < 0 then
  191. begin
  192. InternalFindClose(IFD);
  193. exit;
  194. end;
  195. Rslt.FindHandle:=IFD;
  196. with IFD^.dta_search do
  197. begin
  198. Name:=d_fname;
  199. SetCodePage(Name,DefaultFileSystemCodePage,false);
  200. LongRec(Rslt.Time).hi:=d_date;
  201. LongRec(Rslt.Time).lo:=d_time;
  202. Rslt.Size:=d_length;
  203. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  204. Rslt.Attr := 128 or d_attrib;
  205. end;
  206. result:=0;
  207. end;
  208. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  209. var
  210. dosResult: longint;
  211. IFD: PInternalFindData;
  212. begin
  213. result:=-1;
  214. IFD:=PInternalFindData(Rslt.FindHandle);
  215. if not assigned(IFD) then
  216. exit;
  217. dosResult:=gemdos_fsnext;
  218. if dosResult < 0 then
  219. exit;
  220. with IFD^.dta_search do
  221. begin
  222. Name:=d_fname;
  223. SetCodePage(Name,DefaultFileSystemCodePage,false);
  224. LongRec(Rslt.Time).hi:=d_date;
  225. LongRec(Rslt.Time).lo:=d_time;
  226. Rslt.Size:=d_length;
  227. { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
  228. Rslt.Attr := 128 or d_attrib;
  229. end;
  230. result:=0;
  231. end;
  232. Procedure InternalFindClose(var Handle: Pointer);
  233. var
  234. IFD: PInternalFindData;
  235. begin
  236. IFD:=PInternalFindData(Handle);
  237. if not assigned(IFD) then
  238. exit;
  239. gemdos_setdta(IFD^.dta_original);
  240. dispose(IFD);
  241. IFD:=nil;
  242. end;
  243. (****** end of non portable routines ******)
  244. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  245. begin
  246. FileGetAttr:=gemdos_fattrib(pchar(FileName),0,0);
  247. end;
  248. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  249. begin
  250. FileSetAttr:=gemdos_fattrib(pchar(FileName),1,Attr and faAnyFile);
  251. if FileSetAttr < -1 then
  252. FileSetAttr:=-1
  253. else
  254. FileSetAttr:=0;
  255. end;
  256. {****************************************************************************
  257. Disk Functions
  258. ****************************************************************************}
  259. function DiskSize(Drive: Byte): Int64;
  260. var
  261. dosResult: longint;
  262. di: TDISKINFO;
  263. begin
  264. DiskSize := -1;
  265. dosResult:=gemdos_dfree(@di,drive);
  266. if dosResult < 0 then
  267. exit;
  268. DiskSize:=di.b_total * di.b_secsiz * di.b_clsiz;
  269. end;
  270. function DiskFree(Drive: Byte): Int64;
  271. var
  272. dosResult: longint;
  273. di: TDISKINFO;
  274. begin
  275. DiskFree := -1;
  276. dosResult:=gemdos_dfree(@di,drive);
  277. if dosResult < 0 then
  278. exit;
  279. DiskFree:=di.b_free * di.b_secsiz * di.b_clsiz;
  280. end;
  281. function DirectoryExists(const Directory: RawByteString; FollowLink : Boolean): Boolean;
  282. var
  283. Attr: longint;
  284. begin
  285. DirectoryExists:=false;
  286. Attr:=FileGetAttr(Directory);
  287. if Attr < 0 then
  288. exit;
  289. result:=(Attr and faDirectory) <> 0;
  290. end;
  291. {****************************************************************************
  292. Locale Functions
  293. ****************************************************************************}
  294. Procedure GetLocalTime(var SystemTime: TSystemTime);
  295. var
  296. TOSTime: Longint;
  297. begin
  298. LongRec(TOSTime).hi:=gemdos_tgetdate;
  299. LongRec(TOSTime).lo:=gemdos_tgettime;
  300. DateTimeToSystemTime(FileDateToDateTime(TOSTime),SystemTime);
  301. end;
  302. Procedure InitAnsi;
  303. Var
  304. i : longint;
  305. begin
  306. { Fill table entries 0 to 127 }
  307. for i := 0 to 96 do
  308. UpperCaseTable[i] := chr(i);
  309. for i := 97 to 122 do
  310. UpperCaseTable[i] := chr(i - 32);
  311. for i := 123 to 191 do
  312. UpperCaseTable[i] := chr(i);
  313. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  314. for i := 0 to 64 do
  315. LowerCaseTable[i] := chr(i);
  316. for i := 65 to 90 do
  317. LowerCaseTable[i] := chr(i + 32);
  318. for i := 91 to 191 do
  319. LowerCaseTable[i] := chr(i);
  320. Move (CPISO88591LCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  321. end;
  322. Procedure InitInternational;
  323. begin
  324. InitInternationalGeneric;
  325. InitAnsi;
  326. end;
  327. function SysErrorMessage(ErrorCode: Integer): String;
  328. begin
  329. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  330. end;
  331. function GetLastOSError: Integer;
  332. begin
  333. result:=-1;
  334. end;
  335. {****************************************************************************
  336. OS utility functions
  337. ****************************************************************************}
  338. function GetPathString: String;
  339. begin
  340. {writeln('Unimplemented GetPathString');}
  341. result := '';
  342. end;
  343. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  344. begin
  345. {writeln('Unimplemented GetEnvironmentVariable');}
  346. result:='';
  347. end;
  348. Function GetEnvironmentVariableCount : Integer;
  349. begin
  350. {writeln('Unimplemented GetEnvironmentVariableCount');}
  351. result:=0;
  352. end;
  353. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  354. begin
  355. {writeln('Unimplemented GetEnvironmentString');}
  356. result:='';
  357. end;
  358. function ExecuteProcess (const Path: RawByteString; const ComLine: RawByteString;Flags:TExecuteFlags=[]):
  359. integer;
  360. var
  361. tmpPath: RawByteString;
  362. pcmdline: ShortString;
  363. CommandLine: RawByteString;
  364. E: EOSError;
  365. begin
  366. tmpPath:=ToSingleByteFileSystemEncodedFileName(Path);
  367. pcmdline:=ToSingleByteFileSystemEncodedFileName(ComLine);
  368. { the zero offset for cmdline is actually correct here. pexec() expects
  369. pascal formatted string for cmdline, so length in first byte }
  370. result:=gemdos_pexec(0,PChar(tmpPath),@pcmdline[0],nil);
  371. if result < 0 then begin
  372. if ComLine = '' then
  373. CommandLine := Path
  374. else
  375. CommandLine := Path + ' ' + ComLine;
  376. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, result]);
  377. E.ErrorCode := result;
  378. raise E;
  379. end;
  380. end;
  381. function ExecuteProcess (const Path: RawByteString;
  382. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  383. var
  384. CommandLine: RawByteString;
  385. I: integer;
  386. begin
  387. Commandline := '';
  388. for I := 0 to High (ComLine) do
  389. if Pos (' ', ComLine [I]) <> 0 then
  390. CommandLine := CommandLine + ' ' + '"' + ToSingleByteFileSystemEncodedFileName(ComLine [I]) + '"'
  391. else
  392. CommandLine := CommandLine + ' ' + ToSingleByteFileSystemEncodedFileName(Comline [I]);
  393. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  394. end;
  395. procedure Sleep(Milliseconds: cardinal);
  396. begin
  397. {writeln('Unimplemented Sleep');}
  398. end;
  399. {****************************************************************************
  400. Initialization code
  401. ****************************************************************************}
  402. Initialization
  403. InitExceptions;
  404. InitInternational; { Initialize internationalization settings }
  405. OnBeep:=Nil; { No SysBeep() on Atari for now. }
  406. Finalization
  407. DoneExceptions;
  408. end.