1{
2
3    This file is part of the Free Pascal run time library.
4    Copyright (c) 2004-2005 by Olle Raab
5
6    Sysutils unit for Mac OS.
7
8    NOTE !!! THIS FILE IS UNDER CONSTRUCTION AND DOES NOT WORK CURRENLY.
9
10    THUS IT IS NOT BUILT BY THE MAKEFILES
11
12    See the file COPYING.FPC, included in this distribution,
13    for details about the copyright.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
19 **********************************************************************}
20unit sysutils;
21interface
22
23{$MODE objfpc}
24{$modeswitch out}
25{ force ansistrings }
26{$H+}
27{$modeswitch typehelpers}
28{$modeswitch advancedrecords}
29
30{OS has only 1 byte version for ExecuteProcess}
31{$define executeprocuni}
32
33uses
34  MacOSTP;
35
36{$DEFINE HAS_SLEEP}   {Dummy implementation:  TODO }
37//{$DEFINE HAS_OSERROR}   TODO
38//{$DEFINE HAS_OSCONFIG}  TODO
39
40type
41//TODO Check pad and size
42//TODO unify with Dos.SearchRec
43  PMacOSFindData = ^TMacOSFindData;
44  TMacOSFindData = record
45                {MacOS specific params, private, do not use:}
46                paramBlock: CInfoPBRec;
47                searchFSSpec: FSSpec;
48                searchAttr: Byte;  {attribute we are searching for}
49                exactMatch: Boolean;
50  end;
51
52{ used OS file system APIs use ansistring }
53{$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
54{ OS has an ansistring/single byte environment variable API }
55{$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
56
57{ Include platform independent interface part }
58{$i sysutilh.inc}
59
60implementation
61
62uses
63  Dos, Sysconst, macutils; // For some included files.
64
65{$DEFINE FPC_FEXPAND_VOLUMES}
66{$DEFINE FPC_FEXPAND_NO_DEFAULT_PATHS}
67{$DEFINE FPC_FEXPAND_DRIVESEP_IS_ROOT}
68{$DEFINE FPC_FEXPAND_NO_DOTS_UPDIR}
69{$DEFINE FPC_FEXPAND_NO_CURDIR}
70
71{ Include platform independent implementation part }
72{$i sysutils.inc}
73
74
75{****************************************************************************
76                              File Functions
77****************************************************************************}
78
79Function FileOpen (Const FileName : rawbytestring; Mode : Integer) : Longint;
80
81Var LinuxFlags : longint;
82    SystemFileName: RawByteString;
83begin
84  (* TODO fix
85  SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
86  LinuxFlags:=0;
87  Case (Mode and 3) of
88    0 : LinuxFlags:=LinuxFlags or Open_RdOnly;
89    1 : LinuxFlags:=LinuxFlags or Open_WrOnly;
90    2 : LinuxFlags:=LinuxFlags or Open_RdWr;
91  end;
92  FileOpen:=fdOpen (FileName,LinuxFlags);
93  //!! We need to set locking based on Mode !!
94  *)
95end;
96
97
98Function FileCreate (Const FileName : RawByteString) : Longint;
99
100begin
101  (* TODO fix
102  FileCreate:=fdOpen(FileName,Open_RdWr or Open_Creat or Open_Trunc);
103  *)
104end;
105
106
107Function FileCreate (Const FileName : RawByteString;Rights : Longint) : Longint;
108
109Var LinuxFlags : longint;
110
111BEGIN
112  (* TODO fix
113  LinuxFlags:=0;
114  Case (Mode and 3) of
115    0 : LinuxFlags:=LinuxFlags or Open_RdOnly;
116    1 : LinuxFlags:=LinuxFlags or Open_WrOnly;
117    2 : LinuxFlags:=LinuxFlags or Open_RdWr;
118  end;
119  FileCreate:=fdOpen(FileName,LinuxFlags or Open_Creat or Open_Trunc);
120  *)
121end;
122
123Function FileCreate (Const FileName : RawByteString;ShareMode : Longint; Rights : Longint) : Longint;
124
125Var LinuxFlags : longint;
126
127BEGIN
128  (* TODO fix
129  LinuxFlags:=0;
130  Case (Mode and 3) of
131    0 : LinuxFlags:=LinuxFlags or Open_RdOnly;
132    1 : LinuxFlags:=LinuxFlags or Open_WrOnly;
133    2 : LinuxFlags:=LinuxFlags or Open_RdWr;
134  end;
135  FileCreate:=fdOpen(FileName,LinuxFlags or Open_Creat or Open_Trunc);
136  *)
137end;
138
139
140Function FileRead (Handle : Longint; out Buffer; Count : longint) : Longint;
141
142begin
143  (* TODO fix
144  FileRead:=fdRead (Handle,Buffer,Count);
145  *)
146end;
147
148
149Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
150
151begin
152  (* TODO fix
153  FileWrite:=fdWrite (Handle,Buffer,Count);
154  *)
155end;
156
157
158Function FileSeek (Handle,FOffset,Origin : Longint) : Longint;
159
160begin
161  (* TODO fix
162  FileSeek:=fdSeek (Handle,FOffset,Origin);
163  *)
164end;
165
166
167Function FileSeek (Handle : Longint; FOffset: Int64; Origin : Longint) : Int64;
168
169begin
170  (* TODO fix
171  {$warning need to add 64bit call }
172  FileSeek:=fdSeek (Handle,FOffset,Origin);
173  *)
174end;
175
176
177Procedure FileClose (Handle : Longint);
178
179begin
180  (* TODO fix
181  fdclose(Handle);
182  *)
183end;
184
185Function FileTruncate (Handle: THandle; Size: Int64) : boolean;
186
187begin
188  (* TODO fix
189  FileTruncate:=fdtruncate(Handle,Size);
190  *)
191end;
192
193Function FileAge (Const FileName : RawByteString): Longint;
194
195  (*
196Var Info : Stat;
197    Y,M,D,hh,mm,ss : word;
198  *)
199
200begin
201  (* TODO fix
202  If not fstat (FileName,Info) then
203    exit(-1)
204  else
205    begin
206    EpochToLocal(info.mtime,y,m,d,hh,mm,ss);
207    Result:=DateTimeToFileDate(EncodeDate(y,m,d)+EncodeTime(hh,mm,ss,0));
208    end;
209  *)
210end;
211
212
213function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;
214begin
215  Result := False;
216end;
217
218
219Function FileExists (Const FileName : RawByteString; FollowLink : Boolean) : Boolean;
220
221  (*
222Var Info : Stat;
223  *)
224
225begin
226  (* TODO fix
227  FileExists:=fstat(filename,Info);
228  *)
229end;
230
231
232Function DirectoryExists (Const Directory : RawByteString; FollowLink : Boolean) : Boolean;
233
234  (*
235Var Info : Stat;
236  *)
237
238begin
239  (* TODO fix
240  DirectoryExists:=fstat(Directory,Info) and
241                   ((info.mode and STAT_IFMT)=STAT_IFDIR);
242  *)
243end;
244
245(*
246Function LinuxToWinAttr (FN : Pchar; Const Info : Stat) : Longint;
247
248begin
249  Result:=faArchive;
250  If (Info.Mode and STAT_IFDIR)=STAT_IFDIR then
251    Result:=Result or faDirectory;
252  If (FN[0]='.') and (not (FN[1] in [#0,'.']))  then
253    Result:=Result or faHidden;
254  If (Info.Mode and STAT_IWUSR)=0 Then
255     Result:=Result or faReadOnly;
256  If (Info.Mode and
257      (STAT_IFSOCK or STAT_IFBLK or STAT_IFCHR or STAT_IFIFO))<>0 then
258     Result:=Result or faSysFile;
259end;
260
261{
262 GlobToSearch takes a glob entry, stats the file.
263 The glob entry is removed.
264 If FileAttributes match, the entry is reused
265}
266
267Type
268  TGlobSearchRec = Record
269    Path       : String;
270    GlobHandle : PGlob;
271  end;
272  PGlobSearchRec = ^TGlobSearchRec;
273
274Function GlobToTSearchRec (Var Info : TSearchRec) : Boolean;
275
276Var SInfo : Stat;
277    p     : Pglob;
278    GlobSearchRec : PGlobSearchrec;
279
280begin
281  GlobSearchRec:=PGlobSearchrec(Info.FindHandle);
282  P:=GlobSearchRec^.GlobHandle;
283  Result:=P<>Nil;
284  If Result then
285    begin
286    GlobSearchRec^.GlobHandle:=P^.Next;
287    Result:=Fstat(GlobSearchRec^.Path+StrPas(p^.name),SInfo);
288    If Result then
289      begin
290      Info.Attr:=LinuxToWinAttr(p^.name,SInfo);
291      Result:=(Info.ExcludeAttr and Info.Attr)=0;
292      If Result Then
293         With Info do
294           begin
295           Attr:=Info.Attr;
296           If P^.Name<>Nil then
297           Name:=strpas(p^.name);
298           Time:=Sinfo.mtime;
299           Size:=Sinfo.Size;
300           end;
301      end;
302    P^.Next:=Nil;
303    GlobFree(P);
304    end;
305end;
306*)
307
308
309procedure DoFind (var F: TSearchRec; var retname: RawByteString; firstTime: Boolean);
310
311  var
312    err: OSErr;
313    s: Str255;
314
315begin
316(* TODO fix
317   with Rslt, findData, paramBlock do
318    begin
319      ioVRefNum := searchFSSpec.vRefNum;
320      if firstTime then
321        ioFDirIndex := 0;
322
323      while true do
324        begin
325          s := '';
326          ioDirID := searchFSSpec.parID;
327          ioFDirIndex := ioFDirIndex + 1;
328          ioNamePtr := @s;
329
330          err := PBGetCatInfoSync(@paramBlock);
331
332          if err <> noErr then
333            begin
334              if err = fnfErr then
335                DosError := 18
336              else
337                DosError := MacOSErr2RTEerr(err);
338              break;
339            end;
340
341          attr := GetFileAttrFromPB(Rslt.paramBlock);
342          if ((Attr and not(searchAttr)) = 0) then
343            begin
344              retname := s;
345              SetCodePage(retname, DefaultFileSystemCodePage, false);
346              UpperString(s, true);
347
348              if FNMatch(Rslt.searchFSSpec.name, s) then
349                begin
350                  size := GetFileSizeFromPB(paramBlock);
351                  time := MacTimeToDosPackedTime(ioFlMdDat);
352                  Result := 0;
353                  break;
354                end;
355            end;
356        end;
357    end;
358*)
359end;
360
361
362Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
363  var
364    s: Str255;
365
366begin
367(* TODO fix
368  if path = '' then
369    begin
370      Result := 3;
371      Exit;
372    end;
373
374  {We always also search for readonly and archive, regardless of Attr.}
375  Rslt.searchAttr := (Attr or (archive or readonly));
376
377  { TODO: convert PathArgToFSSpec (and the routines it calls) to rawbytestring }
378  Result := PathArgToFSSpec(path, Rslt.searchFSSpec);
379  with Rslt do
380    if (Result = 0) or (Result = 2) then
381      begin
382        { FIXME: SearchSpec is a shortstring -> ignores encoding }
383        SearchSpec := path;
384        NamePos := Length(path) - Length(searchFSSpec.name);
385
386        if (Pos('?', searchFSSpec.name) = 0) and (Pos('*', searchFSSpec.name) = 0) then  {No wildcards}
387          begin  {If exact match, we don't have to scan the directory}
388            exactMatch := true;
389            Result := DoFindOne(searchFSSpec, paramBlock);
390            if Result = 0 then
391              begin
392                Attr := GetFileAttrFromPB(paramBlock);
393                if ((Attr and not(searchAttr)) = 0) then
394                  begin
395                    name := searchFSSpec.name;
396                    SetCodePage(name, DefaultFileSystemCodePage, false);
397                    size := GetFileSizeFromPB(paramBlock);
398                    time := MacTimeToDosPackedTime(paramBlock.ioFlMdDat);
399                  end
400                else
401                  Result := 18;
402              end
403            else if Result = 2 then
404              Result := 18;
405          end
406        else
407          begin
408            exactMatch := false;
409
410            s := searchFSSpec.name;
411            UpperString(s, true);
412            Rslt.searchFSSpec.name := s;
413
414            DoFind(Rslt, name, true);
415          end;
416      end;
417*)
418end;
419
420
421Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
422
423begin
424(* TODO fix
425  if F.exactMatch then
426    Result := 18
427  else
428    Result:=DoFind (Rslt, Name, false);
429*)
430end;
431
432
433Procedure InternalFindClose (var Handle: THandle; var FindData: TFindData);
434
435  (*
436Var
437  GlobSearchRec : PGlobSearchRec;
438  *)
439
440begin
441  (* TODO fix
442  GlobSearchRec:=PGlobSearchRec(Handle);
443  GlobFree (GlobSearchRec^.GlobHandle);
444  Dispose(GlobSearchRec);
445  *)
446end;
447
448
449Function FileGetDate (Handle : Longint) : Longint;
450
451  (*
452Var Info : Stat;
453  *)
454
455begin
456  (* TODO fix
457  If Not(FStat(Handle,Info)) then
458    Result:=-1
459  else
460    Result:=Info.Mtime;
461  *)
462end;
463
464
465Function FileSetDate (Handle,Age : Longint) : Longint;
466
467begin
468  // TODO fix
469  // Impossible under Linux from FileHandle !!
470  FileSetDate:=-1;
471end;
472
473
474Function FileGetAttr (Const FileName : RawByteString) : Longint;
475
476  (*
477Var Info : Stat;
478  *)
479
480begin
481  (* TODO fix
482  If Not FStat (FileName,Info) then
483    Result:=-1
484  Else
485    Result:=LinuxToWinAttr(Pchar(FileName),Info);
486  *)
487end;
488
489
490Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
491
492begin
493  Result:=-1;
494end;
495
496
497Function DeleteFile (Const FileName : RawByteString) : Boolean;
498
499begin
500  (* TODO fix
501  Result:=UnLink (FileName);
502  *)
503end;
504
505
506Function RenameFile (Const OldName, NewName : RawByteString) : Boolean;
507
508begin
509  (* TODO fix
510  RenameFile:=Unix.FRename(OldNAme,NewName);
511  *)
512end;
513
514
515{****************************************************************************
516                              Disk Functions
517****************************************************************************}
518
519{
520  The Diskfree and Disksize functions need a file on the specified drive, since this
521  is required for the statfs system call.
522  These filenames are set in drivestr[0..26], and have been preset to :
523   0 - '.'      (default drive - hence current dir is ok.)
524   1 - '/fd0/.'  (floppy drive 1 - should be adapted to local system )
525   2 - '/fd1/.'  (floppy drive 2 - should be adapted to local system )
526   3 - '/'       (C: equivalent of dos is the root partition)
527   4..26          (can be set by you're own applications)
528  ! Use AddDisk() to Add new drives !
529  They both return -1 when a failure occurs.
530}
531Const
532  FixDriveStr : array[0..3] of pchar=(
533    '.',
534    '/fd0/.',
535    '/fd1/.',
536    '/.'
537    );
538var
539  Drives   : byte;
540  DriveStr : array[4..26] of pchar;
541
542Procedure AddDisk(const path:string);
543begin
544  if not (DriveStr[Drives]=nil) then
545   FreeMem(DriveStr[Drives],StrLen(DriveStr[Drives])+1);
546  GetMem(DriveStr[Drives],length(Path)+1);
547  StrPCopy(DriveStr[Drives],path);
548  inc(Drives);
549  if Drives>26 then
550   Drives:=4;
551end;
552
553
554Function DiskFree(Drive: Byte): int64;
555  (*
556var
557  fs : tstatfs;
558  *)
559Begin
560  (* TODO fix
561  if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and statfs(StrPas(fixdrivestr[drive]),fs)) or
562     ((not (drivestr[Drive]=nil)) and statfs(StrPas(drivestr[drive]),fs)) then
563   Diskfree:=int64(fs.bavail)*int64(fs.bsize)
564  else
565   Diskfree:=-1;
566  *)
567End;
568
569
570
571Function DiskSize(Drive: Byte): int64;
572  (*
573var
574  fs : tstatfs;
575  *)
576Begin
577  (* TODO fix
578  if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and statfs(StrPas(fixdrivestr[drive]),fs)) or
579     ((not (drivestr[Drive]=nil)) and statfs(StrPas(drivestr[drive]),fs)) then
580   DiskSize:=int64(fs.blocks)*int64(fs.bsize)
581  else
582   DiskSize:=-1;
583  *)
584End;
585
586
587{****************************************************************************
588                              Locale Functions
589****************************************************************************}
590
591Procedure GetLocalTime(var SystemTime: TSystemTime);
592begin
593  (* TODO fix
594  Unix.GetTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second);
595  Unix.GetDate(SystemTime.Year, SystemTime.Month, SystemTime.Day);
596  SystemTime.MilliSecond := 0;
597  *)
598end ;
599
600
601Procedure InitAnsi;
602Var
603  i : longint;
604begin
605  {  Fill table entries 0 to 127  }
606  for i := 0 to 96 do
607    UpperCaseTable[i] := chr(i);
608  for i := 97 to 122 do
609    UpperCaseTable[i] := chr(i - 32);
610  for i := 123 to 191 do
611    UpperCaseTable[i] := chr(i);
612  Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
613
614  for i := 0 to 64 do
615    LowerCaseTable[i] := chr(i);
616  for i := 65 to 90 do
617    LowerCaseTable[i] := chr(i + 32);
618  for i := 91 to 191 do
619    LowerCaseTable[i] := chr(i);
620  Move (CPISO88591LCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
621end;
622
623
624Procedure InitInternational;
625begin
626  InitInternationalGeneric;
627  InitAnsi;
628end;
629
630function SysErrorMessage(ErrorCode: Integer): String;
631
632begin
633  (* TODO fix
634  Result:=StrError(ErrorCode);
635  *)
636end;
637
638{****************************************************************************
639                              OS utility functions
640****************************************************************************}
641
642Function GetEnvironmentVariable(Const EnvVar : String) : String;
643
644begin
645  (* TODO fix
646  Result:=Unix.Getenv(PChar(EnvVar));
647  *)
648end;
649
650Function GetEnvironmentVariableCount : Integer;
651
652begin
653  // Result:=FPCCountEnvVar(EnvP);
654  Result:=0;
655end;
656
657Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
658
659begin
660  // Result:=FPCGetEnvStrFromP(Envp,Index);
661  Result:='';
662end;
663
664{ Create a DoScript AppleEvent that targets the given application with text as the direct object. }
665function CreateDoScriptEvent (applCreator: OSType; scriptText: PChar; var theEvent: AppleEvent): OSErr;
666
667  var
668   err: OSErr;
669   targetAddress: AEDesc;
670   s: signedByte;
671
672begin
673  err := AECreateDesc(FourCharCodeToLongword(typeApplSignature), @applCreator, sizeof(applCreator), targetAddress);
674  if err = noErr then
675    begin
676      err := AECreateAppleEvent(FourCharCodeToLongword('misc'), FourCharCodeToLongword('dosc'),
677          targetAddress, kAutoGenerateReturnID, kAnyTransactionID, theEvent);
678
679      if err = noErr then
680          { Add script text as the direct object parameter. }
681          err := AEPutParamPtr(theEvent, FourCharCodeToLongword('----'),
682                    FourCharCodeToLongword('TEXT'), scriptText, Length(scriptText));
683
684      if err <> noErr then
685        AEDisposeDesc(theEvent);
686      AEDisposeDesc(targetAddress);
687    end;
688
689  CreateDoScriptEvent := err;
690end;
691
692Procedure Fpc_WriteBuffer(var f:Text;const b;len:longint);[external name 'FPC_WRITEBUFFER'];
693{declared in text.inc}
694
695procedure WriteAEDescTypeCharToFile(desc: AEDesc; var f: Text);
696
697begin
698  if desc.descriptorType = FourCharCodeToLongword(typeChar) then
699    begin
700      HLock(desc.dataHandle);
701      Fpc_WriteBuffer(f, PChar(desc.dataHandle^)^, GetHandleSize(desc.dataHandle));
702      Flush(f);
703      HUnLock(desc.dataHandle);
704    end;
705end;
706
707function ExecuteToolserverScript(scriptText: PChar; var statusCode: Longint): OSErr;
708
709  var
710    err: OSErr;
711    err2: OSErr;  {Non serious error}
712    theEvent: AppleEvent;
713    reply: AppleEvent;
714    aresult: AEDesc;
715    applFileSpec: FSSpec;
716    p: SignedByte;
717
718  const
719    applCreator = 'MPSX'; {Toolserver}
720
721begin
722  statusCode:= 3; //3 according to MPW.
723  err:= CreateDoScriptEvent (FourCharCodeToLongword(applCreator), scriptText, theEvent);
724  if err = noErr then
725    begin
726      err := AESend(theEvent, reply, kAEWaitReply, kAENormalPriority, kAEDefaultTimeOut, nil, nil);
727
728      if err = connectionInvalid then  { Toolserver not available }
729        begin
730          err := FindApplication(FourCharCodeToLongword(applCreator), applFileSpec);
731          if err = noErr then
732            err := LaunchFSSpec(false, applFileSpec);
733          if err = noErr then
734            err := AESend(theEvent, reply, kAEWaitReply, kAENormalPriority, kAEDefaultTimeOut, nil, nil);
735        end;
736
737      if err = noErr then
738        begin
739          err:= AEGetParamDesc(reply, FourCharCodeToLongword('stat'),
740                    FourCharCodeToLongword(typeLongInteger), aresult);
741
742          if err = noErr then
743            if aresult.descriptorType = FourCharCodeToLongword(typeLongInteger) then
744              statusCode:= LongintPtr(aresult.dataHandle^)^;
745
746          {If there is no output below, we get a non zero error code}
747
748          err2:= AEGetParamDesc(reply, FourCharCodeToLongword('----'),
749                    FourCharCodeToLongword(typeChar), aresult);
750          if err2 = noErr then
751             WriteAEDescTypeCharToFile(aresult, stdout);
752
753          err2:= AEGetParamDesc(reply, FourCharCodeToLongword('diag'),
754                    FourCharCodeToLongword(typeChar), aresult);
755          if err2 = noErr then
756            WriteAEDescTypeCharToFile(aresult, stderr);
757
758          AEDisposeDesc(reply);
759
760          {$IFDEF TARGET_API_MAC_CARBON }
761          {$ERROR FIXME AEDesc data is not allowed to be directly accessed}
762          {$ENDIF}
763        end;
764
765      AEDisposeDesc(theEvent);
766    end;
767
768  ExecuteToolserverScript:= err;
769end;
770
771
772function ExecuteProcess (const Path: RawByteString; const ComLine: RawByteString;Flags:TExecuteFlags=[]):
773                                                                       integer;
774var
775  s: AnsiString;
776  wdpath: RawByteString;
777  laststatuscode : longint;
778  E: EOSError;
779Begin
780  {Make ToolServers working directory in sync with our working directory}
781  PathArgToFullPath(':', wdpath);
782  wdpath:= 'Directory ' + wdpath;
783  Result := ExecuteToolserverScript(PChar(wdpath), laststatuscode);
784    {TODO Only change path when actually needed. But this requires some
785     change counter to be incremented each time wd is changed. }
786
787  s:= path + ' ' + comline;
788
789  Result := ExecuteToolserverScript(PChar(s), laststatuscode);
790  if Result = afpItemNotFound then
791    Result := 900
792  else
793    Result := MacOSErr2RTEerr(Result);
794  if Result <> 0 then
795    begin
796      E := EOSError.CreateFmt (SExecuteProcessFailed, [Comline, DosError]);
797      E.ErrorCode := DosError;
798      raise E;
799    end;
800  //TODO Better dos error codes
801  if laststatuscode <> 0 then
802    begin
803      {MPW status might be 24 bits}
804      Result := laststatuscode and $ffff;
805      if Result = 0 then
806        Result := 1;
807    end
808  else
809    Result := 0;
810End;
811
812
813function ExecuteProcess (const Path: RawByteString;
814                                  const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
815var
816  CommandLine: RawByteString;
817  I: integer;
818
819begin
820  Commandline := '';
821  for I := 0 to High (ComLine) do
822   if Pos (' ', ComLine [I]) <> 0 then
823    CommandLine := CommandLine + ' ' + '"' + ToSingleByteFileSystemEncodedFileName(ComLine [I]) + '"'
824   else
825    CommandLine := CommandLine + ' ' + ToSingleByteFileSystemEncodedFileName(Comline [I]);
826  ExecuteProcess := ExecuteProcess (Path, CommandLine);
827end;
828
829
830procedure C_usleep(val : uint32); external 'StdCLib' name 'usleep';
831
832procedure Sleep(milliseconds: Cardinal);
833begin
834  C_usleep(milliseconds*1000);
835end;
836
837(*
838Function GetLastOSError : Integer;
839
840begin
841end;
842*)
843
844{****************************************************************************
845                              Initialization code
846****************************************************************************}
847
848Initialization
849  InitExceptions;       { Initialize exceptions. OS independent }
850  InitInternational;    { Initialize internationalization settings }
851Finalization
852  FreeTerminateProcs;
853  DoneExceptions;
854end.
855