1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
|
{
This file is part of the Free Pascal run time library.
Copyright (c) 2002-2004 by Olle Raab
FreePascal system unit for MacOS.
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
unit System;
interface
{ include system-independent routine headers }
{$I systemh.inc}
const
LineEnding = #13;
LFNSupport = true;
DirectorySeparator = ':';
DriveSeparator = ':';
ExtensionSeparator = '.';
PathSeparator = ','; {Is used in MPW and OzTeX}
AllowDirectorySeparators : set of char = [':'];
AllowDriveSeparators : set of char = [':'];
FileNameCaseSensitive = false;
CtrlZMarksEOF: boolean = false; (* #26 not considered as end of file *)
maxExitCode = 65535;
MaxPathLen = 256;
AllFilesMask = '*';
const
{ Default filehandles }
UnusedHandle : Longint = -1;
StdInputHandle : Longint = 0;
StdOutputHandle : Longint = 1;
StdErrorHandle : Longint = 2;
sLineBreak = LineEnding;
DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCR;
var
argc : longint;
argv : ppchar;
envp : ppchar;
{*********************************}
{** MacOS specific functions **}
{*********************************}
{To be called at regular intervals, for lenghty tasks.
Yield might give time for other tasks to run under the cooperative
multitasked macos. For an MPW Tool, it also spinns the cursor.}
procedure Yield;
{To set mac file type and creator codes, to be used for files created
by the FPC runtime library. They must be exactly 4 chars long.}
procedure SetDefaultMacOSFiletype(ftype: ShortString);
procedure SetDefaultMacOSCreator(creator: ShortString);
var
{Whether unix and dos style paths should be translated. Default false}
pathTranslation: Boolean;
{*********************************}
{** Available features on macos **}
{*********************************}
var
macosHasGestalt: Boolean;
macosHasWaitNextEvent: Boolean;
macosHasColorQD: Boolean;
macosHasFPU: Boolean;
macosSystemVersion: Integer;
macosHasSysDebugger: Boolean = false;
macosHasCFM: Boolean;
macosHasAppleEvents: Boolean;
macosHasAliasMgr: Boolean;
macosHasFSSpec: Boolean;
macosHasFindFolder: Boolean;
macosHasScriptMgr: Boolean;
macosNrOfScriptsInstalled: Integer;
macosHasAppearance: Boolean;
macosHasAppearance101: Boolean;
macosHasAppearance11: Boolean;
macosBootVolumeVRefNum: Integer;
macosBootVolumeName: String[31];
{
MacOS paths
===========
MacOS directory separator is a colon ":" which is the only character not
allowed in filenames.
A path containing no colon or which begins with a colon is a partial path.
E g ":kalle:petter" ":kalle" "kalle"
All other paths are full (absolute) paths. E g "HD:kalle:" "HD:"
When generating paths, one is safe is one ensures that all partial paths
begins with a colon, and all full paths ends with a colon.
In full paths the first name (e g HD above) is the name of a mounted volume.
These names are not unique, because, for instance, two diskettes with the
same names could be inserted. This means that paths on MacOS is not
waterproof. In case of equal names the first volume found will do.
Two colons "::" are the relative path to the parent. Three is to the
grandparent etc.
}
implementation
{
About the implementation
========================
A MacOS application is assembled and linked by MPW (Macintosh
Programmers Workshop), which nowadays is free to use. For info
and download of MPW and MacOS api, see www.apple.com
It can be linked to either a graphical user interface application,
a standalone text only application (using SIOW) or
to an MPW tool, this is entirely controlled by the linking step.
It requires system 7 and CFM, which is always the case for PowerPC.
If a m68k version would be implemented, it would save a lot
of efforts if it also uses CFM. This System.pp should, with
minor modifications, probably work with m68k.
Initial working directory is the directory of the application,
or for an MPWTool, the working directory as set by the
Directory command in MPW.
Note about working directory. There is a facility in MacOS which
manages a working directory for an application, initially set to
the applications directory, or for an MPWTool, the tool's directory.
However, this requires the application to have a unique application
signature (creator code), to distinguish its working directory
from working directories of other applications. Due to the fact
that casual applications are anonymous in this sense (without an
application signature), this facility will not work. Also, this
working directory facility is not present in Carbon. Hence we
will manage a working directory by our self.
Deviations
==========
In current implementation, working directory is stored as
directory id. This means there is a possibility the user moves the
working directory or a parent to it, while the application uses it.
Then the path to the wd suddenly changes. This is AFAIK not in
accordance with other OS's. Although this is a minor caveat,
it is mentioned here. To overcome this the wd could be stored
as a path instead, but this imposes translations from fullpath
to directory ID each time the filesystem is accessed.
The initial working directory for an MPWTool, as considered by
FPC, is different from the MacOS working directory facility,
see above.
Possible improvements:
=====================
Perhaps handle readonly filesystems, as in sysunix.inc
}
{******** include system independent routines **********}
{$I system.inc}
{*****************************************************************************
ParamStr/Randomize
*****************************************************************************}
{ number of args }
function paramcount : longint;
begin
paramcount := argc - 1;
//paramcount:=0;
end;
{ argument number l }
function paramstr(l : longint) : string;
begin
if (l>=0) and (l+1<=argc) then
paramstr:=strpas(argv[l])
else
paramstr:='';
end;
{ set randseed to a new pseudo random value }
procedure randomize;
begin
randseed:= Cardinal(TickCount);
end;
{*****************************************************************************
SystemUnit Initialization
*****************************************************************************}
{$ifndef FPC_DARWIN_PASCALMAIN}
procedure pascalmain; external name 'PASCALMAIN';
{Main entry point in C style, needed to capture program parameters.
For this to work, the system unit must be before the main program
in the linking order.}
procedure main(argcparam: Longint; argvparam: ppchar; envpparam: ppchar); cdecl; [public];
{$else FPC_DARWIN_PASCALMAIN}
procedure FPC_SYSTEMMAIN(argcparam: Longint; argvparam: ppchar; envpparam: ppchar); cdecl; [public];
{$endif FPC_DARWIN_PASCALMAIN}
begin
argc:= argcparam;
argv:= argvparam;
envp:= envpparam;
{$ifndef FPC_DARWIN_PASCALMAIN}
pascalmain; {run the pascal main program}
{$endif FPC_DARWIN_PASCALMAIN}
end;
procedure setup_arguments;
begin
{Nothing needs to be done here.}
end;
procedure setup_environment;
begin
end;
{ FindSysFolder returns the (real) vRefNum, and the DirID of the current
system folder. It uses the Folder Manager if present, otherwise it falls
back to SysEnvirons. It returns zero on success, otherwise a standard
system error. }
function FindSysFolder(var foundVRefNum: Integer; var foundDirID: Longint): OSErr;
var
gesResponse: Longint;
envRec: SysEnvRec;
myWDPB: WDPBRec;
volName: String[34];
err: OSErr;
begin
foundVRefNum := 0;
foundDirID := 0;
if macosHasGestalt
and (Gestalt (FourCharCodeToLongword(gestaltFindFolderAttr), gesResponse) = noErr)
and BitIsSet (gesResponse, gestaltFindFolderPresent) then
begin { Does Folder Manager exist? }
err := FindFolder (kOnSystemDisk, FourCharCodeToLongword(kSystemFolderType),
kDontCreateFolder, foundVRefNum, foundDirID);
end
else
begin
{ Gestalt can't give us the answer, so we resort to SysEnvirons }
err := SysEnvirons (curSysEnvVers, envRec);
if (err = noErr) then
begin
myWDPB.ioVRefNum := envRec.sysVRefNum;
volName := '';
myWDPB.ioNamePtr := @volName;
myWDPB.ioWDIndex := 0;
myWDPB.ioWDProcID := 0;
err := PBGetWDInfoSync (@myWDPB);
if (err = noErr) then
begin
foundVRefNum := myWDPB.ioWDVRefNum;
foundDirID := myWDPB.ioWDDirID;
end;
end;
end;
FindSysFolder:= err;
end;
procedure InvestigateSystem;
{$IFDEF CPUM68K}
const
_GestaltDispatch = $A0AD;
_WaitNextEvent = $A860;
_ScriptUtil = $A8B5;
qdOffscreenTrap = $AB1D;
{$ENDIF}
var
err: Integer;
response: Longint;
{$IFDEF CPUM68K}
environs: SysEnvRec;
{$ENDIF}
{Vi rŠknar med att man kšr pŒ minst system 6.0.5. DŒ finns bŒde Gestalt och GDevice med.}
{Enligt Change Histrory Šr MacOS 6.0.5 mera konsistent mellan maskinmodellerna Šn fšregŒende system}
begin
{$IFDEF CPUM68K}
macosHasGestalt := TrapAvailable(_GestaltDispatch);
{$ELSE}
macosHasGestalt := true; {There is always Gestalt on PowerPC}
{$ENDIF}
if not macosHasGestalt then (* If we don't have Gestalt, then we can't have any System 7 features *)
begin
{$IFDEF CPUM68K}
{ Detta kan endast gŠlla pŒ en 68K maskin.}
macosHasScriptMgr := TrapAvailable(_ScriptUtil);
macosNrOfScriptsInstalled := 1; (* assume only Roman script, to start with *)
err := SysEnvirons(1, environs);
if err = noErr then
begin
if environs.machineType < 0 then { gammalt ROM}
macosHasWaitNextEvent := FALSE
else
macosHasWaitNextEvent := TrapAvailable(_WaitNextEvent);
macosHasColorQD := environs.hasColorQD;
macosHasFPU := environs.hasFPU;
macosSystemVersion := environs.systemVersion;
end
else
begin
macosHasWaitNextEvent := FALSE;
macosHasColorQD := FALSE;
macosHasFPU := FALSE;
macosSystemVersion := 0;
end;
macosHasSysDebugger := (LongintPtr(MacJmp)^ <> 0);
macosHasCFM := false;
macosHasAppleEvents := false;
macosHasAliasMgr := false;
macosHasFSSpec := false;
macosHasFindFolder := false;
macosHasAppearance := false;
macosHasAppearance101 := false;
macosHasAppearance11 := false;
{$IFDEF THINK_PASCAL}
if (macosHasScriptMgr) then
macosNrOfScriptsInstalled := GetEnvirons(smEnabled);
{$ELSE}
if (macosHasScriptMgr) then
macosNrOfScriptsInstalled := GetScriptManagerVariable(smEnabled); {Gamla rutinnamnet var GetEnvirons.}
{$ENDIF}
{$ENDIF}
end
else
begin
macosHasScriptMgr := Gestalt(FourCharCodeToLongword(gestaltScriptMgrVersion), response) = noErr; {Fšr att ta reda pŒ om script mgr finns.}
macosNrOfScriptsInstalled := 1; (* assume only Roman script, to start with *)
macosHasWaitNextEvent := true;
if Gestalt(FourCharCodeToLongword(gestaltSystemVersion), response) = noErr then
macosSystemVersion := response
else
macosSystemVersion := 0; {Borde inte kunna hŠnda.}
if Gestalt(FourCharCodeToLongword(gestaltOSAttr), response) = noErr then
macosHasSysDebugger := BitIsSet(response, gestaltSysDebuggerSupport)
else
macosHasSysDebugger := false;
if Gestalt(FourCharCodeToLongword(gestaltQuickdrawVersion), response) = noErr then
macosHasColorQD := (response >= $0100)
else
macosHasColorQD := false;
if Gestalt(FourCharCodeToLongword(gestaltFPUType), response) = noErr then
macosHasFPU := (response <> gestaltNoFPU)
else
macosHasFPU := false;
if Gestalt(FourCharCodeToLongword(gestaltCFMAttr), response) = noErr then
macosHasCFM := BitIsSet(response, gestaltCFMPresent)
else
macosHasCFM := false;
macosHasAppleEvents := Gestalt(FourCharCodeToLongword(gestaltAppleEventsAttr), response) = noErr;
macosHasAliasMgr := Gestalt(FourCharCodeToLongword(gestaltAliasMgrAttr), response) = noErr;
if Gestalt(FourCharCodeToLongword(gestaltFSAttr), response) = noErr then
macosHasFSSpec := BitIsSet(response, gestaltHasFSSpecCalls)
else
macosHasFSSpec := false;
macosHasFindFolder := Gestalt(FourCharCodeToLongword(gestaltFindFolderAttr), response) = noErr;
if macosHasScriptMgr then
begin
err := Gestalt(FourCharCodeToLongword(gestaltScriptCount), response);
if (err = noErr) then
macosNrOfScriptsInstalled := Integer(response);
end;
if (Gestalt(FourCharCodeToLongword(gestaltAppearanceAttr), response) = noErr) then
begin
macosHasAppearance := BitIsSet(response, gestaltAppearanceExists);
if Gestalt(FourCharCodeToLongword(gestaltAppearanceVersion), response) = noErr then
begin
macosHasAppearance101 := (response >= $101);
macosHasAppearance11 := (response >= $110);
end
end
else
begin
macosHasAppearance := false;
macosHasAppearance101 := false;
macosHasAppearance11 := false;
end;
end;
end;
{*****************************************************************************
System Dependent Exit code
*****************************************************************************}
Procedure system_exit;
var
s: ShortString;
begin
if StandAlone <> 0 then
if exitcode <> 0 then
begin
Str(exitcode,s);
if IsConsole then
Writeln( '### Program exited with exit code ' + s)
else if macosHasSysDebugger then
DebugStr('A possible error occured, exit code: ' + s + '. Type "g" and return to continue.')
else
{Be quiet}
end;
{$ifndef MACOS_USE_STDCLIB}
if StandAlone <> 0 then
ExitToShell;
{$else}
c_exit(exitcode); {exitcode is only utilized by an MPW tool}
{$endif}
end;
procedure SysInitStdIO;
begin
{ Setup stdin, stdout and stderr }
{$ifdef MACOS_USE_STDCLIB}
OpenStdIO(Input,fmInput,StdInputHandle);
OpenStdIO(Output,fmOutput,StdOutputHandle);
OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
OpenStdIO(StdOut,fmOutput,StdOutputHandle);
OpenStdIO(StdErr,fmOutput,StdErrorHandle);
{$endif }
end;
function GetProcessID: SizeUInt;
begin
GetProcessID := 1;
{$WARNING To be implemented - using GetProcessInformation???}
end;
function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
begin
result := stklen;
end;
var
resHdl: Mac_Handle;
isFolder, hadAlias, leafIsAlias: Boolean;
dirStr: string[2];
err: OSErr;
dummySysFolderDirID: Longint;
begin
InvestigateSystem; {Must be first}
{Check requred features for system.pp to work.}
if not macosHasFSSpec then
Halt(3); //exit code 3 according to MPW
if FindSysFolder(macosBootVolumeVRefNum, dummySysFolderDirID) <> noErr then
Halt(3); //exit code 3 according to MPW
if GetVolumeName(macosBootVolumeVRefNum, macosBootVolumeName) <> noErr then
Halt(3); //exit code 3 according to MPW
{ To be set if this is a GUI or console application }
if StandAlone = 0 then
IsConsole := true {Its an MPW tool}
else
begin
resHdl:= Get1Resource(FourCharCodeToLongword('siow'),0);
IsConsole := (resHdl <> nil); {A SIOW app is also a console}
ReleaseResource(resHdl);
end;
{ To be set if this is a library and not a program }
IsLibrary := FALSE;
StackLength := CheckInitialStkLen(InitialStkLen);
StackBottom := SPtr - StackLength;
pathTranslation:= false;
{ Setup working directory }
if StandAlone <> 0 then
begin
if not GetAppFileLocation(workingDirectorySpec) then
Halt(3); //exit code 3 according to MPW
end
else
begin
{ The fictive file x is used to make
FSMakeFSSpec return a FSSpec to a file in the directory.
Then by clearing the name, the FSSpec then
points to the directory. It doesn't matter whether x exists or not.}
dirStr:= ':x';
err:= ResolveFolderAliases(0, 0, @dirStr, true,
workingDirectorySpec, isFolder, hadAlias, leafIsAlias);
workingDirectorySpec.name:='';
if (err <> noErr) and (err <> fnfErr) then
Halt(3); //exit code 3 according to MPW
end;
{ Setup heap }
if StandAlone <> 0 then
MaxApplZone;
InitHeap;
SysInitExceptions;
initunicodestringmanager;
SysInitStdIO;
{ Setup environment and arguments }
Setup_Environment;
setup_arguments;
{ Reset IO Error }
InOutRes:=0;
errno:=0;
InitSystemThreads;
initvariantmanager;
if StandAlone = 0 then
begin
InitGraf(@qd.thePort);
SetFScaleDisable(true);
InitCursorCtl(nil);
end;
end.
|