Include build script, System and MPW
This commit is contained in:
parent
3d158703bf
commit
93dfc883a1
|
@ -0,0 +1,626 @@
|
|||
TITLE 'Count - An MPW tool using -model far'
|
||||
*-------------------------------------------------------------------------------------------
|
||||
*
|
||||
* NAME
|
||||
* Count.a -- count lines and characters
|
||||
*
|
||||
* SYNOPSIS
|
||||
* Count [-l] [-c] [file…]
|
||||
*
|
||||
* DESCRIPTION
|
||||
* "Count" counts the lines and characters in its input, and writes the
|
||||
* counts to standard output. If no files are specified standard input is
|
||||
* read. If more than one file is specified, separate counts are written
|
||||
* for each file, one per line, preceeded by the file name. A total is also
|
||||
* written following the list of files.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* Copyright Apple Computer, Inc. 1985-1990
|
||||
* All rights reserved.
|
||||
*
|
||||
* Demonstration of use of "32-bit everything" addressing.
|
||||
* for MPW 3.2b2/3.
|
||||
* Briefly, "32-bit everything" allows the use of absolute long addressing mode of
|
||||
* 680x0instructions in Macintosh code, to refer to both code and data. Normally,
|
||||
* because everything in the Macintosh is considered relocatable, this addressing mode
|
||||
* could not be used; the only "absolute" addresses were low memory globals (and there
|
||||
* have been warnings about using those!). However, with a patch to LoadSeg to allow
|
||||
* for a different format of the CODE 0 segment jump table, and to allow run-time patching
|
||||
* of these "absolute" addresses, it is now possible to use the absolute long addressing
|
||||
* mode. (Note that the linker adds the patch installer/de-installer code to the user's
|
||||
* code, so the effect is localized). Thus, the MPW compilers and linker allow, uh,
|
||||
* "relocatable" (by runtime patch) "absolute" (by 680x0 addressing mode) instructions.
|
||||
* You invoke the feature by using the "-model far" option on the command line for
|
||||
* compilers, assembler and linker.
|
||||
* In addition to the "-model far", the user must enable the feature on a "per-instruction"
|
||||
* basis. This program is a modified version of the count program provided
|
||||
* in the :Aexamples:folder to demonstrate how to use the Assembler
|
||||
* to get the 32-bit everything references. Unlike the compilers, the user must specify --
|
||||
* by explicitly using the absolute addressing mode syntax ("(Mylabel).L") -- which
|
||||
* instructions will use this feature. Further, the label used must be "imported".
|
||||
* To make life easier, there are "implicit" imports provided by the Assembler:
|
||||
* Within the same file, preceding data references are implicitly imported,
|
||||
* as are all preceding module names (you cannot, at this time) use a 32-bit reference
|
||||
* on to refer to a module name within that module, however). Note that the use of 32-bit
|
||||
* addressing in the Assembler is independent of the CODEREFS and DATAREFS directive
|
||||
* settings, and that the 32-bit displacements of the 68020+ addressing modes are not
|
||||
* affected -- for backward compatibility.
|
||||
* Within this program, then, you will see absolute references to all kinds of data
|
||||
* references: simple Data references, qualified field references and field references
|
||||
* under a 'WITH' statement. Since "data" is implicitly imported, no matter where it is
|
||||
* found, Main data and data defined in the 'DATA' section of a code module can be
|
||||
* successfully reference.
|
||||
* Additionally, but more simply, there are numerous JSRs and JMPs to other code
|
||||
* modules, showing both intrasegment and intersegment branching. To show that it is
|
||||
* possible to mix-n-match, some references are made which use A5 and PC-relative
|
||||
* addressing. J. Kettenhofen, Cupertino, 10/15/90.
|
||||
*
|
||||
*-------------------------------------------------------------------------------------------
|
||||
|
||||
CASE OBJ
|
||||
INCLUDE 'traps.a' ; for Pack7
|
||||
INCLUDE 'packmacs.a' ; for NumToStr, which calls Pack7
|
||||
INCLUDE 'intenv.a' ; so we can get our args, open files, etc.
|
||||
INCLUDE 'signal.a' ; so we can handle 'Command-.'
|
||||
IMPORT INITCURSORCTL ; to init the spinning beach ball
|
||||
IMPORT ROTATECURSOR ; for the spinning beach ball
|
||||
|
||||
RC_Normal EQU 0
|
||||
RC_ParmErrs EQU 1
|
||||
RC_Abort EQU 2 ; Return codes
|
||||
|
||||
;SIGINT EQU 2
|
||||
|
||||
EOLChar EQU $0D ; the Return character marks the end of line
|
||||
STRING Pascal ; length byte strings
|
||||
|
||||
BufSize EQU 1024 ; size of input buffer
|
||||
|
||||
* global data--these declarations outside of any module are allocated and accessed
|
||||
* relative to register A5
|
||||
Globals RECORD
|
||||
ArgV DS.L 1 ; the address of our arguments
|
||||
ArgC DS.L 1 ; the number of our arguments
|
||||
RetCode DC.B RC_Normal ; set to RC_ …
|
||||
CRStr DC.W $010D ; a 'string' that is a return character
|
||||
Interrupted DC.B 0 ; not interrupted yet
|
||||
progname DS.L 1 ; the address of our name
|
||||
NumFiles DC.W 0 ; the number of files to process
|
||||
WriteChars DC.B 0 ; TRUE if the user wants line count
|
||||
WriteLines DC.B 0 ; TRUE if the user wants char count
|
||||
Opts DC.B 0 ; TRUE if user has selected either line or char
|
||||
LineCount DC.L 0
|
||||
CharCount DC.L 0
|
||||
TotalLines DC.L 0
|
||||
TotalChars DC.L 0
|
||||
Max DC.B 5 ; length of 'Total' string, or the longest filename
|
||||
myBuf DS.B BufSize ; for reading from the file
|
||||
curByte DC.W -1 ; the current offset in myBuf
|
||||
lastByte DS.W 1 ; last valid byte in myBuf
|
||||
ENDR
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE WriteStrings
|
||||
* FUNCTION calls write for an arbitrary number of strings
|
||||
* INPUT a NIL pointer on stack, followed by arbitrary number of string pointers,
|
||||
* and the file descriptor
|
||||
* OUTPUT none
|
||||
* NOTES PROCEDURE WriteStrings (NIL, Str^ …,FD);
|
||||
*******************************************************************
|
||||
SEG 'Write'
|
||||
WriteStrings PROC
|
||||
Link A6,#0 ; set up a stack frame
|
||||
Move.L A2,-(SP) ; and save one permanent register
|
||||
LEA 8(A6),A2 ; point A2 at first (last) parameter
|
||||
|
||||
* next, create a call block for the write routine on the stack
|
||||
Clr.L -(SP) ; set the length to zero
|
||||
SubQ #8,SP ; make room for the buffer and fd
|
||||
Move.L (A2)+,(SP) ; put the file descriptor in its place
|
||||
|
||||
* now pull the arguments off the stack and write them out
|
||||
@1 Move.L (A2)+,D0 ; get the string pointer
|
||||
BEQ.S @0 ; the list of strings is NIL terminated
|
||||
Move.L D0,A0 ; move the pointer so we can use it
|
||||
Move.B (A0)+,11(SP) ; to move the length byte into the length arg
|
||||
Move.L A0,4(SP) ; move the pointer into the buffer arg
|
||||
JSR (write).L ; write it--CASE is significant
|
||||
BRA.S @1 ; and try again
|
||||
|
||||
* done writing. Clean up the stack and return
|
||||
@0 Move.L A2,A1 ; we still need this
|
||||
Move.L -4(A6),A2 ; restore A2
|
||||
UNLK A6 ; throw away the scratch stack stuff
|
||||
Move.L (SP),A0 ; get the return address
|
||||
Move.L A1,SP ; throw away the parameters
|
||||
JMP (A0) ; and bail out
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE Stop
|
||||
* FUNCTION terminates execution
|
||||
* INPUT Message(A6)--error message to display on exit
|
||||
* OUTPUT Tool execution is terminated--return to MPW shell
|
||||
* NOTES call with a JMP, not a JSR--it doesn't return to caller anyway
|
||||
*******************************************************************
|
||||
SEG 'STOP'
|
||||
Stop PROC
|
||||
|
||||
* don't bother to save permanent registers--we're never going back to the caller
|
||||
WITH Globals
|
||||
MoveQ #0,D0
|
||||
Move.B (RetCode).L,D0 ; we'll return this status
|
||||
TST.B Interrupted
|
||||
BEQ.S @1
|
||||
Move.B #RC_Abort,D0 ; unless we were interrupted
|
||||
|
||||
@1 Move.L D0,-(SP)
|
||||
JSR (exit).L ; (does not return)
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE Intr
|
||||
* FUNCTION sets the global Interrupted to TRUE--passed to the Runtime routine
|
||||
* INPUT
|
||||
* OUTPUT Interrupted is set TRUE
|
||||
* NOTES
|
||||
*******************************************************************
|
||||
|
||||
Intr PROC
|
||||
ST Globals.Interrupted
|
||||
RTS
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE SyntaxError
|
||||
* FUNCTION Report a syntax error for the command line
|
||||
* INPUT above(A7)--pointers to strings to append to the error message
|
||||
* OUTPUT displays error message and calls Stop to terminate program execution
|
||||
* NOTES call with a JMP, not a JSR--it doesn't return anyway
|
||||
*******************************************************************
|
||||
|
||||
SyntaxError PROC
|
||||
|
||||
WITH Globals
|
||||
DC.W $A9FF
|
||||
PEA #' - '
|
||||
Move.L (progName).L,-(SP)
|
||||
PEA #'### '
|
||||
PEA DiagnosticFD
|
||||
JSR (WriteStrings).L ; finish writing the error line
|
||||
CLR.L -(SP)
|
||||
PEA CrStr
|
||||
PEA #' [-l] [-c] [files…].'
|
||||
Move.L progName,-(SP)
|
||||
PEA #'# Usage - '
|
||||
PEA (DiagnosticFD).L
|
||||
JSR (WriteStrings).L ; and write the 'usage' line
|
||||
JMP (Stop).L
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE LetterOpt
|
||||
* FUNCTION Set a letter option
|
||||
* INPUT D0--char
|
||||
* D4--ArgVIndex
|
||||
* A1--address of current option
|
||||
* OUTPUT if char = valid option, set option flag, else syntaxerror
|
||||
* NOTES PROCEDURE LetterOpt(Opt: Char; VAR ArgVIndex: Integer);
|
||||
* ArgVIndex can be updated by this routine to skip arguments to options
|
||||
*******************************************************************
|
||||
|
||||
LetterOpt PROC
|
||||
Cmp.B #'l',D0
|
||||
BEQ.S @0
|
||||
Cmp.B #'L',D0 ; -l?
|
||||
BNE.S @1
|
||||
@0 ST (Globals.WriteLines).L ; means only lines
|
||||
ADDQ #1,Globals.Opts ; yes, an option has been selected
|
||||
RTS
|
||||
@1 Cmp.B #'c',D0 ; -c?
|
||||
BEQ.S @2
|
||||
Cmp.B #'C',D0
|
||||
BNE.S @3
|
||||
@2 ST Globals.WriteChars ; means only characters
|
||||
ADDQ #1,Globals.Opts ; yes, an option has been selected
|
||||
RTS
|
||||
@3 Clr.L -(SP) ; otherwise it's a bad option
|
||||
PEA Globals.CRStr
|
||||
PEA #'" is not an option.'
|
||||
Move.L A1,-(SP) ; pointer to current option
|
||||
PEA #'"' ; the leading quote around the option
|
||||
JMP SyntaxError
|
||||
* SyntaxError never returns
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE Init
|
||||
* FUNCTION Tool initalization
|
||||
* INPUT
|
||||
* OUTPUT
|
||||
* NOTES PROCEDURE Init;
|
||||
*******************************************************************
|
||||
SEG 'INIT'
|
||||
Init PROC
|
||||
|
||||
ForPascal EQU 1 ; Make envp & argv strings "Pascal" format
|
||||
; (preceded with a length byte)
|
||||
|
||||
; Comments about the Init.SF structure
|
||||
; 1. TEMPLATE. Note that this is a template, not a record;
|
||||
; it is equivalent to a 'struct' in C or a type
|
||||
; definition in Pascal. It does not allocate space.
|
||||
; 2. DECREMENT. It is used to describe a "stack frame". Since
|
||||
; the stack grows downward, the keyword 'Decrement' is used.
|
||||
; 3. The bracketed parameter, '{OldA6}'. This tells the Assembler to
|
||||
; calculate field offsets using this field as the '0' offset.
|
||||
; This is explained more fully in the MPW Assembler Manual.
|
||||
; 4. SIZE field. The size field here is the calculated as the
|
||||
; difference from 0...this turns out to be -4, which
|
||||
; turns out to be the amount of space that we have to
|
||||
; allocate on the stack via a Link instruction for our
|
||||
; local parameters.
|
||||
; If we were to have incoming parameters, then we
|
||||
; could allocate them above the OldA6 field; what
|
||||
; order the parameters are found, and their relation
|
||||
; to the routine Return Address varies between C and
|
||||
; Pascal; appendices in the MPW language manuals contain
|
||||
; more details about language calling conventions.
|
||||
|
||||
InitSF RECORD {OldA6},DECREMENT
|
||||
ShellRet DS.L 1 ;'RetPC' in Ch. 12 of MPW Manual
|
||||
RetAddress DS.L 1
|
||||
OldA6 DS.L 1
|
||||
EnvP DS.L 1
|
||||
Size EQU *
|
||||
ENDR
|
||||
|
||||
WITH Globals
|
||||
Link A6,#InitSF.Size
|
||||
PEA ForPascal ; optimized Move.L #1,-(SP)
|
||||
PEA InitSF.EnvP(A6) ; for Shell Exported variables
|
||||
PEA ArgV ; Address to store ptr to Command Line Arguments
|
||||
PEA ArgC ; Address to store ptr to # of Cmd Line Args.
|
||||
Move.L InitSF.ShellRet(A6),-(SP)
|
||||
JSR (_RTInit).L ; get things set up
|
||||
LEA InitSF.Size(A6),SP ; throw away the arguments
|
||||
PEA Intr ; our interrupt handler
|
||||
Move.L #SIGINT,-(SP)
|
||||
JSR (signal).L ; so we can handle user interrupts
|
||||
* D0 has handle to prevSig, which we will ignore
|
||||
LEA InitSF.Size(A6),SP ; throw away the arguments
|
||||
|
||||
MoveM.L A2/D3-D4,-(SP) ; let's do some ArgV processing
|
||||
Move.L ArgV,A2
|
||||
Move.L ArgC,D3
|
||||
Move.L (A2)+,progName ; we now have a global that points to our name
|
||||
Move.B #RC_ParmErrs,(RetCode).L
|
||||
MoveQ #0,D4 ; ArgVIndex := 0;
|
||||
@0 AddQ #1,D4
|
||||
Cmp.L D4,D3
|
||||
BLE.S DoneArgOptions
|
||||
Move.L (A2)+,A0 ; get the next arg
|
||||
Move.L A0,A1 ; keep a pointer to the start of the string
|
||||
Move.B (A0)+,D1 ; get the len
|
||||
BEQ.S @0 ; arg := ''; get the next one
|
||||
Move.B (A0)+,D0
|
||||
Cmp.B #'-',D0 ; is it an option?
|
||||
BNE.S @1
|
||||
Move.B (A0)+,D0
|
||||
JSR (LetterOpt).L
|
||||
* caller to LetterOpt can check if ArgIndex changed--if so, skip the increment of ArgIndex
|
||||
BRA.S @0 ; go again
|
||||
@1 AddQ #1,NumFiles ; bump the file count
|
||||
Cmp.B Max,D1 ; a new longest name?
|
||||
BLE.S @0
|
||||
Move.B D1,Max ; a new max
|
||||
BRA.S @0
|
||||
|
||||
DoneArgOptions
|
||||
Move.B #RC_Normal,RetCode ; parameters ok so far
|
||||
Clr.L -(SP)
|
||||
JSR (InitCursorCtl).L ; initialize the spinning cursor
|
||||
Tst.B Interrupted ; user break yet?
|
||||
BEQ.S @3
|
||||
JMP Stop
|
||||
@3 MoveM.L (SP)+,A2/D3-D4
|
||||
UNLK A6
|
||||
RTS
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE PrintCount
|
||||
* FUNCTION writes the filename (if needed), linecount and/or charcount to standard output
|
||||
* INPUT pointer to the filename in A2 (if counting multiple files)
|
||||
* OUTPUT
|
||||
* NOTES
|
||||
*******************************************************************
|
||||
|
||||
PrintCount PROC
|
||||
PrintSF RECORD 0,DECREMENT
|
||||
LineBuf DS.B 256
|
||||
tempStr DS.B 10
|
||||
MaxBlanks DS.B 1
|
||||
ALIGN
|
||||
Size EQU *
|
||||
ENDR
|
||||
|
||||
LINK A6,#PrintSF.Size
|
||||
MoveM.L D6/A3,-(SP)
|
||||
|
||||
Move.W #(256/4)-1,D0 ; fill LineBuf with blanks
|
||||
Move.L #' ',D1
|
||||
LEA PrintSF.LineBuf(A6),A0
|
||||
@0 Move.L D1,(A0)+
|
||||
DBRA D0,@0
|
||||
|
||||
WITH Globals
|
||||
MoveQ #3,D6 ; skip first three blanks
|
||||
LEA 4+PrintSF.LineBuf(A6),A3 ; A3 is the current offset into lineBuf
|
||||
Cmp.W #1,NumFiles ; >1 if more than one file
|
||||
BLE.S noName
|
||||
|
||||
Move.L D7,A0 ; D7 points to the current filename
|
||||
MoveQ #0,D1
|
||||
Move.B (A0)+,D1 ; get the length byte
|
||||
Add.B D1,D6 ; update the new length
|
||||
MoveQ #0,D0
|
||||
Move.B Max,D0 ; Max is the longest name
|
||||
Sub.B D1,D0 ; D0 is how much shorter current is than max
|
||||
AddQ #3,D0
|
||||
Add.B D0,D6 ; update the counter
|
||||
BRA.S @2 ; zero base the length
|
||||
@1 Move.B (A0)+,(A3)+
|
||||
@2 DBRA D1,@1 ; move in the filename
|
||||
Add.W D0,A3 ; and update our roving pointer
|
||||
|
||||
noName
|
||||
ENTRY DoLines,DoChars,WriteBuf
|
||||
; if no options selected, print both lines and chars.
|
||||
TST.B Opts
|
||||
BNE.S @0
|
||||
|
||||
JSR DoLines ; insert lines into buffer
|
||||
JSR DoChars ; insert chars into buffer
|
||||
BRA.S @Exit
|
||||
|
||||
@0 TST.B WriteLines ; do we want to print the line count?
|
||||
BEQ.S @1
|
||||
JSR DoLines ; insert lines into buffer
|
||||
@1 TST.B WriteChars
|
||||
BEQ.S @Exit
|
||||
JSR DoChars ; insert chars into buffer
|
||||
|
||||
@Exit
|
||||
Move.B D6,PrintSF.lineBuf(A6) ; set the length byte
|
||||
|
||||
CLR.L -(SP) ; set up the stack for WriteStrings
|
||||
PEA CRStr
|
||||
PEA PrintSF.linebuf(A6)
|
||||
PEA OutputFD
|
||||
JSR WriteStrings
|
||||
MoveM.L (SP)+,D6/A3
|
||||
UNLK A6
|
||||
RTS
|
||||
|
||||
|
||||
DoLines
|
||||
Move.L lineCount,D0
|
||||
add.w #10,D6 ; update counter
|
||||
JMP WriteBuf
|
||||
|
||||
DoChars
|
||||
MOVE.L charcount,D0
|
||||
add.w #13,D6 ; add field length and 3 blanks to counter
|
||||
JMP WriteBuf
|
||||
|
||||
WriteBuf
|
||||
LEA PrintSF.tempStr(A6),A0
|
||||
_NumToString
|
||||
|
||||
MoveQ #0,D1
|
||||
Move.B (A0)+,D1
|
||||
MoveQ #10,D0 ; we'll say this field is 10 long
|
||||
Sub.B D1,D0 ; D0 := field length-length of numstring
|
||||
Add.W D0,A3 ; skip the extra padding
|
||||
|
||||
BRA.S @2 ; zero base by doing the DBCC first
|
||||
@1 Move.B (A0)+,(A3)+
|
||||
@2 DBRA D1,@1 ; move in the number
|
||||
RTS
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE PrintTotals
|
||||
* FUNCTION writes the summary line to standard output
|
||||
* INPUT
|
||||
* OUTPUT
|
||||
* NOTES calls PrintCount to print the totals if appropriate
|
||||
*******************************************************************
|
||||
SEG 'PrintTotals'
|
||||
PrintTotals PROC
|
||||
Cmp.W #1,Globals.numFiles
|
||||
BGT.S @0
|
||||
RTS ; do nothing if only one file
|
||||
@0 LEA #'Total',A0
|
||||
Move.L A0,D7 ; our new 'filename'
|
||||
Move.L Globals.totallines,Globals.linecount
|
||||
Move.L Globals.totalchars,Globals.charcount
|
||||
JSR (PrintCount).L ; recycled code
|
||||
RTS
|
||||
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE GetChar
|
||||
* FUNCTION reads from the file in hunks, and hands out a character at a time
|
||||
* INPUT fd: long in D4--the file descriptor for the file to read
|
||||
* OUTPUT the next character in D0--zero = TRUE means end of file
|
||||
* NOTES
|
||||
*******************************************************************
|
||||
SEG 'GetChar'
|
||||
GetChar PROC
|
||||
WITH Globals
|
||||
Move.W curByte,D1 ; get the current offset
|
||||
BPL.S @0 ; we have a valid block currently
|
||||
@1 PEA BufSize ; Move.L #BufSize,-(SP)--count
|
||||
PEA mybuf ; where
|
||||
Move.L D4,-(SP) ; the file descriptor
|
||||
JSR (read).L ; read the next block
|
||||
LEA 12(SP),SP ; clean up the stack
|
||||
MoveQ #0,D1 ; start at the beginning again
|
||||
Move.W D0,lastByte
|
||||
BNE.S @2 ; end of file?
|
||||
RTS ; pass the zero flag back to the caller
|
||||
@0 Move.W lastByte,D0 ; get the last valid byte
|
||||
@2 Cmp.W D0,D1
|
||||
BGE.S @1
|
||||
LEA mybuf,A0
|
||||
Move.B 0(A0,D1),D0 ; read the next character
|
||||
AddQ.W #1,D1
|
||||
Move.W D1,curByte ; update curByte
|
||||
RTS
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE CountFile (fd:filedescriptor)
|
||||
* FUNCTION counts the lines and characters in fd
|
||||
* INPUT fd: long--the file descriptor for the file to count
|
||||
* OUTPUT charcount, linecount, totalchars, totallines updated
|
||||
* NOTES
|
||||
*******************************************************************
|
||||
SEG 'CountFile'
|
||||
CountFile PROC
|
||||
WITH globals
|
||||
CLR.L linecount
|
||||
Move.L (SP)+,A1 ; save the return address
|
||||
Move.L (SP),D0 ; and the file descriptor
|
||||
Move.L A1,(SP) ; return the return address
|
||||
|
||||
MoveM.L D4-D7,-(SP)
|
||||
Move.L D0,D4 ; save the fd for the getchar routine
|
||||
MoveQ #0,D7 ; initialize our counter registers
|
||||
MoveQ #0,D6
|
||||
|
||||
ReadLoop
|
||||
JSR getchar
|
||||
BEQ.S fileEnd ; zero means no more bytes to read
|
||||
AddQ.L #1,D7 ; otherwise bump the char counter
|
||||
Move.B D0,D5 ; save the char in a permanent register
|
||||
CMP.B #EOLChar,D5 ; bump linecount?
|
||||
BNE.S ReadLoop
|
||||
|
||||
AddQ.L #1,D6 ; yes
|
||||
Move.L D6,-(SP)
|
||||
JSR (RotateCursor).L ; spin the ball
|
||||
Tst.B Interrupted ; user break yet?
|
||||
BEQ.S ReadLoop ; no--continue
|
||||
JMP (Stop).L ; abort mission
|
||||
|
||||
fileEnd
|
||||
CMP.B #EOLChar,D5 ; was the last character read a line end?
|
||||
BEQ.S @0
|
||||
TST.L D7 ; have we counted any characters
|
||||
BEQ.S @0 ; no--don't increment line count
|
||||
AddQ.L #1,D6
|
||||
@0 Move.L D6,lineCount ; update globals and leave
|
||||
Move.L D7,charCount
|
||||
Add.L D6,totallines
|
||||
Add.L D7,totalchars
|
||||
MoveM.L (SP)+,D4-D7
|
||||
RTS
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE Count
|
||||
* FUNCTION the MAIN proc--calls Init, then processes the files
|
||||
* INPUT
|
||||
* OUTPUT
|
||||
* NOTES
|
||||
*******************************************************************
|
||||
|
||||
SEG 'MAIN'
|
||||
Count MAIN
|
||||
IMPORT c2pstr,p2cstr
|
||||
WITH Globals
|
||||
JSR (Init).L
|
||||
Move.L ArgV,A2
|
||||
ADDQ #4,A2 ; skip the program name
|
||||
Move.L (A2)+,D7 ; set the cc's
|
||||
BNE.S @0 ; otherwise count stdin
|
||||
|
||||
* CountStdIn
|
||||
Clr.L -(SP) ; we don't need to open standard input
|
||||
JSR (CountFile).L
|
||||
JSR (PrintCount).L
|
||||
JMP (Stop).L
|
||||
|
||||
@1 Move.L (A2)+,D7 ; set the cc's
|
||||
BEQ.S ShowTotals ; ArgV is NIL terminated
|
||||
|
||||
@0 Move.L D7,A0
|
||||
Move.B (A0)+,D0 ; pick up the length byte
|
||||
BEQ.S @1 ; zero length--next, please
|
||||
Move.B (A0)+,D1 ; now the first charcter
|
||||
Cmp.B #'-',D1 ; an option--already handled by Init
|
||||
BEQ.S @1
|
||||
|
||||
* otherwise we have a file to process
|
||||
Move.L D7,-(SP) ; convert the filename to a C string
|
||||
JSR (p2cstr).L
|
||||
PEA O_RDONLY
|
||||
Move.L D7,-(SP)
|
||||
JSR (open).L ; open the file
|
||||
Move.L D0,D6 ; save the result--fd or error
|
||||
JSR (c2pstr).L ; love those length bytes
|
||||
LEA 12(SP),SP ; throw away the arguments
|
||||
Move.L D6,-(SP) ; push the fd
|
||||
BMI.S BailOut ; an error if negative
|
||||
JSR (CountFile).L
|
||||
JSR (PrintCount).L
|
||||
BRA.S @1
|
||||
|
||||
ShowTotals
|
||||
JSR (PrintTotals).L
|
||||
JMP (Stop).L
|
||||
|
||||
BailOut CLR.L (SP) ; space came from move D6 above
|
||||
PEA CRStr
|
||||
Move.L D7,-(SP)
|
||||
PEA #' - could not open file '
|
||||
Move.L progName,-(SP)
|
||||
PEA #'### '
|
||||
PEA DiagnosticFD ; optimized Move.L #DiagnosticFD,-(SP)
|
||||
JSR (WriteStrings).L
|
||||
|
||||
CLR.L -(SP)
|
||||
PEA CRStr
|
||||
PEA #' [-l] [-c] [files…].'
|
||||
Move.L progName,-(SP)
|
||||
PEA #'# Usage - '
|
||||
PEA DiagnosticFD ; optimized Move.L #DiagnosticFD,-(SP)
|
||||
JSR (WriteStrings).L
|
||||
Move.B #RC_ParmErrs,RetCode
|
||||
JMP (Stop).L
|
||||
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
END
|
||||
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0000 0000 0000 0000" /* ..Monaco........ */
|
||||
$"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
Count.r - commando resource file
|
||||
Copyright Apple Computer, Inc. 1987
|
||||
All rights reserved.
|
||||
|
||||
Count [-l] [-c] [file…] < file > counts
|
||||
-l # write only line counts
|
||||
-c # write only character counts
|
||||
*/
|
||||
|
||||
#include "Cmdo.r"
|
||||
|
||||
|
||||
resource 'cmdo' (128) {
|
||||
{
|
||||
245, /* Height of dialog */
|
||||
"Counts the lines and characters in its input, and writes the results to standard output.",
|
||||
{
|
||||
notDependent {}, RadioButtons {
|
||||
{
|
||||
{25, 250, 40, 410},
|
||||
"Lines and characters",
|
||||
"",
|
||||
Set,
|
||||
"Count the number of lines and characters in the input file(s) (or standard input).",
|
||||
|
||||
{40, 250, 55, 340},
|
||||
"Lines",
|
||||
"-l",
|
||||
NotSet,
|
||||
"Only count the number of lines in the input file(s) (or standard input).",
|
||||
|
||||
{55, 250, 70, 340},
|
||||
"Characters",
|
||||
"-c",
|
||||
NotSet,
|
||||
"Only count the number of characters in the input file(s) (or standard input).",
|
||||
}
|
||||
},
|
||||
notDependent {}, TextBox {
|
||||
gray,
|
||||
{17, 240, 75, 450},
|
||||
"Count"
|
||||
},
|
||||
Or {{-4}}, MultiFiles {
|
||||
"Files to count…",
|
||||
"Select the files to count. If no files are specified Count reads "
|
||||
"from standard input.",
|
||||
{36, 35, 56, 200},
|
||||
"Files to count:",
|
||||
"",
|
||||
MultiInputFiles {
|
||||
{TEXT},
|
||||
FilterTypes,
|
||||
"Only text files",
|
||||
"All files",
|
||||
}
|
||||
},
|
||||
Or {{-3}}, Redirection {
|
||||
StandardInput,
|
||||
{85, 30}
|
||||
},
|
||||
notDependent {}, Redirection {
|
||||
StandardOutput,
|
||||
{85, 180}
|
||||
},
|
||||
notDependent {}, Redirection {
|
||||
DiagnosticOutput,
|
||||
{85, 330}
|
||||
},
|
||||
notDependent {}, TextBox {
|
||||
gray,
|
||||
{80, 25, 125, 450},
|
||||
"Redirection"
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 001F 0228 001F 0229" /* ..Monaco...(...) */
|
||||
$"01BF 0009 01BF 000A 01C0 000A 01C0 0229" /* ...............) */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
*******************************************************************************
|
||||
*
|
||||
* File FStubs.a - Stubs for floating point runtime library routines
|
||||
* not used by MPW tools.
|
||||
*
|
||||
* Copyright Apple Computer, Inc. 1986-1987
|
||||
* All rights reserved.
|
||||
*
|
||||
*******************************************************************************
|
||||
|
||||
CASE ON
|
||||
|
||||
* Floating Point Conversion Routines
|
||||
*
|
||||
* These routines, called by printf, are only necessary if floating point
|
||||
* formatting is used.
|
||||
|
||||
ecvt PROC EXPORT
|
||||
RTS
|
||||
fcvt PROC EXPORT
|
||||
RTS
|
||||
|
||||
END
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0000 000C 0001 EDF4" /* ..Monaco........ */
|
||||
$"000A 8001 0000 0068 7FFF 6E64 0000 0060" /* .......h..nd...` */
|
||||
$"4431 0006 0004 002A 0003 0142 01E3 002A" /* D1.....*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# MakeFile - Make instructions for assembly language examples.
|
||||
#
|
||||
# Copyright Apple Computer, Inc. 1986-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# This makefile builds a '32-bit everything' Assembler version of
|
||||
# the MPW Tool 'count'.
|
||||
# The sample MPW Tool: Count
|
||||
|
||||
Count ƒƒ Count.r
|
||||
Rez Count.r -o Count -append
|
||||
Count ƒƒ Count.a.o FStubs.a.o
|
||||
Link -w -model far -c 'MPS ' -t MPST Count.a.o FStubs.a.o ∂
|
||||
-sn INTENV=Main ∂
|
||||
-sn %A5Init=Main ∂
|
||||
"{Libraries}"Stubs.o ∂
|
||||
"{Libraries}"Runtime.o ∂
|
||||
"{Libraries}"ToolLibs.o ∂
|
||||
"{Libraries}"Interface.o ∂
|
||||
-o Count
|
||||
Count.a.o ƒ Count.a
|
||||
Asm -model far Count.a
|
||||
FStubs.a.o ƒ FStubs.a
|
||||
Asm FStubs.a
|
||||
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0000 0034 0001 E9CC" /* ..Monaco...4.... */
|
||||
$"002C FC18 FC18 0197 01C6 FC18 FC18 FC19" /* .,.............. */
|
||||
$"7FFF 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,567 @@
|
|||
*-------------------------------------------------------------------------------------------
|
||||
*
|
||||
* NAME
|
||||
* Count.a -- count lines and characters
|
||||
*
|
||||
* SYNOPSIS
|
||||
* Count [-l] [-c] [file…]
|
||||
*
|
||||
* DESCRIPTION
|
||||
* "Count" counts the lines and characters in its input, and writes the
|
||||
* counts to standard output. If no files are specified standard input is
|
||||
* read. If more than one file is specified, separate counts are written
|
||||
* for each file, one per line, preceeded by the file name. A total is also
|
||||
* written following the list of files.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* Copyright Apple Computer, Inc. 1985-1987
|
||||
* All rights reserved.
|
||||
*
|
||||
* MODIFICATION HISTORY
|
||||
* 10/15/90 JAK No options and both options produce
|
||||
* char and line output.
|
||||
*-------------------------------------------------------------------------------------------
|
||||
|
||||
CASE OBJ
|
||||
INCLUDE 'traps.a' ; for Pack7
|
||||
INCLUDE 'packmacs.a' ; for NumToStr, which calls Pack7
|
||||
INCLUDE 'intenv.a' ; so we can get our args, open files, etc.
|
||||
INCLUDE 'signal.a' ; so we can handle 'Command-.'
|
||||
IMPORT INITCURSORCTL ; to init the spinning beach ball
|
||||
IMPORT ROTATECURSOR ; for the spinning beach ball
|
||||
|
||||
RC_Normal EQU 0
|
||||
RC_ParmErrs EQU 1
|
||||
RC_Abort EQU 2 ; Return codes
|
||||
|
||||
;SIGINT EQU 2
|
||||
|
||||
EOLChar EQU $0D ; the Return character marks the end of line
|
||||
STRING Pascal ; length byte strings
|
||||
|
||||
BufSize EQU 1024 ; size of input buffer
|
||||
|
||||
* global data--these declarations outside of any module are allocated and accessed
|
||||
* relative to register A5
|
||||
Globals RECORD
|
||||
ArgV DS.L 1 ; the address of our arguments
|
||||
ArgC DS.L 1 ; the number of our arguments
|
||||
RetCode DC.B RC_Normal ; set to RC_ …
|
||||
CRStr DC.W $010D ; a 'string' that is a return character
|
||||
Interrupted DC.B 0 ; not interrupted yet
|
||||
progname DS.L 1 ; the address of our name
|
||||
NumFiles DC.W 0 ; the number of files to process
|
||||
WriteChars DC.B 0 ; TRUE if the user wants line count
|
||||
WriteLines DC.B 0 ; TRUE if the user wants char count
|
||||
Opts DC.B 0 ; TRUE if user has selected either line or char
|
||||
LineCount DC.L 0
|
||||
CharCount DC.L 0
|
||||
TotalLines DC.L 0
|
||||
TotalChars DC.L 0
|
||||
Max DC.B 5 ; length of 'Total' string, or the longest filename
|
||||
myBuf DS.B BufSize ; for reading from the file
|
||||
curByte DC.W -1 ; the current offset in myBuf
|
||||
lastByte DS.W 1 ; last valid byte in myBuf
|
||||
ENDR
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE WriteStrings
|
||||
* FUNCTION calls write for an arbitrary number of strings
|
||||
* INPUT a NIL pointer on stack, followed by arbitrary number of string pointers,
|
||||
* and the file descriptor
|
||||
* OUTPUT none
|
||||
* NOTES PROCEDURE WriteStrings (NIL, Str^ …,FD);
|
||||
*******************************************************************
|
||||
|
||||
WriteStrings PROC
|
||||
Link A6,#0 ; set up a stack frame
|
||||
Move.L A2,-(SP) ; and save one permanent register
|
||||
LEA 8(A6),A2 ; point A2 at first (last) parameter
|
||||
|
||||
* next, create a call block for the write routine on the stack
|
||||
Clr.L -(SP) ; set the length to zero
|
||||
SubQ #8,SP ; make room for the buffer and fd
|
||||
Move.L (A2)+,(SP) ; put the file descriptor in its place
|
||||
|
||||
* now pull the arguments off the stack and write them out
|
||||
@1 Move.L (A2)+,D0 ; get the string pointer
|
||||
BEQ.S @0 ; the list of strings is NIL terminated
|
||||
Move.L D0,A0 ; move the pointer so we can use it
|
||||
Move.B (A0)+,11(SP) ; to move the length byte into the length arg
|
||||
Move.L A0,4(SP) ; move the pointer into the buffer arg
|
||||
JSR write ; write it--CASE is significant
|
||||
BRA.S @1 ; and try again
|
||||
|
||||
* done writing. Clean up the stack and return
|
||||
@0 Move.L A2,A1 ; we still need this
|
||||
Move.L -4(A6),A2 ; restore A2
|
||||
UNLK A6 ; throw away the scratch stack stuff
|
||||
Move.L (SP),A0 ; get the return address
|
||||
Move.L A1,SP ; throw away the parameters
|
||||
JMP (A0) ; and bail out
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE Stop
|
||||
* FUNCTION terminates execution
|
||||
* INPUT Message(A6)--error message to display on exit
|
||||
* OUTPUT Tool execution is terminated--return to MPW shell
|
||||
* NOTES call with a JMP, not a JSR--it doesn't return to caller anyway
|
||||
*******************************************************************
|
||||
|
||||
Stop PROC
|
||||
|
||||
* don't bother to save permanent registers--we're never going back to the caller
|
||||
WITH Globals
|
||||
MoveQ #0,D0
|
||||
Move.B RetCode,D0 ; we'll return this status
|
||||
TST.B Interrupted
|
||||
BEQ.S @1
|
||||
Move.B #RC_Abort,D0 ; unless we were interrupted
|
||||
|
||||
@1 Move.L D0,-(SP)
|
||||
JSR exit ; (does not return)
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE Intr
|
||||
* FUNCTION sets the global Interrupted to TRUE--passed to the Runtime routine
|
||||
* INPUT
|
||||
* OUTPUT Interrupted is set TRUE
|
||||
* NOTES
|
||||
*******************************************************************
|
||||
|
||||
Intr PROC
|
||||
ST Globals.Interrupted
|
||||
RTS
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE SyntaxError
|
||||
* FUNCTION Report a syntax error for the command line
|
||||
* INPUT above(A7)--pointers to strings to append to the error message
|
||||
* OUTPUT displays error message and calls Stop to terminate program execution
|
||||
* NOTES call with a JMP, not a JSR--it doesn't return anyway
|
||||
*******************************************************************
|
||||
|
||||
SyntaxError PROC
|
||||
|
||||
WITH Globals
|
||||
PEA #' - '
|
||||
Move.L progName,-(SP)
|
||||
PEA #'### '
|
||||
PEA DiagnosticFD
|
||||
JSR WriteStrings ; finish writing the error line
|
||||
CLR.L -(SP)
|
||||
PEA CrStr
|
||||
PEA #' [-l] [-c] [files…].'
|
||||
Move.L progName,-(SP)
|
||||
PEA #'# Usage - '
|
||||
PEA DiagnosticFD
|
||||
JSR WriteStrings ; and write the 'usage' line
|
||||
JMP Stop
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE LetterOpt
|
||||
* FUNCTION Set a letter option
|
||||
* INPUT D0--char
|
||||
* D4--ArgVIndex
|
||||
* A1--address of current option
|
||||
* OUTPUT if char = valid option, set option flag, else syntaxerror
|
||||
* NOTES PROCEDURE LetterOpt(Opt: Char; VAR ArgVIndex: Integer);
|
||||
* ArgVIndex can be updated by this routine to skip arguments to options
|
||||
*******************************************************************
|
||||
|
||||
LetterOpt PROC
|
||||
Cmp.B #'l',D0
|
||||
BEQ.S @0
|
||||
Cmp.B #'L',D0 ; -l?
|
||||
BNE.S @1
|
||||
@0 ST Globals.WriteLines ; means only lines
|
||||
ADDQ #1,Globals.Opts ; yes, an option has been selected
|
||||
RTS
|
||||
@1 Cmp.B #'c',D0 ; -c?
|
||||
BEQ.S @2
|
||||
Cmp.B #'C',D0
|
||||
BNE.S @3
|
||||
@2 ST Globals.WriteChars ; means only characters
|
||||
ADDQ #1,Globals.Opts ; yes, an option has been selected
|
||||
RTS
|
||||
@3 Clr.L -(SP) ; otherwise its a bad option
|
||||
PEA Globals.CRStr
|
||||
PEA #'" is not an option.'
|
||||
Move.L A1,-(SP) ; pointer to current option
|
||||
PEA #'"' ; the leading quote around the option
|
||||
JMP SyntaxError
|
||||
* SyntaxError never returns
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE Init
|
||||
* FUNCTION Tool initalization
|
||||
* INPUT
|
||||
* OUTPUT
|
||||
* NOTES PROCEDURE Init;
|
||||
*******************************************************************
|
||||
|
||||
Init PROC
|
||||
|
||||
ForPascal EQU 1
|
||||
|
||||
InitSF RECORD {OldA6},DECREMENT
|
||||
ShellRet DS.L 1
|
||||
RetAddress DS.L 1
|
||||
OldA6 DS.L 1
|
||||
EnvP DS.L 1
|
||||
Size EQU *
|
||||
ENDR
|
||||
|
||||
WITH Globals
|
||||
Link A6,#InitSF.Size
|
||||
PEA ForPascal ; optimized Move.L #1,-(SP)
|
||||
PEA InitSF.EnvP(A6)
|
||||
PEA ArgV
|
||||
PEA ArgC
|
||||
Move.L InitSF.ShellRet(A6),-(SP)
|
||||
JSR _RTInit ; get things set up
|
||||
LEA InitSF.Size(A6),SP ; throw away the arguments
|
||||
PEA Intr ; our interrupt handler
|
||||
Move.L #SIGINT,-(SP)
|
||||
JSR signal ; so we can handle user interrupts
|
||||
* D0 has handle to prevSig, which we will ignore
|
||||
LEA InitSF.Size(A6),SP ; throw away the arguments
|
||||
|
||||
MoveM.L A2/D3-D4,-(SP) ; let's do some ArgV processing
|
||||
Move.L ArgV,A2
|
||||
Move.L ArgC,D3
|
||||
Move.L (A2)+,progName ; we now have a global that points to our name
|
||||
Move.B #RC_ParmErrs,RetCode
|
||||
MoveQ #0,D4 ; ArgVIndex := 0;
|
||||
@0 AddQ #1,D4
|
||||
Cmp.L D4,D3
|
||||
BLE.S DoneArgOptions
|
||||
Move.L (A2)+,A0 ; get the next arg
|
||||
Move.L A0,A1 ; keep a pointer to the start of the string
|
||||
Move.B (A0)+,D1 ; get the len
|
||||
BEQ.S @0 ; arg := ''; get the next one
|
||||
Move.B (A0)+,D0
|
||||
Cmp.B #'-',D0 ; is it an option?
|
||||
BNE.S @1
|
||||
Move.B (A0)+,D0
|
||||
JSR LetterOpt
|
||||
* caller to LetterOpt can check if ArgIndex changed--if so, skip the increment of ArgIndex
|
||||
BRA.S @0 ; go again
|
||||
@1 AddQ #1,NumFiles ; bump the file count
|
||||
Cmp.B Max,D1 ; a new longest name?
|
||||
BLE.S @0
|
||||
Move.B D1,Max ; a new max
|
||||
BRA.S @0
|
||||
|
||||
DoneArgOptions
|
||||
Move.B #RC_Normal,RetCode ; parameters ok so far
|
||||
Clr.L -(SP)
|
||||
JSR InitCursorCtl ; initialize the spinning cursor
|
||||
Tst.B Interrupted ; user break yet?
|
||||
BEQ.S @3
|
||||
JMP Stop
|
||||
@3 MoveM.L (SP)+,A2/D3-D4
|
||||
UNLK A6
|
||||
RTS
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE PrintCount
|
||||
* FUNCTION writes the filename (if needed), linecount and/or charcount to standard output
|
||||
* INPUT pointer to the filename in A2 (if counting multiple files)
|
||||
* OUTPUT
|
||||
* NOTES
|
||||
*******************************************************************
|
||||
|
||||
PrintCount PROC
|
||||
PrintSF RECORD 0,DECREMENT
|
||||
LineBuf DS.B 256
|
||||
tempStr DS.B 10
|
||||
MaxBlanks DS.B 1
|
||||
ALIGN
|
||||
Size EQU *
|
||||
ENDR
|
||||
|
||||
LINK A6,#PrintSF.Size
|
||||
MoveM.L D6/A3,-(SP)
|
||||
|
||||
Move.W #(256/4)-1,D0 ; fill LineBuf with blanks
|
||||
Move.L #' ',D1
|
||||
LEA PrintSF.LineBuf(A6),A0
|
||||
@0 Move.L D1,(A0)+
|
||||
DBRA D0,@0
|
||||
|
||||
WITH Globals
|
||||
MoveQ #3,D6 ; skip first three blanks
|
||||
LEA 4+PrintSF.LineBuf(A6),A3 ; A3 is the current offset into lineBuf
|
||||
Cmp.W #1,NumFiles ; >1 if more than one file
|
||||
BLE.S noName
|
||||
|
||||
Move.L D7,A0 ; D7 points to the current filename
|
||||
MoveQ #0,D1
|
||||
Move.B (A0)+,D1 ; get the length byte
|
||||
Add.B D1,D6 ; update the new length
|
||||
MoveQ #0,D0
|
||||
Move.B Max,D0 ; Max is the longest name
|
||||
Sub.B D1,D0 ; D0 is how much shorter current is than max
|
||||
AddQ #3,D0
|
||||
Add.B D0,D6 ; update the counter
|
||||
BRA.S @2 ; zero base the length
|
||||
@1 Move.B (A0)+,(A3)+
|
||||
@2 DBRA D1,@1 ; move in the filename
|
||||
Add.W D0,A3 ; and update our roving pointer
|
||||
|
||||
|
||||
noName
|
||||
ENTRY DoLines,DoChars,WriteBuf
|
||||
; if no options selected, print both lines and chars.
|
||||
TST.B Opts
|
||||
BNE.S @0
|
||||
|
||||
JSR DoLines ; insert lines into buffer
|
||||
JSR DoChars ; insert chars into buffer
|
||||
BRA.S @Exit
|
||||
|
||||
@0 TST.B WriteLines ; do we want to print the line count?
|
||||
BEQ.S @1
|
||||
JSR DoLines ; insert lines into buffer
|
||||
@1 TST.B WriteChars
|
||||
BEQ.S @Exit
|
||||
JSR DoChars ; insert chars into buffer
|
||||
|
||||
@Exit
|
||||
Move.B D6,PrintSF.lineBuf(A6) ; set the length byte
|
||||
|
||||
CLR.L -(SP) ; set up the stack for WriteStrings
|
||||
PEA CRStr
|
||||
PEA PrintSF.linebuf(A6)
|
||||
PEA OutputFD
|
||||
JSR WriteStrings
|
||||
MoveM.L (SP)+,D6/A3
|
||||
UNLK A6
|
||||
RTS
|
||||
|
||||
|
||||
DoLines
|
||||
Move.L lineCount,D0
|
||||
add.w #10,D6 ; update counter
|
||||
JMP WriteBuf
|
||||
|
||||
DoChars
|
||||
MOVE.L charcount,D0
|
||||
add.w #13,D6 ; add field length and 3 blanks to counter
|
||||
JMP WriteBuf
|
||||
|
||||
WriteBuf
|
||||
LEA PrintSF.tempStr(A6),A0
|
||||
_NumToString
|
||||
|
||||
MoveQ #0,D1
|
||||
Move.B (A0)+,D1
|
||||
MoveQ #10,D0 ; we'll say this field is 10 long
|
||||
Sub.B D1,D0 ; D0 := field length-length of numstring
|
||||
Add.W D0,A3 ; skip the extra padding
|
||||
|
||||
BRA.S @2 ; zero base by doing the DBCC first
|
||||
@1 Move.B (A0)+,(A3)+
|
||||
@2 DBRA D1,@1 ; move in the number
|
||||
RTS
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE PrintTotals
|
||||
* FUNCTION writes the summary line to standard output
|
||||
* INPUT
|
||||
* OUTPUT
|
||||
* NOTES calls PrintCount to print the totals if appropriate
|
||||
*******************************************************************
|
||||
|
||||
PrintTotals PROC
|
||||
Cmp.W #1,Globals.numFiles
|
||||
BGT.S @0
|
||||
RTS ; do nothing if only one file
|
||||
@0 LEA #'Total',A0
|
||||
Move.L A0,D7 ; our new 'filename'
|
||||
Move.L Globals.totallines,Globals.linecount
|
||||
Move.L Globals.totalchars,Globals.charcount
|
||||
JSR PrintCount ; recycled code
|
||||
RTS
|
||||
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE GetChar
|
||||
* FUNCTION reads from the file in hunks, and hands out a character at a time
|
||||
* INPUT fd: long in D4--the file descriptor for the file to read
|
||||
* OUTPUT the next character in D0--zero = TRUE means end of file
|
||||
* NOTES
|
||||
*******************************************************************
|
||||
|
||||
GetChar PROC
|
||||
WITH Globals
|
||||
Move.W curByte,D1 ; get the current offset
|
||||
BPL.S @0 ; we have a valid block currently
|
||||
@1 PEA BufSize ; Move.L #BufSize,-(SP)--count
|
||||
PEA mybuf ; where
|
||||
Move.L D4,-(SP) ; the file descriptor
|
||||
JSR read ; read the next block
|
||||
LEA 12(SP),SP ; clean up the stack
|
||||
MoveQ #0,D1 ; start at the beginning again
|
||||
Move.W D0,lastByte
|
||||
BNE.S @2 ; end of file?
|
||||
RTS ; pass the zero flag back to the caller
|
||||
@0 Move.W lastByte,D0 ; get the last valid byte
|
||||
@2 Cmp.W D0,D1
|
||||
BGE.S @1
|
||||
LEA mybuf,A0
|
||||
Move.B 0(A0,D1),D0 ; read the next character
|
||||
AddQ.W #1,D1
|
||||
Move.W D1,curByte ; update curByte
|
||||
RTS
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE CountFile (fd:filedescriptor)
|
||||
* FUNCTION counts the lines and characters in fd
|
||||
* INPUT fd: long--the file descriptor for the file to count
|
||||
* OUTPUT charcount, linecount, totalchars, totallines updated
|
||||
* NOTES
|
||||
*******************************************************************
|
||||
|
||||
CountFile PROC
|
||||
WITH globals
|
||||
CLR.L linecount
|
||||
Move.L (SP)+,A1 ; save the return address
|
||||
Move.L (SP),D0 ; and the file descriptor
|
||||
Move.L A1,(SP) ; return the return address
|
||||
|
||||
MoveM.L D4-D7,-(SP)
|
||||
Move.L D0,D4 ; save the fd for the getchar routine
|
||||
MoveQ #0,D7 ; initialize our counter registers
|
||||
MoveQ #0,D6
|
||||
|
||||
ReadLoop JSR getchar
|
||||
BEQ.S fileEnd ; zero means no more bytes to read
|
||||
AddQ.L #1,D7 ; otherwise bump the char counter
|
||||
Move.B D0,D5 ; save the char in a permanent register
|
||||
CMP.B #EOLChar,D5 ; bump linecount?
|
||||
BNE.S ReadLoop
|
||||
|
||||
AddQ.L #1,D6 ; yes
|
||||
Move.L D6,-(SP)
|
||||
JSR RotateCursor ; spin the ball
|
||||
Tst.B Interrupted ; user break yet?
|
||||
BEQ.S ReadLoop ; no--continue
|
||||
JMP Stop ; abort mission
|
||||
|
||||
fileEnd CMP.B #EOLChar,D5 ; was the last character read a line end?
|
||||
BEQ.S @0
|
||||
TST.L D7 ; have we counted any characters
|
||||
BEQ.S @0 ; no--don't increment line count
|
||||
AddQ.L #1,D6
|
||||
@0 Move.L D6,lineCount ; update globals and leave
|
||||
Move.L D7,charCount
|
||||
Add.L D6,totallines
|
||||
Add.L D7,totalchars
|
||||
MoveM.L (SP)+,D4-D7
|
||||
RTS
|
||||
ENDPROC
|
||||
|
||||
|
||||
*******************************************************************
|
||||
* ROUTINE Count
|
||||
* FUNCTION the MAIN proc--calls Init, then processes the files
|
||||
* INPUT
|
||||
* OUTPUT
|
||||
* NOTES
|
||||
*******************************************************************
|
||||
|
||||
|
||||
Count MAIN
|
||||
IMPORT c2pstr,p2cstr
|
||||
WITH Globals
|
||||
JSR Init
|
||||
Move.L ArgV,A2
|
||||
ADDQ #4,A2 ; skip the program name
|
||||
Move.L (A2)+,D7 ; set the cc's
|
||||
BNE.S @0 ; otherwise count stdin
|
||||
|
||||
* CountStdIn
|
||||
Clr.L -(SP) ; we don't need to open standard input
|
||||
JSR CountFile
|
||||
JSR PrintCount
|
||||
JMP Stop
|
||||
|
||||
@1 Move.L (A2)+,D7 ; set the cc's
|
||||
BEQ.S ShowTotals ; ArgV is NIL terminated
|
||||
|
||||
@0 Move.L D7,A0
|
||||
Move.B (A0)+,D0 ; pick up the length byte
|
||||
BEQ.S @1 ; zero length--next, please
|
||||
Move.B (A0)+,D1 ; now the first charcter
|
||||
Cmp.B #'-',D1 ; an option--already handled by Init
|
||||
BEQ.S @1
|
||||
|
||||
* otherwise we have a file to process
|
||||
Move.L D7,-(SP) ; convert the filename to a C string
|
||||
JSR p2cstr
|
||||
PEA O_RDONLY
|
||||
Move.L D7,-(SP)
|
||||
JSR open ; open the file
|
||||
Move.L D0,D6 ; save the result--fd or error
|
||||
JSR c2pstr ; love those length bytes
|
||||
LEA 12(SP),SP ; throw away the arguments
|
||||
Move.L D6,-(SP) ; push the fd
|
||||
BMI.S BailOut ; an error if negative
|
||||
JSR CountFile
|
||||
JSR PrintCount
|
||||
BRA.S @1
|
||||
|
||||
ShowTotals
|
||||
JSR PrintTotals
|
||||
JMP Stop
|
||||
|
||||
BailOut CLR.L (SP) ; space came from move D6 above
|
||||
PEA CRStr
|
||||
Move.L D7,-(SP)
|
||||
PEA #' - could not open file '
|
||||
Move.L progName,-(SP)
|
||||
PEA #'### '
|
||||
PEA DiagnosticFD ; optimized Move.L #DiagnosticFD,-(SP)
|
||||
JSR WriteStrings
|
||||
|
||||
CLR.L -(SP)
|
||||
PEA CRStr
|
||||
PEA #' [-l] [-c] [files…].'
|
||||
Move.L progName,-(SP)
|
||||
PEA #'# Usage - '
|
||||
PEA DiagnosticFD ; optimized Move.L #DiagnosticFD,-(SP)
|
||||
JSR WriteStrings
|
||||
Move.B #RC_ParmErrs,RetCode
|
||||
JMP Stop
|
||||
|
||||
ENDWITH
|
||||
ENDPROC
|
||||
|
||||
END
|
||||
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 006C 6573 3A41 4578" /* ..Monaco.les:AEx */
|
||||
$"616D 706C 6573 3A43 6F75 6E74 2E61 0022" /* amples:Count.a." */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
Count.r - commando resource file
|
||||
Copyright Apple Computer, Inc. 1987
|
||||
All rights reserved.
|
||||
|
||||
Count [-l] [-c] [file…] < file > counts
|
||||
-l # write only line counts
|
||||
-c # write only character counts
|
||||
*/
|
||||
|
||||
#include "Cmdo.r"
|
||||
|
||||
|
||||
resource 'cmdo' (128) {
|
||||
{
|
||||
245, /* Height of dialog */
|
||||
"Counts the lines and characters in its input, and writes the results to standard output.",
|
||||
{
|
||||
notDependent {}, RadioButtons {
|
||||
{
|
||||
{25, 250, 40, 410},
|
||||
"Lines and characters",
|
||||
"",
|
||||
Set,
|
||||
"Count the number of lines and characters in the input file(s) (or standard input).",
|
||||
|
||||
{40, 250, 55, 340},
|
||||
"Lines",
|
||||
"-l",
|
||||
NotSet,
|
||||
"Only count the number of lines in the input file(s) (or standard input).",
|
||||
|
||||
{55, 250, 70, 340},
|
||||
"Characters",
|
||||
"-c",
|
||||
NotSet,
|
||||
"Only count the number of characters in the input file(s) (or standard input).",
|
||||
}
|
||||
},
|
||||
notDependent {}, TextBox {
|
||||
gray,
|
||||
{17, 240, 75, 450},
|
||||
"Count"
|
||||
},
|
||||
Or {{-4}}, MultiFiles {
|
||||
"Files to count…",
|
||||
"Select the files to count. If no files are specified Count reads "
|
||||
"from standard input.",
|
||||
{36, 35, 56, 200},
|
||||
"Files to count:",
|
||||
"",
|
||||
MultiInputFiles {
|
||||
{TEXT},
|
||||
FilterTypes,
|
||||
"Only text files",
|
||||
"All files",
|
||||
}
|
||||
},
|
||||
Or {{-3}}, Redirection {
|
||||
StandardInput,
|
||||
{85, 30}
|
||||
},
|
||||
notDependent {}, Redirection {
|
||||
StandardOutput,
|
||||
{85, 180}
|
||||
},
|
||||
notDependent {}, Redirection {
|
||||
DiagnosticOutput,
|
||||
{85, 330}
|
||||
},
|
||||
notDependent {}, TextBox {
|
||||
gray,
|
||||
{80, 25, 125, 450},
|
||||
"Redirection"
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 006F 756E 742E 7200" /* ..Monaco.ount.r. */
|
||||
$"2200 0000 0000 00B0 0078 00C0 00DA 8800" /* "........x...... */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
*******************************************************************************
|
||||
*
|
||||
* File FStubs.a - Stubs for floating point runtime library routines
|
||||
* not used by MPW tools.
|
||||
*
|
||||
* Copyright Apple Computer, Inc. 1986-1987
|
||||
* All rights reserved.
|
||||
*
|
||||
*******************************************************************************
|
||||
|
||||
CASE ON
|
||||
|
||||
* Floating Point Conversion Routines
|
||||
*
|
||||
* These routines, called by printf, are only necessary if floating point
|
||||
* formatting is used.
|
||||
|
||||
ecvt PROC EXPORT
|
||||
RTS
|
||||
fcvt PROC EXPORT
|
||||
RTS
|
||||
|
||||
END
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0053 7475 6273 2E61" /* ..Monaco.Stubs.a */
|
||||
$"0022 0000 0000 01D7 7FFF 01B4 0000 022B" /* .".............+ */
|
||||
$"7FFF 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
Instructions - The Assembly Language Examples
|
||||
|
||||
Copyright Apple Computer, Inc. 1987-1990
|
||||
All rights reserved.
|
||||
|
||||
|
||||
About the Examples
|
||||
|
||||
Three sample assembly language programs are included with MPW:
|
||||
an application, a tool, and a desk accessory:
|
||||
|
||||
Sample - a simple MultiFinder-Aware Sample application
|
||||
Count - an MPW tool
|
||||
Memory - a sample desk accessory
|
||||
|
||||
The source files for each of these examples are in the
|
||||
"Examples:AExamples:" folder. In addition, a makefiles
|
||||
that contains the commands needed to build each of the
|
||||
examples is provided in the same folder.
|
||||
|
||||
|
||||
Building the Examples
|
||||
|
||||
You can easily build each of the sample programs using the Directory
|
||||
and Build menus. (See Chapter 2 of the MPW Reference.)
|
||||
|
||||
Set the default directory to "AExamples:"
|
||||
|
||||
The simplest way to do this is to select from the Directory menu
|
||||
the menu item that ends in "AExamples:". You can also set the
|
||||
default directory by using the Directory and SetDirectory commands.
|
||||
|
||||
|
||||
Build the program
|
||||
|
||||
You can use any of the four Build items at the bottom of the Build
|
||||
menu to build the program you have selected. Each of these menu
|
||||
items displays a dialog box that asks for the name of the program
|
||||
you want to build. When this dialog box appears, type the name of
|
||||
one of the sample programs (Sample, Count, or Memory).
|
||||
|
||||
Each of the Build menu items behaves slightly differently:
|
||||
|
||||
Build… - The program is automatically built. The commands
|
||||
used, and any error messages, are displayed in the Worksheet.
|
||||
Only files that have been changed since you last built the
|
||||
program are compiled, saving considerable time.
|
||||
|
||||
Full Build… - The program is completely rebuilt, ignoring
|
||||
any object files or intermediate files that may already exist
|
||||
from a previous build. The commands used, and any errors, are
|
||||
displayed in the Worksheet.
|
||||
|
||||
Show Build Commands… - The commands needed to build the program
|
||||
are written to the Worksheet, but not executed. You can then
|
||||
select any or all of the commands and execute them yourself.
|
||||
(To execute the commands select them and press Enter.)
|
||||
|
||||
Show Full Build Commands… - The commands needed to completely
|
||||
rebuild the program are written to the Worksheet. This is a
|
||||
convenient way to see all of the commands used in building
|
||||
the program you have selected.
|
||||
|
||||
|
||||
Note: For more information about building the sample programs, see
|
||||
Chapter 2 of the MPW Reference.
|
||||
|
||||
|
||||
|
||||
Sample - A Simple MultiFinder-Aware Sample Application
|
||||
|
||||
Sample is an example application that demonstrates how to initialize
|
||||
the commonly used toolbox managers, operate successfully under
|
||||
MultiFinder, handle desk accessories and create windows.
|
||||
The source for Sample provides an excellent framework for basing
|
||||
new applications. The source is contained in the files Sample.a
|
||||
and SampleMisc.a and Sample.inc1.a, resource descriptions are
|
||||
contained in the files Sample.h and Sample.r. The make dependency
|
||||
file is named Sample.make.
|
||||
|
||||
To build Sample, simply select the line below and press Enter.
|
||||
|
||||
BuildProgram Sample ∑∑ {Worksheet}
|
||||
|
||||
To execute Sample, select the line below and press Enter.
|
||||
|
||||
Sample
|
||||
|
||||
|
||||
|
||||
Count - A Sample MPW Tool
|
||||
|
||||
Count, a tool that runs in the MPW environment, counts characters and
|
||||
lines in files. A version of Count is included with MPW, and is
|
||||
documented in the MPW Reference, Part II. The source for Count is in
|
||||
the files Count.a, FStubs.a, and Count.r. MakeFile contains the
|
||||
commands for building Count.
|
||||
|
||||
To build Count, simply select the line below and press Enter.
|
||||
|
||||
BuildProgram Count ∑∑ {Worksheet}
|
||||
|
||||
To test Count, try counting the characters in file Count.a.
|
||||
|
||||
Count -c Count.a
|
||||
|
||||
|
||||
|
||||
Memory - A Sample Desk Accessory
|
||||
|
||||
|
||||
Memory is a sample desk accessory written in assembly language. It
|
||||
displays the memory available in the application and system heaps,
|
||||
and on the boot disk. MakeFile contains the commands for building
|
||||
Memory.
|
||||
|
||||
To build Memory, simply select the line below and press Enter.
|
||||
|
||||
BuildProgram Memory ∑∑ {Worksheet}
|
||||
|
||||
The build process puts the desk accessory into a Font/DA Mover file.
|
||||
To install the Memory desk accessory, use the Font/DA Mover to copy
|
||||
resource Memory from the file Memory into the System file.
|
||||
|
||||
After quitting the Font/DA Mover and returning to the MPW Shell, select
|
||||
"Memory" from the Apple menu.
|
||||
|
||||
|
||||
|
||||
Writing Your Own Programs
|
||||
|
||||
After building (and perhaps modifying) the sample programs, you will
|
||||
undoubtedly want to write a program of your own. Use the New… item in
|
||||
the File menu, to create the source files. Remember that assembly
|
||||
language source filenames should end in .a.
|
||||
|
||||
Create Build Commands… - The Create Build Commands… item in the
|
||||
Build menu runs a script that creates a makefile containing the
|
||||
commands for building programs written in C, Assembly Language, Pascal,
|
||||
and/or Rez. Selecting Create Build Commands… displays a dialog box that
|
||||
allows you to enter information about your program. Type the program's
|
||||
name, select its source files by clicking the Files… button, and click
|
||||
one of the radio buttons to indicate your choice of an application, tool,
|
||||
or desk accessory.
|
||||
|
||||
Create Build Commands… puts the makefile for your program in the file
|
||||
<program>.make. Now you can use the Build menu to build and rebuild
|
||||
your program, just as with the examples.
|
||||
|
||||
Larger Programs - If you add source files as your program grows,
|
||||
use Create Build Commands… again to add the new source files to the build
|
||||
instructions. If you out-grow the capabilities of the simple Create
|
||||
Build Commands… script (perhaps by using tools other than Asm, C, Pascal,
|
||||
Rez, and Link in your builds) you can modify the makefile yourself.
|
||||
|
||||
Modifying the Directory and Build Menus - The Directory and Build
|
||||
menus are both implemented using scripts written in the MPW Shell
|
||||
command language. This has the big advantage that you can modify
|
||||
or customize them to match the way you work.
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 006E 7374 7275 6374" /* ..Monaco.nstruct */
|
||||
$"696F 6E73 0022 0000 6374 696F 6E73 00FF" /* ions."..ctions.. */
|
||||
$"FFFB 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# MakeFile - Make instructions for assembly language examples.
|
||||
#
|
||||
# Copyright Apple Computer, Inc. 1986-1987
|
||||
# All rights reserved.
|
||||
#
|
||||
# This makefile builds:
|
||||
# The sample MPW Tool: Count
|
||||
# The sample desk accessory: Memory
|
||||
#
|
||||
|
||||
Count ƒƒ Count.r
|
||||
Rez Count.r -o Count -append
|
||||
Count ƒƒ Count.a.o FStubs.a.o
|
||||
Link -w -c 'MPS ' -t MPST Count.a.o FStubs.a.o ∂
|
||||
-sn INTENV=Main ∂
|
||||
-sn %A5Init=Main ∂
|
||||
"{Libraries}"Stubs.o ∂
|
||||
"{Libraries}"Runtime.o ∂
|
||||
"{Libraries}"ToolLibs.o ∂
|
||||
"{Libraries}"Interface.o ∂
|
||||
-o Count
|
||||
Count.a.o ƒ Count.a
|
||||
Asm Count.a
|
||||
FStubs.a.o ƒ FStubs.a
|
||||
Asm FStubs.a
|
||||
|
||||
|
||||
Memory ƒ Memory.a.o
|
||||
Link -da -t DFIL -c DMOV -rt DRVR=12 -sg Memory ∂
|
||||
Memory.a.o -o Memory
|
||||
Memory.a.o ƒ Memory.a
|
||||
Asm Memory.a
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0061 6B65 4669 6C65" /* ..Monaco.akeFile */
|
||||
$"0022 0000 6B65 4669 6C65 0020 6F66 2049" /* ."..keFile. of I */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
***************************************************************************
|
||||
****
|
||||
**** MEMORY DESK ACCESSORY - A sample DA written in MPW 68000 Assembly
|
||||
****
|
||||
**** Copyright Apple Computer, Inc. 1985-1987
|
||||
**** All rights reserved.
|
||||
****
|
||||
***************************************************************************
|
||||
|
||||
STRING PASCAL
|
||||
|
||||
MAIN
|
||||
|
||||
INCLUDE 'QuickEqu.a'
|
||||
INCLUDE 'ToolEqu.a'
|
||||
INCLUDE 'SysEqu.a'
|
||||
INCLUDE 'Traps.a'
|
||||
|
||||
; Desk accessories (drivers) cannot use global variables in the normal sense.
|
||||
; Usually, a handle is allocated and stuffed into dCtlStorage and global
|
||||
; variables are stored in this handle. However, in this example, the globals
|
||||
; are allocated at the end of the desk accessory's window record. Since the
|
||||
; window record is always nonrelocatable storage, the variables will never move.
|
||||
; This record structure below defines the layout of our "global variables."
|
||||
|
||||
GlobalVars RECORD windowSize ; Put variables at end of window rec
|
||||
aString DS.B 28 ; vol names must be < 28 char
|
||||
aNumStr DS.B 10 ; sufficient for 10 GB of space
|
||||
GlobalSize EQU *-GlobalVars ; size of my globals
|
||||
ENDR
|
||||
|
||||
WITH GlobalVars
|
||||
|
||||
aPBPtr EQU D7
|
||||
|
||||
|
||||
**************************** DESK ACCESSORY ENTRY **************************
|
||||
|
||||
DAEntry ; See Device Manager IM:2
|
||||
DC.B (1<<dCtlEnable) + (1<<dNeedTime) ; periodic,control flags set
|
||||
DC.B 0 ; Lower byte is unused
|
||||
DC.W 5*60 ; 5 sec periodic update
|
||||
DC.W (1<<updatEvt) ; Handle only update events
|
||||
DC.W 0 ; No menu for this accessory
|
||||
|
||||
DC.W DAOpen-DAEntry ; Open routine
|
||||
DC.W DADone-DAEntry ; Prime - unused
|
||||
DC.W DACtl-DAEntry ; Control
|
||||
DC.W DADone-DAEntry ; Status - unused
|
||||
DC.W DAClose-DAEntry ; Close
|
||||
|
||||
DATitle
|
||||
DC.B 'Free Mem (#Bytes)' ; DA Name (& Window Title)
|
||||
ALIGN 2 ; Word align
|
||||
|
||||
|
||||
************************ DESK ACCESSORY OPEN ROUTINE ***********************
|
||||
|
||||
DAOpen
|
||||
MOVEM.L A1-A4,-(SP) ; preserve A1-A4
|
||||
MOVE.L A1,A4 ; MOVE DCE pointer to a reg
|
||||
|
||||
SUBQ.L #4,SP ; FUNCTION = GrafPtr
|
||||
MOVE.L SP,-(SP) ; push a pointer to it
|
||||
_GetPort ; push it on top of stack
|
||||
TST.L DCtlWindow(A4) ; do we have a window?
|
||||
BNE.S StdReturn ; If so, return, Else…
|
||||
|
||||
******************************* NEW WINDOW ROUTINE *************************
|
||||
MOVE.L #windowSize+GlobalSize,D0
|
||||
_NewPtr ; allocate space for record
|
||||
|
||||
SUBQ #4,SP ; FUNCTION = windowPtr
|
||||
MOVE.L A0,-(SP) ; address of storage
|
||||
PEA theWindow ; boundsRect
|
||||
PEA DATitle ; title
|
||||
CLR.W -(SP) ; visible flag FALSE
|
||||
MOVE.W #noGrowDocProc,-(SP) ; window proc
|
||||
MOVE.L #-1,-(SP) ; window in front
|
||||
MOVE.B #1,-(SP) ; goAway box TRUE
|
||||
CLR.L -(SP) ; refCon is 0
|
||||
_NewWindow
|
||||
|
||||
MOVE.L (SP)+,A0
|
||||
MOVE.L A0,DCtlWindow(A4) ; save windowPtr
|
||||
MOVE.W DCtlRefNum(A4),WindowKind(A0) ; system window
|
||||
|
||||
_MaxMem
|
||||
|
||||
StdReturn
|
||||
_SetPort ; old port on stack
|
||||
MOVEM.L (SP)+,A1-A4 ; restore regs
|
||||
|
||||
|
||||
************************ DESK ACCESSORY DONE ROUTINE ***********************
|
||||
|
||||
DADone
|
||||
MOVEQ #0,D0 ; return no error
|
||||
RTS ; all done, exit
|
||||
|
||||
|
||||
************************ DESK ACCESSORY CLOSE ROUTINE **********************
|
||||
|
||||
DAClose
|
||||
MOVEM.L A1-A4,-(SP) ; preserve A1-A4
|
||||
MOVE.L A1,A4 ; MOVE DCE ptr to A4
|
||||
|
||||
SUBQ.L #4,SP ; FUNCTION = GrafPtr
|
||||
MOVE.L SP,-(SP) ; push a pointer to it
|
||||
_GetPort ; get it, now it's on TOS
|
||||
|
||||
MOVE.L DCtlWindow(A4),-(SP) ; push the window
|
||||
_DisposWindow ; dispose of the window
|
||||
|
||||
CLR.L DCtlWindow(A4) ; mark DCE properly
|
||||
BRA.S StdReturn ; all done with close, exit
|
||||
|
||||
|
||||
********************** DESK ACCESSORY CONTROL ROUTINE **********************
|
||||
|
||||
DACtl
|
||||
MOVE.L A4,-(SP) ; preserve reg
|
||||
MOVE.L A1,A4 ; move DCE ptr to A4
|
||||
MOVE.W CSCode(A0),D0 ; get the control opCode
|
||||
SUB.W #accEvent,D0 ; = 64? (event)
|
||||
BEQ.S DoCtlEvent
|
||||
SUB.W #1,D0 ; = 65? (periodic)
|
||||
BEQ.S DoPeriodic
|
||||
|
||||
CtlDone
|
||||
MOVE.L A4,A1 ; put DCE ptr back in A1
|
||||
MOVE.L (SP)+,A4 ; restore reg
|
||||
MOVEQ #0,D0 ; return no error
|
||||
MOVE.L JIODone,-(SP) ; jump to IODone
|
||||
RTS
|
||||
|
||||
|
||||
************************** EVENT HANDLING ROUTINE **************************
|
||||
|
||||
DoCtlEvent
|
||||
MOVE.L A3,-(SP) ; save reg
|
||||
MOVE.L CSParam(A0),A3 ; get the event pointer
|
||||
MOVE.W EvtNum(A3),D0 ; get the event number
|
||||
SUBQ #updatEvt,D0 ; is it an update?
|
||||
BNE.S CtlEvtDone ; If not, exit
|
||||
|
||||
MOVE.L EvtMessage(A3),-(SP) ; push windowPtr
|
||||
_BeginUpdate ; begin the update operation
|
||||
|
||||
MOVE.L EvtMessage(A3),-(SP) ; push windowPtr again
|
||||
_SetPort
|
||||
BSR.S DrawWindow ; draw our items
|
||||
|
||||
MOVE.L EvtMessage(A3),-(SP) ; one more time
|
||||
_EndUpdate ; end of update
|
||||
|
||||
CtlEvtDone
|
||||
MOVE.L (SP)+,A3 ; restore reg
|
||||
BRA.S CtlDone ; exit
|
||||
|
||||
|
||||
**************************** PERIODIC ROUTINE *****************************
|
||||
|
||||
DoPeriodic
|
||||
MOVE.L DCtlWindow(A4),-(SP) ; set the port
|
||||
_SetPort
|
||||
|
||||
BSR.S DrawWindow ; draw our window every 5s
|
||||
BRA.S CtlDone
|
||||
|
||||
|
||||
****************************** FONT METRICS *******************************
|
||||
|
||||
DrawWindow
|
||||
MOVE.W #SrcCopy,-(SP) ; source mode
|
||||
_TextMode
|
||||
MOVE.W #Monaco,-(SP) ; Monaco
|
||||
_TextFont
|
||||
MOVE.W #9,-(SP) ; 9 point
|
||||
_TextSize
|
||||
MOVE.W #1,-(SP) ; bold
|
||||
_TextFace
|
||||
|
||||
|
||||
********************** WRITE APPLICATION HEAP FREEMEM *********************
|
||||
|
||||
MOVE.W #6,-(SP)
|
||||
MOVE.W #10,-(SP)
|
||||
_MoveTo
|
||||
PEA #'AppHeap: '
|
||||
_DrawString
|
||||
_FreeMem ; free memory -> D0
|
||||
JSR PrintNum ; draw our free mem
|
||||
|
||||
************************* WRITE SYSTEM HEAP FREEMEM ***********************
|
||||
|
||||
PEA #' SysHeap: '
|
||||
_DrawString
|
||||
_FreeMem SYS ; free memory -> D0
|
||||
JSR PrintNum ; draw our free sys mem
|
||||
|
||||
***************************** WRITELN VOL INFO ****************************
|
||||
|
||||
PEA #' Disk: '
|
||||
_DrawString
|
||||
|
||||
MOVE.L #ioHVQElSize,D0 ; size of HFS ParamBlock
|
||||
_NewPtr CLEAR ; NewPtr -> A0
|
||||
BNE.S Exit ; IF Error THEN Exit
|
||||
MOVE.L A0,aPBPtr ; save PBPtr in D7
|
||||
MOVE.L DCtlWindow(A4),A1 ; get window rec pointer
|
||||
LEA aString(A1),A1 ; address of string buffer
|
||||
MOVE.L A1,ioVNPtr(A0) ; ioVNPtr = Volume Name
|
||||
_HGetVInfo ; _GetVolInfo info -> A0^
|
||||
|
||||
MOVE.L aPBPtr,A0
|
||||
MOVE.L ioVAlBlkSiz(A0),D1 ; block size in D1
|
||||
MOVE.W ioVFrBlk(A0),D2 ; free blocks in D2
|
||||
MOVE.W D1,D0 ; 32 bit * 16 bit multiply
|
||||
MULU.W D2,D0 ; right half of size
|
||||
SWAP D1
|
||||
MOVE.W D1,D3
|
||||
MULU.W D2,D3 ; left half of size
|
||||
SWAP D3
|
||||
ADD.L D3,D0 ; total bytes free on vol
|
||||
JSR PrintNum ; write # bytes free
|
||||
|
||||
PEA #' free on '
|
||||
_DrawString
|
||||
MOVE.W #4,-(SP) ; underlined
|
||||
_TextFace
|
||||
MOVE.L aPBPtr,A0
|
||||
MOVE.L ioVNPtr(A0),-(SP) ; offset for volName
|
||||
_DrawString
|
||||
|
||||
MOVE.L aPBPtr,A0 ; free the memory
|
||||
_DisposPtr
|
||||
|
||||
Exit
|
||||
RTS
|
||||
|
||||
***************************** SUBROUTINES ****************************
|
||||
|
||||
PrintNum
|
||||
|
||||
; Binary integer to be drawn at CurPenPos in D0 on entry
|
||||
; number drawn in plain text, bolding restored afterwords
|
||||
|
||||
MOVE.L D0,D6 ; for safe keeping
|
||||
CLR.W -(SP) ; plain text
|
||||
_TextFace
|
||||
MOVE.L D6,D0 ; and back again
|
||||
MOVE.L DCtlWindow(A4),A0 ; get window rec pointer
|
||||
LEA aNumStr(A0),A0 ; get buffer address
|
||||
CLR.W -(SP) ; selector for NumToString
|
||||
_Pack7 ; Binary-Decimal Package
|
||||
MOVE.L A0,-(SP) ; push the pointer to the str
|
||||
_DrawString
|
||||
MOVE.W #1,-(SP) ; bold text restored
|
||||
_TextFace
|
||||
RTS
|
||||
|
||||
|
||||
******************************* DATA AREA **********************************
|
||||
|
||||
theWindow DC.W 322,10,338,500 ; window top,left,bottom,right
|
||||
|
||||
ENDWITH
|
||||
END
|
||||
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0065 6D6F 7279 2E61" /* ..Monaco.emory.a */
|
||||
$"0022 0000 0045 1C84 0080 000E 0094 0056" /* ."...E.........V */
|
||||
$"FF00 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,987 @@
|
|||
*
|
||||
* Apple Macintosh Developer Technical Support
|
||||
*
|
||||
* MultiFinder-Aware Simple Sample Application
|
||||
*
|
||||
* Sample
|
||||
*
|
||||
* Sample.a - Assembler Source
|
||||
*
|
||||
* Copyright © Apple Computer, Inc. 1989-1990
|
||||
* All rights reserved.
|
||||
*
|
||||
* Versions:
|
||||
* 1.00 08/88
|
||||
* 1.01 11/88
|
||||
* 1.02 04/89 MPW 3.1
|
||||
* 1.03 02/90 MPW 3.2
|
||||
*
|
||||
* Components:
|
||||
* Sample.a Feb. 1, 1990
|
||||
* Sample.inc1.a Feb. 1, 1990
|
||||
* SampleMisc.a Feb. 1, 1990
|
||||
* Sample.r Feb. 1, 1990
|
||||
* Sample.h Feb. 1, 1990
|
||||
* Sample.make Feb. 1, 1990
|
||||
*
|
||||
* Sample is an example application that demonstrates how to
|
||||
* initialize the commonly used toolbox managers, operate
|
||||
* successfully under MultiFinder, handle desk accessories,
|
||||
* and create, grow, and zoom windows.
|
||||
*
|
||||
* It does not by any means demonstrate all the techniques
|
||||
* you need for a large application. In particular, Sample
|
||||
* does not cover exception handling, multiple windows/documents,
|
||||
* sophisticated memory management, printing, or undo. All of
|
||||
* these are vital parts of a normal full-sized application.
|
||||
*
|
||||
* This application is an example of the form of a Macintosh
|
||||
* application; it is NOT a template. It is NOT intended to be
|
||||
* used as a foundation for the next world-class, best-selling,
|
||||
* 600K application. A stick figure drawing of the human body may
|
||||
* be a good example of the form for a painting, but that does not
|
||||
* mean it should be used as the basis for the next Mona Lisa.
|
||||
*
|
||||
* We recommend that you review this program or TESample before
|
||||
* beginning a new application.
|
||||
|
||||
* This example program is to be considered an introduction to coding in the
|
||||
* MPW Assembly language. This sample program demonstrates the use of RECORD,
|
||||
* PROC, WITH, MACROs, IMPORT, and other coding practices used by MPW. Although
|
||||
* this code will not be compatible with other assemblers, there is enough code
|
||||
* contained within the procedures that demonstrate 68000 programming on the Mac.
|
||||
|
||||
* The main purpose of this example is to have an easy to understand sample
|
||||
* assembly program that follows very closely the same sample program available
|
||||
* in Pascal and C. Programmers not familiar with assembly code should refer to
|
||||
* these high level versions and follow the procedures while examining the assembly
|
||||
* code. This is a great way to learn how to read assembly listings, and that is
|
||||
* the first step in using a debugger.
|
||||
|
||||
* Stack frame strategy:
|
||||
* -----------------------------------------------
|
||||
* Here is an example of a typical stack frame. An example of the stack frame
|
||||
* RECORD is shown. Using this strategy for procedures makes life much easier
|
||||
* while writing assembly code. The procedure outlined in Pascal here is
|
||||
* followed by the same outline in assembly.
|
||||
|
||||
* PROCEDURE MyProcedure (Param1: type, Param2: type, ParamN: type) Result1: type;
|
||||
|
||||
* VAR Local1: type;
|
||||
* Local2: type;
|
||||
* LocalN: type;
|
||||
|
||||
|
||||
* MyProcedure PROC EXPORT ; any source file can use this routine
|
||||
|
||||
* define registors that need to be saved as EQUATES (typically A3-A7 and D4-D7)
|
||||
|
||||
* StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
* Result1 DS.{size} ; function's result returned to caller
|
||||
* ParamBegin EQU * ; start parameters after this point
|
||||
* Param1 DS.{size} ; the first parameter on the stack
|
||||
* Param2 DS.{size} ; rest of the parameters passed by caller
|
||||
* ParamN DS.{size} ; the last parameter passed by caller
|
||||
* ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
* RetAddr DS.L 1 ; place holder for return address
|
||||
* A6Link DS.L 1 ; place holder for A6 link
|
||||
* Local1 DS.{size} ; a local variable for this procedure only
|
||||
* Local2 DS.{size} ; other local variables for this procedure
|
||||
* LocalN DS.{size} ; the last local variable
|
||||
* LocalSize EQU * ; size of all the local variables
|
||||
* ENDR
|
||||
|
||||
* WITH StackFrame ; cover our local stack frame
|
||||
* LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
* save registors trashed by this routine
|
||||
|
||||
* # # INSERT YOUR CODE HERE # #
|
||||
|
||||
* Exit restore registors trashed by this routine
|
||||
* UNLK A6 ; destroy the link
|
||||
* MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
* ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
* JMP (A0) ; return to the caller
|
||||
* DbgInfo MyProcedure ; this name will appear in the debugger
|
||||
* ENDP
|
||||
|
||||
* The Macro DbgInfo is optional. I prefer to use it, since it aids in
|
||||
* debugging. There are more macros in the "AStructMacs" folder of MPW. Put on
|
||||
* a pot of coffee and take a look at them and the Sample program that uses these
|
||||
* macros. There is one macro in particular that builds the entire stack frame
|
||||
* structure as outlined above, including the debug info.
|
||||
|
||||
* Segmentation strategy:
|
||||
* -----------------------------------------------
|
||||
* This program consists of three segments. Main contains most of the code.
|
||||
* Initialize contains code that is only used once, during startup, and can be
|
||||
* unloaded after the program starts. %A5Init is automatically created by the
|
||||
* Linker to initialize globals and constants, and is unloaded right away.
|
||||
|
||||
* SetPort strategy:
|
||||
* -----------------------------------------------
|
||||
* Tool box routines do not change the current port. In spite of this, in this
|
||||
* program we use a strategy of calling SetPort whenever we want to draw or
|
||||
* make calls which depend on the current port. This makes us less vulnerable
|
||||
* to bugs in other software which might alter the current port (such as the
|
||||
* bug (feature?) in many desk accessories which change the port on OpenDeskAcc).
|
||||
* Hopefully, this also makes the routines from this program more self-contained,
|
||||
* since they don't depend on the current port setting.
|
||||
|
||||
* ================================================
|
||||
* -------------- INCLUDES SECTION ----------------
|
||||
* ================================================
|
||||
|
||||
PRINT PUSH,OFF ; don't print any of this stuff
|
||||
|
||||
INCLUDE 'ToolEqu.a'
|
||||
INCLUDE 'Traps.a'
|
||||
INCLUDE 'PackMacs.a'
|
||||
INCLUDE 'QuickEqu.a'
|
||||
INCLUDE 'SysEqu.a'
|
||||
INCLUDE 'Sample.inc1.a' ; all our macros and data templates
|
||||
|
||||
PRINT POP ; restore the PRINT options
|
||||
|
||||
|
||||
* ================================================
|
||||
* --------- DATA STORAGE ALLOCATION ------------
|
||||
* ================================================
|
||||
* Global data storage. All global memory is allocated here. The
|
||||
* Linker will load all global data offset from A5, and the Asm knows this.
|
||||
* Therefore, no reference to (A5) is required in the code. Hooray!
|
||||
* Here we declare two data structures using our templates defined previously.
|
||||
* They must be EXPORTed here for other files that need to IMPORT them.
|
||||
|
||||
EXPORT (QD,G):DATA
|
||||
|
||||
QD DS MyQDGlobals ; QuickDraw's globals
|
||||
G DS AppGlobals ; application's globals
|
||||
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE Initialize;
|
||||
* ================================================
|
||||
* Set up the whole world, including global variables, Toolbox managers, and menus.
|
||||
* Check to see if a given trap is implemented. The recommended approach to see if
|
||||
* a trap is implemented is to see if the address of the trap routine is the same
|
||||
* as the address of the Unimplemented trap. We also create our one application
|
||||
* window at this time. Since window storage is non-relocateable, how and when to
|
||||
* allocate space for windows is very important so that heap fragmentation does not
|
||||
* occur. Because Sample has only one window and it is only disposed when the
|
||||
* application quits, we will allocate its space here, before anything that might
|
||||
* be a locked relocatable object gets into the heap. This way, we can force its
|
||||
* storage to be in the lowest memory available in the heap. Window storage can
|
||||
* differ widely amongst applications depending on how many windows are created
|
||||
* and disposed. If a failure occurs here, we will consider that the application
|
||||
* is in such bad shape that we should just exit. Your error handling may differ,
|
||||
* but the checks should still be made.
|
||||
|
||||
* If an error is detected, instead of merely doing an ExitToShell, which leaves
|
||||
* the user without much to go on, we call AlertUser, which puts up a simple alert
|
||||
* that just says an error occurred and then calls ExitToShell. In the interests
|
||||
* of keeping things simple, the alert does not state the specific cause of the error,
|
||||
* but a more informative alert would be appropriate for more sophisticated applications.
|
||||
* Since there is no other cleanup needed at this point if an error is detected, this
|
||||
* form of error- handling is acceptable. If more sophisticated error recovery is needed,
|
||||
* a signal mechanism, such as is provided by Signals, can be used.
|
||||
|
||||
* Something worth noting here. Since the AlertUser routine is in a different segment,
|
||||
* we have to use a Jump instruction to get there. In other words, we must go through the
|
||||
* jump table. This causes extra test and branch instructions to get over the JMP AlertUser.
|
||||
|
||||
SEG 'Initialize' ; case sensitive
|
||||
Initialize PROC ; Initialize everything
|
||||
|
||||
CountReg EQU D4 ; temporary registor to count loops
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
CurMBar DS.L 1 ; local handle to our menubar
|
||||
TheEvent DS EventRecord ; local copy of the event record
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
IMPORT GoGetRect,AlertUser,SysEnvirons, \
|
||||
TrapAvailable ; linked in with Interface.o
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVEM.L CountReg,-(SP) ; save the current registor values
|
||||
MOVE.W #False,G.InBackground ; we start out in the foreground
|
||||
MOVE.W #True,G.Stopped ; we'll start with the red light on
|
||||
|
||||
* ------------- INITIALIZE MANAGERS -------------
|
||||
|
||||
@1 PEA QD.GrafPort ; initialize all of the Managers
|
||||
_InitGraf ; please don't flush my events
|
||||
_InitFonts
|
||||
_InitWindows
|
||||
_InitMenus
|
||||
_TEInit
|
||||
CLR.L -(SP)
|
||||
_InitDialogs
|
||||
_InitCursor
|
||||
|
||||
* Call MPPOpen and ATPLoad at this point to initialize AppleTalk, if you are using it.
|
||||
* NOTE -- It is no longer necessary, and actually unhealthy, to check PortBUse and
|
||||
* SPConfig before opening AppleTalk. The drivers are capable of checking for port
|
||||
* availability themselves. This next bit of code is necessary to allow the default
|
||||
* button of our alert be outlined.
|
||||
|
||||
* ------------- WASTE THREE EVENTS -------------
|
||||
|
||||
MOVE.W #2,CountReg ; set register value to loop 3 times
|
||||
Loop CLR.W -(SP) ; space for result
|
||||
MOVE.W #EveryEvent,-(SP) ; the events we want
|
||||
PEA TheEvent(A6) ; pass a pointer to our event
|
||||
_EventAvail
|
||||
MOVE.W (SP)+,D0 ; result code
|
||||
DBF CountReg,Loop ; decrement count, if count < 0 then continue
|
||||
|
||||
* ------------- GET THE ENVIRONMENT -------------
|
||||
|
||||
CLR.W -(SP) ; create space for result
|
||||
MOVE.W #EnvironsVersion,-(SP) ; version of SysEnvirons we want
|
||||
PEA G.Mac ; the global environment record
|
||||
JSR SysEnvirons ; we can ignore any errors here,
|
||||
MOVE.W (SP)+,D0 ; SysEnvirons will fill in regardless
|
||||
MOVE.W G.Mac.MachineType,D0 ; negitive value means old ROMs
|
||||
BPL.S @2 ; 128k ROMs or better, continue on
|
||||
JMP AlertUser ; we don't want to run on 64k ROMs
|
||||
|
||||
* ------------- TEST FOR WAITNEXTEVENT -------------
|
||||
* 1.02 - Move TrapAvailable call to after SysEnvirons so that
|
||||
* we can tell in TrapAvailable if a tool trap value is out of range.
|
||||
|
||||
@2 CLR.W -(SP) ; space for result of trap test
|
||||
MOVE.W #WaitNextEvent,-(SP) ; pass the trap number of WaitNextEvent trap
|
||||
BSR TrapAvailable ; test for this trap
|
||||
MOVE.W (SP)+,G.HasWNEvent ; put the result in our global flag
|
||||
|
||||
* ------------- CHECK FOR ENOUGH MEMORY -------------
|
||||
* It is better to first check the size of the application heap against a value
|
||||
* that you have determined is the smallest heap the application can reasonably
|
||||
* work in. This number should be derived by examining the size of the heap that
|
||||
* is actually provided by MultiFinder when the minimum size requested is used.
|
||||
* The derivation of the minimum size requested from MultiFinder is described
|
||||
* in ASample.r. The check should be made because the preferred size can end up
|
||||
* being set smaller than the minimum size by the user. This extra check acts to
|
||||
* insure that your application is starting from a solid memory foundation.
|
||||
|
||||
* IF applLimit - applZone < MinHeap THEN AlertUser
|
||||
|
||||
* Next, make sure that enough memory is free for your application to run. It
|
||||
* is possible for a situation to arise where the heap may have been of required
|
||||
* size, but a large scrap was loaded which left too little memory. To check for
|
||||
* this, call PurgeSpace and compare the result with a value that you have determined
|
||||
* is the minimum amount of free memory your application needs at initialization.
|
||||
* This number can be derived several different ways. One way that is fairly
|
||||
* straightforward is to run the application in the minimum size configuration
|
||||
* as described previously. Call PurgeSpace at initialization and examine the value
|
||||
* returned. However, you should make sure that this result is not being modified
|
||||
* by the scrap's presence. You can do that by calling ZeroScrap before calling
|
||||
* PurgeSpace. Make sure to remove that call before shipping, though.
|
||||
|
||||
* The extra benefit to waiting until after the Toolbox Managers have been initialized
|
||||
* before checking memory is that we can now give the user an alert to tell him what
|
||||
* happened. Although it is possible that the memory situation could be worsened by
|
||||
* displaying an alert, MultiFinder would gracefully exit the application with
|
||||
* an informative alert if memory became critical. Here we are acting more
|
||||
* in a preventative manner to avoid future disaster from low-memory problems.
|
||||
|
||||
MOVE.L applLimit,D1 ; get pointer to ApplLimit
|
||||
MOVE.L applZone,D0 ; get pointer to ApplicZone
|
||||
SUB.L D0,D1 ; subtract the ApplicZone from ApplLimit
|
||||
CMPI.L #MinHeap,D1 ; do we have enough memory?
|
||||
BPL.S @3 ; yes we do, continue on
|
||||
JMP AlertUser ; no, report the error
|
||||
|
||||
@3 _PurgeSpace ; results will be in A0 and D0
|
||||
CMPI.L #MinSpace,D0 ; do we have enough purgeable space?
|
||||
BPL.S @4
|
||||
JMP AlertUser ; no, report the error
|
||||
|
||||
* ------------- SET UP THE TRAFFIC LIGHT WINDOW -------------
|
||||
* We will allocate our own window storage instead of letting the Window Manager
|
||||
* for two reasons. One, GetNewWindow locks the 'WIND' resource handle before calling
|
||||
* NewWindow and this can lead to heap fragmentation. Two, it takes just as much time
|
||||
* for NewWindow to get the memory as it does for us to get it.
|
||||
|
||||
@4 MOVE.L #windowSize,D0
|
||||
_NewPtr ,Clear ; create a pointer in A0 and clear memory
|
||||
CMPA.L #NIL,A0 ; check for NIL pointer (result in D0)
|
||||
BNE.S @5 ; must have been a valid pointer
|
||||
JMP AlertUser ; couldn't get memory, report error
|
||||
|
||||
@5 CLR.L -(SP) ; create space for result
|
||||
MOVE.W #rWindow,-(SP) ; out window resource definition
|
||||
MOVE.L A0,-(SP) ; our window record storage
|
||||
MOVE.L #-1,-(SP) ; make it on top
|
||||
_GetNewWindow ; create the window
|
||||
MOVE.L (SP)+,D0 ; we're not saving our window pointer
|
||||
|
||||
* ------------- SET UP THE MENUS -------------
|
||||
|
||||
CLR.L -(SP) ; space for MenuBar handle
|
||||
MOVE.W #rMenuBar,-(SP) ; our MenuBar resource
|
||||
_GetNewMBar ; the modern way, get a MenuBar
|
||||
MOVE.L (SP),CurMBar(A6)
|
||||
_SetMenuBar
|
||||
MOVEA.L CurMBar(A6),A0 ; we're done with that handle
|
||||
_DisposHandle ; there is a result in D0
|
||||
CLR.L -(SP)
|
||||
MOVE.W #AppleMenu,-(SP)
|
||||
_GetMHandle ; put Apple menu handle on stack
|
||||
MOVE.L #'DRVR',-(SP) ; get all the DAs
|
||||
_AddResMenu
|
||||
_DrawMenuBar
|
||||
|
||||
* ------------- SET UP RECTS FOR THE LIGHTS -------------
|
||||
|
||||
CLR.W -(SP) ; space for result of GoGetRect
|
||||
MOVE.W #rStopRect,-(SP) ; pass the stop light's rect
|
||||
PEA G.StopRect ; pass the stop light's rect pointer
|
||||
BSR GoGetRect ; go get the stop light rect
|
||||
MOVE.W (SP)+,D0 ; get the result of GoGetRect
|
||||
CMPI.W #True,D0 ; did we get the RECT resource?
|
||||
BEQ.S @6 ; yes, then continue
|
||||
JMP AlertUser ; otherwise, we're having some trouble
|
||||
|
||||
@6 CLR.W -(SP) ; space for result of GoGetRect
|
||||
MOVE.W #rGoRect,-(SP) ; pass the go light's rect
|
||||
PEA G.GoRect ; pass the go light's rect pointer
|
||||
BSR GoGetRect ; go get the go light rect
|
||||
MOVE.W (SP)+,D0 ; get the result of GoGetRect
|
||||
CMPI.W #True,D0 ; did we get the RECT resource?
|
||||
BEQ.S Exit ; yes, then continue
|
||||
JMP AlertUser ; otherwise, we're having some trouble
|
||||
|
||||
Exit MOVEM.L (SP)+,CountReg ; restore the registors
|
||||
UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo Initialz ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE DoContentClick(window: WindowPtr; event: EventRecord);
|
||||
* ================================================
|
||||
* This is called when a mouse-down event occurs in the content of a window.
|
||||
* Other applications might want to call FindControl, TEClick, etc., to
|
||||
* further process the click.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
DoContentClick PROC
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
WindowPtr DS.L 1 ; passed parameter of the window pointer
|
||||
EventPtr DS.L 1 ; pointer to the event record
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
IMPORT SetLight
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVE.L WindowPtr(A6),-(SP) ; pass the window pointer
|
||||
MOVE.W G.Stopped,D0 ; get current state of the light
|
||||
EORI.W #True,D0 ; exclusive OR the current state
|
||||
MOVE.W D0,-(SP) ; pass new state to switch light
|
||||
BSR SetLight ; set the traffic light
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo DoContnt ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE DoUpdate(window: WindowPtr);
|
||||
* ================================================
|
||||
* This is called when an update event is received for a window.
|
||||
* It calls DrawWindow to draw the contents of an application window.
|
||||
* As an efficiency measure that does not have to be followed, it
|
||||
* calls the drawing routine only if the visRgn is non-empty. This
|
||||
* will handle situations where calculations for drawing or drawing
|
||||
* itself is very time-consuming.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
DoUpdate PROC
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
WindowPtr DS.L 1 ; passed parameter of the window pointer
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
IMPORT IsAppWindow,DrawWindow
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
CLR.W -(SP) ; space for result of IsAppWindow
|
||||
MOVE.L WindowPtr(A6),-(SP) ; pass the window pointer
|
||||
BSR IsAppWindow ; test if this window was ours
|
||||
MOVE.W (SP)+,D0
|
||||
CMPI.W #True,D0 ; it must be our window
|
||||
BNE.S Exit ; it wasn't our window
|
||||
|
||||
MOVE.L WindowPtr(A6),-(SP) ; update only the visible region
|
||||
_BeginUpDate ; region of the window
|
||||
CLR.W -(SP) ; space for result
|
||||
MOVEA.L WindowPtr(A6),A0 ; the window pointer
|
||||
MOVE.L visRgn(A0),-(SP) ; the window's visRgn handle
|
||||
_EmptyRgn
|
||||
MOVE.W (SP)+,D0 ; result of EmptyRgn
|
||||
CMPI.W #True,D0 ; was the visRgn empty?
|
||||
BEQ.S @1 ; yes, then no update is needed
|
||||
|
||||
MOVE.L WindowPtr(A6),-(SP)
|
||||
BSR DrawWindow ; draw the traffic lights
|
||||
|
||||
@1 MOVE.L WindowPtr(A6),-(SP) ; get pointer to window
|
||||
_EndUpdate
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo DoUpdate ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE DoActivate(window: WindowPtr; becomingActive: BOOLEAN);
|
||||
* ================================================
|
||||
* In this sample there is no other processing necessary other than what
|
||||
* the Window Manager has already done for us. This would be the place to
|
||||
* perform an activate on TextEdit records, controls, lists, update GrowIcon, etc.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
DoActivate PROC
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
WindowPtr DS.L 1 ; passed parameter of the window pointer
|
||||
Active DS.W 1 ; modifiers from the event record
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
IMPORT IsAppWindow
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
CLR.W -(SP) ; space for result of IsAppWindow
|
||||
MOVE.L WindowPtr(A6),-(SP) ; pass the window pointer
|
||||
BSR IsAppWindow ; test if this window was ours
|
||||
MOVE.W (SP)+,D0 ; get the result
|
||||
CMPI.W #True,D0 ; it must be our window
|
||||
BNE.S Exit ; it wasn't our window
|
||||
|
||||
CMPI.W #True,Active(A6) ; was it an Activate?
|
||||
BNE.S DeActivate ; no, perform a Deactivate
|
||||
|
||||
* do the activate event processing here, then "BRA.S Exit"
|
||||
|
||||
DeActivate ; do the deactivate event
|
||||
|
||||
* do the deactivate event processing here, then fall through to Exit
|
||||
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo Activate ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE DoMenuCommand(menuResult: LONGINT);
|
||||
* ================================================
|
||||
* This is called when an item is chosen from the menu bar (after calling
|
||||
* MenuSelect or MenuKey). It performs the right operation for each command.
|
||||
* It is good to have both the result of MenuSelect and MenuKey go to
|
||||
* one routine like this to keep everything organized.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
DoMenuCommand PROC
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
MenuItem DS.W 1 ; result from _MenuKey or _MenuSelect
|
||||
MenuID DS.W 1 ; caller passed a long word, ID + Item
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
Deskname DS.B 256 ; local storage for Desk Accs name
|
||||
TempPort DS.L 1 ; local storage for the current port
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
IMPORT SetLight,DoCloseWindow,Terminate
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVE.W MenuID(A6),D0 ; a nifty Pascal case-like macro
|
||||
CASE#.W (D0,IF), \
|
||||
(AppleMenu, DoAppleMenu), \
|
||||
(FileMenu, DoFileMenu), \
|
||||
(EditMenu, DoEditMenu), \
|
||||
(LightMenu, DoLightMenu)
|
||||
; add additional Menus would go here
|
||||
BRA.W Exit ; otherwise we will exit this procedure
|
||||
|
||||
* ------------- THE APPLE MENU ROUTINES -------------
|
||||
DoAppleMenu
|
||||
CMPI.W #AboutItem,MenuItem(A6) ; was it the about item?
|
||||
BNE.S @1 ; no, must be a Desk Acc
|
||||
|
||||
CLR.W -(SP) ; show the About dialog
|
||||
MOVE.W #rAboutAlert,-(SP) ; resource for alert dialog
|
||||
CLR.L -(SP) ; no filter procedure used here
|
||||
_Alert ; read the resource and display it
|
||||
MOVE.W (SP)+,D0 ; I don't care which item is was
|
||||
BRA.W Exit ; all done with with Apple menu
|
||||
|
||||
@1 PEA TempPort(A6) ; open a desk accessory
|
||||
_GetPort ; save the current port
|
||||
CLR.L -(SP) ; space for result of GetMHandle
|
||||
MOVE.W #AppleMenu,-(SP)
|
||||
_GetMHandle ; put Apple menu on stack
|
||||
MOVE.W MenuItem(A6),-(SP) ; and here's the MenuItem
|
||||
PEA DeskName(A6) ; now tell me the DA's name
|
||||
_GetItem
|
||||
CLR.W -(SP) ; space for OpenDeskAcc result
|
||||
PEA DeskName(A6)
|
||||
_OpenDeskAcc ; open that puppy
|
||||
MOVE.W (SP)+,D0 ; result
|
||||
MOVE.L TempPort(A6),-(SP) ; restore the port
|
||||
_SetPort
|
||||
BRA.S Exit
|
||||
|
||||
* ------------- THE FILE MENU ROUTINES -------------
|
||||
DoFileMenu
|
||||
MOVE.W MenuItem(A6),D0 ; test the MenuItem
|
||||
Case#.W (D0,IF), \
|
||||
(CloseItem, FileClose), \
|
||||
(QuitItem, FileQuit)
|
||||
BRA.S Exit ; add additional menus here
|
||||
FileClose
|
||||
CLR.L -(SP) ; bug fix, didn't clear space for result -JDR 2/27/89
|
||||
_FrontWindow
|
||||
BSR DoCloseWindow ; close the window
|
||||
BRA.S Exit
|
||||
|
||||
FileQuit BSR Terminate ; let's get out of here
|
||||
BRA.S Exit ; Terminate may return if user cancels
|
||||
|
||||
* ------------- THE EDIT MENU ROUTINES -------------
|
||||
DoEditMenu
|
||||
CLR.W -(SP) ; system will handle editing of desk accs.
|
||||
MOVE.W MenuItem(A6),-(SP) ; get the MenuItem
|
||||
SUBQ.W #1,(SP) ; SystemEdit is off by one
|
||||
_SysEdit
|
||||
MOVE.B (SP)+,D0 ; drop result from SystemEdit
|
||||
BRA.S Exit ; we don't have anything to edit
|
||||
|
||||
* ------------- THE LIGHT MENU ROUTINES -------------
|
||||
DoLightMenu
|
||||
MOVE.W MenuItem(A6),D0 ; test the MenuItem
|
||||
Case#.W (D0,IF), \
|
||||
(StopItem, StopSelect), \
|
||||
(GoItem, GoSelect)
|
||||
BRA.S Exit ; add additional menus here
|
||||
|
||||
StopSelect CLR.L -(SP) ; bug fix, didn't clear space for result -JDR 2/27/89
|
||||
_FrontWindow ; pass our window, we only have one
|
||||
MOVE.W #TRUE,-(SP) ; pass true to set stop light on
|
||||
BSR SetLight ; switch the traffic light
|
||||
BRA.S Exit
|
||||
|
||||
GoSelect CLR.L -(SP) ; bug fix, didn't clear space for result -JDR 2/27/89
|
||||
_FrontWindow ; pass our window, we only have one
|
||||
MOVE.W #FALSE,-(SP) ; pass false to set stop light off
|
||||
BSR SetLight ; switch the traffic light
|
||||
|
||||
Exit CLR.W -(SP)
|
||||
_HiLiteMenu ; unhilite all Menus
|
||||
UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo DoMenuCm ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE DoMouseDown(Event: EventRecord);
|
||||
* ================================================
|
||||
* Handle all of the MouseDown events.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
DoMouseDown PROC
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
EventPtr DS.L 1 ; pointer to current event
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
WindowPtr DS.L 1 ; local Window pointer variable
|
||||
Where DS.L 1 ; local variable where the click was
|
||||
NewGrowRect DS Rect ; local rect variable for SizeWindow
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
IMPORT AdjustMenus,DoContentClick
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVEA.L EventPtr(A6),A0 ; event record only needed by SystemClick
|
||||
MOVE.L evtMouse(A0),Where(A6) ; make a local copy of the mouse location
|
||||
|
||||
CLR.W -(SP) ; space for FindWindow result
|
||||
MOVE.L Where(A6),-(SP) ; the mouse point
|
||||
PEA WindowPtr(A6) ; a local variable
|
||||
_FindWindow ; put the result in a register
|
||||
MOVE.W (SP)+,D0 ; a nifty Pascal case-like macro
|
||||
Case#.W (D0,IF), \
|
||||
(InMenuBar, MenuEvent), \
|
||||
(InSysWindow, SystemEvent), \
|
||||
(InContent, Content), \
|
||||
(InDrag, Drag)
|
||||
; add additional routines here
|
||||
BRA.S Exit ; otherwise we will exit this procedure
|
||||
|
||||
* ------------- THE DESK ACCS EVENT -------------
|
||||
MenuEvent
|
||||
BSR.W AdjustMenus
|
||||
CLR.L -(SP) ; space for MenuSelect
|
||||
MOVE.L Where(A6),-(SP) ; Mouse coordinates
|
||||
_MenuSelect ; pass MenuSelect's result
|
||||
BSR DoMenuCommand ; go do the menu and return
|
||||
BRA.S Exit
|
||||
|
||||
* ------------- THE DESK ACCS EVENT -------------
|
||||
SystemEvent
|
||||
MOVE.L EventPtr(A6),-(SP) ; get EventRecord and WindowPtr
|
||||
MOVE.L WindowPtr(A6),-(SP) ; pass the window pointer and...
|
||||
_SystemClick ; let the system handle it
|
||||
BRA.S Exit
|
||||
|
||||
* ------------- THE CONTENT EVENT -------------
|
||||
Content
|
||||
CLR.L -(SP) ; was our window in front?
|
||||
_FrontWindow ; get front window's pointer
|
||||
MOVE.L (SP)+,D0
|
||||
CMP.L WindowPtr(A6),D0 ; was it in the front window?
|
||||
BNE.S @1 ; no, then just select window
|
||||
|
||||
MOVE.L WindowPtr(A6),-(SP) ; pass the window pointer
|
||||
MOVE.L EventPtr(A6),-(SP) ; pass a pointer to the event
|
||||
BSR DoContentClick ; do a click in content region
|
||||
BRA.S Exit
|
||||
|
||||
@1 MOVE.L WindowPtr(A6),-(SP) ; only select this window
|
||||
_SelectWindow ; and take no further action
|
||||
BRA.S Exit
|
||||
|
||||
* ------------- THE DRAG A WINDOW EVENT -------------
|
||||
Drag
|
||||
MOVE.L WindowPtr(A6),-(SP) ; pass Window Pointer
|
||||
MOVE.L Where(A6),-(SP) ; Mouse coordinates and boundary
|
||||
PEA QD.Screenbits.bounds
|
||||
_DragWindow ; drag it the screen's boundary
|
||||
|
||||
Exit
|
||||
UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo MouseDwn ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE DoEvent(event: EventRecord);
|
||||
* ================================================
|
||||
* Do the right thing for an event. Determine what kind of event it is,
|
||||
* and call the appropriate routines.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
DoEvent PROC
|
||||
|
||||
ModifyReg EQU D4 ; we'll use this register locally
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start listing parameters here
|
||||
EventPtr DS.L 1 ; pointer to current event
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
TheEvent DS EventRecord ; local copy of the event record
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
IMPORT DoMouseDown,DrawWindow, \
|
||||
AdjustMenus,IsAppWindow,\
|
||||
DoUpdate,DoActivate
|
||||
|
||||
WITH StackFrame,TheEvent ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
MOVEM.L ModifyReg,-(SP) ; save this register before using it
|
||||
|
||||
MOVEA.L EventPtr(A6),A0 ; pointer of event passed by caller
|
||||
LEA TheEvent(A6),A1 ; pointer to local variable TheEvent
|
||||
MOVE.L #evtBlkSize,D0 ; size of an event record
|
||||
_BlockMove ; we now have a local copy of the event
|
||||
|
||||
MOVE.W Modify(A6),ModifyReg ; a nifty Pascal case-like macro
|
||||
MOVE.W What(A6),D0 ; get the event number
|
||||
Case# (D0,Exit), \ ; if not an event we support, then exit
|
||||
, \ ; 0 Null (not used)
|
||||
MouseDown, \ ; 1 Mouse down
|
||||
, \ ; 2 Mouse up (not used)
|
||||
KeyDown, \ ; 3 Key down
|
||||
, \ ; 4 Key up (not used)
|
||||
KeyDown, \ ; 5 Auto key
|
||||
Update, \ ; 6 Update
|
||||
Disk, \ ; 7 Disk inserted
|
||||
Activate, \ ; 8 Activate/Deactivate
|
||||
, \ ; 9 (not used)
|
||||
, \ ; 10 Network (not used)
|
||||
, \ ; 11 I/O Driver (not used)
|
||||
, \ ; 12 App1 (not used)
|
||||
, \ ; 13 App2 (not used)
|
||||
, \ ; 14 App3 (not used)
|
||||
OSEvent, ; 15 OS Event or Suspend/Resume
|
||||
|
||||
|
||||
* ------------- THE MOUSEDOWN EVENT -------------
|
||||
MouseDown
|
||||
PEA TheEvent(A6) ; pass Event pointer in case of SystemClick
|
||||
BSR DoMouseDown
|
||||
BRA Exit
|
||||
|
||||
* ------------- THE KEYDOWN EVENT -------------
|
||||
KeyDown
|
||||
BTST #CmdKey,ModifyReg ; command key?
|
||||
BEQ Exit ; no, then we're done
|
||||
BSR.W AdjustMenus ; first, adjust the menus
|
||||
CLR.L -(SP) ; space for MenuKey
|
||||
MOVE.W 2+Message(A6),-(SP) ; get the character
|
||||
_MenuKey ; is it a command?
|
||||
BSR DoMenuCommand ; handle the command and return
|
||||
BRA.S Exit
|
||||
|
||||
* ------------- THE UPDATE EVENT -------------
|
||||
Update
|
||||
MOVE.L Message(A6),-(SP) ; pass the window pointer
|
||||
BSR DoUpdate ; do the update
|
||||
BRA.S Exit
|
||||
|
||||
* ------------- THE DISK EVENT -------------
|
||||
Disk
|
||||
TST.W Message(A6) ; check for error
|
||||
BEQ.S @1 ; if none, skip
|
||||
CLR.W -(SP)
|
||||
MOVE.L #DITopLeft,-(SP)
|
||||
MOVE.L Message(A6),-(SP)
|
||||
MOVE.W #diBadMount,-(SP)
|
||||
_Pack2 ; go through disk init package
|
||||
ADDQ #2,SP ; throw away result
|
||||
@1 BRA.S Exit
|
||||
|
||||
* ------------- THE ACTIVATE/DEACTIVATE EVENT -------------
|
||||
Activate
|
||||
BTST #ActiveFlag,ModifyReg ; was it an Activate?
|
||||
BEQ.S @1 ; no, perform a Deactivate
|
||||
|
||||
MOVE.L Message(A6),-(SP) ; pass the current window pointer
|
||||
MOVE.W #True,-(SP) ; set up for an Activate event
|
||||
BSR DoActivate ; do the activate routine
|
||||
BRA.S Exit ; we're done
|
||||
|
||||
@1 MOVE.L Message(A6),-(SP) ; pass current window pointer
|
||||
MOVE.W #False,-(SP) ; set up for an Deactivate event
|
||||
BSR DoActivate ; go do the activate routine
|
||||
BRA.S Exit ; we're done
|
||||
|
||||
* ------------- THE SUSPEND/RESUME EVENT -------------
|
||||
* OSEvent is the event number of the suspend/resume and mouse-moved events sent
|
||||
* by MultiFinder. Once we determine that an event is an osEvent, we look at the
|
||||
* high byte of the message sent to determine which kind it is. To differentiate
|
||||
* suspend and resume events we check the resumeMask bit.
|
||||
|
||||
OSEvent MOVE.B Message(A6),D1 ; get high byte of Message in reg
|
||||
CMPI.B #SuspendResume,D1 ; test for message event type
|
||||
BNE.S Exit ; not a suspend/resume event
|
||||
|
||||
BTST #0,3+Message(A6) ; test bit zero in low byte of Message
|
||||
BNE.S @1 ; this is a resume event
|
||||
|
||||
MOVE.W #True,G.InBackground ; a suspend event
|
||||
CLR.L -(SP) ; bug fix, was passing Message to DoActivate -JDR 2/27/89
|
||||
_FrontWindow ; pass the front window to DoActivate -JDR 2/27/89
|
||||
MOVE.W #False,-(SP) ; pass false to cause deactivate
|
||||
BSR DoActivate ; go do the activate routine
|
||||
BRA.S Exit
|
||||
|
||||
@1 MOVE.W #False,G.InBackground ; a resume event
|
||||
CLR.L -(SP) ; bug fix, was passing Message to DoActivate -JDR 2/27/89
|
||||
_FrontWindow ; pass the front window to DoActivate -JDR 2/27/89
|
||||
MOVE.W #True,-(SP) ; pass false to cause activate
|
||||
BSR DoActivate ; go do the activate routine
|
||||
|
||||
Exit
|
||||
MOVEM.L (SP)+,ModifyReg ; restore this register after use
|
||||
UNLK A6
|
||||
MOVEA.L (SP)+,A0 ; save the caller's address
|
||||
ADDA.L #ParamSize,SP ; strip the caller's parameters
|
||||
JMP (A0)
|
||||
|
||||
DbgInfo DoEvent ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE EventLoop;
|
||||
* ================================================
|
||||
* Get the events by calling WaitNextEvent, if it's available, otherwise
|
||||
* by calling GetNextEvent. Also call AdjustCursor before doing the event.
|
||||
* After returning from handling the event, we have to make sure the cursor
|
||||
* is still adjusted proper ONLY because this application can "sleep" forever.
|
||||
|
||||
* An event record is allocated on the stack. A pointer to this event is
|
||||
* passed to "DoEvent". We loop until the user has selects "Quit" in the
|
||||
* file menu. This program will exit through the DoMenuCommand routine.
|
||||
|
||||
* 1.02 made adjustments to the event loop logic. There was a bug in calling
|
||||
* AdjustCursor at the wrong time. (it crashed under _GetNextEvent too!)
|
||||
|
||||
* If you are using modeless dialogs that have editText items,
|
||||
* you will want to call IsDialogEvent to give the caret a chance
|
||||
* to blink, even if WNE/GNE returned FALSE. However, check FrontWindow
|
||||
* for a non-NIL value before calling IsDialogEvent.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
EventLoop PROC ; any source file can use this routine
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start listing parameters here
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
TheEvent DS EventRecord ; local copy of the event record
|
||||
MouseMvdRgn DS.L 1 ; local region for MouseMoved events
|
||||
MousePos DS.L 1 ; local point for mouse position
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
IMPORT AdjustCursor,GetGlobalMouse
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
CLR.L -(SP)
|
||||
_NewRgn ; create region for AdjustCursor
|
||||
MOVE.L (SP)+,MouseMvdRgn(A6) ; save the handle to this region
|
||||
|
||||
* ------------- GET NEXT EVENT LOOP -------------
|
||||
NextEvent
|
||||
CMPI.W #True,G.HasWNEvent ; see if we can call WaitNextEvent
|
||||
BNE.S @1 ; nope, old time events
|
||||
|
||||
PEA MousePos(A6) ; here's the mouse
|
||||
BSR GetGlobalMouse ; get global coordinate
|
||||
MOVE.L MousePos(A6),-(SP) ; here's the mouse
|
||||
MOVE.L MouseMvdRgn(A6),-(SP) ; the region to change
|
||||
BSR AdjustCursor ; adjust the cursor and region
|
||||
CLR.W -(SP) ; space for result
|
||||
MOVE.W #EveryEvent,-(SP) ; the events we want
|
||||
PEA TheEvent(A6) ; pointer to the event record
|
||||
MOVE.L #SleepValue,-(SP) ; the sleeping time value
|
||||
MOVE.L MouseMvdRgn(A6),-(SP) ; the current MouseRgn
|
||||
_WaitNextEvent
|
||||
BRA.S @2 ; got an event to handle?
|
||||
|
||||
; no WaitNextEvent trap available
|
||||
@1 _SystemTask ; call SystemTask for drivers and DAs
|
||||
CLR.W -(SP) ; space for result
|
||||
MOVE.W #EveryEvent,-(SP) ; the events we want
|
||||
PEA TheEvent(A6) ; pass a pointer to our event
|
||||
_GetNextEvent
|
||||
@2 MOVE.W (SP)+,D0 ; result code
|
||||
BEQ.S NextEvent ; no event, get another one
|
||||
|
||||
GotEvent MOVE.L TheEvent.where(A6),-(SP); the mouse location
|
||||
MOVE.L MouseMvdRgn(A6),-(SP) ; the region to change
|
||||
BSR AdjustCursor ; adjust cursor BEFORE doing event
|
||||
PEA TheEvent(A6) ; pass the pointer to our event
|
||||
BSR DoEvent ; do the event and return
|
||||
|
||||
BRA.S NextEvent ; done with that event, get the next
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo EvntLoop ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* --------------- MAIN ENTRY POINT ---------------
|
||||
* ================================================
|
||||
* This is the entry point of the program. We start with data initializing
|
||||
* and then to get the System environment (SysEnvirons). We unload the
|
||||
* initialization code segment and finally get started with the EventLoop.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
StartUp MAIN ; entry point of the program
|
||||
|
||||
IMPORT _DataInit,Initialize, \
|
||||
ForceEnvirons,EventLoop
|
||||
|
||||
JSR _DataInit ; initialize those constants
|
||||
PEA _DataInit ; get rid of that segment
|
||||
_UnloadSeg
|
||||
|
||||
* If you have stack requirements that differ from the default, then you could
|
||||
* use SetApplLimit to increase StackSpace at this point, before calling MaxApplZone.
|
||||
|
||||
_MaxApplZone ; result in D0
|
||||
JSR Initialize ; get things the program set up
|
||||
PEA Initialize
|
||||
_UnloadSeg ; we're done this that segment too
|
||||
LEA EventLoop,A0 ; on your mark, get set,...
|
||||
JMP (A0) ; go into the event loop
|
||||
ENDP
|
||||
|
||||
END ; end of this source file
|
||||
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0061 6D70 6C65 2E61" /* ..Monaco.ample.a */
|
||||
$"0022 0000 0000 0000 0000 0009 8400 000C" /* .".............. */
|
||||
$"0001 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
#
|
||||
# Apple Macintosh Developer Technical Support
|
||||
#
|
||||
# MultiFinder-Aware Simple Sample Application
|
||||
#
|
||||
# Sample
|
||||
#
|
||||
# Sample.h - Rez and C Include Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1989-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions:
|
||||
# 1.00 08/88
|
||||
# 1.01 11/88
|
||||
# 1.02 04/89 MPW 3.1
|
||||
# 1.03 02/90 MPW 3.2
|
||||
#
|
||||
# Components:
|
||||
# Sample.a Feb. 1, 1990
|
||||
# Sample.inc1.a Feb. 1, 1990
|
||||
# SampleMisc.a Feb. 1, 1990
|
||||
# Sample.r Feb. 1, 1990
|
||||
# Sample.h Feb. 1, 1990
|
||||
# Sample.make Feb. 1, 1990
|
||||
#
|
||||
# Sample is an example application that demonstrates how to
|
||||
# initialize the commonly used toolbox managers, operate
|
||||
# successfully under MultiFinder, handle desk accessories,
|
||||
# and create, grow, and zoom windows.
|
||||
#
|
||||
# It does not by any means demonstrate all the techniques
|
||||
# you need for a large application. In particular, Sample
|
||||
# does not cover exception handling, multiple windows/documents,
|
||||
# sophisticated memory management, printing, or undo. All of
|
||||
# these are vital parts of a normal full-sized application.
|
||||
#
|
||||
# This application is an example of the form of a Macintosh
|
||||
# application; it is NOT a template. It is NOT intended to be
|
||||
# used as a foundation for the next world-class, best-selling,
|
||||
# 600K application. A stick figure drawing of the human body may
|
||||
# be a good example of the form for a painting, but that does not
|
||||
# mean it should be used as the basis for the next Mona Lisa.
|
||||
#
|
||||
# We recommend that you review this program or TESample before
|
||||
# beginning a new application.
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/* These #defines correspond to values defined in the Pascal source code.
|
||||
Sample.c and Sample.r include this file. */
|
||||
|
||||
/* Determining an application's minimum size to request from MultiFinder depends
|
||||
on many things, each of which can be unique to an application's function,
|
||||
the anticipated environment, the developer's attitude of what constitutes
|
||||
reasonable functionality and performance, etc. Here is a list of some things to
|
||||
consider when determining the minimum size (and preferred size) for your
|
||||
application. The list is pretty much in order of importance, but by no means
|
||||
complete.
|
||||
|
||||
1. What is the minimum size needed to give almost 100 percent assurance
|
||||
that the application won't crash because it ran out of memory? This
|
||||
includes not only things that you do have direct control over such as
|
||||
checking for NIL handles and pointers, but also things that some
|
||||
feel are not so much under their control such as QuickDraw and the
|
||||
Segment Loader.
|
||||
|
||||
2. What kind of performance can a user expect from the application when
|
||||
it is running in the minimum memory configuration? Performance includes
|
||||
not only speed in handling data, but also things like how many documents
|
||||
can be opened, etc.
|
||||
|
||||
3. What are the typical sizes of scraps [is a boy dog] that a user might
|
||||
wish to work with when lauching or switching to your application? If
|
||||
the amount of memory is too small, the scrap may get lost [will have
|
||||
to be shot]. This can be quite frustrating to the user.
|
||||
|
||||
4. The previous items have concentrated on topics that tend to cause an
|
||||
increase in the minimum size to request from MultiFinder. On the flip
|
||||
side, however, should be the consideration of what environments the
|
||||
application may be running in. There may be a high probability that
|
||||
many users with relatively small memory configurations will want to
|
||||
avail themselves of your application. Or, many users might want to use it
|
||||
while several other, possibly related/complementary applications are
|
||||
running. If that is the case, it would be helpful to have a fairly
|
||||
small minimum size.
|
||||
|
||||
So, what did we decide on Sample? First, Sample has little risk of
|
||||
running out of memory once it starts. Second, performance isn't much
|
||||
of an issue since it doesn't do much and multiple windows are not
|
||||
allowed. Third, there are no edit operations in Sample itself, so we
|
||||
just want to provide enough space for a reasonable scrap to survive
|
||||
between desk accessory launches. Lastly, Sample should intrude as little
|
||||
as possible, so the effort should be towards making it as small as possible.
|
||||
We looked at some heap dumps while the application was running under
|
||||
various partition sizes. With a size of 23K, there was approximately
|
||||
8-9K free, which is a good 'slop' factor in an application like this
|
||||
which doesn't do much, but where we'd still like the scrap to survive
|
||||
most of the time. */
|
||||
|
||||
#define kMinSize 23 /* application's minimum size (in K) */
|
||||
|
||||
/* We made the preferred size bigger than the minimum size by 12K, so that
|
||||
there would be even more room for the scrap, FKEYs, etc. */
|
||||
|
||||
#define kPrefSize 35 /* application's preferred size (in K) */
|
||||
|
||||
#define rMenuBar 128 /* application's menu bar */
|
||||
#define rAboutAlert 128 /* about alert */
|
||||
#define rUserAlert 129 /* error user alert */
|
||||
#define rWindow 128 /* application's window */
|
||||
#define rStopRect 128 /* rectangle for Stop light */
|
||||
#define rGoRect 129 /* rectangle for Go light */
|
||||
|
||||
/* kSysEnvironsVersion is passed to SysEnvirons to tell it which version of the
|
||||
SysEnvRec we understand. */
|
||||
|
||||
#define kSysEnvironsVersion 1
|
||||
|
||||
/* kOSEvent is the event number of the suspend/resume and mouse-moved events sent
|
||||
by MultiFinder. Once we determine that an event is an osEvent, we look at the
|
||||
high byte of the message sent to determine which kind it is. To differentiate
|
||||
suspend and resume events we check the resumeMask bit. */
|
||||
|
||||
#define kOSEvent app4Evt /* event used by MultiFinder */
|
||||
#define kSuspendResumeMessage 1 /* high byte of suspend/resume event message */
|
||||
#define kResumeMask 1 /* bit of message field for resume vs. suspend */
|
||||
#define kMouseMovedMessage 0xFA /* high byte of mouse-moved event message */
|
||||
|
||||
/* The following constants are used to identify menus and their items. The menu IDs
|
||||
have an "m" prefix and the item numbers within each menu have an "i" prefix. */
|
||||
|
||||
#define mApple 128 /* Apple menu */
|
||||
#define iAbout 1
|
||||
|
||||
#define mFile 129 /* File menu */
|
||||
#define iNew 1
|
||||
#define iClose 4
|
||||
#define iQuit 12
|
||||
|
||||
#define mEdit 130 /* Edit menu */
|
||||
#define iUndo 1
|
||||
#define iCut 3
|
||||
#define iCopy 4
|
||||
#define iPaste 5
|
||||
#define iClear 6
|
||||
|
||||
#define mLight 131 /* Light menu */
|
||||
#define iStop 1
|
||||
#define iGo 2
|
||||
|
||||
/* 1.01 - kTopLeft - This is for positioning the Disk Initialization dialogs. */
|
||||
|
||||
#define kDITop 0x0050
|
||||
#define kDILeft 0x0070
|
||||
|
||||
/* 1.01 - kMinHeap - This is the minimum result from the following
|
||||
equation:
|
||||
|
||||
ORD(GetApplLimit) - ORD(ApplicZone)
|
||||
|
||||
for the application to run. It will insure that enough memory will
|
||||
be around for reasonable-sized scraps, FKEYs, etc. to exist with the
|
||||
application, and still give the application some 'breathing room'.
|
||||
To derive this number, we ran under a MultiFinder partition that was
|
||||
our requested minimum size, as given in the 'SIZE' resource. */
|
||||
|
||||
#define kMinHeap 21 * 1024
|
||||
|
||||
/* 1.01 - kMinSpace - This is the minimum result from PurgeSpace, when called
|
||||
at initialization time, for the application to run. This number acts
|
||||
as a double-check to insure that there really is enough memory for the
|
||||
application to run, including what has been taken up already by
|
||||
pre-loaded resources, the scrap, code, and other sundry memory blocks. */
|
||||
|
||||
#define kMinSpace 8 * 1024
|
||||
|
||||
/* kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions. */
|
||||
|
||||
#define kExtremeNeg -32768
|
||||
#define kExtremePos 32767 - 1 /* required to address an old region bug */
|
||||
|
||||
/* these #defines are used to set enable/disable flags of a menu */
|
||||
|
||||
#define AllItems 0b1111111111111111111111111111111 /* 31 flags */
|
||||
#define NoItems 0b0000000000000000000000000000000
|
||||
#define MenuItem1 0b0000000000000000000000000000001
|
||||
#define MenuItem2 0b0000000000000000000000000000010
|
||||
#define MenuItem3 0b0000000000000000000000000000100
|
||||
#define MenuItem4 0b0000000000000000000000000001000
|
||||
#define MenuItem5 0b0000000000000000000000000010000
|
||||
#define MenuItem6 0b0000000000000000000000000100000
|
||||
#define MenuItem7 0b0000000000000000000000001000000
|
||||
#define MenuItem8 0b0000000000000000000000010000000
|
||||
#define MenuItem9 0b0000000000000000000000100000000
|
||||
#define MenuItem10 0b0000000000000000000001000000000
|
||||
#define MenuItem11 0b0000000000000000000010000000000
|
||||
#define MenuItem12 0b0000000000000000000100000000000
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0061 6D70 6C65 2E68" /* ..Monaco.ample.h */
|
||||
$"0022 0000 6D70 6C65 2E68 0061 7475 7320" /* ."..mple.h.atus */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,370 @@
|
|||
*
|
||||
* Apple Macintosh Developer Technical Support
|
||||
*
|
||||
* MultiFinder-Aware Simple Sample Application
|
||||
*
|
||||
* Sample
|
||||
*
|
||||
* Sample.inc1.a - Assembler Source
|
||||
*
|
||||
* Copyright © Apple Computer, Inc. 1989-1990
|
||||
* All rights reserved.
|
||||
*
|
||||
* Versions:
|
||||
* 1.00 08/88
|
||||
* 1.01 11/88
|
||||
* 1.02 04/89 MPW 3.1
|
||||
* 1.03 02/90 MPW 3.2
|
||||
*
|
||||
* Components:
|
||||
* Sample.a Feb. 1, 1990
|
||||
* Sample.inc1.a Feb. 1, 1990
|
||||
* SampleMisc.a Feb. 1, 1990
|
||||
* Sample.r Feb. 1, 1990
|
||||
* Sample.h Feb. 1, 1990
|
||||
* Sample.make Feb. 1, 1990
|
||||
*
|
||||
* Sample is an example application that demonstrates how to
|
||||
* initialize the commonly used toolbox managers, operate
|
||||
* successfully under MultiFinder, handle desk accessories,
|
||||
* and create, grow, and zoom windows.
|
||||
*
|
||||
* It does not by any means demonstrate all the techniques
|
||||
* you need for a large application. In particular, Sample
|
||||
* does not cover exception handling, multiple windows/documents,
|
||||
* sophisticated memory management, printing, or undo. All of
|
||||
* these are vital parts of a normal full-sized application.
|
||||
*
|
||||
* This application is an example of the form of a Macintosh
|
||||
* application; it is NOT a template. It is NOT intended to be
|
||||
* used as a foundation for the next world-class, best-selling,
|
||||
* 600K application. A stick figure drawing of the human body may
|
||||
* be a good example of the form for a painting, but that does not
|
||||
* mean it should be used as the basis for the next Mona Lisa.
|
||||
*
|
||||
* We recommend that you review this program or TESample before
|
||||
* beginning a new application.
|
||||
|
||||
* ----------- DEBUGGING INFORMATION -------------
|
||||
* This is used as a global switch to turn off the generation of debugging information.
|
||||
* The MACRO "DbgInfo" will generate this debugging information if set to 1.
|
||||
|
||||
DebuggerInfo EQU 1
|
||||
|
||||
|
||||
* ================================================
|
||||
* -------- MACRO DEFINITIONS SECTION ----------
|
||||
* ================================================
|
||||
|
||||
* ------------- GENERATE A PASCAL "CASE" OR "IF" SEQUENCE -------------
|
||||
* The following macro is used to generate a branch based on an index value
|
||||
* in a D-register with a value from 0 to N. The branch is through a table
|
||||
* of relative addresses also generated by this macro. The macro is called
|
||||
* in one of two forms as follows:
|
||||
|
||||
* {Form #1} Case# (Dreg,Default),case0,case1,...caseN
|
||||
* {Form #2} Case#.<size> (Dreg,IF),(cst0,case0),...,(cstN,caseN)
|
||||
|
||||
* In Form #1, the "Default" specifies a label for any omitted case labels not
|
||||
* specified explicitly. The "case0", "case1",..."caseN" are case labels
|
||||
* identifying the various cases to be processed. A case label may be omitted,
|
||||
* in which case the "Default" is used. The "Default" may also be omitted, but
|
||||
* in that case all case labels must be specified. If there are fewer case labels
|
||||
* than there are cases, but there are N possible values for the case index, the
|
||||
* proper number of trailing commas must be supplied to generate the defaults.
|
||||
|
||||
* In Form #2, the default is specified as the word "IF". In this form the macro
|
||||
* generates a set of compares (CMPI's) and branches (BEQ) for each specified
|
||||
* case (there is no implicit default). Each case is a constant/label pair.
|
||||
* The constant is compared (CMPI.W) and an branch is done (BEQ) to the case if
|
||||
* the Dreg equals the constant. A size may be specified for all the branches
|
||||
* as a <size> attribute to the Case# call itself. This must either be an "S"
|
||||
* or "W" to generate BEQ.S's or BEQ.W's. The default is for "S".
|
||||
|
||||
MACRO
|
||||
Case#.&Size &IdxDef
|
||||
PRINT Push,NoMDir ; only list generated code
|
||||
LCLA &i ; index to macro parameters
|
||||
LCLA &n ; total number of macro parameters
|
||||
LCLC &Dreg,&Def ; the Dreg and Default parameters
|
||||
LCLC &sz ; the <size> value
|
||||
|
||||
&Dreg SETC &IdxDef[1] ; pick off 1st opnd of sublist
|
||||
&Def SETC &IdxDef[2] ; pick off 2nd opnd of sublist
|
||||
&n SETA &Nbr(&Syslist) ; done for efficiency
|
||||
&i SETA 2 ; cases start at 2nd parameter
|
||||
|
||||
IF &UpCase(&Def) <> 'IF' THEN
|
||||
.* Create the jump table and the index value
|
||||
* -----------------------------------------------
|
||||
ADD &Dreg,&Dreg
|
||||
MOVE Case&SysNdx(&Dreg),&Dreg
|
||||
JMP Case&SysNdx(&Dreg)
|
||||
|
||||
Case&SysNdx
|
||||
WHILE &i <= &n DO ; process each case label
|
||||
IF &SysList[&i] <> '' THEN
|
||||
DC.W &SysList[&i]-Case&SysNdx
|
||||
ELSE
|
||||
DC.W &Def-Case&SysNdx
|
||||
ENDIF
|
||||
&i: SETA &i+1 ; count off parameter
|
||||
ENDWHILE
|
||||
ELSE ; process (Cst,lbl) pairs
|
||||
|
||||
.* Create a series of CMPI and BEQ instructions
|
||||
* -----------------------------------------------
|
||||
&Sz: SETC &Default(&Size, 'S') ; setup size attribute
|
||||
WHILE &i <= &n DO ; process each (Cst,lbl) pair
|
||||
CMPI #&SysList[&i,1],&Dreg
|
||||
BEQ.&Sz &SysList[&i,2]
|
||||
&i: SETA &i+1 ; count off parameter
|
||||
ENDWHILE
|
||||
ENDIF
|
||||
|
||||
PRINT Pop ; restore original print status
|
||||
ENDM
|
||||
|
||||
|
||||
* ------------- GENERATE DEBUGGER SYMBOL INFORMATION -------------
|
||||
* This Macro will generate information for the debugger to read and display
|
||||
* as its module name. This aids in debugging Asm code while looking at it
|
||||
* in the debugger. This macro can only work if called at the end of stack
|
||||
* frame. The appearance of the Macro statement in the source code must occur
|
||||
* immediately after the final "JMP (A0)" or "RTS" instruction following the UNLINK.
|
||||
* Spaces may be included in the name, but no quotes are allowed.
|
||||
|
||||
* {Form #1} DbgInfo ModName
|
||||
* {Form #2} DbgInfo.New Really Long Module Name For MacsBug 6.0
|
||||
|
||||
* There are now two naming conventions used in MacsBug, Form #1 is the older MacsBug,
|
||||
* or TMON, and Form #2 is the newer MacsBug 6.0. The older method would only
|
||||
* allow for a fixed length of eight characters. If a shorter name is passed to
|
||||
* this Macro, it will extend the length to 8 chars with trailing spaces.
|
||||
* MacsBug 6.0 will now allow for a variable length C type string. This Macro will
|
||||
* create the proper DC statements and takes into account word alignment issues.
|
||||
|
||||
|
||||
MACRO
|
||||
DbgInfo.&Opt &ModName# ; the name to be used in the Debugger
|
||||
PRINT Push,NoMDir ; Only list generated code
|
||||
LCLC &DbgName# ; name to generate for MacsBug
|
||||
LCLC &DbgTemp ; temporary name variable
|
||||
LCLC &New ; variable used to test old vs. new
|
||||
LCLC &S ; variable used to save PRINT state
|
||||
|
||||
IF DebuggerInfo THEN ; do we want debugging info?
|
||||
IF &ModName# ≠ '' THEN ; did we get a module name?
|
||||
&New: SETC &UpCase(&Opt) ; make option all upper case
|
||||
IF (&New = 'NEW') THEN ; do we want new style?
|
||||
|
||||
.* Create the new MacsBug naming convention
|
||||
* -----------------------------------------------
|
||||
&DbgTemp: SETC &ModName# ; generate new type symbols
|
||||
IF &Len(&ModName#) < 32 THEN ; if module name < 32 chars
|
||||
IF &Len(&ModName#) // 2 = 0 THEN ; add space if even so that...
|
||||
&DbgTemp: SETC &Concat(&ModName#,' ') ; string length plus length byte...
|
||||
ENDIF ; will align to word boundary
|
||||
&DbgName#: SETC &Concat(&Chr($80 + &Len(&ModName#)), &DbgTemp)
|
||||
ELSE ; Length > 32 characters
|
||||
IF &Len(&ModName#) // 2 = 1 THEN ; add space if length is odd
|
||||
&DbgTemp: SETC &Concat(&ModName#,' ')
|
||||
ENDIF
|
||||
&DbgName#: SETC &Concat(&Chr($80), &Chr(&Len(&ModName#)), &DbgTemp)
|
||||
ENDIF
|
||||
ELSE ; make it the older style
|
||||
|
||||
.* Create the older MacsBug naming convention
|
||||
* -----------------------------------------------
|
||||
IF &Len(&ModName#) < 8 THEN ; if module name < 8 chars
|
||||
&DbgName#: SETC &Concat(&ModName#,' ') ; add at least 7 spaces
|
||||
&DbgName#: SETC &Concat(&Chr($80 + &ORD(&SubStr(&DbgName#,1,1))), &SubStr(&DbgName#,2,7))
|
||||
ELSE ; there are at least 8 chars
|
||||
&DbgName#: SETC &Concat(&Chr($80 + &ORD(&SubStr(&ModName#,1,1))), &SubStr(&ModName#,2,7))
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
.* Create the DC.B with the debugger name, and include the NULs if new MacsBug option
|
||||
* -----------------------------------------------
|
||||
&S: SETC &Setting('STRING') ; preserve STRING status
|
||||
IF &S ≠ 'ASIS' THEN ; only change it if not already ASIS
|
||||
STRING ASIS
|
||||
DC.B '&DbgName#'
|
||||
IF (&New = 'NEW') THEN
|
||||
DC.W 0 ; fake literal size for new MacsBug
|
||||
ENDIF
|
||||
STRING &S
|
||||
ELSE
|
||||
DC.B '&DbgName#'
|
||||
IF (&New = 'NEW') THEN
|
||||
DC.W 0 ; fake literal size for new MacsBug
|
||||
ENDIF
|
||||
ENDIF
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
PRINT Pop ; restore original print status
|
||||
ENDM
|
||||
|
||||
|
||||
* ================================================
|
||||
* --------------- EQUATE SECTION ---------------
|
||||
* ================================================
|
||||
|
||||
* Some various EQUATES we'll use throughout the program.
|
||||
* -----------------------------------------------
|
||||
False EQU 0 ; the value of False
|
||||
True EQU $0100 ; and you thought True = 1, HA!
|
||||
NIL EQU 0 ; a NIL pointer to test against
|
||||
|
||||
ToolTrapBit EQU 11 ; this bit is on for Tool traps
|
||||
WaitNextEvent EQU $A860 ; the WaitNextEvent trap number
|
||||
Unimplemented EQU $A89F ; the Unimplemented trap number
|
||||
EnvironsVersion EQU 1 ; this is the version of the SysEnvirons we want
|
||||
SleepValue EQU $7FFFFFFF ; the sleeping time ($7FFFFFFF = MaxLongInt)
|
||||
SuspendResume EQU 1 ; the suspend/resume event number of an OSEvent
|
||||
NoEvents EQU 0 ; no events mask
|
||||
ExtremeNeg EQU -32768 ; for wide open rects and regions, see AdjustCursor
|
||||
ExtremePos EQU 32767-1 ; -1 is because of a bug in regions, see AdjustCursor
|
||||
|
||||
* This is the minimum result from the following equation:
|
||||
|
||||
* applLimit - applZone = minimum heap size
|
||||
|
||||
* for the application to run. It will insure that enough memory will
|
||||
* be around for reasonable-sized scraps, FKEYs, etc. to exist with the
|
||||
* application, and still give the application some 'breathing room'.
|
||||
* To derive this number, we ran under a MultiFinder partition that was
|
||||
* our requested minimum size, as given in the 'SIZE' resource.
|
||||
|
||||
MinHeap EQU 21*1024 ; minimum heap size in bytes
|
||||
|
||||
* This is the minimum exceptable result from PurgeSpace, when called
|
||||
* at initialization time, for the application to run. This number acts
|
||||
* as a double-check to insure that there really is enough memory for the
|
||||
* application to run, including what has been taken up already by
|
||||
* pre-loaded resources, the scrap, code, and other sundry memory blocks.
|
||||
|
||||
MinSpace EQU 8*1024 ; minimum stack space in bytes
|
||||
|
||||
|
||||
* The following equates use for resources. That's why they have a "r" in front.
|
||||
* -----------------------------------------------
|
||||
rMenuBar EQU 128 ; application's menu bar
|
||||
rUserAlert EQU 129 ; error alert for user
|
||||
rWindow EQU 128 ; application's window
|
||||
rAboutAlert EQU 128 ; about alert
|
||||
rStopRect EQU 128 ; rectangle for Stop light
|
||||
rGoRect EQU 129 ; rectangle for Go light
|
||||
|
||||
|
||||
* The following equates are for menu definitions, obviously.
|
||||
* -----------------------------------------------
|
||||
AppleMenu EQU 128 ; Apple menu
|
||||
AboutItem EQU 1
|
||||
|
||||
FileMenu EQU 129 ; File menu
|
||||
NewItem EQU 1
|
||||
OpenItem EQU 2
|
||||
CloseItem EQU 4
|
||||
SaveItem EQU 5
|
||||
SaveAsItem EQU 6
|
||||
RevertItem EQU 7
|
||||
PageSetupItem EQU 9
|
||||
PrintItem EQU 10
|
||||
QuitItem EQU 12
|
||||
|
||||
EditMenu EQU 130 ; Edit menu
|
||||
UndoItem EQU 1
|
||||
CutItem EQU 3
|
||||
CopyItem EQU 4
|
||||
PasteItem EQU 5
|
||||
ClearItem EQU 6
|
||||
|
||||
LightMenu EQU 131 ; Light menu
|
||||
StopItem EQU 1
|
||||
GoItem EQU 2
|
||||
|
||||
* -----------------------------------------------
|
||||
DITopLeft EQU $00500070 ; position of Disk Init dialogs
|
||||
|
||||
* ================================================
|
||||
* ---------------- RECORD TYPES ----------------
|
||||
* ================================================
|
||||
* This section is declaring record structures. These records are
|
||||
* templates. No data is allocated at this point. These are just
|
||||
* structures, similar to Pascal TYPEs. They simply generate a list
|
||||
* of equate offsets. Since none of these types are defined already
|
||||
* in the MPW AIncludes, we'll need to define them.
|
||||
|
||||
* ------------- MOUSE POINT TYPE -------------
|
||||
|
||||
Point RECORD 0
|
||||
v DS.W 1
|
||||
h DS.W 1
|
||||
ORG v
|
||||
vh DS.W h
|
||||
ENDR
|
||||
|
||||
* ------------- RECTANGLE TYPE -------------
|
||||
|
||||
Rect RECORD 0
|
||||
Top DS.W 1
|
||||
Left DS.W 1
|
||||
Bottom DS.W 1
|
||||
Right DS.W 1
|
||||
ORG Top
|
||||
TopLeft DS.L 1
|
||||
BotRight DS.L 1
|
||||
ENDR
|
||||
|
||||
* ------------- BITMAP TYPE -------------
|
||||
|
||||
BitMap RECORD 0
|
||||
baseAddr DS.L 1
|
||||
rowBytes DS.W 1
|
||||
bounds DS.L Rect
|
||||
ENDR
|
||||
|
||||
* ------------- EVENT RECORD TYPE -------------
|
||||
|
||||
EventRecord RECORD 0
|
||||
What DS.W 1
|
||||
Message DS.L 1
|
||||
When DS.L 1
|
||||
Where DS.L Point
|
||||
Modify DS.W 1
|
||||
ENDR
|
||||
|
||||
* ------------- THE QUICKDRAW WORLD -------------
|
||||
|
||||
MyQDGlobals RECORD 0,DECREMENT
|
||||
GrafPort DS.L 1
|
||||
White DS.B 8
|
||||
Black DS.B 8
|
||||
Gray DS.B 8
|
||||
LtGray DS.B 8
|
||||
DkGray DS.B 8
|
||||
Arrow DS.B cursRec
|
||||
ScreenBits DS.B BitMap
|
||||
RandSeed DS.L 1
|
||||
ORG -GrafSize
|
||||
ENDR
|
||||
|
||||
* ------------- ALL OF OUR GLOBAL DATA -------------
|
||||
* Note the minimal amount of globals we're using. Data such as
|
||||
* the EventRecord, WindowRecords, etc. do not belong in global data
|
||||
* allocation. Only data that basically doesn't change through out the
|
||||
* execution of the program is considered global. The boolean flags are
|
||||
* global, since they affect the state of the program at any given time.
|
||||
* Also note that any appearance of a DS outside of a stack frame will
|
||||
* be allocated off of A5 and becomes part of global data storage.
|
||||
|
||||
AppGlobals RECORD 0 ; this is our global data storage
|
||||
Stopped DS.W 1 ; boolean for the state of the light
|
||||
HasWNEvent DS.W 1 ; boolean for WaitNextEvent trap, see ForceEnvirons
|
||||
InBackground DS.W 1 ; boolean for if in background, see OSEvent
|
||||
StopRect DS Rect ; rect for the Stop light, set from a resource
|
||||
GoRect DS Rect ; rect for the Go light, set from a resource
|
||||
Mac DS SysEnvRec ; the system environment record, see ForceEnvirons
|
||||
ENDR
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 004E 6577 5072 6F67" /* ..Monaco.NewProg */
|
||||
$"7261 6D20 2260 5265 7175 6573 7420 2250" /* ram "`Request "P */
|
||||
$"726F 0006 0004 002A 0003 0142 01E3 002A" /* ro.....*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
#
|
||||
# Apple Macintosh Developer Technical Support
|
||||
#
|
||||
# MultiFinder-Aware Simple Sample Application
|
||||
#
|
||||
# Sample
|
||||
#
|
||||
# [A]Sample.make - Make Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1989-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions:
|
||||
# 1.00 08/88
|
||||
# 1.01 11/88
|
||||
# 1.02 04/89 MPW 3.1
|
||||
# 1.03 02/90 MPW 3.2
|
||||
#
|
||||
# Components:
|
||||
# Sample.a Feb. 1, 1990
|
||||
# Sample.inc1.a Feb. 1, 1990
|
||||
# SampleMisc.a Feb. 1, 1990
|
||||
# Sample.r Feb. 1, 1990
|
||||
# Sample.h Feb. 1, 1990
|
||||
# Sample.make Feb. 1, 1990
|
||||
#
|
||||
# Sample is an example application that demonstrates how to
|
||||
# initialize the commonly used toolbox managers, operate
|
||||
# successfully under MultiFinder, handle desk accessories,
|
||||
# and create, grow, and zoom windows.
|
||||
#
|
||||
# It does not by any means demonstrate all the techniques
|
||||
# you need for a large application. In particular, Sample
|
||||
# does not cover exception handling, multiple windows/documents,
|
||||
# sophisticated memory management, printing, or undo. All of
|
||||
# these are vital parts of a normal full-sized application.
|
||||
#
|
||||
# This application is an example of the form of a Macintosh
|
||||
# application; it is NOT a template. It is NOT intended to be
|
||||
# used as a foundation for the next world-class, best-selling,
|
||||
# 600K application. A stick figure drawing of the human body may
|
||||
# be a good example of the form for a painting, but that does not
|
||||
# mean it should be used as the basis for the next Mona Lisa.
|
||||
#
|
||||
# We recommend that you review this program or TESample before
|
||||
# beginning a new application.
|
||||
|
||||
# NOTE: The Asm has warnings turned off here. This is because the
|
||||
# Macro "Case#" builds a list of BEQ instructions that could be
|
||||
# optimized into BEQ.S. Everyone of these causes a warning
|
||||
# message to appear while building this sample. With warnings
|
||||
# turned off, they don't appear. Code generation is NOT effected.
|
||||
|
||||
# If ANY changes are made to the include file, you MUST perform
|
||||
# a full build of ALL source files. The dependencies below will
|
||||
# cause all source file to be assembled if the Sample.inc1.a is updated.
|
||||
|
||||
AOptions = -w
|
||||
|
||||
AObjs = Sample.a.o ∂
|
||||
SampleMisc.a.o ∂
|
||||
"{Libraries}"Runtime.o ∂
|
||||
"{Libraries}"Interface.o
|
||||
|
||||
Sample.a.o ƒƒ Sample.make Sample.inc1.a
|
||||
|
||||
SampleMisc.a.o ƒƒ Sample.make Sample.inc1.a
|
||||
|
||||
Sample ƒƒ {AObjs} Sample.make
|
||||
Link -o {Targ} {AObjs}
|
||||
SetFile {Targ} -t APPL -c 'MOOS' -a B
|
||||
|
||||
Sample ƒƒ Sample.r Sample.h Sample.make
|
||||
Rez -rd -o {Targ} Sample.r -append
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0061 6D70 6C65 2E6D" /* ..Monaco.ample.m */
|
||||
$"616B 6500 2200 0016 0009 0021 000A 0000" /* ake."......!.... */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,286 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
#
|
||||
# Apple Macintosh Developer Technical Support
|
||||
#
|
||||
# MultiFinder-Aware Simple Sample Application
|
||||
#
|
||||
# Sample
|
||||
#
|
||||
# Sample.r - Rez Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1989-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions:
|
||||
# 1.00 08/88
|
||||
# 1.01 11/88
|
||||
# 1.02 04/89 MPW 3.1
|
||||
# 1.03 02/90 MPW 3.2
|
||||
#
|
||||
# Components:
|
||||
# Sample.a Feb. 1, 1990
|
||||
# Sample.inc1.a Feb. 1, 1990
|
||||
# SampleMisc.a Feb. 1, 1990
|
||||
# Sample.r Feb. 1, 1990
|
||||
# Sample.h Feb. 1, 1990
|
||||
# Sample.make Feb. 1, 1990
|
||||
#
|
||||
# Sample is an example application that demonstrates how to
|
||||
# initialize the commonly used toolbox managers, operate
|
||||
# successfully under MultiFinder, handle desk accessories,
|
||||
# and create, grow, and zoom windows.
|
||||
#
|
||||
# It does not by any means demonstrate all the techniques
|
||||
# you need for a large application. In particular, Sample
|
||||
# does not cover exception handling, multiple windows/documents,
|
||||
# sophisticated memory management, printing, or undo. All of
|
||||
# these are vital parts of a normal full-sized application.
|
||||
#
|
||||
# This application is an example of the form of a Macintosh
|
||||
# application; it is NOT a template. It is NOT intended to be
|
||||
# used as a foundation for the next world-class, best-selling,
|
||||
# 600K application. A stick figure drawing of the human body may
|
||||
# be a good example of the form for a painting, but that does not
|
||||
# mean it should be used as the basis for the next Mona Lisa.
|
||||
#
|
||||
# We recommend that you review this program or TESample before
|
||||
# beginning a new application.
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "SysTypes.r"
|
||||
#include "Types.r"
|
||||
|
||||
#include "Sample.h"
|
||||
|
||||
resource 'vers' (1) {
|
||||
0x02, 0x00, release, 0x00,
|
||||
verUS,
|
||||
"1.03",
|
||||
"1.03, Copyright \251 Apple Computer, Inc. 1989-1990"
|
||||
};
|
||||
|
||||
|
||||
/* this is a definition for a resource which contains only a rectangle */
|
||||
|
||||
type 'RECT' {
|
||||
rect;
|
||||
};
|
||||
|
||||
|
||||
/* we use an MBAR resource to conveniently load all the menus */
|
||||
|
||||
resource 'MBAR' (rMenuBar, preload) {
|
||||
{ mApple, mFile, mEdit, mLight }; /* four menus */
|
||||
};
|
||||
|
||||
|
||||
resource 'MENU' (mApple, preload) {
|
||||
mApple, textMenuProc,
|
||||
AllItems & ~MenuItem2, /* Disable dashed line, enable About and DAs */
|
||||
enabled, apple,
|
||||
{
|
||||
"About Sample…",
|
||||
noicon, nokey, nomark, plain;
|
||||
"-",
|
||||
noicon, nokey, nomark, plain
|
||||
}
|
||||
};
|
||||
|
||||
resource 'MENU' (mFile, preload) {
|
||||
mFile, textMenuProc,
|
||||
MenuItem12, /* enable Quit only, program enables others */
|
||||
enabled, "File",
|
||||
{
|
||||
"New",
|
||||
noicon, "N", nomark, plain;
|
||||
"Open",
|
||||
noicon, "O", nomark, plain;
|
||||
"-",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Close",
|
||||
noicon, "W", nomark, plain;
|
||||
"Save",
|
||||
noicon, "S", nomark, plain;
|
||||
"Save As…",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Revert",
|
||||
noicon, nokey, nomark, plain;
|
||||
"-",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Page Setup…",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Print…",
|
||||
noicon, nokey, nomark, plain;
|
||||
"-",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Quit",
|
||||
noicon, "Q", nomark, plain
|
||||
}
|
||||
};
|
||||
|
||||
resource 'MENU' (mEdit, preload) {
|
||||
mEdit, textMenuProc,
|
||||
NoItems, /* disable everything, program does the enabling */
|
||||
enabled, "Edit",
|
||||
{
|
||||
"Undo",
|
||||
noicon, "Z", nomark, plain;
|
||||
"-",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Cut",
|
||||
noicon, "X", nomark, plain;
|
||||
"Copy",
|
||||
noicon, "C", nomark, plain;
|
||||
"Paste",
|
||||
noicon, "V", nomark, plain;
|
||||
"Clear",
|
||||
noicon, nokey, nomark, plain
|
||||
}
|
||||
};
|
||||
|
||||
resource 'MENU' (mLight, preload) {
|
||||
mLight, textMenuProc,
|
||||
NoItems, /* disable everything, program does the enabling */
|
||||
enabled, "Traffic",
|
||||
{
|
||||
"Red Light",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Green Light",
|
||||
noicon, nokey, nomark, plain
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* this ALRT and DITL are used as an About screen */
|
||||
|
||||
resource 'ALRT' (rAboutAlert, purgeable) {
|
||||
{40, 20, 160, 297},
|
||||
rAboutAlert,
|
||||
{ /* array: 4 elements */
|
||||
/* [1] */
|
||||
OK, visible, silent,
|
||||
/* [2] */
|
||||
OK, visible, silent,
|
||||
/* [3] */
|
||||
OK, visible, silent,
|
||||
/* [4] */
|
||||
OK, visible, silent
|
||||
}
|
||||
};
|
||||
|
||||
resource 'DITL' (rAboutAlert, purgeable) {
|
||||
{ /* array DITLarray: 5 elements */
|
||||
/* [1] */
|
||||
{88, 185, 108, 265},
|
||||
Button {
|
||||
enabled,
|
||||
"OK"
|
||||
},
|
||||
/* [2] */
|
||||
{8, 8, 24, 214},
|
||||
StaticText {
|
||||
disabled,
|
||||
"Simple Sample (Traffic Light)"
|
||||
},
|
||||
/* [3] */
|
||||
{32, 8, 48, 296},
|
||||
StaticText {
|
||||
disabled,
|
||||
"Copyright © Apple Computer 1989-1990"
|
||||
},
|
||||
/* [4] */
|
||||
{56, 8, 72, 136},
|
||||
StaticText {
|
||||
disabled,
|
||||
"Brought to you by:"
|
||||
},
|
||||
/* [5] */
|
||||
{80, 24, 112, 167},
|
||||
StaticText {
|
||||
disabled,
|
||||
"Macintosh Developer Technical Support"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* this ALRT and DITL are used as an error screen */
|
||||
|
||||
resource 'ALRT' (rUserAlert, purgeable) {
|
||||
{40, 20, 120, 260},
|
||||
rUserAlert,
|
||||
{ /* array: 4 elements */
|
||||
/* [1] */
|
||||
OK, visible, silent,
|
||||
/* [2] */
|
||||
OK, visible, silent,
|
||||
/* [3] */
|
||||
OK, visible, silent,
|
||||
/* [4] */
|
||||
OK, visible, silent
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
resource 'DITL' (rUserAlert, purgeable) {
|
||||
{ /* array DITLarray: 3 elements */
|
||||
/* [1] */
|
||||
{50, 150, 70, 230},
|
||||
Button {
|
||||
enabled,
|
||||
"OK"
|
||||
},
|
||||
/* [2] */
|
||||
{10, 60, 30, 230},
|
||||
StaticText {
|
||||
disabled,
|
||||
"Sample - Error occurred!"
|
||||
},
|
||||
/* [3] */
|
||||
{8, 8, 40, 40},
|
||||
Icon {
|
||||
disabled,
|
||||
2
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
resource 'WIND' (rWindow, preload, purgeable) {
|
||||
{60, 40, 290, 160},
|
||||
noGrowDocProc, visible, noGoAway, 0x0, "Traffic"
|
||||
};
|
||||
|
||||
resource 'RECT' (rStopRect, preload, purgeable) {
|
||||
{10, 10, 110, 110}
|
||||
};
|
||||
|
||||
resource 'RECT' (rGoRect, preload, purgeable) {
|
||||
{120, 10, 220, 110}
|
||||
};
|
||||
|
||||
|
||||
/* here is the quintessential MultiFinder friendliness device, the SIZE resource */
|
||||
|
||||
resource 'SIZE' (-1) {
|
||||
dontSaveScreen,
|
||||
acceptSuspendResumeEvents,
|
||||
enableOptionSwitch,
|
||||
canBackground, /* we can background; we don't currently, but our sleep value */
|
||||
/* guarantees we don't hog the Mac while we are in the background */
|
||||
multiFinderAware, /* this says we do our own activate/deactivate; don't fake us out */
|
||||
backgroundAndForeground, /* this is definitely not a background-only application! */
|
||||
dontGetFrontClicks, /* change this is if you want "do first click" behavior like the Finder */
|
||||
ignoreChildDiedEvents, /* essentially, I'm not a debugger (sub-launching) */
|
||||
not32BitCompatible, /* this app should not be run in 32-bit address space */
|
||||
reserved,
|
||||
reserved,
|
||||
reserved,
|
||||
reserved,
|
||||
reserved,
|
||||
reserved,
|
||||
reserved,
|
||||
kPrefSize * 1024,
|
||||
kMinSize * 1024
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0000 0000 0000 0000" /* ..Monaco........ */
|
||||
$"0000 0000 0000 0000 0000 0000 0000 00A4" /* ................ */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,899 @@
|
|||
*
|
||||
* Apple Macintosh Developer Technical Support
|
||||
*
|
||||
* MultiFinder-Aware Simple Sample Application
|
||||
*
|
||||
* Sample
|
||||
*
|
||||
* SampleMisc.a - Assembler Source
|
||||
*
|
||||
* Copyright © Apple Computer, Inc. 1989-1990
|
||||
* All rights reserved.
|
||||
*
|
||||
* Versions:
|
||||
* 1.00 08/88
|
||||
* 1.01 11/88
|
||||
* 1.02 04/89 MPW 3.1
|
||||
* 1.03 02/90 MPW 3.2
|
||||
*
|
||||
* Components:
|
||||
* Sample.a Feb. 1, 1990
|
||||
* Sample.inc1.a Feb. 1, 1990
|
||||
* SampleMisc.a Feb. 1, 1990
|
||||
* Sample.r Feb. 1, 1990
|
||||
* Sample.h Feb. 1, 1990
|
||||
* Sample.make Feb. 1, 1990
|
||||
*
|
||||
* Sample is an example application that demonstrates how to
|
||||
* initialize the commonly used toolbox managers, operate
|
||||
* successfully under MultiFinder, handle desk accessories,
|
||||
* and create, grow, and zoom windows.
|
||||
*
|
||||
* It does not by any means demonstrate all the techniques
|
||||
* you need for a large application. In particular, Sample
|
||||
* does not cover exception handling, multiple windows/documents,
|
||||
* sophisticated memory management, printing, or undo. All of
|
||||
* these are vital parts of a normal full-sized application.
|
||||
*
|
||||
* This application is an example of the form of a Macintosh
|
||||
* application; it is NOT a template. It is NOT intended to be
|
||||
* used as a foundation for the next world-class, best-selling,
|
||||
* 600K application. A stick figure drawing of the human body may
|
||||
* be a good example of the form for a painting, but that does not
|
||||
* mean it should be used as the basis for the next Mona Lisa.
|
||||
*
|
||||
* We recommend that you review this program or TESample before
|
||||
* beginning a new application.
|
||||
|
||||
* ================================================
|
||||
* -------------- INCLUDES SECTION ----------------
|
||||
* ================================================
|
||||
|
||||
PRINT PUSH,OFF ; don't print any of this stuff
|
||||
|
||||
INCLUDE 'ToolEqu.a'
|
||||
INCLUDE 'Traps.a'
|
||||
INCLUDE 'PackMacs.a'
|
||||
INCLUDE 'QuickEqu.a'
|
||||
INCLUDE 'SysEqu.a'
|
||||
INCLUDE 'Sample.inc1.a' ; all our macros and data templates
|
||||
|
||||
PRINT POP ; restore the PRINT options
|
||||
|
||||
|
||||
* ================================================
|
||||
* ----------- DATA STORAGE USAGE ---------------
|
||||
* ================================================
|
||||
* Here we will IMPORT the data that is being from the
|
||||
* DATA STORAGE ALLOCATION section of ASample.a. By IMPORTing them
|
||||
* at this point, they will be accessible by this entire source file.
|
||||
* The symbol is IMPORTed and associated with the original template
|
||||
* as defined in the ASample.inc1.a file. This allows us to use
|
||||
* the identifiers in the template.
|
||||
|
||||
IMPORT QD:QDGlobals
|
||||
IMPORT G:AppGlobals
|
||||
|
||||
|
||||
* ================================================
|
||||
* FUNCTION TrapAvailable(tNumber: INTEGER): BOOLEAN;
|
||||
* ================================================
|
||||
* Check to see if a given trap is implemented. This is only used by the
|
||||
* Initialize routine in this program, so we put it in the Initialize segment.
|
||||
* The recommended approach to see if a trap is implemented is to see if
|
||||
* the address of the trap routine is the same as the address of the
|
||||
* Unimplemented trap. Needs to be called after call to _SysEnvirons so that it can
|
||||
* check if a ToolTrap is out of range of a pre-Mac II ROM. This routine
|
||||
* assumes we're running on 128k ROMs. It also requires the entire trap
|
||||
* word so that it knows if it is a ToolTrap or an OSTrap.
|
||||
|
||||
SEG 'Initialize' ; case sensitive
|
||||
TrapAvailable FUNC EXPORT ; any source file can use this routine
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
Result DS.W 1 ; function's result returned to caller
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
tNumber DS.W 1 ; the trap number passed by caller
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
TrapAddress DS.L 1 ; local copy of trap address
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVE.W #False,Result(A6) ; initialize function's result
|
||||
|
||||
MOVE.W tNumber(A6),D0 ; get trap word into D0
|
||||
BTST #ToolTrapBit,D0 ; test if number is Tool trap
|
||||
BEQ.S GetOSTrap ; off means a new OS trap number
|
||||
|
||||
MOVE.W G.Mac.machineType,D1 ; get the machine type we're running
|
||||
CMPI.W #envMachUnknown,D1 ; are we on a future machine?
|
||||
BEQ.S GetToolTrap ; yes, go ahead and test for a new Tool trap
|
||||
|
||||
CMPI.W #envMacII,D1 ; are we on a Mac II or better?
|
||||
BGE.S GetToolTrap ; yes, go ahead and test for a new Tool trap
|
||||
|
||||
* ------------- TEST FOR EXCEEDING TRAP TABLE -------------
|
||||
* At this point we know we're on a Mac 512E, Plus, or SE and need to
|
||||
* test the trap number for being in the range of < $0200
|
||||
|
||||
AND.W #$03FF,D0 ; mask off the ToolTrap bits
|
||||
CMPI.W #$01FF,D0 ; is this trap in our trap table?
|
||||
BLE.S GetToolTrap ; yes, go ahead and test for a new Tool trap
|
||||
BRA.S Exit ; no, then this trap cannot be present
|
||||
|
||||
* ------------- TEST FOR NEW TOOL TRAP -------------
|
||||
|
||||
GetToolTrap _GetTrapAddress ,NewTool ; NewTool trap macro, trap is in D0
|
||||
MOVE.L A0,TrapAddress(A6) ; save a copy of the trap address
|
||||
BRA.S TestUnimp ; test against Unimplemented trap
|
||||
|
||||
* ------------- TEST FOR NEW OS TRAP -------------
|
||||
|
||||
GetOSTrap _GetTrapAddress ,NewOS ; NewOS trap macro, trap is in D0
|
||||
MOVE.L A0,TrapAddress(A6) ; save a copy of the trap address
|
||||
TestUnimp MOVE.W #Unimplemented,D0 ; get address of Unimplemented trap
|
||||
_GetTrapAddress
|
||||
CMPA.L TrapAddress(A6),A0 ; see if trap is implemented
|
||||
BEQ.S Exit ; nope, they're the same
|
||||
MOVE.W #True,Result(A6) ; yes, we've got the trap
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo TrapAval ; this name will appear in the debugger
|
||||
ENDF
|
||||
|
||||
* ================================================
|
||||
* FUNCTION GoGetRect(rectID: INTEGER; VAR theRect: Rect) : BOOLEAN;
|
||||
* ================================================
|
||||
* This utility loads the global rectangles that are used by the window
|
||||
* drawing routines. It shows how the resource manager can be used to hold
|
||||
* values in a convenient manner. These values are then easily altered without
|
||||
* having to re-compile the source code. GoGetRect will return a BOOLEAN that
|
||||
* indicates if it was successful in getting the rectangle.
|
||||
|
||||
* A0 is being used for resource handle.
|
||||
|
||||
SEG 'Initialize' ; case sensitive
|
||||
GoGetRect FUNC EXPORT ; any source file can use this routine
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
Result DS.W 1 ; function's result returned to caller
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
RectID DS.W 1 ; resource ID of rect passed by caller
|
||||
TheRect DS.L 1 ; the rect's pointer passed by caller
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVE.W #False,Result(A6) ; initialize function's result
|
||||
|
||||
CLR.L -(SP) ; create space for result
|
||||
MOVE.L #'RECT',-(SP)
|
||||
MOVE.W RectID(A6),-(SP) ; get the stop light's rect
|
||||
_GetResource
|
||||
MOVEA.L (SP)+,A0 ; handle to RECT resource in A0
|
||||
CMPA.L #NIL,A0 ; test for NIL handle
|
||||
BEQ.S Exit ; didn't get resource, exit this procedure
|
||||
|
||||
|
||||
* -------- COPY THE RESOURCE TO THE RECT --------
|
||||
|
||||
MOVE.W #True,Result(A6) ; we got the resource, return true
|
||||
MOVEA.L (A0),A0 ; pointer to RECT resource in A0
|
||||
MOVEA.L TheRect(A6),A1 ; pointer to the dest. RECT in A1
|
||||
MOVE.L topLeft(A0),topLeft(A1) ; copy to the rect passed to us
|
||||
MOVE.L botRight(A0),botRight(A1)
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo GetRect ; this name will appear in the debugger
|
||||
ENDF
|
||||
|
||||
* ================================================
|
||||
* FUNCTION IsDAWindow(window: WindowPtr): BOOLEAN;
|
||||
* ================================================
|
||||
* Check if a window belongs to a desk accessory. DA window has a negitive kind.
|
||||
|
||||
SEG 'Main'
|
||||
IsDAWindow FUNC EXPORT ; any source file can use this routine
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
Result DS.W 1 ; function's result returned to caller
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
TheWindow DS.L 1 ; a window's pointer passed by caller
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVE.W #False,Result(A6) ; first, initialize the result
|
||||
CMPI.L #NIL,TheWindow(A6) ; valid pointer?
|
||||
BEQ.S Exit ; it was NIL, look out!
|
||||
|
||||
MOVEA.L TheWindow(A6),A0 ; get the window pointer
|
||||
MOVE.W WindowKind(A0),D0 ; what kind of window was it?
|
||||
BPL.S Exit ; DA windows are negitive
|
||||
|
||||
MOVE.W #True,Result(A6) ; return true to the caller
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo IsDAWind ; this name will appear in the debugger
|
||||
ENDF
|
||||
|
||||
* ================================================
|
||||
* FUNCTION IsAppWindow(window: WindowPtr): BOOLEAN;
|
||||
* ================================================
|
||||
* Check to see if a window belongs to the application. If the window pointer
|
||||
* passed was NIL, then it could not be an application window. WindowKinds
|
||||
* that are negative belong to the system and windowKinds less than userKind
|
||||
* are reserved by Apple except for windowKinds equal to dialogKind, which
|
||||
* means it is a dialog.
|
||||
* In order to reduce the chance of accidentally treating some window
|
||||
* as an AppWindow that shouldn't be, we'll only return true if the windowkind
|
||||
* is userKind. If you add different kinds of windows to Sample you'll need
|
||||
* to change how this all works.
|
||||
|
||||
SEG 'Main'
|
||||
IsAppWindow FUNC EXPORT ; any source file can use this routine
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
Result DS.W 1 ; function's result returned to caller
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
TheWindow DS.L 1 ; a window's pointer passed by caller
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVE.W #False,Result(A6) ; first, initialize the result
|
||||
CMPI.L #NIL,TheWindow(A6) ; valid pointer?
|
||||
BEQ.S Exit ; it was NIL, look out!
|
||||
|
||||
MOVEA.L TheWindow(A6),A0 ; get the window pointer
|
||||
MOVE.W WindowKind(A0),D0 ; what kind of window was it?
|
||||
CMPI.W #UserKind,D0 ; was it an application window?
|
||||
BNE.S Exit ; no, result is going to be false
|
||||
|
||||
MOVE.W #True,Result(A6) ; return true to the caller
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo IsAppWin ; this name will appear in the debugger
|
||||
ENDF
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE AlertUser;
|
||||
* ================================================
|
||||
* Display an alert that tells the user an error occurred, then exit the program.
|
||||
* This routine is used as an ultimate bail-out for serious errors that prohibit
|
||||
* the continuation of the application. Errors that do not require the termination
|
||||
* of the application should be handled in a different manner. Error checking and
|
||||
* reporting has a place even in the simplest application. For simplicity, the alert
|
||||
* displayed here only says that an error occurred, but not what it was. There are
|
||||
* various methods available for being more specific.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
AlertUser PROC EXPORT ; any source file can use this routine
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
CLR.W -(SP) ; space for result of Alert
|
||||
MOVE.W #rUserAlert,-(SP) ; resource for alert dialog
|
||||
CLR.L -(SP) ; no filter procedure used here
|
||||
_Alert ; read the resource and display it
|
||||
MOVE.W (SP)+,D0 ; I don't care which item is was
|
||||
_ExitToShell ; we're out of here, no error recovery
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo AlrtUser ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* FUNCTION DoCloseWindow(window: WindowPtr) : BOOLEAN;
|
||||
* ================================================
|
||||
* At this point, if there was a document associated with a window, you could
|
||||
* do any document saving processing if it is 'dirty'. DoCloseWindow would
|
||||
* return TRUE if the window actually closes, i.e., the user does not cancel
|
||||
* from a save dialog. This result is handy when the user quits an application,
|
||||
* but then cancels a save of a document associated with a window. We also added
|
||||
* code to close the application window since otherwise, the termination routines
|
||||
* would never stop looping, waiting for FrontWindow to return NIL.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
DoCloseWindow FUNC EXPORT ; any source file can use this routine
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
Result DS.W 1 ; function's result returned to caller
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
WindowPtr DS.L 1 ; passed window pointer parameter
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVE.W #True,Result(A6); ; initialize the function's result
|
||||
|
||||
CLR.W -(SP) ; space for result of IsDAWindow
|
||||
MOVE.L WindowPtr(A6),-(SP) ; pass the window pointer
|
||||
BSR IsDAWindow
|
||||
MOVE.W (SP)+,D0 ; result of IsDAWindow
|
||||
CMPI.W #True,D0
|
||||
BNE.S @1 ; this wasn't a DA window
|
||||
|
||||
MOVEA.L WindowPtr(A6),A0 ; get window pointer
|
||||
MOVE.W WindowKind(A0),-(SP) ; pass the refNum of DA
|
||||
_CloseDeskAcc
|
||||
BRA.S Exit ; all done
|
||||
|
||||
@1 CLR.W -(SP) ; space for result of IsAppWindow
|
||||
MOVE.L WindowPtr(A6),-(SP) ; pass a the window pointer
|
||||
BSR IsAppWindow
|
||||
MOVE.W (SP)+,D0 ; result of IsAppWindow
|
||||
CMPI.W #True,D0
|
||||
BNE.S Exit ; it wasn't our application's window
|
||||
|
||||
MOVE.L WindowPtr(A6),-(SP) ; close window, it shouldn't be a dialog
|
||||
_CloseWindow ; close the application window
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo ClosWind ; this name will appear in the debugger
|
||||
ENDF
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE Terminate;
|
||||
* ================================================
|
||||
* Clean up the application and exit. We close all of the windows so that
|
||||
* they can update their documents, if any. We don't have much to do here.
|
||||
* Just close our windows and then exit. If we find out that a Cancel has
|
||||
* occurred (DoCloseWindow will return False) we won't exit to the shell,
|
||||
* but will simply exit this procedure.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
Terminate PROC EXPORT
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
WindowPtr DS.L 1 ; local variable for a window pointer
|
||||
Closed DS.W 1 ; local variable for looping
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
IMPORT DoCloseWindow
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVE.W #True,Closed(A6) ; initialize local variable
|
||||
|
||||
Loop CLR.L -(SP) ; space for front window pointer
|
||||
_FrontWindow
|
||||
MOVE.L (SP)+,WindowPtr(A6) ; get the front window pointer
|
||||
CMPI.L #NIL,WindowPtr(A6) ; is there a front window?
|
||||
BEQ.S @1 ; there are no more windows
|
||||
|
||||
CLR.W -(SP) ; space for result of DoCloseWindow
|
||||
MOVE.L WindowPtr(A6),-(SP) ; pass the window pointer
|
||||
BSR DoCloseWindow ; close all our windows
|
||||
MOVE.W (SP)+,Closed(A6) ; get result of DoCloseWindow
|
||||
CMPI.W #True,Closed(A6) ; what's the result of DoCloseWindow?
|
||||
BNE.S Exit ; user didn't want to close that window
|
||||
|
||||
BRA.S Loop ; loop again and close the next window
|
||||
|
||||
@1 CMPI.W #True,Closed(A6) ; should we really terminate?
|
||||
BNE.S Exit ; no, exit this procedure
|
||||
|
||||
_ExitToShell ; we're done, let's get out of here
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo Terminat ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE SetLight(window: WindowPtr; newStopped: BOOLEAN);
|
||||
* ================================================
|
||||
* Change the setting of the light and force an update event.
|
||||
* newStopped is the state of the stop light the user is requesting.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
SetLight PROC EXPORT ; any source file can use this routine
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
WindowPtr DS.L 1 ; passed parameter of the window pointer
|
||||
newStopped DS.W 1 ; test value passed by caller
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVE.W G.Stopped,D0 ; get state of stop light
|
||||
CMP.W newStopped(A6),D0 ; compare to the new state
|
||||
BEQ.S Exit ; they're the same, stupid user!
|
||||
|
||||
MOVE.W newStopped(A6),G.Stopped ; set global to the new state
|
||||
MOVE.L WindowPtr(A6),-(SP)
|
||||
_SetPort ; set the port to us
|
||||
MOVEA.L WindowPtr(A6),A0 ; force update event for window
|
||||
PEA portRect(A0) ; invalidate entire window
|
||||
_InvalRect
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo SetLight ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE AdjustMenus;
|
||||
* ================================================
|
||||
* Enable and disable menus based on the current state. The user can only select
|
||||
* enabled menu items. We set up all the menu items before calling MenuSelect or
|
||||
* MenuKey, since these are the only times that a menu item can be selected. Note
|
||||
* that MenuSelect is also the only time the user will see menu items. This
|
||||
* approach to deciding what enable/disable state a menu item has the advantage
|
||||
* of concentrating all the decision making in one routine, as opposed to being
|
||||
* spread throughout the application. Other application designs may take a
|
||||
* different approach that are just as valid.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
AdjustMenus PROC EXPORT ; any source file can use this routine
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
FrontMost DS.L 1 ; local copy of the front window
|
||||
Menu DS.L 1 ; local copy of the menu handle
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
CLR.L -(SP) ; space for result
|
||||
_FrontWindow
|
||||
MOVE.L (SP)+,FrontMost(A6) ; save the front window
|
||||
|
||||
* ------------- ADJUST THE FILE MENU -------------
|
||||
AdjustFile
|
||||
CLR.L -(SP) ; space for result
|
||||
MOVE.W #FileMenu,-(SP) ; get the File menu handle
|
||||
_GetMHandle
|
||||
MOVE.L (SP)+,Menu(A6) ; save the menu handle
|
||||
CLR.W -(SP) ; space for result
|
||||
MOVE.L FrontMost(A6),-(SP)
|
||||
BSR IsDAWindow
|
||||
MOVE.W (SP)+,D0 ; get the result of the function
|
||||
CMPI.W #True,D0 ; was it the DA window?
|
||||
BNE.S @1 ; no, then disable the close item
|
||||
|
||||
MOVE.L Menu(A6),-(SP) ; it was an application window
|
||||
MOVE.W #CloseItem,-(SP)
|
||||
_EnableItem ; enable the close for DAs only
|
||||
BRA.S AdjustEdit
|
||||
|
||||
@1 MOVE.L Menu(A6),-(SP) ; it was not a DA window
|
||||
MOVE.W #CloseItem,-(SP)
|
||||
_DisableItem ; disable close for all others
|
||||
|
||||
* ------------- ADJUST THE EDIT MENU -------------
|
||||
AdjustEdit
|
||||
CLR.L -(SP) ; space for result
|
||||
MOVE.W #EditMenu,-(SP) ; get the Edit menu handle
|
||||
_GetMHandle
|
||||
MOVE.L (SP)+,Menu(A6) ; save the menu handle
|
||||
CLR.W -(SP) ; space for result
|
||||
MOVE.L FrontMost(A6),-(SP)
|
||||
BSR IsDAWindow
|
||||
MOVE.W (SP)+,D0 ; get the result of the function
|
||||
CMPI.W #True,D0 ; was it the DA window?
|
||||
BNE.S @2 ; no, disable the edit menu
|
||||
|
||||
MOVE.L Menu(A6),-(SP) ; it was for a DA window
|
||||
MOVE.W #CutItem,-(SP)
|
||||
_EnableItem ; enable the Cut
|
||||
MOVE.L Menu(A6),-(SP)
|
||||
MOVE.W #CopyItem,-(SP)
|
||||
_EnableItem ; enable the Copy
|
||||
MOVE.L Menu(A6),-(SP)
|
||||
MOVE.W #PasteItem,-(SP)
|
||||
_EnableItem ; enable the Paste
|
||||
MOVE.L Menu(A6),-(SP)
|
||||
MOVE.W #ClearItem,-(SP)
|
||||
_EnableItem ; enable the Clear
|
||||
BRA.S AdjustLight ; done with the edit menu
|
||||
|
||||
@2 MOVE.L Menu(A6),-(SP) ; disable the edit menu
|
||||
MOVE.W #UndoItem,-(SP)
|
||||
_DisableItem ; disable the Undo
|
||||
MOVE.L Menu(A6),-(SP)
|
||||
MOVE.W #CutItem,-(SP)
|
||||
_DisableItem ; disable the Cut
|
||||
MOVE.L Menu(A6),-(SP)
|
||||
MOVE.W #CopyItem,-(SP)
|
||||
_DisableItem ; disable the Copy
|
||||
MOVE.L Menu(A6),-(SP)
|
||||
MOVE.W #PasteItem,-(SP)
|
||||
_DisableItem ; disable the Paste
|
||||
MOVE.L Menu(A6),-(SP)
|
||||
MOVE.W #ClearItem,-(SP)
|
||||
_DisableItem ; disable the Clear
|
||||
|
||||
* ------------- ADJUST THE LIGHT MENU -------------
|
||||
AdjustLight
|
||||
CLR.L -(SP) ; space for result
|
||||
MOVE.W #LightMenu,-(SP) ; get the Edit menu handle
|
||||
_GetMHandle
|
||||
MOVE.L (SP)+,Menu(A6) ; save the menu handle
|
||||
CLR.W -(SP) ; space for result
|
||||
MOVE.L FrontMost(A6),-(SP) ; the front window
|
||||
BSR IsAppWindow
|
||||
MOVE.W (SP)+,D3 ; save the result of the function
|
||||
CMPI.W #True,D3 ; was our window in front?
|
||||
BNE.S @3 ; no, disable the menu items
|
||||
|
||||
MOVE.L Menu(A6),-(SP) ; enable the light menu
|
||||
MOVE.W #StopItem,-(SP)
|
||||
_EnableItem ; enable the stop
|
||||
MOVE.L Menu(A6),-(SP)
|
||||
MOVE.W #GoItem,-(SP)
|
||||
_EnableItem ; enable the go for our window
|
||||
BRA.S @4 ; now check the menu items
|
||||
|
||||
@3 MOVE.L Menu(A6),-(SP) ; disable the light menu
|
||||
MOVE.W #StopItem,-(SP)
|
||||
_DisableItem ; disable the stop
|
||||
MOVE.L Menu(A6),-(SP)
|
||||
MOVE.W #GoItem,-(SP)
|
||||
_DisableItem ; disable the go
|
||||
BRA.S Exit ; nothing to check, get out of here
|
||||
|
||||
@4 MOVE.W G.Stopped,D0 ; get the current state of the light
|
||||
CMPI.W #True,D0 ; is the stop light on?
|
||||
BNE.S @5 ; no, the green light is on
|
||||
|
||||
MOVE.L Menu(A6),-(SP) ; set menu to red light = on
|
||||
MOVE.W #StopItem,-(SP)
|
||||
MOVE.W #True,-(SP)
|
||||
_CheckItem ; check the StopItem in the menu
|
||||
MOVE.L Menu(A6),-(SP)
|
||||
MOVE.W #GoItem,-(SP)
|
||||
MOVE.W #False,-(SP)
|
||||
_CheckItem ; un-check the GoItem in the menu
|
||||
BRA.S Exit ; now we're done, get out of here
|
||||
|
||||
@5 MOVE.L Menu(A6),-(SP) ; set menu to green light = on
|
||||
MOVE.W #StopItem,-(SP)
|
||||
MOVE.W #False,-(SP)
|
||||
_CheckItem ; un-check the StopItem in the menu
|
||||
MOVE.L Menu(A6),-(SP)
|
||||
MOVE.W #GoItem,-(SP)
|
||||
MOVE.W #True,-(SP)
|
||||
_CheckItem ; check the GoItem in the menu
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo AdjstMnu ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE DrawWindow(window: WindowPtr);
|
||||
* ================================================
|
||||
* Draw the contents of the application's window. We do some drawing in color,
|
||||
* using Classic QuickDraw's color capabilities. This will be black and white on
|
||||
* old machines, but color on color machines. The window's visRgn has been set by
|
||||
* the Update routine to cause drawing only where it needs to be done.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
DrawWindow PROC EXPORT ; any source file can use this routine
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
WindowPtr DS.L 1 ; passed parameter of the window pointer
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVE.L WindowPtr(A6),-(SP)
|
||||
_SetPort ; set the current port to us
|
||||
MOVEA.L WindowPtr(A6),A0 ; erase the entire window
|
||||
PEA portRect(A0) ; the window's rect
|
||||
_EraseRect ; clear out anything remaining
|
||||
MOVE.W G.Stopped,D0 ; find the state of the lights
|
||||
CMPI.W #True,D0
|
||||
BNE.S @1 ; red light should be off
|
||||
|
||||
* ------------- RED LIGHT -------------
|
||||
|
||||
MOVE.L #redColor,-(SP) ; make the red light go on
|
||||
_ForeColor
|
||||
PEA G.StopRect
|
||||
_PaintOval
|
||||
MOVE.L #whiteColor,-(SP) ; make the green light go off
|
||||
_ForeColor
|
||||
PEA G.GoRect
|
||||
_PaintOval
|
||||
BRA.S @2
|
||||
|
||||
* ------------- GREEN LIGHT -------------
|
||||
|
||||
@1 MOVE.L #greenColor,-(SP) ; make the green light go on
|
||||
_ForeColor
|
||||
PEA G.GoRect
|
||||
_PaintOval
|
||||
MOVE.L #whiteColor,-(SP) ; make the red light go off
|
||||
_ForeColor
|
||||
PEA G.StopRect
|
||||
_PaintOval
|
||||
|
||||
* ------------- FRAME THE LIGHTS -------------
|
||||
|
||||
@2 MOVE.L #blackColor,-(SP)
|
||||
_ForeColor
|
||||
PEA G.StopRect
|
||||
_FrameOval ; draw black line around light
|
||||
PEA G.GoRect
|
||||
_FrameOval ; draw black line around light
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo DrawWind ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE GetGlobalMouse(VAR mouse: Point);
|
||||
* ================================================
|
||||
* Get the global coordinates of the mouse. When you call OSEventAvail
|
||||
* it will return either a pending event or a null event. In either case,
|
||||
* the where field of the event record will contain the current position
|
||||
* of the mouse in global coordinates and the modifiers field will reflect
|
||||
* the current state of the modifiers. Another way to get the global
|
||||
* coordinates is to call GetMouse and LocalToGlobal, but that requires
|
||||
* being sure that thePort is set to a valid port.}
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
GetGlobalMouse PROC EXPORT ; any source file can use this routine
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
Mouse DS.L 1 ; passed reference to mouse position
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
TheEvent DS EventRecord ; local copy of the event record
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
MOVE.W #NoEvents,D0 ; we aren't interested in any events
|
||||
LEA TheEvent(A6),A0 ; point to event record
|
||||
_OSEventAvail ; just the mouse position
|
||||
MOVE.L Mouse(A6),A0 ; deref address of mouse
|
||||
MOVE.L TheEvent.Where(A6),(A0) ; stuff new value
|
||||
|
||||
UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo GetGlobalMouse ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
* ================================================
|
||||
* PROCEDURE AdjustCursor(mouse: Point; region: RgnHandle);
|
||||
* ================================================
|
||||
* Change the cursor's shape, depending on its position. This also calculates the
|
||||
* region where the current cursor resides (for WaitNextEvent). If the mouse is
|
||||
* ever outside of that region, an event would be generated, causing this routine
|
||||
* to be called, allowing us to change the region to the region the mouse is
|
||||
* currently in. If there is more to the event than just the mouse moved, we
|
||||
* get called before the event is processed to make sure the cursor is the right
|
||||
* one. In any (ahem) event, this is called again before we fall back into WNE.
|
||||
* 1.02 - Removed the mouse position parameter and instead use the current position
|
||||
* of the mouse by calling GetMouse and LocalToGlobal.
|
||||
|
||||
SEG 'Main' ; case sensitive
|
||||
AdjustCursor PROC EXPORT
|
||||
|
||||
StackFrame RECORD {A6Link},DECR ; build a stack frame record
|
||||
ParamBegin EQU * ; start parameters after this point
|
||||
Where DS.L 1 ; the mouse location passed to us
|
||||
MouseRegion DS.L 1 ; passed pointer to current region
|
||||
ParamSize EQU ParamBegin-* ; size of all the passed parameters
|
||||
RetAddr DS.L 1 ; place holder for return address
|
||||
A6Link DS.L 1 ; place holder for A6 link
|
||||
FrontMost DS.L 1 ; local pointer to the front window
|
||||
ArrowRgn DS.L 1 ; local handle to the arrow cursor region
|
||||
PlusRgn DS.L 1 ; local handle to the plus cursor region
|
||||
LocalSize EQU * ; size of all the local variables
|
||||
ENDR
|
||||
|
||||
IMPORT IsDAWindow,IsAppWindow
|
||||
|
||||
WITH StackFrame ; cover our local stack frame
|
||||
LINK A6,#LocalSize ; allocate our local stack frame
|
||||
|
||||
CLR.W -(SP) ; space for result of IsAppWindow
|
||||
CLR.L -(SP) ; space for result of FrontWindow
|
||||
_FrontWindow ; push front window pointer
|
||||
MOVE.L (SP),FrontMost(A6) ; copy pointer and keep it on stack
|
||||
BSR IsDAWindow ; is this an application window?
|
||||
MOVE.W (SP)+,D0
|
||||
CMPI.W #True,D0
|
||||
BEQ.W Exit ; not our window, don't adjust the cursor
|
||||
CMPI.W #True,G.InBackground
|
||||
BEQ.W Exit ; and do nothing if we're in the background
|
||||
|
||||
* ------------- INITIALIZE SOME REGION DATA -------------
|
||||
|
||||
CLR.L -(SP)
|
||||
_NewRgn ; create an empty plus region
|
||||
MOVE.L (SP)+,PlusRgn(A6)
|
||||
CLR.L -(SP)
|
||||
_NewRgn ; create an empty arrow region
|
||||
MOVE.L (SP)+,ArrowRgn(A6)
|
||||
MOVE.L ArrowRgn(A6),-(SP) ; arrow region handle
|
||||
MOVE.W #ExtremeNeg,-(SP) ; big left corner
|
||||
MOVE.W #ExtremeNeg,-(SP) ; big top corner
|
||||
MOVE.W #ExtremePos,-(SP) ; big right corner
|
||||
MOVE.W #ExtremePos,-(SP) ; big bottom corner
|
||||
_SetRecRgn ; really big rectangular region
|
||||
|
||||
CLR.W -(SP)
|
||||
MOVE.L FrontMost(A6),-(SP)
|
||||
BSR IsAppWindow ; is this an application window?
|
||||
MOVE.W (SP)+,D0
|
||||
CMPI.W #True,D0
|
||||
BNE.S @1 ; our window isn't in front?
|
||||
|
||||
* ------------- CALCULATE THE PLUS REGION -------------
|
||||
|
||||
MOVE.L FrontMost(A6),-(SP)
|
||||
_SetPort ; set the current port to us
|
||||
MOVEA.L FrontMost(A6),A0
|
||||
MOVE.W portBits+bounds+left(A0),D0
|
||||
NEG.W D0 ; offset window's left edge...
|
||||
MOVE.W D0,-(SP) ; to the screen's left edge
|
||||
MOVEA.L FrontMost(A6),A0
|
||||
MOVE.W portBits+bounds+top(A0),D0
|
||||
NEG.W D0 ; offset window's top edge...
|
||||
MOVE.W D0,-(SP) ; to the screen's top edge
|
||||
_SetOrigin ; make window rect global
|
||||
MOVE.L PlusRgn(A6),-(SP) ; handle to empty plus region
|
||||
MOVEA.L FrontMost(A6),A0 ; pointer to our window
|
||||
PEA portRect(A0) ; window rect's global coordinates
|
||||
_RectRgn ; make global window rect into region
|
||||
MOVE.L PlusRgn(A6),-(SP) ; get intersection of plus and window region
|
||||
MOVEA.L FrontMost(A6),A0
|
||||
MOVE.L visRgn(A0),-(SP) ; get front window's visRgn
|
||||
MOVE.L PlusRgn(A6),-(SP) ; resulting region will be in PlusRgn
|
||||
_SectRgn ; intersection the two regions
|
||||
CLR.L -(SP) ; reset the origin of our window to 0,0
|
||||
_SetOrigin
|
||||
|
||||
@1 MOVE.L ArrowRgn(A6),-(SP) ; the really big rectangular region
|
||||
MOVE.L PlusRgn(A6),-(SP) ; the region of our window
|
||||
MOVE.L ArrowRgn(A6),-(SP) ; intersetion of the Arrow and Plus region
|
||||
_DiffRgn ; this is the region where the Arrow shows
|
||||
CLR.W -(SP) ; space for result of PtInRect
|
||||
MOVE.L Where(A6),-(SP) ; here's the mouse
|
||||
MOVE.L PlusRgn(A6),-(SP) ; where the arrow should show up
|
||||
_PtInRgn ; was cursor in the arrow region?
|
||||
MOVE.W (SP)+,D0
|
||||
CMPI.W #True,D0
|
||||
BNE.S @2 ; cursor was in arrow region
|
||||
|
||||
* ------------- SET THE CURSOR AND NEW MOUSE REGION -------------
|
||||
|
||||
CLR.L -(SP) ; space for result
|
||||
MOVE.W #plusCursor,-(SP) ; I want the plus cursor now!
|
||||
_GetCursor
|
||||
MOVEA.L (SP)+,A0 ; get the handle
|
||||
CMPA.L #NIL,A0
|
||||
BEQ.S Exit ; check for NIL like a good boy
|
||||
MOVE.L (A0),-(SP) ; got the plus cursor
|
||||
_SetCursor ; set cursor to plus
|
||||
MOVE.L PlusRgn(A6),-(SP) ; current region containing cursor
|
||||
MOVE.L MouseRegion(A6),-(SP) ; set it to the new region
|
||||
_CopyRgn
|
||||
BRA.S @3 ; we're done, get out of here
|
||||
|
||||
@2 PEA QD.Arrow ; got arrow cursor at InitGraf
|
||||
_SetCursor ; set cursor to the Arrow
|
||||
MOVE.L ArrowRgn(A6),-(SP) ; current region containing cursor
|
||||
MOVE.L MouseRegion(A6),-(SP) ; set it to the new region
|
||||
_CopyRgn
|
||||
|
||||
@3 MOVE.L PlusRgn(A6),-(SP) ; dispose of our two temporary regions
|
||||
_DisposRgn
|
||||
MOVE.L ArrowRgn(A6),-(SP)
|
||||
_DisposRgn
|
||||
|
||||
Exit UNLK A6 ; destroy the link
|
||||
MOVEA.L (SP)+,A0 ; pull off the return address
|
||||
ADDA.L #ParamSize,SP ; strip all of the caller's parameters
|
||||
JMP (A0) ; return to the caller
|
||||
|
||||
DbgInfo AdjstCur ; this name will appear in the debugger
|
||||
ENDP
|
||||
|
||||
END ; end of this source file
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0061 6D70 6C65 4D69" /* ..Monaco.ampleMi */
|
||||
$"7363 2E61 0022 0000 4D69 7363 2E61 0045" /* sc.a."..Misc.a.E */
|
||||
$"16DC 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
|
||||
NAME
|
||||
Count -- count lines and characters
|
||||
|
||||
SYNOPSIS
|
||||
Count [-l] [-c] [file…]
|
||||
|
||||
DESCRIPTION
|
||||
"Count" counts the lines and characters in its input, and writes the
|
||||
counts to standard output. If no files are specified standard input is
|
||||
read. If more than one file is specified, separate counts are written
|
||||
for each file, one per line, preceeded by the file name. A total is also
|
||||
written following the list of files.
|
||||
|
||||
COPYRIGHT
|
||||
Copyright Apple Computer, Inc. 1985-1988
|
||||
All rights reserved.
|
||||
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
#include <Types.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ErrMgr.h>
|
||||
#include <CursorCtl.h>
|
||||
#include <Errors.h>
|
||||
|
||||
|
||||
#define InputSize (1024*8)
|
||||
|
||||
/* Variables local to this file */
|
||||
|
||||
static char inputBuffer[InputSize + 1];
|
||||
static char errorBuffer[256];
|
||||
|
||||
static char *usage = "# Usage - %s [-l] [-c] [file…].\n";
|
||||
static long optionsSpecified;
|
||||
static long lineOption;
|
||||
static long charOption;
|
||||
|
||||
struct counts {
|
||||
long lines;
|
||||
long characters;
|
||||
};
|
||||
|
||||
struct counts count(long input)
|
||||
{
|
||||
char c;
|
||||
char *ptr;
|
||||
long lines = 0;
|
||||
long characters = 0;
|
||||
long charsRead;
|
||||
struct counts cnts;
|
||||
|
||||
while ((charsRead = read(input, inputBuffer, InputSize)) > 0) {
|
||||
ptr = inputBuffer;
|
||||
inputBuffer[charsRead] = 0;
|
||||
characters += charsRead;
|
||||
while ((c = *ptr++) != 0 || ptr <= &inputBuffer[charsRead]) {
|
||||
if (c == '\n') {
|
||||
lines++;
|
||||
if ((lines & 0x0F) == 0)
|
||||
SpinCursor(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (characters > 0 && *(ptr-2) != '\n')
|
||||
lines++;
|
||||
cnts.lines = lines;
|
||||
cnts.characters = characters;
|
||||
return cnts;
|
||||
}
|
||||
|
||||
|
||||
void print(long files, long max, char *name, struct counts cnts)
|
||||
{
|
||||
long space;
|
||||
|
||||
space = 0;
|
||||
if (files > 1) {
|
||||
fprintf(stdout,"%s ", name);
|
||||
space = max - strlen(name);
|
||||
}
|
||||
if (optionsSpecified == false || lineOption == true) {
|
||||
fprintf(stdout, "%*d ", space + 5, cnts.lines);
|
||||
space = 0;
|
||||
}
|
||||
if (optionsSpecified == false || charOption == true) {
|
||||
fprintf(stdout, "%*d ", space + 7, cnts.characters);
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
long status;
|
||||
long parms;
|
||||
long files;
|
||||
long done;
|
||||
long length;
|
||||
long max;
|
||||
long input;
|
||||
struct counts cnts;
|
||||
struct counts total;
|
||||
|
||||
status = files = 0;
|
||||
max = strlen("Total");
|
||||
optionsSpecified = lineOption = charOption = false;
|
||||
InitCursorCtl(nil);
|
||||
|
||||
for (parms = 1; parms < argc; parms++) {
|
||||
length = strlen(argv[parms]);
|
||||
if (*argv[parms] != '-') {
|
||||
argv[++files] = argv[parms];
|
||||
if (max < length)
|
||||
max = length;
|
||||
} else if (tolower(*(argv[parms]+1)) == 'c' && length == 2) {
|
||||
optionsSpecified = charOption = true;
|
||||
} else if (tolower(*(argv[parms]+1)) == 'l' && length == 2) {
|
||||
optionsSpecified = lineOption = true;
|
||||
} else {
|
||||
fprintf(stderr,"### %s - \"%s\" is not an option.\n", argv[0], argv[parms]);
|
||||
fprintf(stderr, usage, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (files == 0) {
|
||||
cnts = count(fileno(stdin));
|
||||
print(files, max, NULL, cnts);
|
||||
} else {
|
||||
total.lines = total.characters = done = 0;
|
||||
for (parms = 1; parms <= files; parms++) {
|
||||
if ((input = open(argv[parms], O_RDONLY)) >= 0) {
|
||||
cnts = count(input);
|
||||
close(input);
|
||||
total.lines += cnts.lines;
|
||||
total.characters += cnts.characters;
|
||||
print(files, max, argv[parms], cnts);
|
||||
done++;
|
||||
} else {
|
||||
fprintf(stderr,"### %s - Unable to open file %s.\n", argv[0], argv[parms]);
|
||||
fprintf(stderr,"# %s\n", GetSysErrText(MacOSErr, errorBuffer));
|
||||
status = 2;
|
||||
}
|
||||
}
|
||||
if (done > 1) {
|
||||
print(files,max,"Total",total);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 006F 756E 742E 6300" /* ..Monaco.ount.c. */
|
||||
$"2200 006F 756E 742E 6300 0050 0000 004C" /* "..ount.c..P...L */
|
||||
$"0004 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
Count.r - commando resource file
|
||||
Copyright Apple Computer, Inc. 1985-1987
|
||||
All rights reserved.
|
||||
|
||||
Count [-l] [-c] [file…] < file > counts
|
||||
-l # write only line counts
|
||||
-c # write only character counts
|
||||
*/
|
||||
|
||||
#include "Cmdo.r"
|
||||
|
||||
|
||||
resource 'cmdo' (128) {
|
||||
{
|
||||
245, /* Height of dialog */
|
||||
"Counts the lines and characters in its input, and writes the results to standard output.",
|
||||
{
|
||||
notDependent {}, RadioButtons {
|
||||
{
|
||||
{25, 250, 40, 410},
|
||||
"Lines and characters",
|
||||
"",
|
||||
Set,
|
||||
"Count the number of lines and characters in the input file(s) (or standard input).",
|
||||
|
||||
{40, 250, 55, 340},
|
||||
"Lines",
|
||||
"-l",
|
||||
NotSet,
|
||||
"Only count the number of lines in the input file(s) (or standard input).",
|
||||
|
||||
{55, 250, 70, 340},
|
||||
"Characters",
|
||||
"-c",
|
||||
NotSet,
|
||||
"Only count the number of characters in the input file(s) (or standard input).",
|
||||
}
|
||||
},
|
||||
notDependent {}, TextBox {
|
||||
gray,
|
||||
{17, 240, 75, 450},
|
||||
"Count"
|
||||
},
|
||||
Or {{-4}}, MultiFiles {
|
||||
"Files to count…",
|
||||
"Select the files to count. If no files are specified Count reads "
|
||||
"from standard input.",
|
||||
{36, 35, 56, 200},
|
||||
"Files to count:",
|
||||
"",
|
||||
MultiInputFiles {
|
||||
{TEXT},
|
||||
FilterTypes,
|
||||
"Only text files",
|
||||
"All files",
|
||||
}
|
||||
},
|
||||
Or {{-3}}, Redirection {
|
||||
StandardInput,
|
||||
{85, 30}
|
||||
},
|
||||
notDependent {}, Redirection {
|
||||
StandardOutput,
|
||||
{85, 180}
|
||||
},
|
||||
notDependent {}, Redirection {
|
||||
DiagnosticOutput,
|
||||
{85, 330}
|
||||
},
|
||||
notDependent {}, TextBox {
|
||||
gray,
|
||||
{80, 25, 125, 450},
|
||||
"Redirection"
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 006F 756E 742E 7200" /* ..Monaco.ount.r. */
|
||||
$"2200 0000 0000 0000 0000 0000 0000 0000" /* "............... */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
***************************************************************************
|
||||
****
|
||||
**** DESK ACCESSORY and DEVICE DRIVER Entry Code/Data
|
||||
****
|
||||
***************************************************************************
|
||||
|
||||
STRING PASCAL
|
||||
|
||||
INCLUDE 'ToolEqu.a'
|
||||
INCLUDE 'SysEqu.a'
|
||||
|
||||
CASE OBJ
|
||||
**************************** DESK ACCESSORY ENTRY **************************
|
||||
IMPORT %DRVRMain
|
||||
|
||||
DAEntry Proc Export ; See Device Manager IM:2
|
||||
;
|
||||
; First we need to set the drvrFlags (IM II-188), choose from
|
||||
;
|
||||
; dReadEnable enable driver for read operations (drivers only)
|
||||
; dWritEnable enable driver for writing (drivers only)
|
||||
; dCtlEnable enable driver/da for control operations
|
||||
; dStatEnable enable driver/da for status operations (drivers only)
|
||||
; dNeedGoodBye driver/da needs a "goodbye kiss"
|
||||
; dNeedTime driver/da needs "main thread" time
|
||||
; dNeedLock driver will be accessed at interrupt level (drivers only)
|
||||
;
|
||||
DC.B (1<<dCtlEnable) + (1<<dNeedTime) ; periodic, control flags set
|
||||
DC.B 0 ; Lower byte is unused
|
||||
;
|
||||
; Next is the the drvrDelay (IM II-188), set only if dNeedTime flag set above
|
||||
;
|
||||
DC.W 5*60 ; 5 sec periodic update
|
||||
;
|
||||
; Next is the the drvrEMask (IM I-444), which events DA can respond to...
|
||||
; Must be NIL for drivers, for DA's choose from
|
||||
; mButDwnEvt mouse button down is event 1
|
||||
; keyDwnEvt key down is event 3
|
||||
; keyUpEvt key up is event 4
|
||||
; autoKeyEvt auto-repeated key is event 5
|
||||
; updatEvt update event
|
||||
; activateEvt activate/deactive event
|
||||
;
|
||||
DC.W (1<<updatEvt) ; Handle activate, update events
|
||||
;
|
||||
; Next is the the drvrMenu (IM I-444), Menu ID of DA's menu, or NIL
|
||||
;
|
||||
DC.W 0 ; No associated menu
|
||||
;
|
||||
; Next are the offsets to the main routines of the driver/DA
|
||||
;
|
||||
DC.W %DRVRMain - DAEntry ; Open routine
|
||||
DC.W %DRVRMain - DAEntry +4 ; Prime - unused for DA's
|
||||
DC.W %DRVRMain - DAEntry +8 ; Control
|
||||
DC.W %DRVRMain - DAEntry +12 ; Status - unused for DA's
|
||||
DC.W %DRVRMain - DAEntry +16 ; Close
|
||||
|
||||
;
|
||||
; Next are the offsets to the main routines of the driver/DA
|
||||
;
|
||||
DAName
|
||||
DC.B 'Memory' ; DA/DRVR Name
|
||||
ORG DAName+32 ; Pad string out to 32 bytes
|
||||
|
||||
END
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0041 456E 7472 792E" /* ..Monaco.AEntry. */
|
||||
$"6100 2200 006E 7472 792E 6100 0000 0013" /* a."..ntry.a..... */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
#
|
||||
# Macintosh Developer Technical Support
|
||||
#
|
||||
# EditText Sample Control Panel Device
|
||||
#
|
||||
# EditCdev
|
||||
#
|
||||
# EditCdev.make - Make Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1988-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions: 1.1 7/88
|
||||
# 1.0 6/88
|
||||
#
|
||||
# Components: EditCdev.c Feb. 1, 1990
|
||||
# EditCdev.r Feb. 1, 1990
|
||||
# EditCdev.make Feb. 1, 1990
|
||||
#
|
||||
# EditCdev demonstrates how to implement an editText item
|
||||
# in a Control Panel Device. It utilizes the new undo, cut, copy,
|
||||
# paste, and delete messages that are sent to cdevs in
|
||||
# response to user menu selections. How to handle private
|
||||
# storage is also covered.
|
||||
#
|
||||
# Enforce strict ptotype checking in ≥MPW 3.0 C
|
||||
COptions = -r
|
||||
|
||||
SrcName = EditCdev
|
||||
Lang = C
|
||||
CdevName = {SrcName}
|
||||
|
||||
Objs = {SrcName}.{Lang}.o ∂
|
||||
"{Libraries}"Interface.o
|
||||
|
||||
{SrcName}.rsrc ƒ {SrcName}.r {CdevName}.make
|
||||
Rez -o {Targ} {SrcName}.r -t cdev -c hack
|
||||
|
||||
{CdevName} ƒ {SrcName}.rsrc {Objs} {CdevName}.make
|
||||
Duplicate -y {SrcName}.rsrc {Targ}
|
||||
Link -o {Targ} -rt cdev=-4064 -m TEXTCDEV {Objs} && ∂
|
||||
Setfile {CdevName} -a B && ∂
|
||||
Duplicate -y {CdevName} "{SystemFolder}"
|
||||
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0064 6974 4344 6576" /* ..Monaco.ditCDev */
|
||||
$"2E6D 616B 6500 2200 0076 2E6D 616B 6500" /* .make."..v.make. */
|
||||
$"6972 0006 0004 002A 0003 0142 01E3 002A" /* ir.....*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
#
|
||||
# Macintosh Developer Technical Support
|
||||
#
|
||||
# EditText Sample Control Panel Device
|
||||
#
|
||||
# EditCdev
|
||||
#
|
||||
# EditCdev.c - C Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1988-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions: 1.1 7/88
|
||||
# 1.0 6/88
|
||||
#
|
||||
# Components: EditCdev.c Feb. 1, 1990
|
||||
# EditCdev.r Feb. 1, 1990
|
||||
# EditCdev.make Feb. 1, 1990
|
||||
#
|
||||
# EditCdev demonstrates how to implement an editText item
|
||||
# in a Control Panel Device. It utilizes the new undo, cut, copy,
|
||||
# paste, and delete messages that are sent to cdevs in
|
||||
# response to user menu selections. How to handle private
|
||||
# storage is also covered.
|
||||
#
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
#include <Types.h>
|
||||
#include <Memory.h>
|
||||
#include <Quickdraw.h>
|
||||
#include <TextEdit.h>
|
||||
#include <Dialogs.h>
|
||||
#include <Devices.h>
|
||||
#include <Scrap.h>
|
||||
|
||||
/* Constants */
|
||||
#define textItm 1 /* first editTExt item in cdev */
|
||||
|
||||
|
||||
/* Types */
|
||||
typedef struct CDEVRec {
|
||||
TEHandle myTE;
|
||||
} CDEVRec, *CDEVPtr, **CDEVHnd;
|
||||
|
||||
/* Prototypes */
|
||||
void DoEditCommand (short message, DialogPtr CPDialog);
|
||||
|
||||
/* This is the main dispatcher. It must be the first code in the cdev.
|
||||
EditCdev's dispatcher responds only to the following messages from
|
||||
the Control Panel:
|
||||
|
||||
macDev - To indicate what machines it is available on.
|
||||
initDev - To set up some temporary storage and get the caret started.
|
||||
keyEvtDev - To check for an edit command and do the appropriate action.
|
||||
cutDev - To cut the current selection.
|
||||
copyDev - To copy the current selection.
|
||||
pasteDev - To paste the contents of the clipboard.
|
||||
clearDev - To delete the current selection.
|
||||
|
||||
The Dialog Manager's services are used to handle entry of text, selection
|
||||
of text, editing of text, and moving between the editText items via the
|
||||
tab key. Since the Dialog Manager handles the selection of text, we do not
|
||||
have to be concerned with hitDev messages for the editText items. The only
|
||||
things we have to take care of are calling the Dialog Manager editing
|
||||
routines in response to an edit command, and getting the caret to show up
|
||||
at the beginning. In response to an edit command that was the result of
|
||||
a command-key equivalent, we must also eliminate the event so that it does
|
||||
not get processed as a keyDown by the Dialog Manager. Otherwise, an 'x'
|
||||
would show up in the editText item when the user did a command-x to cut
|
||||
the text.*/
|
||||
|
||||
pascal Handle
|
||||
TextCDEV(short message, short item, short numItems, short CPanelID,
|
||||
EventRecord *theEvent, Handle cdevStorage, DialogPtr CPDialog)
|
||||
{
|
||||
#pragma unused (item, CPanelID) /* unused formal parameters */
|
||||
|
||||
char tempChar;
|
||||
|
||||
if (message == macDev) return((Handle) 1); /* we work on every machine */
|
||||
else if (cdevStorage != nil) {
|
||||
switch (message) {
|
||||
case initDev: /* initialize cdev */
|
||||
cdevStorage = NewHandle(sizeof(CDEVRec)); /* create provate storage */
|
||||
SelIText(CPDialog, numItems + textItm, 0, 999); /* make caret show up */
|
||||
break;
|
||||
|
||||
case hitDev: /* handle hit on item */
|
||||
case closeDev: /* clean up and dispose */
|
||||
case nulDev:
|
||||
case updateDev: /* handle any update drawing */
|
||||
case activDev: /* activate any needed items */
|
||||
case deactivDev: /* deactivate any needed items */
|
||||
break;
|
||||
|
||||
case keyEvtDev: /* respond to keydown */
|
||||
tempChar = theEvent->message & charCodeMask;/* get the character, and check */
|
||||
if (theEvent->modifiers & cmdKey) { /* status of command key */
|
||||
message = nulDev; /* start with no message */
|
||||
theEvent->what = nullEvent; /* and empty event type */
|
||||
|
||||
switch (tempChar) { /* set appropriate message */
|
||||
|
||||
case 'X':
|
||||
case 'x':
|
||||
message = cutDev;
|
||||
break;
|
||||
case 'C':
|
||||
case 'c':
|
||||
message = copyDev;
|
||||
break;
|
||||
case 'V':
|
||||
case 'v':
|
||||
message = pasteDev;
|
||||
break;
|
||||
}
|
||||
DoEditCommand(message, CPDialog); /* Let edit command handler take it */
|
||||
}
|
||||
break;
|
||||
|
||||
case macDev:
|
||||
case undoDev:
|
||||
break;
|
||||
|
||||
case cutDev:
|
||||
case copyDev:
|
||||
case pasteDev:
|
||||
case clearDev:
|
||||
DoEditCommand(message, CPDialog); /* respond to edit command */
|
||||
break;
|
||||
}
|
||||
|
||||
return (cdevStorage);
|
||||
} /* cdevStorage != nil */
|
||||
|
||||
/*
|
||||
** if cdevStorage = NIL then ControlPanel
|
||||
** will put up memory error
|
||||
*/
|
||||
return (nil);
|
||||
}
|
||||
|
||||
/* Call the appropriate Dialog Manager routine to handle an edit command for
|
||||
an editText item. It will do all the work regarding the TEScrap. */
|
||||
void
|
||||
DoEditCommand (short message, DialogPtr CPDialog)
|
||||
{
|
||||
switch (message) {
|
||||
case cutDev:
|
||||
DlgCut(CPDialog);
|
||||
break;
|
||||
case copyDev:
|
||||
DlgCopy(CPDialog);
|
||||
break;
|
||||
case pasteDev:
|
||||
DlgPaste(CPDialog);
|
||||
break;
|
||||
case clearDev:
|
||||
DlgDelete(CPDialog);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0064 6974 4364 6576" /* ..Monaco.ditCdev */
|
||||
$"2E63 0022 0000 0014 0001 E78C 4275 696C" /* .c."........Buil */
|
||||
$"64C9 0006 0004 002A 0003 0142 01E3 002A" /* d......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
#
|
||||
# Macintosh Developer Technical Support
|
||||
#
|
||||
# EditText Sample Control Panel Device
|
||||
#
|
||||
# EditCdev
|
||||
#
|
||||
# EditCdev.r - Rez Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1988-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions: 1.1 7/88
|
||||
# 1.0 6/88
|
||||
#
|
||||
# Components: EditCdev.c Feb. 1, 1990
|
||||
# EditCdev.r Feb. 1, 1990
|
||||
# EditCdev.make Feb. 1, 1990
|
||||
#
|
||||
# EditCdev demonstrates how to implement an editText item
|
||||
# in a Control Panel Device. It utilizes the new undo, cut, copy,
|
||||
# paste, and delete messages that are sent to cdevs in
|
||||
# response to user menu selections. How to handle private
|
||||
# storage is also covered.
|
||||
#
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "Types.r"
|
||||
#include "SysTypes.r"
|
||||
|
||||
type 'hack' as 'STR ';
|
||||
|
||||
resource 'vers' (1) {
|
||||
0x01, 0x00, release, 0x00,
|
||||
verUS,
|
||||
"1.1",
|
||||
"1.1, Copyright © Apple Computer, Inc. 1988-1990"
|
||||
};
|
||||
|
||||
resource 'hack' (0, purgeable) {
|
||||
"Control Panel Device, INIT and CODE by Macintosh Developer Technical Support"
|
||||
};
|
||||
|
||||
resource 'BNDL' (-4064, purgeable) {
|
||||
'hack', 0,
|
||||
{ 'ICN#', {0, -4064},
|
||||
'FREF', {0, -4064}
|
||||
}
|
||||
};
|
||||
|
||||
resource 'ICN#' (-4064, purgeable) {
|
||||
{ /* array: 2 elements */
|
||||
/* [1] */
|
||||
$"00 00 00 00 00 00 3F E0 00 00 48 10 00 00 44 10"
|
||||
$"00 01 83 10 00 02 01 90 00 04 01 90 00 04 01 90"
|
||||
$"00 04 01 90 00 04 03 90 00 04 02 90 00 04 02 90"
|
||||
$"00 08 02 90 00 08 02 90 00 10 06 90 00 20 0C 90"
|
||||
$"03 C0 18 90 04 00 3F 10 0F FF C0 10 08 00 00 10"
|
||||
$"08 00 00 10 08 00 00 10 08 00 FF 10 08 00 00 10"
|
||||
$"08 00 00 10 08 00 00 10 08 00 00 10 07 FF FF E0"
|
||||
$"04 00 00 20 04 00 00 20 04 00 00 20 07 FF FF E0",
|
||||
/* [2] */
|
||||
$"00 00 00 00 00 00 3F E0 00 00 7F F0 00 00 7F F0"
|
||||
$"00 01 FF F0 00 03 FF F0 00 07 FF F0 00 07 FF F0"
|
||||
$"00 07 FF F0 00 07 FF F0 00 07 FF F0 00 07 FF F0"
|
||||
$"00 0F FF F0 00 0F FF F0 00 1F FF F0 00 3F FF F0"
|
||||
$"03 FF FF F0 07 FF FF F0 0F FF FF F0 0F FF FF F0"
|
||||
$"0F FF FF F0 0F FF FF F0 0F FF FF F0 0F FF FF F0"
|
||||
$"0F FF FF F0 0F FF FF F0 0F FF FF F0 07 FF FF E0"
|
||||
$"07 FF FF E0 07 FF FF E0 07 FF FF E0 07 FF FF E0"
|
||||
}
|
||||
};
|
||||
|
||||
resource 'DITL' (-4064) {
|
||||
{ /* array DITLarray: 1 elements */
|
||||
/* [1] */
|
||||
{60, 110, 76, 280},
|
||||
EditText {
|
||||
enabled, ""
|
||||
};
|
||||
/* [2] */
|
||||
{85, 110, 101, 280},
|
||||
EditText {
|
||||
enabled, ""
|
||||
};
|
||||
/* [3] */
|
||||
{15, 110, 50, 380},
|
||||
StaticText {
|
||||
disabled, "Apple Macintosh Developer Technical Support"
|
||||
"\nTextEdit Control Panel Device Example"
|
||||
"\n© Apple Computer, Inc. 1988-1990"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
resource 'FREF' (-4064, purgeable) {
|
||||
'cdev', 0, ""
|
||||
};
|
||||
|
||||
resource 'nrct' (-4064, purgeable) {
|
||||
{ /* array RectArray: 1 elements */
|
||||
/* [1] */
|
||||
{-1, 87, 130, 322}
|
||||
}
|
||||
};
|
||||
|
||||
resource 'mach' (-4064, purgeable) {
|
||||
0xFFFF,
|
||||
0
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0064 6974 4364 6576" /* ..Monaco.ditCdev */
|
||||
$"2E72 0022 0000 0064 6669 6E64 00A5 0048" /* .r."...dfind...H */
|
||||
$"443A 0006 0004 002A 0003 0142 01E3 002A" /* D:.....*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
|
||||
FILE
|
||||
FStubs.c - Stubs for floating point runtime library routines not
|
||||
used by MPW tools
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
This file provides additional stubs for several routines defined
|
||||
in the runtine library that aren't necessary in MPW tools. These
|
||||
routines are referenced by the Standard C Library I/O functions,
|
||||
but are never called. Because they are referenced, the linker
|
||||
can't remove them. The stubs in this file provide dummy routines
|
||||
which are never called, but reduce the size of the tool. The file
|
||||
{Libraries}Stubs.o contains most of the stub routines. This
|
||||
file only contains routines not found in {Libraries}Stubs.o.
|
||||
|
||||
COPYRIGHT
|
||||
Copyright Apple Computer, Inc. 1986-1987
|
||||
All rights reserved.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/* Floating Point Conversion Routines
|
||||
|
||||
These routines, called by printf, are only necessary if floating point
|
||||
formatting is used.
|
||||
*/
|
||||
|
||||
ecvt() {}
|
||||
fcvt() {}
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0053 7475 6273 2E63" /* ..Monaco.Stubs.c */
|
||||
$"0022 0000 7475 6273 2E63 0004 556E 646F" /* ."..tubs.c..Undo */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,305 @@
|
|||
Instructions - The C Examples
|
||||
|
||||
Copyright Apple Computer, Inc. 1987-1990
|
||||
All rights reserved.
|
||||
|
||||
|
||||
About the Examples
|
||||
|
||||
Eight sample C programs are included with MPW C: an application,
|
||||
a tool, a desk accessory, and a program that demonstrates the
|
||||
use of performance tools:
|
||||
|
||||
Sample - a simple MultiFinder-Aware Sample application
|
||||
TESample - a simple MultiFinder-Aware TextEdit application
|
||||
SillyBalls - a simple Color Quickdraw sample application
|
||||
(Requires Color Quickdraw, e.g. MacII)
|
||||
TubeTest - a simple Color Quickdraw & Palette Manager
|
||||
Sample application
|
||||
(Requires Color Quickdraw, e.g. MacII)
|
||||
Count - an MPW tool
|
||||
Memory - a sample desk accessory
|
||||
EditCdev - a sample Control Panel Device with a TextEdit item
|
||||
TestPerf - a performance demonstration tool
|
||||
|
||||
The source files for each of these examples are in the
|
||||
"Examples:CExamples:" folder. In addition, the makefiles
|
||||
containing the commands needed to build each of the
|
||||
examples are provided in the same folder.
|
||||
|
||||
|
||||
Building the Examples
|
||||
|
||||
You can easily build each of the sample programs using the Directory
|
||||
and Build menus. (See Chapter 2 of the MPW Reference.)
|
||||
|
||||
Set the default directory to "CExamples:"
|
||||
|
||||
The simplest way to do this is to select from the Directory menu
|
||||
the menu item that ends in "CExamples:". You can also set the
|
||||
default directory by using the Directory and SetDirectory commands.
|
||||
|
||||
|
||||
Build the program
|
||||
|
||||
You can use any of the four Build items at the bottom of the Build
|
||||
menu to build the program you have selected. Each of these menu
|
||||
items displays a dialog box that asks for the name of the program
|
||||
you want to build. When this dialog box appears, type the name of
|
||||
one of the sample programs (Sample, TESample, SillyBalls,
|
||||
TubeTest, Count, Memory, EditCdev or TestPerf).
|
||||
|
||||
Each of the Build menu items behaves slightly differently:
|
||||
|
||||
Build… - The program is automatically built. The commands
|
||||
used, and any error messages, are displayed in the Worksheet.
|
||||
Only files that have been changed since you last built the
|
||||
program are compiled, saving considerable time.
|
||||
|
||||
Full Build… - The program is completely rebuilt, ignoring
|
||||
any object files or intermediate files that may already exist
|
||||
from a previous build. The commands used, and any errors, are
|
||||
displayed in the Worksheet.
|
||||
|
||||
Show Build Commands… - The commands needed to build the program
|
||||
are written to the Worksheet, but not executed. You can then
|
||||
select any or all of the commands and execute them yourself.
|
||||
(To execute the commands select them and press Enter.)
|
||||
|
||||
Show Full Build Commands… - The commands needed to completely
|
||||
rebuild the program are written to the Worksheet. This is a
|
||||
convenient way to see all of the commands used in building
|
||||
the program you have selected.
|
||||
|
||||
|
||||
Note: For more information about building the sample programs, see
|
||||
Chapter 2 of the MPW Reference.
|
||||
|
||||
|
||||
|
||||
Sample - A Simple MultiFinder-Aware Sample Application
|
||||
|
||||
Sample is an example application that demonstrates how to initialize
|
||||
the commonly used toolbox managers, operate successfully under
|
||||
MultiFinder, handle desk accessories and create, grow, and zoom windows.
|
||||
The source for Sample (or TESample below) provides an excellent
|
||||
framework for basing new applications.
|
||||
The source is contained in the files Sample.c and Sample.h, resource
|
||||
descriptions are contained in the files Sample.h and Sample.r.
|
||||
The make dependency file is named Sample.make.
|
||||
|
||||
To build Sample, simply select the line below and press Enter.
|
||||
|
||||
BuildProgram Sample ∑∑ {Worksheet}
|
||||
|
||||
To execute Sample, select the line below and press Enter.
|
||||
|
||||
Sample
|
||||
|
||||
|
||||
|
||||
TESample - A Simple MultiFinder-Aware TextEdit Application
|
||||
|
||||
TESample is an example application that demonstrates how to initialize
|
||||
the commonly used toolbox managers, operate successfully under
|
||||
MultiFinder, handle desk accessories and create, grow, and zoom windows.
|
||||
The fundamental TextEdit toolbox calls and TextEdit autoscroll are
|
||||
demonstrated. TESample also shows how to create and maintain scrollbar
|
||||
controls.
|
||||
The source for TESample (or Sample above) provides an excellent
|
||||
framework for basing new applications.
|
||||
The source is contained in the files TESample.c, TESampleGlue.a and
|
||||
TESample.h, resource descriptions are contained in the files
|
||||
TESample.h and TESample.r. The make dependency file is named
|
||||
TESample.make.
|
||||
|
||||
To build TESample, simply select the line below and press Enter.
|
||||
|
||||
BuildProgram TESample ∑∑ {Worksheet}
|
||||
|
||||
To execute TESample, select the line below and press Enter.
|
||||
|
||||
TESample
|
||||
|
||||
|
||||
|
||||
SillyBalls - A Simple Color Quickdraw Sample Application
|
||||
|
||||
(Requires Color Quickdraw, e.g. MacII)
|
||||
|
||||
SillyBalls is a very simple sample program that demonstrates
|
||||
how to use Color QuickDraw. It is about two pages of code, and
|
||||
does nothing more than open a color window and draw randomly
|
||||
colored ovals in the window.
|
||||
The purpose is to show how to get some initial results with Color
|
||||
QuickDraw. It is a complete program and is very short to be as
|
||||
clear as possible.
|
||||
The source is contained in the file SillyBalls.c.
|
||||
|
||||
To build SillyBalls, simply select the line below and press Enter.
|
||||
|
||||
BuildProgram SillyBalls ∑∑ {Worksheet}
|
||||
|
||||
To execute SillyBalls, select the line below and press Enter.
|
||||
|
||||
SillyBalls
|
||||
|
||||
|
||||
|
||||
TubeTest - A Simple Color Quickdraw & Palette Manager Sample Application
|
||||
|
||||
(Requires Color Quickdraw, e.g. MacII)
|
||||
|
||||
TubeTest is a simple demonstration of how to use
|
||||
the Palette Manager in a color program. It has a special color
|
||||
palette that is associated with the main window. The colors are
|
||||
animated using the Palette Manager to give a flowing tube effect.
|
||||
The program is very simple, and the Palette Manager and drawing
|
||||
parts are put in separate subroutines to make it easier to figure
|
||||
out what is happening.
|
||||
The source is contained in the files TubeTest.c and TubeTest.r
|
||||
|
||||
To build TubeTest, simply select the line below and press Enter.
|
||||
|
||||
BuildProgram TubeTest ∑∑ {Worksheet}
|
||||
|
||||
To execute TubeTest, select the line below and press Enter.
|
||||
|
||||
TubeTest
|
||||
|
||||
|
||||
|
||||
Count - A Sample MPW Tool
|
||||
|
||||
Count, a tool that runs in the MPW environment, counts characters and
|
||||
lines in files. A version of Count is included with MPW, and is
|
||||
documented in the MPW Reference, Part II. The source for Count is in
|
||||
the files Count.c, FStubs.c, and Count.r. MakeFile contains the
|
||||
commands for building Count.
|
||||
|
||||
To build Count, simply select the line below and press Enter.
|
||||
|
||||
BuildProgram Count ∑∑ {Worksheet}
|
||||
|
||||
To test Count, try counting the characters in file Count.c.
|
||||
|
||||
Count -c Count.c
|
||||
|
||||
|
||||
|
||||
Memory - A Sample Desk Accessory
|
||||
|
||||
|
||||
Memory is a sample desk accessory written in C. It displays the memory
|
||||
available in the application and system heaps, and on the boot disk.
|
||||
MakeFile contains the commands for building Memory.
|
||||
|
||||
To build Memory, simply select the line below and press Enter.
|
||||
|
||||
BuildProgram Memory ∑∑ {Worksheet}
|
||||
|
||||
NOTE: If you don't have the MPW Assembler, you'll need to select the
|
||||
line below and press Enter. You won't be able to use SADE to
|
||||
debug DA's built without the assembler though...
|
||||
|
||||
BuildProgram Memory.NOASM ∑∑ {Worksheet}
|
||||
|
||||
The build process puts the desk accessory into a Font/DA Mover file.
|
||||
To install the Memory desk accessory, use the Font/DA Mover to copy
|
||||
resource Memory from the file Memory into the System file.
|
||||
|
||||
After quitting the Font/DA Mover and returning to the MPW Shell, select
|
||||
"Memory" from the Apple menu.
|
||||
|
||||
|
||||
|
||||
EditCdev - A Sample Control Panel Device in C
|
||||
|
||||
EditCdev demonstrates how to implement a editText item
|
||||
in a Control Panel Device. It utilizes the new undo, cut, copy,
|
||||
paste, and delete messages that are sent to cdevs in
|
||||
response to user menu selections.
|
||||
|
||||
To build EditCdev, simply select the line below and press Enter.
|
||||
|
||||
BuildProgram EditCdev ∑∑ {Worksheet}
|
||||
|
||||
To execute EditCdev, after building it, simply select the Control
|
||||
Panel desk accessory from the Apple menu, and click on the EditCdev
|
||||
icon in the list of Control Panel Devices.
|
||||
|
||||
|
||||
|
||||
TestPerf - An example of Using Performance Tools in C
|
||||
|
||||
TestPerf is an MPW tool that demonstrates the use of the performance
|
||||
measurement tools. MakeFile contains the commands for building TestPerf.
|
||||
|
||||
To build TestPerf, simply select the line below and press Enter.
|
||||
|
||||
BuildProgram TestPerf ∑∑ {Worksheet}
|
||||
|
||||
To execute TestPerf, select and execute the following command. (This
|
||||
test will run about 15 to 60 seconds, depending upon the machine, with
|
||||
only internal computations being performed):
|
||||
|
||||
TestPerf
|
||||
|
||||
TestPerf's raw performance data is written to the file Perform.out.
|
||||
In this sample use of the performance measurement tools, the ROM was
|
||||
measured. So the ROM link map file needs to be combined with the program
|
||||
link map file. Because there are three different ROM maps, select and
|
||||
execute the line that corresponds to the machine TestPerf was run on:
|
||||
|
||||
# For Macintosh Plus:
|
||||
Catenate "{MPW}ROM Maps:MacPlusROM.map" >> TestPerf.map
|
||||
|
||||
# For Macintosh SE:
|
||||
Catenate "{MPW}ROM Maps:MacSEROM.map" >> TestPerf.map
|
||||
|
||||
# For Macintosh II:
|
||||
Catenate "{MPW}ROM Maps:MacIIROM.map" >> TestPerf.map
|
||||
|
||||
PerformReport is an MPW Tool that combines the output of the performance
|
||||
tools with the link map file and produces a list of procedures, sorted by
|
||||
estimated percent of time spent in each procedure. To run PerformReport
|
||||
execute the following command:
|
||||
|
||||
PerformReport -l TestPerf.map -m Perform.Out > Report.Out
|
||||
|
||||
The output of PerformReport is written to the file Report.Out. To examine
|
||||
this output, execute the following command:
|
||||
|
||||
Open Report.Out
|
||||
|
||||
|
||||
Writing Your Own Programs
|
||||
|
||||
After building (and perhaps modifying) the sample programs, you will
|
||||
undoubtedly want to write a program of your own. Use the New… item in
|
||||
the File menu, to create the source files. Remember that C language
|
||||
source filenames should end in .c.
|
||||
|
||||
Create Build Commands… - The Create Build Commands… item in the
|
||||
Build menu runs a script that creates a makefile containing the
|
||||
commands for building programs written in C, Assembly Language, Pascal,
|
||||
and/or Rez. Selecting Create Build Commands… displays a dialog box that
|
||||
allows you to enter information about your program. Type the program's
|
||||
name, select its source files by clicking the Files… button, and click
|
||||
one of the radio buttons to indicate your choice of an application, tool,
|
||||
or desk accessory.
|
||||
|
||||
Create Build Commands… puts the makefile for your program in the file
|
||||
<program>.make. Now you can use the Build menu to build and rebuild
|
||||
your program, just as with the examples.
|
||||
|
||||
Larger Programs - If you add source files as your program grows,
|
||||
use Create Build Commands… again to add the new source files to the build
|
||||
instructions. If you out-grow the capabilities of the simple Create
|
||||
Build Commands… script (perhaps by using tools other than Asm, C, Pascal,
|
||||
Rez, and Link in your builds) you can modify the makefile yourself.
|
||||
|
||||
Modifying the Directory and Build Menus - The Directory and Build
|
||||
menus are both implemented using scripts written in the MPW Shell
|
||||
command language. This has the big advantage that you can modify
|
||||
or customize them to match the way you work.
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 006E 7374 7275 6374" /* ..Monaco.nstruct */
|
||||
$"696F 6E73 0022 0000 6E73 0000 0000 0000" /* ions."..ns...... */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
# File MakeFile - Make instructions for C examples.
|
||||
#
|
||||
# Copyright Apple Computer, Inc. 1986-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# This makefile builds:
|
||||
# The sample C tool: Count
|
||||
# The sample desk accessory: Memory
|
||||
# The sample performance tool: TestPerf
|
||||
#
|
||||
# You can define {SymOptions} as "-sym on" or "-sym off" for use with SADE
|
||||
# We also recommend requiring prototypes for all functions
|
||||
COptions = -r {SymOptions}
|
||||
|
||||
Count ƒƒ Count.r
|
||||
Rez Count.r -o Count -append
|
||||
Count ƒƒ Count.c.o FStubs.c.o
|
||||
Link {SymOptions} -w -c 'MPS ' -t MPST Count.c.o FStubs.c.o ∂
|
||||
-sn STDIO=Main ∂
|
||||
-sn INTENV=Main ∂
|
||||
-sn %A5Init=Main ∂
|
||||
"{Libraries}"Stubs.o ∂
|
||||
"{CLibraries}"StdCLib.o ∂
|
||||
"{Libraries}"Interface.o ∂
|
||||
"{Libraries}"Runtime.o ∂
|
||||
"{Libraries}"ToolLibs.o ∂
|
||||
-o Count
|
||||
|
||||
|
||||
Memory ƒƒ Memory.c.o DAEntry.a.o
|
||||
Link {SymOptions} -w -da -rt DRVR=12 ∂
|
||||
-m DAEntry -sg Memory # DAEntry is located in DAEntry.a.o ∂
|
||||
DAEntry.a.o # This must preceed DRVRRuntime.o ∂
|
||||
"{Libraries}"DRVRRuntime.o # This must preceed Runtime.o ∂
|
||||
Memory.c.o ∂
|
||||
"{Libraries}"Runtime.o ∂
|
||||
"{Libraries}"Interface.o ∂
|
||||
-o Memory -c DMOV -t DFIL
|
||||
|
||||
Memory ƒƒ Memory.r
|
||||
Rez -rd -c DMOV -t DFIL Memory.r -a -o Memory
|
||||
|
||||
Memory.NOASM ƒ Memory.DRVW Memory.r
|
||||
Rez -rd -c DMOV -t DFIL -d NOASM_BUILD Memory.r -o Memory.NOASM
|
||||
Duplicate -y Memory.NOASM Memory
|
||||
|
||||
Memory.DRVW ƒ Memory.c.o
|
||||
Link -w -rt DRVW=0 ∂
|
||||
-sg Memory ∂
|
||||
"{Libraries}"DRVRRuntime.o ∂
|
||||
Memory.c.o ∂
|
||||
"{Libraries}"Runtime.o ∂
|
||||
"{Libraries}"Interface.o ∂
|
||||
-o Memory.DRVW -c "????" -t "????"
|
||||
|
||||
|
||||
TestPerf ƒ TestPerf.c.o
|
||||
Link -d # suppress duplicate warnings ∂
|
||||
-o TestPerf -t MPST -c 'MPS ' ∂
|
||||
-l -la > TestPerf.map # produce link map file ∂
|
||||
TestPerf.c.o "{Libraries}"PerformLib.o ∂
|
||||
"{Libraries}"Interface.o ∂
|
||||
"{Libraries}"Runtime.o ∂
|
||||
"{CLibraries}"StdCLib.o
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0061 6B65 4669 6C65" /* ..Monaco.akeFile */
|
||||
$"0022 0000 0000 0000 0000 0000 0000 0000" /* .".............. */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
File Memory.c
|
||||
Copyright Apple Computer, Inc. 1985-1987
|
||||
All rights reserved.
|
||||
|
||||
* Memory - report the amount of free space in the
|
||||
* application and system heap, and on the boot volume.
|
||||
*
|
||||
* This is the sample C desk accessory. The desk accessory does not
|
||||
* use any global variables. Instead, it allocates a handle to a
|
||||
* structure that holds some "global" variables. This sample program
|
||||
* could be written without having to use this structure, but then it
|
||||
* wouldn't be as informative...
|
||||
*/
|
||||
#include <types.h>
|
||||
#include <osutils.h>
|
||||
#include <memory.h>
|
||||
#include <devices.h>
|
||||
#include <events.h>
|
||||
#include <quickdraw.h>
|
||||
#include <fonts.h>
|
||||
#include <windows.h>
|
||||
#include <files.h>
|
||||
#include <errors.h>
|
||||
#include <toolutils.h>
|
||||
#include <packages.h>
|
||||
|
||||
/*
|
||||
* Macro to compute owned resource id
|
||||
*/
|
||||
|
||||
#define OWNEDRSRCID(id) (0xC000 | (((-(id)) - 1) << 5))
|
||||
|
||||
/*
|
||||
* String constant indexes for STR# resource
|
||||
*/
|
||||
|
||||
#define APPHEAP 1
|
||||
#define SYSHEAP 2
|
||||
#define DISK 3
|
||||
#define FREEON 4
|
||||
|
||||
#define ACCEVENT 64
|
||||
#define ACCRUN 65
|
||||
|
||||
/* This structure type holds the global variables used by this desk accessory */
|
||||
|
||||
typedef struct {
|
||||
int rsrcID; /* Computed rsrc id of STR# and WIND resources */
|
||||
Str255 strBuf; /* Buffer to read strings into */
|
||||
} Globals;
|
||||
|
||||
|
||||
pascal short DRVROpen(CntrlParam *ctlPB, DCtlPtr dCtl)
|
||||
{
|
||||
#pragma unused (ctlPB)
|
||||
GrafPtr savePort;
|
||||
WindowPeek myWindow;
|
||||
long heapGrow;
|
||||
|
||||
/*
|
||||
* If the windowPtr is non-nil, we already have a window open.
|
||||
* This desk accessory ignores multiple opens.
|
||||
*/
|
||||
if (dCtl->dCtlWindow != nil)
|
||||
return noErr;
|
||||
|
||||
GetPort(&savePort);
|
||||
|
||||
/*
|
||||
* Get a handle to some storage that will hold our pseudo-global
|
||||
* variables. Save the handle in a location accessible by
|
||||
* all the driver routines.
|
||||
*/
|
||||
dCtl->dCtlStorage = NewHandle(sizeof(Globals));
|
||||
/*
|
||||
* Compute the resource id of the owned 'STR#' resource that
|
||||
* contains all of the program's text strings. The id is saved
|
||||
* in one place that can be accessed by all the driver routines.
|
||||
*/
|
||||
((Globals *)(*dCtl->dCtlStorage))->rsrcID = OWNEDRSRCID(dCtl->dCtlRefNum);
|
||||
|
||||
/*
|
||||
* wStorage = nil (allocate on the heap)
|
||||
* visible = false, behind = -1, goAway = true, refCon = 0
|
||||
*/
|
||||
myWindow = (WindowPeek)GetNewWindow(((Globals *)(*dCtl->dCtlStorage))->rsrcID, nil, (WindowPtr) -1);
|
||||
/*
|
||||
* Set windowKind to the DA refNum, which is negative.
|
||||
*/
|
||||
myWindow->windowKind = dCtl->dCtlRefNum;
|
||||
/*
|
||||
* Store the windowPtr in the Device Control Entry
|
||||
*/
|
||||
dCtl->dCtlWindow = (WindowPtr)myWindow;
|
||||
/*
|
||||
* Now compact the heap in the most violent way.
|
||||
* Purge whatever's purgeable.
|
||||
*/
|
||||
(void) MaxMem(&heapGrow);
|
||||
|
||||
SetPort(savePort);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
pascal short DRVRPrime(CntrlParam *ctlPB, DCtlPtr dCtl)
|
||||
{
|
||||
#pragma unused (ctlPB, dCtl)
|
||||
return noErr; /* Not used in this desk accessory */
|
||||
}
|
||||
|
||||
pascal short DRVRStatus(CntrlParam *ctlPB, DCtlPtr dCtl)
|
||||
{
|
||||
#pragma unused (ctlPB, dCtl)
|
||||
return noErr; /* Not used in this desk accessory */
|
||||
}
|
||||
|
||||
pascal short DRVRControl(CntrlParam *ctlPB, DCtlPtr dCtl)
|
||||
{
|
||||
extern void doCtlEvent();
|
||||
extern void doPeriodic();
|
||||
|
||||
/*
|
||||
* The current grafPort is saved & restored by the Desk Manager
|
||||
*/
|
||||
switch (ctlPB->csCode) {
|
||||
case ACCEVENT: /* accEvent */
|
||||
HLock(dCtl->dCtlStorage); /* Lock handle since it will be dereferenced */
|
||||
doCtlEvent( *((EventRecord **) &ctlPB->csParam[0]),
|
||||
(Globals *)(*dCtl->dCtlStorage));
|
||||
HUnlock(dCtl->dCtlStorage);
|
||||
break;
|
||||
|
||||
case ACCRUN: /* periodicEvent */
|
||||
doPeriodic(dCtl);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void doCtlEvent(register EventRecord *theEvent, Globals *globals)
|
||||
{
|
||||
register WindowPtr myWindow;
|
||||
extern void drawWindow();
|
||||
|
||||
if (theEvent->what == updateEvt) {
|
||||
myWindow = (WindowPtr) theEvent->message;
|
||||
SetPort(myWindow);
|
||||
BeginUpdate(myWindow);
|
||||
drawWindow(myWindow, globals);
|
||||
EndUpdate(myWindow);
|
||||
}
|
||||
}
|
||||
|
||||
static void doPeriodic(DCtlPtr dCtl)
|
||||
{
|
||||
extern void drawWindow();
|
||||
|
||||
SetPort(dCtl->dCtlWindow);
|
||||
HLock(dCtl->dCtlStorage); /* Lock handle since it will be dereferenced */
|
||||
drawWindow(dCtl->dCtlWindow, (Globals *)(*dCtl->dCtlStorage));
|
||||
HUnlock(dCtl->dCtlStorage);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display the contents of the window.
|
||||
* The current port is assumed to be set to the window.
|
||||
*/
|
||||
static void drawWindow(WindowPtr window, Globals *globals)
|
||||
{
|
||||
THz saveZone;
|
||||
Str27 volName;
|
||||
HVolumeParam myParamBlk;
|
||||
void printNum(unsigned long);
|
||||
static StringPtr text(int index, Globals *globals);
|
||||
|
||||
if (window == nil)
|
||||
return; /* "can't happen" */
|
||||
|
||||
TextMode(srcCopy);
|
||||
TextFont(monaco);
|
||||
TextSize(9);
|
||||
|
||||
MoveTo(6, 10);
|
||||
TextFace(bold);
|
||||
|
||||
saveZone = GetZone();
|
||||
|
||||
DrawString(text(APPHEAP, globals));
|
||||
SetZone(ApplicZone());
|
||||
printNum(FreeMem());
|
||||
|
||||
DrawString(text(SYSHEAP, globals));
|
||||
SetZone(SystemZone());
|
||||
printNum(FreeMem());
|
||||
|
||||
SetZone(saveZone);
|
||||
|
||||
DrawString(text(DISK, globals));
|
||||
myParamBlk.ioNamePtr = volName;
|
||||
myParamBlk.ioVRefNum = 0; /* Boot volume */
|
||||
myParamBlk.ioVolIndex = 0;
|
||||
(void) PBHGetVInfo((HParmBlkPtr)&myParamBlk, false);
|
||||
printNum((unsigned long)myParamBlk.ioVAlBlkSiz * myParamBlk.ioVFrBlk);
|
||||
|
||||
DrawString(text(FREEON, globals));
|
||||
TextFace(underline);
|
||||
DrawString(volName);
|
||||
}
|
||||
|
||||
static void printNum(unsigned long num)
|
||||
{
|
||||
unsigned char numStr[32];
|
||||
|
||||
TextFace(normal);
|
||||
NumToString(num, numStr); /* Its possible that a large unsigned
|
||||
will come back negative! */
|
||||
DrawString(numStr);
|
||||
TextFace(bold);
|
||||
}
|
||||
|
||||
pascal short DRVRClose(char *ctlPB, DCtlPtr dCtl)
|
||||
{ /* Save & Restore current grafPort? */
|
||||
#pragma unused (ctlPB)
|
||||
WindowPtr window;
|
||||
|
||||
window = (WindowPtr) dCtl->dCtlWindow;
|
||||
if ( window != nil) {
|
||||
dCtl->dCtlWindow = nil;
|
||||
DisposHandle(dCtl->dCtlStorage);
|
||||
DisposeWindow(window);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static StringPtr text(int index, Globals *globals)
|
||||
{
|
||||
GetIndString(globals->strBuf, globals->rsrcID, index);
|
||||
return(globals->strBuf);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0065 6D6F 7279 2E63" /* ..Monaco.emory.c */
|
||||
$"0022 0000 0000 0036 0000 0064 6669 6E64" /* .".....6...dfind */
|
||||
$"00A5 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* File Memory.r
|
||||
*
|
||||
* Copyright Apple Computer, Inc. 1985-1987
|
||||
* All rights reserved.
|
||||
*
|
||||
* Sample desk accessory resource file.
|
||||
* This incorporates the DRVR header information (defined here)
|
||||
* with the linked code (stored as a 'DRVW' resource in the link command)
|
||||
*/
|
||||
|
||||
#include "Types.r" /* To get system types */
|
||||
#include "MPWTypes.r" /* To get 'DRVW' type */
|
||||
|
||||
#define DriverID 12
|
||||
|
||||
#ifdef NOASM_BUILD
|
||||
/*
|
||||
* This will produce a DRVR resource from the special DRVW type.
|
||||
* (this eliminates the need for using the Assembler to create
|
||||
* the DA header, but makes it impossible to use SADE, oops!)
|
||||
*
|
||||
* Note that the ID 12 is irrelevant, since the Font/DA Mover
|
||||
* will renumber it to something else when installing it anyway.
|
||||
*
|
||||
* The leading NUL in the resource name is required to
|
||||
* conform to the desk accessory naming convention.
|
||||
*
|
||||
* The resource is declared purgeable. If the code were to
|
||||
* do funky things like SetTrapAddress calls (requiring the code to
|
||||
* be around at all times), we would have to set it nonpurgeable.
|
||||
*/
|
||||
|
||||
type 'DRVR' as 'DRVW'; /* Map 'DRVW' => 'DRVR' */
|
||||
|
||||
resource 'DRVR' (DriverID, "\0x00Memory", purgeable) {
|
||||
/*
|
||||
* DRVR flags
|
||||
*/
|
||||
dontNeedLock, /* OK to float around, not saving ProcPtrs */
|
||||
needTime, /* Yes, give us periodic Control calls */
|
||||
dontNeedGoodbye, /* No special requirements */
|
||||
noStatusEnable,
|
||||
ctlEnable, /* Desk accessories only do Control calls */
|
||||
noWriteEnable,
|
||||
noReadEnable,
|
||||
5*60, /* drvrDelay - Wake up every 5 seconds */
|
||||
updateMask, /* drvrEMask - This DA only handles update events */
|
||||
0, /* drvrMenu - This DA has no menu */
|
||||
"Memory", /* drvrName - This isn't used by the DA */
|
||||
/*
|
||||
* This directive inserts the contents of the DRVW resource
|
||||
* produced by linking DRVRRuntime.o with our DA code
|
||||
*/
|
||||
$$resource("Memory.DRVW", 'DRVW', 0)
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Since desk accessories cannot use global data (and the C compiler
|
||||
* considers string constants to be global data) and we really don't
|
||||
* want to hard-code strings in our source, the strings used by the
|
||||
* DA are stored in the resource file. Note the expression used to
|
||||
* figure out the resource id.
|
||||
*/
|
||||
|
||||
resource 'STR#' (0xC000 | (DriverID << 5), "Memory's Strings") {
|
||||
{
|
||||
"AppHeap: ";
|
||||
" SysHeap: ";
|
||||
" Disk: ";
|
||||
" free on "
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
resource 'WIND' (0xC000 | (DriverID << 5), "Memory's Window") {
|
||||
{322, 10, 338, 500},
|
||||
noGrowDocProc,
|
||||
visible,
|
||||
goAway,
|
||||
0x0,
|
||||
"Free Memory (# Bytes)"
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0065 6D6F 7279 2E72" /* ..Monaco.emory.r */
|
||||
$"0022 0000 6D6F 7279 2E72 00D4 0045 14E0" /* ."..mory.r...E.. */
|
||||
$"0000 0006 0004 002A 0003 0142 01E3 002A" /* .......*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,878 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
#
|
||||
# Apple Macintosh Developer Technical Support
|
||||
#
|
||||
# MultiFinder-Aware Simple Sample Application
|
||||
#
|
||||
# Sample
|
||||
#
|
||||
# Sample.c - C Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1989-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions:
|
||||
# 1.00 08/88
|
||||
# 1.01 11/88
|
||||
# 1.02 04/89 MPW 3.1
|
||||
# 1.03 02/90 MPW 3.2
|
||||
#
|
||||
# Components:
|
||||
# Sample.c Feb. 1, 1990
|
||||
# Sample.r Feb. 1, 1990
|
||||
# Sample.h Feb. 1, 1990
|
||||
# Sample.make Feb. 1, 1990
|
||||
#
|
||||
# Sample is an example application that demonstrates how to
|
||||
# initialize the commonly used toolbox managers, operate
|
||||
# successfully under MultiFinder, handle desk accessories,
|
||||
# and create, grow, and zoom windows.
|
||||
#
|
||||
# It does not by any means demonstrate all the techniques
|
||||
# you need for a large application. In particular, Sample
|
||||
# does not cover exception handling, multiple windows/documents,
|
||||
# sophisticated memory management, printing, or undo. All of
|
||||
# these are vital parts of a normal full-sized application.
|
||||
#
|
||||
# This application is an example of the form of a Macintosh
|
||||
# application; it is NOT a template. It is NOT intended to be
|
||||
# used as a foundation for the next world-class, best-selling,
|
||||
# 600K application. A stick figure drawing of the human body may
|
||||
# be a good example of the form for a painting, but that does not
|
||||
# mean it should be used as the basis for the next Mona Lisa.
|
||||
#
|
||||
# We recommend that you review this program or TESample before
|
||||
# beginning a new application.
|
||||
#
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/* Segmentation strategy:
|
||||
|
||||
This program consists of three segments. Main contains most of the code,
|
||||
including the MPW libraries, and the main program. Initialize contains
|
||||
code that is only used once, during startup, and can be unloaded after the
|
||||
program starts. %A5Init is automatically created by the Linker to initialize
|
||||
globals for the MPW libraries and is unloaded right away. */
|
||||
|
||||
|
||||
/* SetPort strategy:
|
||||
|
||||
Toolbox routines do not change the current port. In spite of this, in this
|
||||
program we use a strategy of calling SetPort whenever we want to draw or
|
||||
make calls which depend on the current port. This makes us less vulnerable
|
||||
to bugs in other software which might alter the current port (such as the
|
||||
bug (feature?) in many desk accessories which change the port on OpenDeskAcc).
|
||||
Hopefully, this also makes the routines from this program more self-contained,
|
||||
since they don't depend on the current port setting. */
|
||||
|
||||
|
||||
#include <Values.h>
|
||||
#include <Types.h>
|
||||
#include <Resources.h>
|
||||
#include <QuickDraw.h>
|
||||
#include <Fonts.h>
|
||||
#include <Events.h>
|
||||
#include <Windows.h>
|
||||
#include <Menus.h>
|
||||
#include <TextEdit.h>
|
||||
#include <Dialogs.h>
|
||||
#include <Desk.h>
|
||||
#include <ToolUtils.h>
|
||||
#include <Memory.h>
|
||||
#include <SegLoad.h>
|
||||
#include <Files.h>
|
||||
#include <OSUtils.h>
|
||||
#include <OSEvents.h>
|
||||
#include <DiskInit.h>
|
||||
#include <Packages.h>
|
||||
#include <Traps.h>
|
||||
#include "Sample.h" /* bring in all the #defines for Sample */
|
||||
|
||||
|
||||
/* The "g" prefix is used to emphasize that a variable is global. */
|
||||
|
||||
/* GMac is used to hold the result of a SysEnvirons call. This makes
|
||||
it convenient for any routine to check the environment. */
|
||||
SysEnvRec gMac; /* set up by Initialize */
|
||||
|
||||
/* GHasWaitNextEvent is set at startup, and tells whether the WaitNextEvent
|
||||
trap is available. If it is false, we know that we must call GetNextEvent. */
|
||||
Boolean gHasWaitNextEvent; /* set up by Initialize */
|
||||
|
||||
/* GInBackground is maintained by our osEvent handling routines. Any part of
|
||||
the program can check it to find out if it is currently in the background. */
|
||||
Boolean gInBackground; /* maintained by Initialize and DoEvent */
|
||||
|
||||
|
||||
/* The following globals are the state of the window. If we supported more than
|
||||
one window, they would be attatched to each document, rather than globals. */
|
||||
|
||||
/* GStopped tells whether the stop light is currently on stop or go. */
|
||||
Boolean gStopped; /* maintained by Initialize and SetLight */
|
||||
|
||||
/* GStopRect and gGoRect are the rectangles of the two stop lights in the window. */
|
||||
Rect gStopRect; /* set up by Initialize */
|
||||
Rect gGoRect; /* set up by Initialize */
|
||||
|
||||
|
||||
/* Here are declarations for all of the C routines. In MPW 3.0 we can use
|
||||
actual prototypes for parameter type checking. */
|
||||
void EventLoop( void );
|
||||
void DoEvent( EventRecord *event );
|
||||
void AdjustCursor( Point mouse, RgnHandle region );
|
||||
void GetGlobalMouse( Point *mouse );
|
||||
void DoUpdate( WindowPtr window );
|
||||
void DoActivate( WindowPtr window, Boolean becomingActive );
|
||||
void DoContentClick( WindowPtr window );
|
||||
void DrawWindow( WindowPtr window );
|
||||
void AdjustMenus( void );
|
||||
void DoMenuCommand( long menuResult );
|
||||
void SetLight( WindowPtr window, Boolean newStopped );
|
||||
Boolean DoCloseWindow( WindowPtr window );
|
||||
void Terminate( void );
|
||||
void Initialize( void );
|
||||
Boolean GoGetRect( short rectID, Rect *theRect );
|
||||
void ForceEnvirons( void );
|
||||
Boolean IsAppWindow( WindowPtr window );
|
||||
Boolean IsDAWindow( WindowPtr window );
|
||||
Boolean TrapAvailable( short tNumber, TrapType tType );
|
||||
void AlertUser( void );
|
||||
|
||||
|
||||
/* Define HiWrd and LoWrd macros for efficiency. */
|
||||
#define HiWrd(aLong) (((aLong) >> 16) & 0xFFFF)
|
||||
#define LoWrd(aLong) ((aLong) & 0xFFFF)
|
||||
|
||||
/* Define TopLeft and BotRight macros for convenience. Notice the implicit
|
||||
dependency on the ordering of fields within a Rect */
|
||||
#define TopLeft(aRect) (* (Point *) &(aRect).top)
|
||||
#define BotRight(aRect) (* (Point *) &(aRect).bottom)
|
||||
|
||||
|
||||
extern void _DataInit();
|
||||
|
||||
/* This routine is part of the MPW runtime library. This external
|
||||
reference to it is done so that we can unload its segment, %A5Init. */
|
||||
|
||||
|
||||
#pragma segment Main
|
||||
main()
|
||||
{
|
||||
UnloadSeg((Ptr) _DataInit); /* note that _DataInit must not be in Main! */
|
||||
|
||||
/* 1.01 - call to ForceEnvirons removed */
|
||||
|
||||
/* If you have stack requirements that differ from the default,
|
||||
then you could use SetApplLimit to increase StackSpace at
|
||||
this point, before calling MaxApplZone. */
|
||||
MaxApplZone(); /* expand the heap so code segments load at the top */
|
||||
|
||||
Initialize(); /* initialize the program */
|
||||
UnloadSeg((Ptr) Initialize); /* note that Initialize must not be in Main! */
|
||||
|
||||
EventLoop(); /* call the main event loop */
|
||||
}
|
||||
|
||||
|
||||
/* Get events forever, and handle them by calling DoEvent.
|
||||
Get the events by calling WaitNextEvent, if it's available, otherwise
|
||||
by calling GetNextEvent. Also call AdjustCursor each time through the loop. */
|
||||
|
||||
#pragma segment Main
|
||||
void EventLoop()
|
||||
{
|
||||
RgnHandle cursorRgn;
|
||||
Boolean gotEvent;
|
||||
EventRecord event;
|
||||
Point mouse;
|
||||
|
||||
cursorRgn = NewRgn(); /* we’ll pass WNE an empty region the 1st time thru */
|
||||
do {
|
||||
/* use WNE if it is available */
|
||||
if ( gHasWaitNextEvent ) {
|
||||
GetGlobalMouse(&mouse);
|
||||
AdjustCursor(mouse, cursorRgn);
|
||||
gotEvent = WaitNextEvent(everyEvent, &event, MAXLONG, cursorRgn);
|
||||
}
|
||||
else {
|
||||
SystemTask();
|
||||
gotEvent = GetNextEvent(everyEvent, &event);
|
||||
}
|
||||
if ( gotEvent ) {
|
||||
/* make sure we have the right cursor before handling the event */
|
||||
AdjustCursor(event.where, cursorRgn);
|
||||
DoEvent(&event);
|
||||
}
|
||||
/* If you are using modeless dialogs that have editText items,
|
||||
you will want to call IsDialogEvent to give the caret a chance
|
||||
to blink, even if WNE/GNE returned FALSE. However, check FrontWindow
|
||||
for a non-NIL value before calling IsDialogEvent. */
|
||||
} while ( true ); /* loop forever; we quit via ExitToShell */
|
||||
} /*EventLoop*/
|
||||
|
||||
|
||||
/* Do the right thing for an event. Determine what kind of event it is, and call
|
||||
the appropriate routines. */
|
||||
|
||||
#pragma segment Main
|
||||
void DoEvent(event)
|
||||
EventRecord *event;
|
||||
{
|
||||
short part, err;
|
||||
WindowPtr window;
|
||||
Boolean hit;
|
||||
char key;
|
||||
Point aPoint;
|
||||
|
||||
switch ( event->what ) {
|
||||
case mouseDown:
|
||||
part = FindWindow(event->where, &window);
|
||||
switch ( part ) {
|
||||
case inMenuBar: /* process a mouse menu command (if any) */
|
||||
AdjustMenus();
|
||||
DoMenuCommand(MenuSelect(event->where));
|
||||
break;
|
||||
case inSysWindow: /* let the system handle the mouseDown */
|
||||
SystemClick(event, window);
|
||||
break;
|
||||
case inContent:
|
||||
if ( window != FrontWindow() ) {
|
||||
SelectWindow(window);
|
||||
/*DoEvent(event);*/ /* use this line for "do first click" */
|
||||
} else
|
||||
DoContentClick(window);
|
||||
break;
|
||||
case inDrag: /* pass screenBits.bounds to get all gDevices */
|
||||
DragWindow(window, event->where, &qd.screenBits.bounds);
|
||||
break;
|
||||
case inGrow:
|
||||
break;
|
||||
case inZoomIn:
|
||||
case inZoomOut:
|
||||
hit = TrackBox(window, event->where, part);
|
||||
if ( hit ) {
|
||||
SetPort(window); /* the window must be the current port... */
|
||||
EraseRect(&window->portRect); /* because of a bug in ZoomWindow */
|
||||
ZoomWindow(window, part, true); /* note that we invalidate and erase... */
|
||||
InvalRect(&window->portRect); /* to make things look better on-screen */
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case keyDown:
|
||||
case autoKey: /* check for menukey equivalents */
|
||||
key = event->message & charCodeMask;
|
||||
if ( event->modifiers & cmdKey ) /* Command key down */
|
||||
if ( event->what == keyDown ) {
|
||||
AdjustMenus(); /* enable/disable/check menu items properly */
|
||||
DoMenuCommand(MenuKey(key));
|
||||
}
|
||||
break;
|
||||
case activateEvt:
|
||||
DoActivate((WindowPtr) event->message, (event->modifiers & activeFlag) != 0);
|
||||
break;
|
||||
case updateEvt:
|
||||
DoUpdate((WindowPtr) event->message);
|
||||
break;
|
||||
/* 1.01 - It is not a bad idea to at least call DIBadMount in response
|
||||
to a diskEvt, so that the user can format a floppy. */
|
||||
case diskEvt:
|
||||
if ( HiWord(event->message) != noErr ) {
|
||||
SetPt(&aPoint, kDILeft, kDITop);
|
||||
err = DIBadMount(aPoint, event->message);
|
||||
}
|
||||
break;
|
||||
case kOSEvent:
|
||||
/* 1.02 - must BitAND with 0x0FF to get only low byte */
|
||||
switch ((event->message >> 24) & 0x0FF) { /* high byte of message */
|
||||
case kSuspendResumeMessage: /* suspend/resume is also an activate/deactivate */
|
||||
gInBackground = (event->message & kResumeMask) == 0;
|
||||
DoActivate(FrontWindow(), !gInBackground);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} /*DoEvent*/
|
||||
|
||||
|
||||
/* Change the cursor's shape, depending on its position. This also calculates the region
|
||||
where the current cursor resides (for WaitNextEvent). If the mouse is ever outside of
|
||||
that region, an event would be generated, causing this routine to be called,
|
||||
allowing us to change the region to the region the mouse is currently in. If
|
||||
there is more to the event than just “the mouse moved”, we get called before the
|
||||
event is processed to make sure the cursor is the right one. In any (ahem) event,
|
||||
this is called again before we fall back into WNE. */
|
||||
|
||||
#pragma segment Main
|
||||
void AdjustCursor(mouse,region)
|
||||
Point mouse;
|
||||
RgnHandle region;
|
||||
{
|
||||
WindowPtr window;
|
||||
RgnHandle arrowRgn;
|
||||
RgnHandle plusRgn;
|
||||
Rect globalPortRect;
|
||||
|
||||
window = FrontWindow(); /* we only adjust the cursor when we are in front */
|
||||
if ( (! gInBackground) && (! IsDAWindow(window)) ) {
|
||||
/* calculate regions for different cursor shapes */
|
||||
arrowRgn = NewRgn();
|
||||
plusRgn = NewRgn();
|
||||
|
||||
/* start with a big, big rectangular region */
|
||||
SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
|
||||
|
||||
/* calculate plusRgn */
|
||||
if ( IsAppWindow(window) ) {
|
||||
SetPort(window); /* make a global version of the viewRect */
|
||||
SetOrigin(-window->portBits.bounds.left, -window->portBits.bounds.top);
|
||||
globalPortRect = window->portRect;
|
||||
RectRgn(plusRgn, &globalPortRect);
|
||||
SectRgn(plusRgn, window->visRgn, plusRgn);
|
||||
SetOrigin(0, 0);
|
||||
}
|
||||
|
||||
/* subtract other regions from arrowRgn */
|
||||
DiffRgn(arrowRgn, plusRgn, arrowRgn);
|
||||
|
||||
/* change the cursor and the region parameter */
|
||||
if ( PtInRgn(mouse, plusRgn) ) {
|
||||
SetCursor(*GetCursor(plusCursor));
|
||||
CopyRgn(plusRgn, region);
|
||||
} else {
|
||||
SetCursor(&qd.arrow);
|
||||
CopyRgn(arrowRgn, region);
|
||||
}
|
||||
|
||||
/* get rid of our local regions */
|
||||
DisposeRgn(arrowRgn);
|
||||
DisposeRgn(plusRgn);
|
||||
}
|
||||
} /*AdjustCursor*/
|
||||
|
||||
|
||||
/* Get the global coordinates of the mouse. When you call OSEventAvail
|
||||
it will return either a pending event or a null event. In either case,
|
||||
the where field of the event record will contain the current position
|
||||
of the mouse in global coordinates and the modifiers field will reflect
|
||||
the current state of the modifiers. Another way to get the global
|
||||
coordinates is to call GetMouse and LocalToGlobal, but that requires
|
||||
being sure that thePort is set to a valid port. */
|
||||
|
||||
#pragma segment Main
|
||||
void GetGlobalMouse(mouse)
|
||||
Point *mouse;
|
||||
{
|
||||
EventRecord event;
|
||||
|
||||
OSEventAvail(kNoEvents, &event); /* we aren't interested in any events */
|
||||
*mouse = event.where; /* just the mouse position */
|
||||
} /*GetGlobalMouse*/
|
||||
|
||||
|
||||
/* This is called when an update event is received for a window.
|
||||
It calls DrawWindow to draw the contents of an application window.
|
||||
As an effeciency measure that does not have to be followed, it
|
||||
calls the drawing routine only if the visRgn is non-empty. This
|
||||
will handle situations where calculations for drawing or drawing
|
||||
itself is very time-consuming. */
|
||||
|
||||
#pragma segment Main
|
||||
void DoUpdate(window)
|
||||
WindowPtr window;
|
||||
{
|
||||
if ( IsAppWindow(window) ) {
|
||||
BeginUpdate(window); /* this sets up the visRgn */
|
||||
if ( ! EmptyRgn(window->visRgn) ) /* draw if updating needs to be done */
|
||||
DrawWindow(window);
|
||||
EndUpdate(window);
|
||||
}
|
||||
} /*DoUpdate*/
|
||||
|
||||
|
||||
/* This is called when a window is activated or deactivated.
|
||||
In Sample, the Window Manager's handling of activate and
|
||||
deactivate events is sufficient. Other applications may have
|
||||
TextEdit records, controls, lists, etc., to activate/deactivate. */
|
||||
|
||||
#pragma segment Main
|
||||
void DoActivate(window, becomingActive)
|
||||
WindowPtr window;
|
||||
Boolean becomingActive;
|
||||
{
|
||||
if ( IsAppWindow(window) ) {
|
||||
if ( becomingActive )
|
||||
/* do whatever you need to at activation */ ;
|
||||
else
|
||||
/* do whatever you need to at deactivation */ ;
|
||||
}
|
||||
} /*DoActivate*/
|
||||
|
||||
|
||||
/* This is called when a mouse-down event occurs in the content of a window.
|
||||
Other applications might want to call FindControl, TEClick, etc., to
|
||||
further process the click. */
|
||||
|
||||
#pragma segment Main
|
||||
void DoContentClick(window)
|
||||
WindowPtr window;
|
||||
{
|
||||
SetLight(window, ! gStopped);
|
||||
} /*DoContentClick*/
|
||||
|
||||
|
||||
/* Draw the contents of the application window. We do some drawing in color, using
|
||||
Classic QuickDraw's color capabilities. This will be black and white on old
|
||||
machines, but color on color machines. At this point, the window’s visRgn
|
||||
is set to allow drawing only where it needs to be done. */
|
||||
|
||||
#pragma segment Main
|
||||
void DrawWindow(window)
|
||||
WindowPtr window;
|
||||
{
|
||||
SetPort(window);
|
||||
|
||||
EraseRect(&window->portRect); /* clear out any garbage that may linger */
|
||||
if ( gStopped ) /* draw a red (or white) stop light */
|
||||
ForeColor(redColor);
|
||||
else
|
||||
ForeColor(whiteColor);
|
||||
PaintOval(&gStopRect);
|
||||
ForeColor(blackColor);
|
||||
FrameOval(&gStopRect);
|
||||
if ( ! gStopped ) /* draw a green (or white) go light */
|
||||
ForeColor(greenColor);
|
||||
else
|
||||
ForeColor(whiteColor);
|
||||
PaintOval(&gGoRect);
|
||||
ForeColor(blackColor);
|
||||
FrameOval(&gGoRect);
|
||||
} /*DrawWindow*/
|
||||
|
||||
|
||||
/* Enable and disable menus based on the current state.
|
||||
The user can only select enabled menu items. We set up all the menu items
|
||||
before calling MenuSelect or MenuKey, since these are the only times that
|
||||
a menu item can be selected. Note that MenuSelect is also the only time
|
||||
the user will see menu items. This approach to deciding what enable/
|
||||
disable state a menu item has the advantage of concentrating all
|
||||
the decision-making in one routine, as opposed to being spread throughout
|
||||
the application. Other application designs may take a different approach
|
||||
that is just as valid. */
|
||||
|
||||
#pragma segment Main
|
||||
void AdjustMenus()
|
||||
{
|
||||
WindowPtr window;
|
||||
MenuHandle menu;
|
||||
|
||||
window = FrontWindow();
|
||||
|
||||
menu = GetMHandle(mFile);
|
||||
if ( IsDAWindow(window) ) /* we can allow desk accessories to be closed from the menu */
|
||||
EnableItem(menu, iClose);
|
||||
else
|
||||
DisableItem(menu, iClose); /* but not our traffic light window */
|
||||
|
||||
menu = GetMHandle(mEdit);
|
||||
if ( IsDAWindow(window) ) { /* a desk accessory might need the edit menu… */
|
||||
EnableItem(menu, iUndo);
|
||||
EnableItem(menu, iCut);
|
||||
EnableItem(menu, iCopy);
|
||||
EnableItem(menu, iClear);
|
||||
EnableItem(menu, iPaste);
|
||||
} else { /* …but we don’t use it */
|
||||
DisableItem(menu, iUndo);
|
||||
DisableItem(menu, iCut);
|
||||
DisableItem(menu, iCopy);
|
||||
DisableItem(menu, iClear);
|
||||
DisableItem(menu, iPaste);
|
||||
}
|
||||
|
||||
menu = GetMHandle(mLight);
|
||||
if ( IsAppWindow(window) ) { /* we know that it must be the traffic light */
|
||||
EnableItem(menu, iStop);
|
||||
EnableItem(menu, iGo);
|
||||
} else {
|
||||
DisableItem(menu, iStop);
|
||||
DisableItem(menu, iGo);
|
||||
}
|
||||
CheckItem(menu, iStop, gStopped); /* we can also determine check/uncheck state, too */
|
||||
CheckItem(menu, iGo, ! gStopped);
|
||||
} /*AdjustMenus*/
|
||||
|
||||
|
||||
/* This is called when an item is chosen from the menu bar (after calling
|
||||
MenuSelect or MenuKey). It performs the right operation for each command.
|
||||
It is good to have both the result of MenuSelect and MenuKey go to
|
||||
one routine like this to keep everything organized. */
|
||||
|
||||
#pragma segment Main
|
||||
void DoMenuCommand(menuResult)
|
||||
long menuResult;
|
||||
{
|
||||
short menuID; /* the resource ID of the selected menu */
|
||||
short menuItem; /* the item number of the selected menu */
|
||||
short itemHit;
|
||||
Str255 daName;
|
||||
short daRefNum;
|
||||
Boolean handledByDA;
|
||||
|
||||
menuID = HiWord(menuResult); /* use macros for efficiency to... */
|
||||
menuItem = LoWord(menuResult); /* get menu item number and menu number */
|
||||
switch ( menuID ) {
|
||||
case mApple:
|
||||
switch ( menuItem ) {
|
||||
case iAbout: /* bring up alert for About */
|
||||
itemHit = Alert(rAboutAlert, nil);
|
||||
break;
|
||||
default: /* all non-About items in this menu are DAs */
|
||||
/* type Str255 is an array in MPW 3 */
|
||||
GetItem(GetMHandle(mApple), menuItem, daName);
|
||||
daRefNum = OpenDeskAcc(daName);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case mFile:
|
||||
switch ( menuItem ) {
|
||||
case iClose:
|
||||
DoCloseWindow(FrontWindow());
|
||||
break;
|
||||
case iQuit:
|
||||
Terminate();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case mEdit: /* call SystemEdit for DA editing & MultiFinder */
|
||||
handledByDA = SystemEdit(menuItem-1); /* since we don’t do any Editing */
|
||||
break;
|
||||
case mLight:
|
||||
switch ( menuItem ) {
|
||||
case iStop:
|
||||
SetLight(FrontWindow(), true);
|
||||
break;
|
||||
case iGo:
|
||||
SetLight(FrontWindow(), false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
HiliteMenu(0); /* unhighlight what MenuSelect (or MenuKey) hilited */
|
||||
} /*DoMenuCommand*/
|
||||
|
||||
|
||||
/* Change the setting of the light. */
|
||||
|
||||
#pragma segment Main
|
||||
void SetLight( window, newStopped )
|
||||
WindowPtr window;
|
||||
Boolean newStopped;
|
||||
{
|
||||
if ( newStopped != gStopped ) {
|
||||
gStopped = newStopped;
|
||||
SetPort(window);
|
||||
InvalRect(&window->portRect);
|
||||
}
|
||||
} /*SetLight*/
|
||||
|
||||
|
||||
/* Close a window. This handles desk accessory and application windows. */
|
||||
|
||||
/* 1.01 - At this point, if there was a document associated with a
|
||||
window, you could do any document saving processing if it is 'dirty'.
|
||||
DoCloseWindow would return true if the window actually closed, i.e.,
|
||||
the user didn’t cancel from a save dialog. This result is handy when
|
||||
the user quits an application, but then cancels the save of a document
|
||||
associated with a window. */
|
||||
|
||||
#pragma segment Main
|
||||
Boolean DoCloseWindow(window)
|
||||
WindowPtr window;
|
||||
{
|
||||
if ( IsDAWindow(window) )
|
||||
CloseDeskAcc(((WindowPeek) window)->windowKind);
|
||||
else if ( IsAppWindow(window) )
|
||||
CloseWindow(window);
|
||||
return true;
|
||||
} /*DoCloseWindow*/
|
||||
|
||||
|
||||
/**************************************************************************************
|
||||
*** 1.01 DoCloseBehind(window) was removed ***
|
||||
|
||||
1.01 - DoCloseBehind was a good idea for closing windows when quitting
|
||||
and not having to worry about updating the windows, but it suffered
|
||||
from a fatal flaw. If a desk accessory owned two windows, it would
|
||||
close both those windows when CloseDeskAcc was called. When DoCloseBehind
|
||||
got around to calling DoCloseWindow for that other window that was already
|
||||
closed, things would go very poorly. Another option would be to have a
|
||||
procedure, GetRearWindow, that would go through the window list and return
|
||||
the last window. Instead, we decided to present the standard approach
|
||||
of getting and closing FrontWindow until FrontWindow returns NIL. This
|
||||
has a potential benefit in that the window whose document needs to be saved
|
||||
may be visible since it is the front window, therefore decreasing the
|
||||
chance of user confusion. For aesthetic reasons, the windows in the
|
||||
application should be checked for updates periodically and have the
|
||||
updates serviced.
|
||||
**************************************************************************************/
|
||||
|
||||
|
||||
/* Clean up the application and exit. We close all of the windows so that
|
||||
they can update their documents, if any. */
|
||||
|
||||
/* 1.01 - If we find out that a cancel has occurred, we won't exit to the
|
||||
shell, but will return instead. */
|
||||
|
||||
#pragma segment Main
|
||||
void Terminate()
|
||||
{
|
||||
WindowPtr aWindow;
|
||||
Boolean closed;
|
||||
|
||||
closed = true;
|
||||
do {
|
||||
aWindow = FrontWindow(); /* get the current front window */
|
||||
if (aWindow != nil)
|
||||
closed = DoCloseWindow(aWindow); /* close this window */
|
||||
}
|
||||
while (closed && (aWindow != nil));
|
||||
if (closed)
|
||||
ExitToShell(); /* exit if no cancellation */
|
||||
} /*Terminate*/
|
||||
|
||||
|
||||
/* Set up the whole world, including global variables, Toolbox managers,
|
||||
and menus. We also create our one application window at this time.
|
||||
Since window storage is non-relocateable, how and when to allocate space
|
||||
for windows is very important so that heap fragmentation does not occur.
|
||||
Because Sample has only one window and it is only disposed when the application
|
||||
quits, we will allocate its space here, before anything that might be a locked
|
||||
relocatable object gets into the heap. This way, we can force the storage to be
|
||||
in the lowest memory available in the heap. Window storage can differ widely
|
||||
amongst applications depending on how many windows are created and disposed. */
|
||||
|
||||
/* 1.01 - The code that used to be part of ForceEnvirons has been moved into
|
||||
this module. If an error is detected, instead of merely doing an ExitToShell,
|
||||
which leaves the user without much to go on, we call AlertUser, which puts
|
||||
up a simple alert that just says an error occurred and then calls ExitToShell.
|
||||
Since there is no other cleanup needed at this point if an error is detected,
|
||||
this form of error- handling is acceptable. If more sophisticated error recovery
|
||||
is needed, an exception mechanism, such as is provided by Signals, can be used. */
|
||||
|
||||
#pragma segment Initialize
|
||||
void Initialize()
|
||||
{
|
||||
Handle menuBar;
|
||||
WindowPtr window;
|
||||
long total, contig;
|
||||
EventRecord event;
|
||||
short count;
|
||||
|
||||
gInBackground = false;
|
||||
|
||||
InitGraf((Ptr) &qd.thePort);
|
||||
InitFonts();
|
||||
InitWindows();
|
||||
InitMenus();
|
||||
TEInit();
|
||||
InitDialogs(nil);
|
||||
InitCursor();
|
||||
|
||||
/* Call MPPOpen and ATPLoad at this point to initialize AppleTalk,
|
||||
if you are using it. */
|
||||
/* NOTE -- It is no longer necessary, and actually unhealthy, to check
|
||||
PortBUse and SPConfig before opening AppleTalk. The drivers are capable
|
||||
of checking for port availability themselves. */
|
||||
|
||||
/* This next bit of code is necessary to allow the default button of our
|
||||
alert be outlined.
|
||||
1.02 - Changed to call EventAvail so that we don't lose some important
|
||||
events. */
|
||||
|
||||
for (count = 1; count <= 3; count++)
|
||||
EventAvail(everyEvent, &event);
|
||||
|
||||
/* Ignore the error returned from SysEnvirons; even if an error occurred,
|
||||
the SysEnvirons glue will fill in the SysEnvRec. You can save a redundant
|
||||
call to SysEnvirons by calling it after initializing AppleTalk. */
|
||||
|
||||
SysEnvirons(kSysEnvironsVersion, &gMac);
|
||||
|
||||
/* Make sure that the machine has at least 128K ROMs. If it doesn't, exit. */
|
||||
|
||||
if (gMac.machineType < 0) AlertUser();
|
||||
|
||||
/* 1.02 - Move TrapAvailable call to after SysEnvirons so that we can tell
|
||||
in TrapAvailable if a tool trap value is out of range. */
|
||||
|
||||
gHasWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap);
|
||||
|
||||
/* 1.01 - We used to make a check for memory at this point by examining ApplLimit,
|
||||
ApplicZone, and StackSpace and comparing that to the minimum size we told
|
||||
MultiFinder we needed. This did not work well because it assumed too much about
|
||||
the relationship between what we asked MultiFinder for and what we would actually
|
||||
get back, as well as how to measure it. Instead, we will use an alternate
|
||||
method comprised of two steps. */
|
||||
|
||||
/* It is better to first check the size of the application heap against a value
|
||||
that you have determined is the smallest heap the application can reasonably
|
||||
work in. This number should be derived by examining the size of the heap that
|
||||
is actually provided by MultiFinder when the minimum size requested is used.
|
||||
The derivation of the minimum size requested from MultiFinder is described
|
||||
in Sample.h. The check should be made because the preferred size can end up
|
||||
being set smaller than the minimum size by the user. This extra check acts to
|
||||
insure that your application is starting from a solid memory foundation. */
|
||||
|
||||
if ((long) GetApplLimit() - (long) ApplicZone() < kMinHeap) AlertUser();
|
||||
|
||||
/* Next, make sure that enough memory is free for your application to run. It
|
||||
is possible for a situation to arise where the heap may have been of required
|
||||
size, but a large scrap was loaded which left too little memory. To check for
|
||||
this, call PurgeSpace and compare the result with a value that you have determined
|
||||
is the minimum amount of free memory your application needs at initialization.
|
||||
This number can be derived several different ways. One way that is fairly
|
||||
straightforward is to run the application in the minimum size configuration
|
||||
as described previously. Call PurgeSpace at initialization and examine the value
|
||||
returned. However, you should make sure that this result is not being modified
|
||||
by the scrap's presence. You can do that by calling ZeroScrap before calling
|
||||
PurgeSpace. Make sure to remove that call before shipping, though. */
|
||||
|
||||
/* ZeroScrap(); */
|
||||
|
||||
PurgeSpace(&total, &contig);
|
||||
if (total < kMinSpace) AlertUser();
|
||||
|
||||
/* The extra benefit to waiting until after the Toolbox Managers have been initialized
|
||||
to check memory is that we can now give the user an alert to tell him/her what
|
||||
happened. Although it is possible that the memory situation could be worsened by
|
||||
displaying an alert, MultiFinder would gracefully exit the application with
|
||||
an informative alert if memory became critical. Here we are acting more
|
||||
in a preventative manner to avoid future disaster from low-memory problems. */
|
||||
|
||||
/* we will allocate our own window storage instead of letting the Window
|
||||
Manager do it because GetNewWindow may load in temp. resources before
|
||||
making the NewPtr call, and this can lead to heap fragmentation. */
|
||||
window = (WindowPtr) NewPtr(sizeof(WindowRecord));
|
||||
if ( window == nil ) AlertUser();
|
||||
window = GetNewWindow(rWindow, (Ptr) window, (WindowPtr) -1);
|
||||
|
||||
menuBar = GetNewMBar(rMenuBar); /* read menus into menu bar */
|
||||
if ( menuBar == nil ) AlertUser();
|
||||
SetMenuBar(menuBar); /* install menus */
|
||||
DisposHandle(menuBar);
|
||||
AddResMenu(GetMHandle(mApple), 'DRVR'); /* add DA names to Apple menu */
|
||||
DrawMenuBar();
|
||||
|
||||
gStopped = true;
|
||||
if ( !GoGetRect(rStopRect, &gStopRect) )
|
||||
AlertUser(); /* the stop light rectangle */
|
||||
if ( !GoGetRect(rGoRect, &gGoRect) )
|
||||
AlertUser(); /* the go light rectangle */
|
||||
} /*Initialize*/
|
||||
|
||||
|
||||
/* This utility loads the global rectangles that are used by the window
|
||||
drawing routines. It shows how the resource manager can be used to hold
|
||||
values in a convenient manner. These values are then easily altered without
|
||||
having to re-compile the source code. In this particular case, we know
|
||||
that this routine is being called at initialization time. Therefore,
|
||||
if a failure occurs here, we will assume that the application is in such
|
||||
bad shape that we should just exit. Your error handling may differ, but
|
||||
the check should still be made. */
|
||||
|
||||
#pragma segment Initialize
|
||||
Boolean GoGetRect(rectID,theRect)
|
||||
short rectID;
|
||||
Rect *theRect;
|
||||
{
|
||||
Handle resource;
|
||||
|
||||
resource = GetResource('RECT', rectID);
|
||||
if ( resource != nil ) {
|
||||
*theRect = **((Rect**) resource);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
} /* GoGetRect */
|
||||
|
||||
|
||||
/* Check to see if a window belongs to the application. If the window pointer
|
||||
passed was NIL, then it could not be an application window. WindowKinds
|
||||
that are negative belong to the system and windowKinds less than userKind
|
||||
are reserved by Apple except for windowKinds equal to dialogKind, which
|
||||
mean it is a dialog.
|
||||
1.02 - In order to reduce the chance of accidentally treating some window
|
||||
as an AppWindow that shouldn't be, we'll only return true if the windowkind
|
||||
is userKind. If you add different kinds of windows to Sample you'll need
|
||||
to change how this all works. */
|
||||
|
||||
#pragma segment Main
|
||||
Boolean IsAppWindow(window)
|
||||
WindowPtr window;
|
||||
{
|
||||
short windowKind;
|
||||
|
||||
if ( window == nil )
|
||||
return false;
|
||||
else { /* application windows have windowKinds = userKind (8) */
|
||||
windowKind = ((WindowPeek) window)->windowKind;
|
||||
return (windowKind == userKind);
|
||||
}
|
||||
} /*IsAppWindow*/
|
||||
|
||||
|
||||
/* Check to see if a window belongs to a desk accessory. */
|
||||
|
||||
#pragma segment Main
|
||||
Boolean IsDAWindow(window)
|
||||
WindowPtr window;
|
||||
{
|
||||
if ( window == nil )
|
||||
return false;
|
||||
else /* DA windows have negative windowKinds */
|
||||
return ((WindowPeek) window)->windowKind < 0;
|
||||
} /*IsDAWindow*/
|
||||
|
||||
|
||||
/* Check to see if a given trap is implemented. This is only used by the
|
||||
Initialize routine in this program, so we put it in the Initialize segment.
|
||||
The recommended approach to see if a trap is implemented is to see if
|
||||
the address of the trap routine is the same as the address of the
|
||||
Unimplemented trap. */
|
||||
/* 1.02 - Needs to be called after call to SysEnvirons so that it can check
|
||||
if a ToolTrap is out of range of a pre-MacII ROM. */
|
||||
|
||||
#pragma segment Initialize
|
||||
Boolean TrapAvailable(tNumber,tType)
|
||||
short tNumber;
|
||||
TrapType tType;
|
||||
{
|
||||
if ( ( tType == ToolTrap ) &&
|
||||
( gMac.machineType > envMachUnknown ) &&
|
||||
( gMac.machineType < envMacII ) ) { /* it's a 512KE, Plus, or SE */
|
||||
tNumber = tNumber & 0x03FF;
|
||||
if ( tNumber > 0x01FF ) /* which means the tool traps */
|
||||
tNumber = _Unimplemented; /* only go to 0x01FF */
|
||||
}
|
||||
return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
|
||||
} /*TrapAvailable*/
|
||||
|
||||
|
||||
/* Display an alert that tells the user an error occurred, then exit the program.
|
||||
This routine is used as an ultimate bail-out for serious errors that prohibit
|
||||
the continuation of the application. Errors that do not require the termination
|
||||
of the application should be handled in a different manner. Error checking and
|
||||
reporting has a place even in the simplest application. The error number is used
|
||||
to index an 'STR#' resource so that a relevant message can be displayed. */
|
||||
|
||||
#pragma segment Main
|
||||
void AlertUser()
|
||||
{
|
||||
short itemHit;
|
||||
|
||||
SetCursor(&qd.arrow);
|
||||
itemHit = Alert(rUserAlert, nil);
|
||||
ExitToShell();
|
||||
} /* AlertUser */
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 006C 6F73 6500 4844" /* ..Monaco.lose.HD */
|
||||
$"3A43 6F70 7920 6F66 204D 5057 5F4F 7574" /* :Copy of MPW_Out */
|
||||
$"3A45 0006 0004 002A 0003 0142 01E3 002A" /* :E.....*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
#
|
||||
# Apple Macintosh Developer Technical Support
|
||||
#
|
||||
# MultiFinder-Aware Simple Sample Application
|
||||
#
|
||||
# Sample
|
||||
#
|
||||
# Sample.h - Rez and C Include Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1989-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions:
|
||||
# 1.00 08/88
|
||||
# 1.01 11/88
|
||||
# 1.02 04/89 MPW 3.1
|
||||
# 1.03 02/90 MPW 3.2
|
||||
#
|
||||
# Components:
|
||||
# Sample.c Feb. 1, 1990
|
||||
# Sample.r Feb. 1, 1990
|
||||
# Sample.h Feb. 1, 1990
|
||||
# Sample.make Feb. 1, 1990
|
||||
#
|
||||
# Sample is an example application that demonstrates how to
|
||||
# initialize the commonly used toolbox managers, operate
|
||||
# successfully under MultiFinder, handle desk accessories,
|
||||
# and create, grow, and zoom windows.
|
||||
#
|
||||
# It does not by any means demonstrate all the techniques
|
||||
# you need for a large application. In particular, Sample
|
||||
# does not cover exception handling, multiple windows/documents,
|
||||
# sophisticated memory management, printing, or undo. All of
|
||||
# these are vital parts of a normal full-sized application.
|
||||
#
|
||||
# This application is an example of the form of a Macintosh
|
||||
# application; it is NOT a template. It is NOT intended to be
|
||||
# used as a foundation for the next world-class, best-selling,
|
||||
# 600K application. A stick figure drawing of the human body may
|
||||
# be a good example of the form for a painting, but that does not
|
||||
# mean it should be used as the basis for the next Mona Lisa.
|
||||
#
|
||||
# We recommend that you review this program or TESample before
|
||||
# beginning a new application.
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/* These #defines correspond to values defined in the Pascal source code.
|
||||
Sample.c and Sample.r include this file. */
|
||||
|
||||
/* Determining an application's minimum size to request from MultiFinder depends
|
||||
on many things, each of which can be unique to an application's function,
|
||||
the anticipated environment, the developer's attitude of what constitutes
|
||||
reasonable functionality and performance, etc. Here is a list of some things to
|
||||
consider when determining the minimum size (and preferred size) for your
|
||||
application. The list is pretty much in order of importance, but by no means
|
||||
complete.
|
||||
|
||||
1. What is the minimum size needed to give almost 100 percent assurance
|
||||
that the application won't crash because it ran out of memory? This
|
||||
includes not only things that you do have direct control over such as
|
||||
checking for NIL handles and pointers, but also things that some
|
||||
feel are not so much under their control such as QuickDraw and the
|
||||
Segment Loader.
|
||||
|
||||
2. What kind of performance can a user expect from the application when
|
||||
it is running in the minimum memory configuration? Performance includes
|
||||
not only speed in handling data, but also things like how many documents
|
||||
can be opened, etc.
|
||||
|
||||
3. What are the typical sizes of scraps [is a boy dog] that a user might
|
||||
wish to work with when lauching or switching to your application? If
|
||||
the amount of memory is too small, the scrap may get lost [will have
|
||||
to be shot]. This can be quite frustrating to the user.
|
||||
|
||||
4. The previous items have concentrated on topics that tend to cause an
|
||||
increase in the minimum size to request from MultiFinder. On the flip
|
||||
side, however, should be the consideration of what environments the
|
||||
application may be running in. There may be a high probability that
|
||||
many users with relatively small memory configurations will want to
|
||||
avail themselves of your application. Or, many users might want to use it
|
||||
while several other, possibly related/complementary applications are
|
||||
running. If that is the case, it would be helpful to have a fairly
|
||||
small minimum size.
|
||||
|
||||
So, what did we decide on Sample? First, Sample has little risk of
|
||||
running out of memory once it starts. Second, performance isn't much
|
||||
of an issue since it doesn't do much and multiple windows are not
|
||||
allowed. Third, there are no edit operations in Sample itself, so we
|
||||
just want to provide enough space for a reasonable scrap to survive
|
||||
between desk accessory launches. Lastly, Sample should intrude as little
|
||||
as possible, so the effort should be towards making it as small as possible.
|
||||
We looked at some heap dumps while the application was running under
|
||||
various partition sizes. With a size of 23K, there was approximately
|
||||
8-9K free, which is a good 'slop' factor in an application like this
|
||||
which doesn't do much, but where we'd still like the scrap to survive
|
||||
most of the time. */
|
||||
|
||||
#define kMinSize 23 /* application's minimum size (in K) */
|
||||
|
||||
/* We made the preferred size bigger than the minimum size by 12K, so that
|
||||
there would be even more room for the scrap, FKEYs, etc. */
|
||||
|
||||
#define kPrefSize 35 /* application's preferred size (in K) */
|
||||
|
||||
#define rMenuBar 128 /* application's menu bar */
|
||||
#define rAboutAlert 128 /* about alert */
|
||||
#define rUserAlert 129 /* error user alert */
|
||||
#define rWindow 128 /* application's window */
|
||||
#define rStopRect 128 /* rectangle for Stop light */
|
||||
#define rGoRect 129 /* rectangle for Go light */
|
||||
|
||||
/* kSysEnvironsVersion is passed to SysEnvirons to tell it which version of the
|
||||
SysEnvRec we understand. */
|
||||
|
||||
#define kSysEnvironsVersion 1
|
||||
|
||||
/* kOSEvent is the event number of the suspend/resume and mouse-moved events sent
|
||||
by MultiFinder. Once we determine that an event is an osEvent, we look at the
|
||||
high byte of the message sent to determine which kind it is. To differentiate
|
||||
suspend and resume events we check the resumeMask bit. */
|
||||
|
||||
#define kOSEvent app4Evt /* event used by MultiFinder */
|
||||
#define kSuspendResumeMessage 1 /* high byte of suspend/resume event message */
|
||||
#define kResumeMask 1 /* bit of message field for resume vs. suspend */
|
||||
#define kMouseMovedMessage 0xFA /* high byte of mouse-moved event message */
|
||||
#define kNoEvents 0 /* no events mask */
|
||||
|
||||
/* The following constants are used to identify menus and their items. The menu IDs
|
||||
have an "m" prefix and the item numbers within each menu have an "i" prefix. */
|
||||
|
||||
#define mApple 128 /* Apple menu */
|
||||
#define iAbout 1
|
||||
|
||||
#define mFile 129 /* File menu */
|
||||
#define iNew 1
|
||||
#define iClose 4
|
||||
#define iQuit 12
|
||||
|
||||
#define mEdit 130 /* Edit menu */
|
||||
#define iUndo 1
|
||||
#define iCut 3
|
||||
#define iCopy 4
|
||||
#define iPaste 5
|
||||
#define iClear 6
|
||||
|
||||
#define mLight 131 /* Light menu */
|
||||
#define iStop 1
|
||||
#define iGo 2
|
||||
|
||||
/* 1.01 - kTopLeft - This is for positioning the Disk Initialization dialogs. */
|
||||
|
||||
#define kDITop 0x0050
|
||||
#define kDILeft 0x0070
|
||||
|
||||
/* 1.01 - kMinHeap - This is the minimum result from the following
|
||||
equation:
|
||||
|
||||
ORD(GetApplLimit) - ORD(ApplicZone)
|
||||
|
||||
for the application to run. It will insure that enough memory will
|
||||
be around for reasonable-sized scraps, FKEYs, etc. to exist with the
|
||||
application, and still give the application some 'breathing room'.
|
||||
To derive this number, we ran under a MultiFinder partition that was
|
||||
our requested minimum size, as given in the 'SIZE' resource. */
|
||||
|
||||
#define kMinHeap 21 * 1024
|
||||
|
||||
/* 1.01 - kMinSpace - This is the minimum result from PurgeSpace, when called
|
||||
at initialization time, for the application to run. This number acts
|
||||
as a double-check to insure that there really is enough memory for the
|
||||
application to run, including what has been taken up already by
|
||||
pre-loaded resources, the scrap, code, and other sundry memory blocks. */
|
||||
|
||||
#define kMinSpace 8 * 1024
|
||||
|
||||
/* kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions. */
|
||||
|
||||
#define kExtremeNeg -32768
|
||||
#define kExtremePos 32767 - 1 /* required to address an old region bug */
|
||||
|
||||
/* these #defines are used to set enable/disable flags of a menu */
|
||||
|
||||
#define AllItems 0b1111111111111111111111111111111 /* 31 flags */
|
||||
#define NoItems 0b0000000000000000000000000000000
|
||||
#define MenuItem1 0b0000000000000000000000000000001
|
||||
#define MenuItem2 0b0000000000000000000000000000010
|
||||
#define MenuItem3 0b0000000000000000000000000000100
|
||||
#define MenuItem4 0b0000000000000000000000000001000
|
||||
#define MenuItem5 0b0000000000000000000000000010000
|
||||
#define MenuItem6 0b0000000000000000000000000100000
|
||||
#define MenuItem7 0b0000000000000000000000001000000
|
||||
#define MenuItem8 0b0000000000000000000000010000000
|
||||
#define MenuItem9 0b0000000000000000000000100000000
|
||||
#define MenuItem10 0b0000000000000000000001000000000
|
||||
#define MenuItem11 0b0000000000000000000010000000000
|
||||
#define MenuItem12 0b0000000000000000000100000000000
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0045 9B74 0000 0000" /* ..Monaco.E.t.... */
|
||||
$"0000 0074 0001 E6B8 0000 0035 0000 0064" /* ...t.......5...d */
|
||||
$"636C 0006 0004 002A 0003 0142 01E3 002A" /* cl.....*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
#
|
||||
# Apple Macintosh Developer Technical Support
|
||||
#
|
||||
# MultiFinder-Aware Simple Sample Application
|
||||
#
|
||||
# Sample
|
||||
#
|
||||
# [C]Sample.make - Make Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1989-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions:
|
||||
# 1.00 08/88
|
||||
# 1.01 11/88
|
||||
# 1.02 04/89 MPW 3.1
|
||||
# 1.03 02/90 MPW 3.2
|
||||
#
|
||||
# Components:
|
||||
# Sample.c Feb. 1, 1990
|
||||
# Sample.r Feb. 1, 1990
|
||||
# Sample.h Feb. 1, 1990
|
||||
# Sample.make Feb. 1, 1990
|
||||
#
|
||||
# Sample is an example application that demonstrates how to
|
||||
# initialize the commonly used toolbox managers, operate
|
||||
# successfully under MultiFinder, handle desk accessories,
|
||||
# and create, grow, and zoom windows.
|
||||
#
|
||||
# It does not by any means demonstrate all the techniques
|
||||
# you need for a large application. In particular, Sample
|
||||
# does not cover exception handling, multiple windows/documents,
|
||||
# sophisticated memory management, printing, or undo. All of
|
||||
# these are vital parts of a normal full-sized application.
|
||||
#
|
||||
# This application is an example of the form of a Macintosh
|
||||
# application; it is NOT a template. It is NOT intended to be
|
||||
# used as a foundation for the next world-class, best-selling,
|
||||
# 600K application. A stick figure drawing of the human body may
|
||||
# be a good example of the form for a painting, but that does not
|
||||
# mean it should be used as the basis for the next Mona Lisa.
|
||||
#
|
||||
# We recommend that you review this program or TESample before
|
||||
# beginning a new application.
|
||||
#
|
||||
# You can define {SymOptions} as "-sym on" or "-sym off" for use with SADE
|
||||
# We also recommend requiring prototypes for all functions
|
||||
COptions = -r {SymOptions}
|
||||
|
||||
CObjs = Sample.c.o ∂
|
||||
"{Libraries}"Runtime.o ∂
|
||||
"{Libraries}"Interface.o
|
||||
|
||||
Sample ƒƒ {CObjs} Sample.make
|
||||
Link -o {Targ} {CObjs} {SymOptions}
|
||||
SetFile {Targ} -t APPL -c 'MOOS' -a B
|
||||
|
||||
Sample ƒƒ Sample.r Sample.h Sample.make
|
||||
Rez -rd -o {Targ} Sample.r -append
|
||||
|
||||
Sample.c.o ƒƒ Sample.make
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0061 6D70 6C65 2E6D" /* ..Monaco.ample.m */
|
||||
$"616B 6500 2200 0024 2F2D FD58 2F2D FD54" /* ake."..$/-.X/-.T */
|
||||
$"2F2D 0006 0004 002A 0003 0142 01E3 002A" /* /-.....*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,284 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
#
|
||||
# Apple Macintosh Developer Technical Support
|
||||
#
|
||||
# MultiFinder-Aware Simple Sample Application
|
||||
#
|
||||
# Sample
|
||||
#
|
||||
# Sample.r - Rez Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1989-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions:
|
||||
# 1.00 08/88
|
||||
# 1.01 11/88
|
||||
# 1.02 04/89 MPW 3.1
|
||||
# 1.03 02/90 MPW 3.2
|
||||
#
|
||||
# Components:
|
||||
# Sample.c Feb. 1, 1990
|
||||
# Sample.r Feb. 1, 1990
|
||||
# Sample.h Feb. 1, 1990
|
||||
# Sample.make Feb. 1, 1990
|
||||
#
|
||||
# Sample is an example application that demonstrates how to
|
||||
# initialize the commonly used toolbox managers, operate
|
||||
# successfully under MultiFinder, handle desk accessories,
|
||||
# and create, grow, and zoom windows.
|
||||
#
|
||||
# It does not by any means demonstrate all the techniques
|
||||
# you need for a large application. In particular, Sample
|
||||
# does not cover exception handling, multiple windows/documents,
|
||||
# sophisticated memory management, printing, or undo. All of
|
||||
# these are vital parts of a normal full-sized application.
|
||||
#
|
||||
# This application is an example of the form of a Macintosh
|
||||
# application; it is NOT a template. It is NOT intended to be
|
||||
# used as a foundation for the next world-class, best-selling,
|
||||
# 600K application. A stick figure drawing of the human body may
|
||||
# be a good example of the form for a painting, but that does not
|
||||
# mean it should be used as the basis for the next Mona Lisa.
|
||||
#
|
||||
# We recommend that you review this program or TESample before
|
||||
# beginning a new application.
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "SysTypes.r"
|
||||
#include "Types.r"
|
||||
|
||||
#include "Sample.h"
|
||||
|
||||
resource 'vers' (1) {
|
||||
0x02, 0x00, release, 0x00,
|
||||
verUS,
|
||||
"1.03",
|
||||
"1.03, Copyright \251 Apple Computer, Inc. 1989-1990"
|
||||
};
|
||||
|
||||
|
||||
/* this is a definition for a resource which contains only a rectangle */
|
||||
|
||||
type 'RECT' {
|
||||
rect;
|
||||
};
|
||||
|
||||
|
||||
/* we use an MBAR resource to conveniently load all the menus */
|
||||
|
||||
resource 'MBAR' (rMenuBar, preload) {
|
||||
{ mApple, mFile, mEdit, mLight }; /* four menus */
|
||||
};
|
||||
|
||||
|
||||
resource 'MENU' (mApple, preload) {
|
||||
mApple, textMenuProc,
|
||||
AllItems & ~MenuItem2, /* Disable dashed line, enable About and DAs */
|
||||
enabled, apple,
|
||||
{
|
||||
"About Sample…",
|
||||
noicon, nokey, nomark, plain;
|
||||
"-",
|
||||
noicon, nokey, nomark, plain
|
||||
}
|
||||
};
|
||||
|
||||
resource 'MENU' (mFile, preload) {
|
||||
mFile, textMenuProc,
|
||||
MenuItem12, /* enable Quit only, program enables others */
|
||||
enabled, "File",
|
||||
{
|
||||
"New",
|
||||
noicon, "N", nomark, plain;
|
||||
"Open",
|
||||
noicon, "O", nomark, plain;
|
||||
"-",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Close",
|
||||
noicon, "W", nomark, plain;
|
||||
"Save",
|
||||
noicon, "S", nomark, plain;
|
||||
"Save As…",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Revert",
|
||||
noicon, nokey, nomark, plain;
|
||||
"-",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Page Setup…",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Print…",
|
||||
noicon, nokey, nomark, plain;
|
||||
"-",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Quit",
|
||||
noicon, "Q", nomark, plain
|
||||
}
|
||||
};
|
||||
|
||||
resource 'MENU' (mEdit, preload) {
|
||||
mEdit, textMenuProc,
|
||||
NoItems, /* disable everything, program does the enabling */
|
||||
enabled, "Edit",
|
||||
{
|
||||
"Undo",
|
||||
noicon, "Z", nomark, plain;
|
||||
"-",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Cut",
|
||||
noicon, "X", nomark, plain;
|
||||
"Copy",
|
||||
noicon, "C", nomark, plain;
|
||||
"Paste",
|
||||
noicon, "V", nomark, plain;
|
||||
"Clear",
|
||||
noicon, nokey, nomark, plain
|
||||
}
|
||||
};
|
||||
|
||||
resource 'MENU' (mLight, preload) {
|
||||
mLight, textMenuProc,
|
||||
NoItems, /* disable everything, program does the enabling */
|
||||
enabled, "Traffic",
|
||||
{
|
||||
"Red Light",
|
||||
noicon, nokey, nomark, plain;
|
||||
"Green Light",
|
||||
noicon, nokey, nomark, plain
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* this ALRT and DITL are used as an About screen */
|
||||
|
||||
resource 'ALRT' (rAboutAlert, purgeable) {
|
||||
{40, 20, 160, 297},
|
||||
rAboutAlert,
|
||||
{ /* array: 4 elements */
|
||||
/* [1] */
|
||||
OK, visible, silent,
|
||||
/* [2] */
|
||||
OK, visible, silent,
|
||||
/* [3] */
|
||||
OK, visible, silent,
|
||||
/* [4] */
|
||||
OK, visible, silent
|
||||
}
|
||||
};
|
||||
|
||||
resource 'DITL' (rAboutAlert, purgeable) {
|
||||
{ /* array DITLarray: 5 elements */
|
||||
/* [1] */
|
||||
{88, 185, 108, 265},
|
||||
Button {
|
||||
enabled,
|
||||
"OK"
|
||||
},
|
||||
/* [2] */
|
||||
{8, 8, 24, 214},
|
||||
StaticText {
|
||||
disabled,
|
||||
"Simple Sample (Traffic Light)"
|
||||
},
|
||||
/* [3] */
|
||||
{32, 8, 48, 296},
|
||||
StaticText {
|
||||
disabled,
|
||||
"Copyright © Apple Computer 1989-1990"
|
||||
},
|
||||
/* [4] */
|
||||
{56, 8, 72, 136},
|
||||
StaticText {
|
||||
disabled,
|
||||
"Brought to you by:"
|
||||
},
|
||||
/* [5] */
|
||||
{80, 24, 112, 167},
|
||||
StaticText {
|
||||
disabled,
|
||||
"Macintosh Developer Technical Support"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* this ALRT and DITL are used as an error screen */
|
||||
|
||||
resource 'ALRT' (rUserAlert, purgeable) {
|
||||
{40, 20, 120, 260},
|
||||
rUserAlert,
|
||||
{ /* array: 4 elements */
|
||||
/* [1] */
|
||||
OK, visible, silent,
|
||||
/* [2] */
|
||||
OK, visible, silent,
|
||||
/* [3] */
|
||||
OK, visible, silent,
|
||||
/* [4] */
|
||||
OK, visible, silent
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
resource 'DITL' (rUserAlert, purgeable) {
|
||||
{ /* array DITLarray: 3 elements */
|
||||
/* [1] */
|
||||
{50, 150, 70, 230},
|
||||
Button {
|
||||
enabled,
|
||||
"OK"
|
||||
},
|
||||
/* [2] */
|
||||
{10, 60, 30, 230},
|
||||
StaticText {
|
||||
disabled,
|
||||
"Sample - Error occurred!"
|
||||
},
|
||||
/* [3] */
|
||||
{8, 8, 40, 40},
|
||||
Icon {
|
||||
disabled,
|
||||
2
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
resource 'WIND' (rWindow, preload, purgeable) {
|
||||
{60, 40, 290, 160},
|
||||
noGrowDocProc, visible, noGoAway, 0x0, "Traffic"
|
||||
};
|
||||
|
||||
resource 'RECT' (rStopRect, preload, purgeable) {
|
||||
{10, 10, 110, 110}
|
||||
};
|
||||
|
||||
resource 'RECT' (rGoRect, preload, purgeable) {
|
||||
{120, 10, 220, 110}
|
||||
};
|
||||
|
||||
|
||||
/* here is the quintessential MultiFinder friendliness device, the SIZE resource */
|
||||
|
||||
resource 'SIZE' (-1) {
|
||||
dontSaveScreen,
|
||||
acceptSuspendResumeEvents,
|
||||
enableOptionSwitch,
|
||||
canBackground, /* we can background; we don't currently, but our sleep value */
|
||||
/* guarantees we don't hog the Mac while we are in the background */
|
||||
multiFinderAware, /* this says we do our own activate/deactivate; don't fake us out */
|
||||
backgroundAndForeground, /* this is definitely not a background-only application! */
|
||||
dontGetFrontClicks, /* change this is if you want "do first click" behavior like the Finder */
|
||||
ignoreChildDiedEvents, /* essentially, I'm not a debugger (sub-launching) */
|
||||
not32BitCompatible, /* this app should not be run in 32-bit address space */
|
||||
reserved,
|
||||
reserved,
|
||||
reserved,
|
||||
reserved,
|
||||
reserved,
|
||||
reserved,
|
||||
reserved,
|
||||
kPrefSize * 1024,
|
||||
kMinSize * 1024
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0061 6D70 6C65 2E72" /* ..Monaco.ample.r */
|
||||
$"0022 0000 00C0 FFF8 4E5E 4E75 8773 6967" /* ."......N^Nu.sig */
|
||||
$"5F64 0006 0004 002A 0003 0142 01E3 002A" /* _d.....*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0045 9B80 0000 0000" /* ..Monaco.E...... */
|
||||
$"0000 0074 0001 E72C 0000 0037 0000 0064" /* ...t...,...7...d */
|
||||
$"636C 0006 0004 002A 0003 0142 01E3 002A" /* cl.....*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
#
|
||||
# Apple Macintosh Developer Technical Support
|
||||
#
|
||||
# MultiFinder-Aware TextEdit Sample Application
|
||||
#
|
||||
# TESample
|
||||
#
|
||||
# TESample.h - Rez and C Include Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1989-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions:
|
||||
# 1.00 08/88
|
||||
# 1.01 11/88
|
||||
# 1.02 04/89 MPW 3.1
|
||||
# 1.03 02/90 MPW 3.2
|
||||
#
|
||||
# Components:
|
||||
# TESample.c Feb. 1, 1990
|
||||
# TESampleGlue.a Feb. 1, 1990
|
||||
# TESample.r Feb. 1, 1990
|
||||
# TESample.h Feb. 1, 1990
|
||||
# TESample.make Feb. 1, 1990
|
||||
#
|
||||
# TESample is an example application that demonstrates how
|
||||
# to initialize the commonly used toolbox managers, operate
|
||||
# successfully under MultiFinder, handle desk accessories and
|
||||
# create, grow, and zoom windows. The fundamental TextEdit
|
||||
# toolbox calls and TextEdit autoscroll are demonstrated. It
|
||||
# also shows how to create and maintain scrollbar controls.
|
||||
#
|
||||
# It does not by any means demonstrate all the techniques you
|
||||
# need for a large application. In particular, Sample does not
|
||||
# cover exception handling, multiple windows/documents,
|
||||
# sophisticated memory management, printing, or undo. All of
|
||||
# these are vital parts of a normal full-sized application.
|
||||
#
|
||||
# This application is an example of the form of a Macintosh
|
||||
# application; it is NOT a template. It is NOT intended to be
|
||||
# used as a foundation for the next world-class, best-selling,
|
||||
# 600K application. A stick figure drawing of the human body may
|
||||
# be a good example of the form for a painting, but that does not
|
||||
# mean it should be used as the basis for the next Mona Lisa.
|
||||
#
|
||||
# We recommend that you review this program or Sample before
|
||||
# beginning a new application. Sample is a simple app. which doesn’t
|
||||
# use TextEdit or the Control Manager.
|
||||
#
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/* These #defines correspond to values in the Pascal source code.
|
||||
TESample.c and TESample.r include this file. */
|
||||
|
||||
/* Determining an application's minimum size to request from MultiFinder depends
|
||||
on many things, each of which can be unique to an application's function,
|
||||
the anticipated environment, the developer's attitude of what constitutes
|
||||
reasonable functionality and performance, etc. Here is a list of some things to
|
||||
consider when determining the minimum size (and preferred size) for your
|
||||
application. The list is pretty much in order of importance, but by no means
|
||||
complete.
|
||||
|
||||
1. What is the minimum size needed to give almost 100 percent assurance
|
||||
that the application won't crash because it ran out of memory? This
|
||||
includes not only things that you do have direct control over such as
|
||||
checking for NIL handles and pointers, but also things that some
|
||||
feel are not so much under their control such as QuickDraw and the
|
||||
Segment Loader.
|
||||
|
||||
2. What kind of performance can a user expect from the application when
|
||||
it is running in the minimum memory configuration? Performance includes
|
||||
not only speed in handling data, but also things like how many documents
|
||||
can be opened, etc.
|
||||
|
||||
3. What are the typical sizes of scraps is [a boy dog] that a user might
|
||||
wish to work with when lauching or switching to your application? If
|
||||
the amount of memory is too small, the scrap may get lost [will have
|
||||
to be shot]. This can be quite frustrating to the user.
|
||||
|
||||
4. The previous items have concentrated on topics that tend to cause an
|
||||
increase in the minimum size to request from MultiFinder. On the flip
|
||||
side, however, should be the consideration of what environments the
|
||||
application may be running in. There may be a high probability that
|
||||
many users with relatively small memory configurations will want to
|
||||
avail themselves of your application. Or, many users might want to use it
|
||||
while several other, possibly related/complementary applications are
|
||||
running. If that is the case, it would be helpful to have a fairly
|
||||
small minimum size.
|
||||
|
||||
What we did for TESample:
|
||||
|
||||
We determined the smallest heap size that TESample could have and still
|
||||
run (22K). For the preferred size we added enough space to permit:
|
||||
a. a maximum size TextEdit text handle (32000 characters)
|
||||
b. a maximum usable TextEdit scrap (32000 characters)
|
||||
b. a maximum scrap as a result of Copy (32000 characters)
|
||||
d. a little performance cushion (see 2, above) (10K)
|
||||
Result: 122K for preferred size
|
||||
|
||||
For the minimum size we took the 22K and then scaled down our requirements
|
||||
for a,b, and c above. We thought that providing 16K more would be lean
|
||||
and mean (see 4, above).
|
||||
Result: 38K for minimum size
|
||||
*/
|
||||
|
||||
#define kPrefSize 122
|
||||
#define kMinSize 38
|
||||
|
||||
/* The following constants are used to identify menus and their items. The menu IDs
|
||||
have an "m" prefix and the item numbers within each menu have an "i" prefix. */
|
||||
#define mApple 128 /* Apple menu */
|
||||
#define iAbout 1
|
||||
|
||||
#define mFile 129 /* File menu */
|
||||
#define iNew 1
|
||||
#define iClose 4
|
||||
#define iQuit 12
|
||||
|
||||
#define mEdit 130 /* Edit menu */
|
||||
#define iUndo 1
|
||||
#define iCut 3
|
||||
#define iCopy 4
|
||||
#define iPaste 5
|
||||
#define iClear 6
|
||||
|
||||
/* 1.01 - kTopLeft - This is for positioning the Disk Initialization dialogs. */
|
||||
|
||||
#define kDITop 0x0050
|
||||
#define kDILeft 0x0070
|
||||
|
||||
/* 1.01 - changed constants to begin with 'k' for consistency, except for resource IDs */
|
||||
/* kTextMargin is the number of pixels we leave blank at the edge of the window. */
|
||||
#define kTextMargin 2
|
||||
|
||||
/* kMaxOpenDocuments is used to determine whether a new document can be opened
|
||||
or created. We keep track of the number of open documents, and disable the
|
||||
menu items that create a new document when the maximum is reached. If the
|
||||
number of documents falls below the maximum, the items are enabled again. */
|
||||
#define kMaxOpenDocuments 1
|
||||
|
||||
/* kMaxDocWidth is an arbitrary number used to specify the width of the TERec's
|
||||
destination rectangle so that word wrap and horizontal scrolling can be
|
||||
demonstrated. */
|
||||
#define kMaxDocWidth 576
|
||||
|
||||
/* kMinDocDim is used to limit the minimum dimension of a window when GrowWindow
|
||||
is called. */
|
||||
#define kMinDocDim 64
|
||||
|
||||
/* kControlInvisible is used to 'turn off' controls (i.e., cause the control not
|
||||
to be redrawn as a result of some Control Manager call such as SetCtlValue)
|
||||
by being put into the contrlVis field of the record. kControlVisible is used
|
||||
the same way to 'turn on' the control. */
|
||||
#define kControlInvisible 0
|
||||
#define kControlVisible 0xFF
|
||||
|
||||
/* kScrollbarAdjust and kScrollbarWidth are used in calculating
|
||||
values for control positioning and sizing. */
|
||||
#define kScrollbarWidth 16
|
||||
#define kScrollbarAdjust (kScrollbarWidth - 1)
|
||||
|
||||
/* kScrollTweek compensates for off-by-one requirements of the scrollbars
|
||||
to have borders coincide with the growbox. */
|
||||
#define kScrollTweek 2
|
||||
|
||||
/* kCrChar is used to match with a carriage return when calculating the
|
||||
number of lines in the TextEdit record. kDelChar is used to check for
|
||||
delete in keyDowns. */
|
||||
#define kCrChar 13
|
||||
#define kDelChar 8
|
||||
|
||||
/* kButtonScroll is how many pixels to scroll horizontally when the button part
|
||||
of the horizontal scrollbar is pressed. */
|
||||
#define kButtonScroll 4
|
||||
|
||||
/* kMaxTELength is an arbitrary number used to limit the length of text in the TERec
|
||||
so that various errors won't occur from too many characters in the text. */
|
||||
#define kMaxTELength 32000
|
||||
|
||||
/* kSysEnvironsVersion is passed to SysEnvirons to tell it which version of the
|
||||
SysEnvRec we understand. */
|
||||
#define kSysEnvironsVersion 1
|
||||
|
||||
/* kOSEvent is the event number of the suspend/resume and mouse-moved events sent
|
||||
by MultiFinder. Once we determine that an event is an OSEvent, we look at the
|
||||
high byte of the message sent to determine which kind it is. To differentiate
|
||||
suspend and resume events we check the resumeMask bit. */
|
||||
#define kOSEvent app4Evt /* event used by MultiFinder */
|
||||
#define kSuspendResumeMessage 1 /* high byte of suspend/resume event message */
|
||||
#define kResumeMask 1 /* bit of message field for resume vs. suspend */
|
||||
#define kMouseMovedMessage 0xFA /* high byte of mouse-moved event message */
|
||||
#define kNoEvents 0 /* no events mask */
|
||||
|
||||
/* 1.01 - kMinHeap - This is the minimum result from the following
|
||||
equation:
|
||||
|
||||
ORD(GetApplLimit) - ORD(ApplicZone)
|
||||
|
||||
for the application to run. It will insure that enough memory will
|
||||
be around for reasonable-sized scraps, FKEYs, etc. to exist with the
|
||||
application, and still give the application some 'breathing room'.
|
||||
To derive this number, we ran under a MultiFinder partition that was
|
||||
our requested minimum size, as given in the 'SIZE' resource. */
|
||||
|
||||
#define kMinHeap (29 * 1024)
|
||||
|
||||
/* 1.01 - kMinSpace - This is the minimum result from PurgeSpace, when called
|
||||
at initialization time, for the application to run. This number acts
|
||||
as a double-check to insure that there really is enough memory for the
|
||||
application to run, including what has been taken up already by
|
||||
pre-loaded resources, the scrap, code, and other sundry memory blocks. */
|
||||
|
||||
#define kMinSpace (20 * 1024)
|
||||
|
||||
/* kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions. */
|
||||
#define kExtremeNeg -32768
|
||||
#define kExtremePos (32767 - 1) /* required to address an old region bug */
|
||||
|
||||
/* kTESlop provides some extra security when pre-flighting edit commands. */
|
||||
#define kTESlop 1024
|
||||
|
||||
/* The following are indicies into STR# resources. */
|
||||
#define eWrongMachine 1
|
||||
#define eSmallSize 2
|
||||
#define eNoMemory 3
|
||||
#define eNoSpaceCut 4
|
||||
#define eNoCut 5
|
||||
#define eNoCopy 6
|
||||
#define eExceedPaste 7
|
||||
#define eNoSpacePaste 8
|
||||
#define eNoWindow 9
|
||||
#define eExceedChar 10
|
||||
#define eNoPaste 11
|
||||
|
||||
#define rMenuBar 128 /* application's menu bar */
|
||||
#define rAboutAlert 128 /* about alert */
|
||||
#define rUserAlert 129 /* user error alert */
|
||||
#define rDocWindow 128 /* application's window */
|
||||
#define rVScroll 128 /* vertical scrollbar control */
|
||||
#define rHScroll 129 /* horizontal scrollbar control */
|
||||
#define kErrStrings 128 /* error string list */
|
|
@ -0,0 +1 @@
|
|||
TEXTMPS
|
|
@ -0,0 +1,18 @@
|
|||
data 'MPSR' (1005) {
|
||||
$"0009 4D6F 6E61 636F 0045 9B80 0000 0000" /* ..Monaco.E...... */
|
||||
$"0000 0074 0001 E6B4 0000 0037 0000 0064" /* ...t.......7...d */
|
||||
$"636C 0006 0004 002A 0003 0142 01E3 002A" /* cl.....*...B...* */
|
||||
$"0003 0142 01E3 A42B A620 0000 0000 0000" /* ...B...+. ...... */
|
||||
$"0000 0000 0000 0100" /* ........ */
|
||||
};
|
||||
|
||||
data 'MPSR' (1008) {
|
||||
$"002A 0003 0142 01E3 002A 0003 0142 01E3" /* .*...B...*...B.. */
|
||||
$"0000 0000 0000 0000 0000 0000 0000" /* .............. */
|
||||
};
|
||||
|
||||
data 'vers' (2, purgeable) {
|
||||
$"0320 8000 0000 0333 2E32 074D 5057 2033" /* . .....3.2.MPW 3 */
|
||||
$"2E32" /* .2 */
|
||||
};
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
#
|
||||
# Apple Macintosh Developer Technical Support
|
||||
#
|
||||
# MultiFinder-Aware Simple TextEdit Sample Application
|
||||
#
|
||||
# TESample
|
||||
#
|
||||
# [C]TESample.make - Make Source
|
||||
#
|
||||
# Copyright © Apple Computer, Inc. 1989-1990
|
||||
# All rights reserved.
|
||||
#
|
||||
# Versions:
|
||||
# 1.00 08/88
|
||||
# 1.01 11/88
|
||||
# 1.02 04/89 MPW 3.1
|
||||
# 1.03 02/90 MPW 3.2
|
||||
#
|
||||
# Components:
|
||||
# TESample.c Feb. 1, 1990
|
||||
# TESampleGlue.a Feb. 1, 1990
|
||||
# TESample.r Feb. 1, 1990
|
||||
# TESample.h Feb. 1, 1990
|
||||
# TESample.make Feb. 1, 1990
|
||||
#
|
||||
# TESample is an example application that demonstrates how
|
||||
# to initialize the commonly used toolbox managers, operate
|
||||
# successfully under MultiFinder, handle desk accessories and
|
||||
# create, grow, and zoom windows. The fundamental TextEdit
|
||||
# toolbox calls and TextEdit autoscroll are demonstrated. It
|
||||
# also shows how to create and maintain scrollbar controls.
|
||||
#
|
||||
# It does not by any means demonstrate all the techniques you
|
||||
# need for a large application. In particular, Sample does not
|
||||
# cover exception handling, multiple windows/documents,
|
||||
# sophisticated memory management, printing, or undo. All of
|
||||
# these are vital parts of a normal full-sized application.
|
||||
#
|
||||
# This application is an example of the form of a Macintosh
|
||||
# application; it is NOT a template. It is NOT intended to be
|
||||
# used as a foundation for the next world-class, best-selling,
|
||||
# 600K application. A stick figure drawing of the human body may
|
||||
# be a good example of the form for a painting, but that does not
|
||||
# mean it should be used as the basis for the next Mona Lisa.
|
||||
#
|
||||
# We recommend that you review this program or Sample before
|
||||
# beginning a new application. Sample is a simple app. which doesn’t
|
||||
# use TextEdit or the Control Manager.
|
||||
#
|
||||
# You can define {SymOptions} as "-sym on" or "-sym off" for use with SADE
|
||||
# We also recommend requiring prototypes for all functions
|
||||
COptions = -r {SymOptions}
|
||||
|
||||
CObjs = TESample.c.o ∂
|
||||
TESampleGlue.a.o ∂
|
||||
"{Libraries}"Runtime.o ∂
|
||||
"{Libraries}"Interface.o
|
||||
|
||||
TESample ƒƒ {CObjs} TESample.make
|
||||
Link -o {Targ} {CObjs} {SymOptions}
|
||||
SetFile {Targ} -t APPL -c 'MOOT' -a B
|
||||
|
||||
TESample ƒƒ TESample.r TESample.h TESample.make
|
||||
Rez -rd -append -o {Targ} TESample.r
|
||||
|
||||
TESample.c.o ƒƒ TESample.c TESample.make
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue