TweetFollow Us on Twitter

Number Format
Volume Number:3
Issue Number:11
Column Tag:Assembly Language Lab

Formatted Output for Numbers

By Mike™ Scanlin, San Diego, CA

On most systems, programmers of high level languages have an advantage over assembly language programmers in that a lot of the nitty gritty detail work has been done for them by what ever compiler or interpretter they’re using. An example of this is in the outputting of numbers. High level language programmers usually take it for granted that they can output a number in just about any format they want to. Pascal’s writeln and C’s printf make it a trivial task to change the field width of both integers and reals. While it’s true that assembly programmers can make use of _NumToString or the SANE formatter, we still need to play with the resulting strings to get nice formatted numbers. Until now.

CONVERTING INTEGERS

The basic idea when converting an integer into its string equivalent is to first break it down into its digits and then convert each digit into its ASCII equivalent. The only tricky part is that a number is represented as binary internally and we need its decimal equivalent.

There are at least 2 different ways to approach the problem of extracting base 10 digits from a binary number. The _NumToString routine that Apple provides in the system file (see listing 1) uses binary coded decimal (BCD) arithmetic to calculate the digits and then calls a separate subroutine to build the string two digits at a time (the least significant bytes of registers D1-D5 are used to store 2 BCD digits each). The main problem with this algorithm is that it runs in more or less constant time (the number 1 takes as long to convert as 2147483648 = 2^31) and isn’t very efficient except for very large numbers (about 7 or more digits).

Another way to get digits one by one is to subtract by successively smaller powers of 10, starting with 10^9 (since it is the largest power of 10 that can be represented by a 32 bit integer). Count how many times you can subtract each power of 10 from the number and then convert that number (which will be in the range 0..9) to its ASCII equivalent. If you use multi-word compares and subtracts, this method can be used to convert any size integers (like 64 or 128 bits) into strings.

My own NumToString routine (Shown in the program listing) uses the subtract method. How does the subtract method compare to the real _NumToString? As for size, _NumToString is 118 bytes (after all of the trap related instructions are removed) and my routine is 120 bytes. Pretty close. As for speed, time trials on 10,000 random 32 bit signed integers showed my routine to be faster by about 2% -- no big deal. But for time trials on 10,000 16 bit signed integers my routine was faster by 32% and for 10,000 8 bit signed integers my routine was faster by 45% (to be fair, _NumToString was timed after it had been isolated so there was no overhead for trap calling). The reason the smaller numbers showed so much improvement is because my routine doesn’t spend much time on little digits (0,1,2...) and virtually no time on leading zeros. If you have a time critical application that makes a lot of calls to _NumToString, it may be worthwhile to use my routine instead. Of course, you could just patch my routine over the existing _NumToString in the system file to speed up all applications that use _NumToString -- no, wait, I didn’t just say that (and I’m not responsible for the consequences. Is there any reason that wouldn’t work?).

Fig. 1 Demo Program formats numerical output

CONVERTING FIXED POINT REALS

When you use DIVS or DIVU, the 32 bit result is made up of 16 bits of quotient and 16 bits of remainder. The FixPtToString routine uses these two pieces to convert a fixed point number to a string. Since the quotient is just an integer, we can use NumToString to convert it. Then add a decimal point and convert the remainder. But in order to convert the remainder into a fractional number, we need to know the original divisor. We also need to specify how many digits we want after the decimal point.

For each digit you want after the decimal point, the routine multiplies the remainder by 10 and then divides the it by the divisor, getting a new remainder in the process. It adds the digit to the string and then repeats the process for the next digit. However, there is a limited number of times that this can be done accurately (since we only have 16 bits of remainder to begin with). The number of digits that can be accurately calculated depends on the magnitude of the divisor, but 5 or 6 digits should be safe.

Note that the number you pass to FixPtToString doesn’t have to be the result of a divide instruction. You can output any arbitrary fixed point number you want by using the same basic idea. If you wanted an integer part bigger than 16 bits, you could output the number in a two part process. FixPtToString could be modified to be FractionToString by eliminating instructions 3 (EXT.L D0) thru 17 (BEQ.S @6) inclusive. Then it will tack on whatever fraction you pass it to what ever string you pass it. For instance, to output the number 1864723135.24226 (.24226 = 47/194):

 MOVE.L stringPtr(A5),A0
 MOVE.L #1864723135,D0  ;quotient
 JSR    NumToString
 MOVE   #47,D0   ;remainder
 SWAP   D0;no need to set quot
 MOVE   #194,D1  ;divisor
 MOVE   #5,D2    ;5 digits accuracy
 JSR    FractionToString
 MOVE.L A0,-(SP)
 _DrawString

FORMATTING

Now that we can get integers and reals into strings we need to be able to set field widths. Also, an option to add commas would be nice. The FormNumString routine does both of these. You pass it a pointer to a format string of the form: [‘,’][q[‘.’[r]]] where [ ] denotes something optional and ‘.’ and ‘,’ denote a constant character. Q and r are string variables in the range [‘0’..’99'] and represent how many spaces should be allocated for the quotient (including sign and commas) and remainder (not including decimal point). Notice that everything is optional, so the empty string is a legal one, but one that won’t do much (i.e. any) formatting. Also, the word “string” here does not mean a pascal string; i.e. there is no length byte. The nested brackets mean that you can’t have a ‘.’ if a q was not provided and you can’t have an r if a ‘.’ wasn’t provided. If q is too small to contain the number, space is used as needed. If it is too big, the number will be padded with spaces. If r is bigger than any existing remainder the number might have, zeros are appended after the decimal point (which doesn’t do much for the accuracy of the extra digits). If r is smaller than any existing remainder, then digits are just dropped. No attempt at rounding is made.

Another use for this routine is to reformat the output string from the SANE formatter. The SANE formatter can format any SANE data type into a fixed sytle number (see the Apple Numerics Manual for everything you ever wanted to know about SANE). So, you could use SANE to do all of your calculations in floating point and have your result formatted into a fixed style string and then use FormNumString to add commas, pad with spaces and delete decimal places (or add zeros) to make all your numbers uniform.

Fig. 2 Program supports easy updating with a picture

PUTTING IT ALL TOGETHER

The 3 routines NumToString, FixPtToString and FormNumString have been pieced together to form DrawNumsInAString which can be used to output complete sentences containing any number of formatted numbers. For instance, you could pass it the string “result = \f,8.4.” along with the fixed point number 123456.789 and it will output “result = 12,3456.7890.” Each number you want formatted in the input string will begin with a ‘\’ character and be followed by an ‘i’ (for longints) or an ‘f’ (for fixed points). After that comes the FormNumString style format codes for the number. The only peculiar part of using the routine is that the numbers you want formatted have to be pushed on the stack in reverse of their occuring order in the string. For instance, if your input string looks like “x = \i4 y = \i4 z = \i4” then you would do this:

 MOVE.L z,-(SP)  ;3rd parameter
 MOVE.L y,-(SP)  ;2nd
 MOVE.L x,-(SP)  ;1st
 PEA    inputString
 JSR    DrawNumsInAString

The reason for passing the parameters that way is (1) because we don’t know how many will be present in advance, and (2) so that they can be taken off the stack in the order needed.

DEMO PROGRAM

The FormatDemo program shows how all of this comes together. It is a bare bones application that demonstrates how the routines presented here might be used. A click in the window will generate another set of random numbers to format. Desk accessories are supported and you can see a simple technique for providing window updating without an update event. Whenever a content click is detected, a set of addition and division problems are displayed in formatted output using the formatting routines discussed. After displaying the numbers, a quickdraw picture is taken of the window output using copybits on the portRect of the window. The appropriate field in the window record is set with the pointer to this picture so that when the window needs updating, it is updated automatically from the picture. Figures 1 and 2 show the demo program in operation with a desk accessory showing this easy update method. A good reference book for this and all assembly language techniques is Dan Weston’s classic The Complete Book of Macintosh Assembly Language Programming, vol. 1 and 2, from Scott, Foresman and Company.


{1}
Listing 1. The Apple Way
; NOTE: This code is Apple Computer’s. Only 
; the comments are mine.

;==========
NumToString
;==========
; convert a 32 bit longint into a pascal string
;  input: D0 longint
;  A0 points to a space of at least 12 bytes
; output: A0 points to pascal string

 MOVEM.LD0-D6/A1,-(SP)
 MOVEQ  #0,D1    ;init digits
 MOVEQ  #0,D2
 MOVEQ  #0,D3
 MOVEQ  #0,D4
 MOVEQ  #0,D5
 MOVEQ  #31,D6   ;loop counter
 LEA    1(A0),A1 ;skip length byte
 TST.L  D0;is num zero?
 BGT.S  @2
 BMI.S  @1
 MOVE.B #’0',(A1)+ ;special case for zero
 BRA.S  @3
@1 MOVE.B #’-’,(A1)+ ;give string a minus sign
 NEG.L  D0;make number positive
@2 ADD.LD0,D0    ;shift a bit into extend flag
 ABCD   D5,D5    ;tens’ & ones’ digits
 ABCD   D4,D4    ;thous’ & hunds’ digits
 ABCD   D3,D3    ;hund thous’ & ten thous’ digits
 ABCD   D2,D2    ;ten mils’ & mils’ digits
 ABCD   D1,D1    ;bils’ & hund mils’ digits
 DBRA   D6,@2    ;do next bit
; NOTE: at this point D6 = -1. It is used as a flag to 
; kill leading zeros.
 BSR.S  Do2Digits
 MOVE.B D2,D1
 BSR.S  Do2Digits
 MOVE.B D3,D1
 BSR.S  Do2Digits
 MOVE.B D4,D1
 BSR.S  Do2Digits
 MOVE.B D5,D1
 BSR.S  Do2Digits
;calculate length of string that was created
@3 MOVE A1,D0    ;end of string + 1
 SUB    A0,D0    ;beginning of string
 SUBQ.B #1,D0    ;minus 1 for length byte
 MOVE.B D0,(A0)
 MOVEM.L(SP)+,A1/D0-D6
 RTS

Do2Digits
;convert BCD byte in D1 into 2 ASCII digits.
;do most significant digit
 ROR    #4,D1
 BSR.S  DoADigit
;do least significant digit
 ROL    #4,D1
DoADigit
 TST    D6;have we had a non-zero digit yet?
 BPL.S  @6
 TST.B  D1;is this a leading zero?
 BEQ.S  @7
 MOVEQ  #0,D6    ;print all zeros from now on
@6 ORI.B#$30,D1  ;covert BCD digit to ASCII
 MOVE.B D1,(A1)+ ;add it to the string
 SUB.B  D1,D1
@7 RTS

; DrawNumsInAString.asm
;----------------------
; by Mike™ Scanlin  

Include Traps.D

Xref  DrawNumsInAString,NumToString,FixPtToString,FormNumString
Xref  GetANumber

;================
DrawNumsInAString
;================

Draw a string that may contain implicit formatted numbers. input: stack contains numbers that will be needed and a pointer a string. The numbers should be pushed on the stack in order from last to first (so they can be poped off in order from first to last). The last thing to be pushed on the stack is the string pointer. Each formatted number within the input string begins with a ‘\’ and then either an ‘i’ (for longints) or a ‘f’ (for a fixed point number). For fixed points, first push the fixed point number, then the divisor to be used to calculate the remainder. The formatting after the ‘i’ or ‘f’ is the same as for the FormNumString routine. output: a string is drawn A0,D0 are trashed.

{2}
 MOVEM.LA0-A3/D1-D2,-(SP)
 LEA    28(SP),A3;point to first parameter
 MOVE.L A3,-(SP) ;save initial position
 MOVE.L (A3)+,A2 ;string pointer
@1 MOVEQ#0,D0
 MOVE.B (A2)+,D0
 BEQ.S  @10 ;end of string found
 CMPI.B #’\’,D0  ;is it a number?
 BEQ.S  @2
 MOVE   D0,-(SP)
 _DrawChar
 BRA.S  @1
;we got a number to format
@2 LEA  scratch,A0
 MOVE.B (A2)+,D0
 CMPI.B #’i’,D0  ;is it a longint?
 BNE.S  @4
;handle integers
 MOVE.L (A3)+,D0 ;get longint
 JSR    NumToString
 BRA.S  @5;go format it
@4 CMPI.B #’f’,D0;is it a fixed point?
 BNE.S  @1;if not, ignore it
;handle fixed point
 MOVEA.LA2,A1
;find out how many decimal places should be passed to 
; FixPtToString
 MOVE.B (A1)+,D0 ;skip comma, if present
 CMPI.B #’,’,D0
 BEQ.S  @4.1
 SUBA   #1,A1
@4.1  JSR GetANumber
 BMI.S  @1;no quotient present
 MOVE.B (A1)+,D0
 CMPI.B #’.’,D0
 BNE.S  @4.2
 JSR    GetANumber
 MOVE   D0,D2
 BPL.S  @4.3
@4.2  MOVEQ #0,D2;no remainder
@4.3  MOVE(A3)+,D1 ;get divisor
 MOVE.L (A3)+,D0 ;get fixed point num
 JSR    FixPtToString
;do the formatting
@5 MOVEA.LA2,A1  ;addr of format string
 JSR    FormNumString
 MOVEA.LA1,A2    ;point past format string
 MOVE.L A0,-(SP)
 _DrawString
 BRA.S  @1
@10SUBA.L (SP)+,A3 ;calc len of params
 MOVE   A3,D0
 MOVEM.L(SP)+,D1-D2/A0-A3
 MOVE.L (SP)+,A0 ;get return addr
 ADDA   D0,SP    ;length of parameters
 JMP    (A0)

scratch DCB.B  40,0


; FixPtToString.asm
;------------------
; by Mike™ Scanlin 

Xref  FixPtToString,NumToString

;============
FixPtToString
;============
; convert a 32 bit fixed point number into a pascal 
; string.
;  input: D0 fixed point number
;  D1 16 bit divisor used when D0 was calculated
;  D2 # of digits after decimal point (D2=0 for no 
;          dec point)
;  A0 points to a space of at least (8 + D2) bytes
; output: A0 points to pascal string

 MOVEM.LD0-D3/A1,-(SP)
 MOVE.L D0,D3    ;save quotient & remainder
 EXT.L  D0;sign extend quotient
 JSR    NumToString
;if q = 0 and the result should be < 0, we’ll have to 
; add a minus sign.
;(NumToString won’t know about it, since all it sees is 
; a zero quotient)
 TST    D3;q = 0?
 BNE.S  @0
 TST.L  D3;check remainder
 BEQ.S  @0;q & r both zero
;if r & divisor have the same sign, then result will 
; be > 0
 EXT.L  D1
 MOVE.L D1,D0    
 EOR.L  D3,D0
 BPL.S  @0
 MOVE.B #’-’,1(A0)
 MOVE.B #’0',2(A0)
 MOVE.B #2,(A0)  ;new length
@0 TST  D2;do we want a decimal point?
 BEQ.S  @6
 MOVEQ  #0,D0
 MOVE.B (A0),D0  ;length of quotient
 LEA    1(A0,D0),A1;end of string + 1
 MOVE.B #’.’,(A1)+
 TST.L  D1;make divisor positive
 BPL.S  @1
 NEG.L  D1
@1 TST.LD3;make remainder positive
 BPL.S  @2
 NEG.L  D3
@2 SWAP D3
 ANDI.L #$FFFF,D3;isolate remainder
 SUBQ   #1,D2    ;loop control
@3 ADD.LD3,D3    ;mult r by 10
 MOVE.L D3,D0
 ADD.L  D0,D0    ;4x
 ADD.L  D0,D0    ;8x
 ADD.L  D0,D3    ;10x = 8x + 2x
 MOVEQ  #’0',D0  ;init digit
@4 CMP.LD1,D3    ;is 10r > divisor?
 BLT.S  @5
 ADDQ   #1,D0    ;increase digit
 SUB.L  D1,D3    ;subtract divisor
 BNE.S  @4
@5 MOVE.B D0,(A1)+ ;add to string
 DBRA   D2,@3
 MOVE   A1,D0    ;calc length of new string
 SUB    A0,D0
 SUBQ.B #1,D0    ;minus 1 for length byte
 MOVE.B D0,(A0)
@6 MOVEM.L(SP)+,A1/D0-D3
 RTS


; FormNumString.asm
;------------------
; by Mike™ Scanlin  

Xref  FormNumString,GetANumber

;============
FormNumString
;============
; format the string representation of a number (integer 
; or real) according to a format string.
; input: A0 points to string of a number (which should 
; be in a space big enough for formatting result)
;  A1 points to format string
;  syntax of format string is [‘,’]d[d][‘.’[d[d]]] 
;     where ‘’ denote a constant char and d denotes 
;     a digit ‘0’..’9'
;  there is no length byte for these strings.
;   valid strings  invalid strings
;3 230. (230 too big [99 max])
;    4.0 or 4.   .0(need a d before ‘.’)
;,3.4   ,.4 (need a d between ‘,.’)
;,12.20 0.123  (123 too big)
; output: A0 points to formatted string of a number
;  A1 points to first byte after format string

 MOVEM.LD0-D5/A2,-(SP)
 CMPI.B #’,’,(A1)
 BNE.S  @6
 ADDA   #1,A1
;do commas
;first find out if a decimal point in the string
 MOVEQ  #0,D0
 MOVE.B (A0),D0  ;length of string
 MOVE   D0,D2    ;save in case it’s and int
 SUBQ   #1,D0    ;loop control
; D0 counts how many digits from the end of the string 
; to the decimal point (including the decimal 
; point -- which is why it starts out as 1 and not 0). 
 ; If the number is an int, then D0=0
 MOVEQ  #1,D1
@1 CMPI.B #’.’,1(A0,D0) ;dec point, it’s a real
 BEQ.S  @2
 ADDQ   #1,D1
 DBRA   D0,@1
;it’s an integer
 MOVE   D2,D0
 MOVEQ  #0,D1
;now add some commas
@2 MOVE D1,D5    ;save length of fraction
 MOVEQ  #3,D2    ;# of digits until next comma
 SUBQ   #1,D0
@3 ADDQ #1,D1    ;total len, from end to cur pos
 SUBQ   #1,D2
 BNE.S  @5
 MOVE   D0,D3
 MOVE.B (A0,D0),D0
 BSR    IsItADigit ;test next digit
 BNE.S  @6
 MOVE   D3,D0
;move some chars, add a comma, increase string length.
 MOVE   D1,D4    ;loop control
 SUBQ   #1,D4
 LEA    1(A0,D0),A2
@4 MOVE.B (A2,D4),1(A2,D4)
 DBRA   D4,@4
 MOVE.B #’,’,(A2)
 ADDI.B #1,(A0)
 ADDQ   #1,D1    ;for the comma
 MOVEQ  #3,D2    ;reset counter
@5 DBRA D0,@3
;get next byte of format string
@6 BSR.SGetANumber ;D0 = q
 BMI.S  @16 ;no q provided -- leave
 MOVEQ  #0,D2
 MOVE.B (A0),D2  ;length of string
 MOVE   D2,D1
 SUB    D5,D1    ;D1=len of quotient now
 SUB    D1,D0
 BMI.S  @10
 BEQ.S  @10
 ADD.B  D0,(A0)  ;increase length by D0 spaces
;add D0 # of preceeding spaces
@7 LEA  1(A0,D0),A2
 SUBQ   #1,D2
@8 MOVE.B 1(A0,D2),(A2,D2)
 DBRA   D2,@8
 SUBQ   #1,D0
@9 MOVE.B #’ ‘,1(A0,D0)
 DBRA   D0,@9
;do remainder
@10CMPI.B #’.’,(A1)
 BNE.S  @16
 ADDA   #1,A1
;make sure there is a decimal point already
 LEA    1(A0),A2
 MOVEQ  #0,D0
 MOVE.B (A0),D0
 SUBQ   #1,D0
@11CMP.B#’.’,(A2)+
 BEQ.S  @12
 DBRA   D0,@11
 MOVE.B #’.’,(A2)+
 ADD.B  #1,(A0)
@12BSR.SGetANumber
 BMI.S  @16 ;no r provided -- leave
; D0 is how many digits they want. D5 is 
; what we’ve already got.
@13SUBQ #1,D5
@14CMP  D5,D0
 BEQ.S  @16
 BPL.S  @15
 SUB.B  #1,(A0)
 BRA.S  @13
@15MOVE.B #’0',(A2,D5)  ;add a zero
 ADD.B  #1,(A0)
 ADDQ   #1,D5
 BRA.S  @14
@16MOVEM.L(SP)+,A2/D0-D5
 RTS

;=========
GetANumber
;=========
; convert a one or two digit ASCII integer into 
; its numerical form
;  input: A1 points to digit(s)
; output: D0 is the decimal equivalent (-1 if A1 
; didn’t point to a digit)
;  A1 points to byte after digit(s)
;  Z and N flags reflect the value of D0
 MOVEM.LD1-D2,-(SP)
 MOVEQ  #0,D0
 MOVE.B (A1),D0
@1 BSR.SIsItADigit
 BEQ.S  @2
 MOVEQ  #-1,D0
 BRA.S  @4
@2 ADDA #1,A1
 MOVE   D0,D1    ;save first digit
 MOVE.B (A1),D0
 BSR.S  IsItADigit
 BEQ.S  @3
 MOVE   D1,D0
 BRA.S  @4
@3 ADDA #1,A1
 ADD    D1,D1    ;multiply first digit by 10
 MOVE   D1,D2
 ADD    D2,D2
 ADD    D2,D2
 ADD    D2,D1
 ADD    D1,D0    ;add to second digit
@4 MOVEM.L(SP)+,D1-D2
 TST    D0
 RTS

;=========
IsItADigit
;=========
; If the ASCII byte in D0 is in ‘0’..’9' it’s 
; value [0..9] 
; is returned in D0. If D0 is a digit, all 
; flags are set.
 CMPI.B #’0',D0
 BLT.S  @1
 CMPI.B #’9',D0
 BGT.S  @1
 SUBI.B #’0',D0
 MOVE   #-1,CCR  ;set all flags
 RTS
@1 MOVE #0,CCR   ;clear all flags
 RTS


; NumToString.asm
;----------------
; by Mike™ Scanlin  
; an alternative to _NumToString

Xref  NumToString

;==========
NumToString
;==========
; convert a 32 bit integer into a pascal string
;  input: D0 longint
;  A0 points to a space of at least 12 bytes
; output: A0 points to pascal string

 MOVEM.LD0-D4/A1-A2,-(SP)
 LEA    1(A0),A1 ;skip length byte
 TST.L  D0;is number zero?
 BGT.S  @2
 BMI.S  @1
 MOVE.B #’0',(A1)+ ;special case for zero
 BRA.S  @8
@1 MOVE.B #’-’,(A1)+ ;give string a minus sign
 NEG.L  D0;make number positive
@2 LEA  PowersTable,A2
 MOVEQ  #1,D3    ;set leading zeros flag
 MOVEQ  #9,D4    ;loop counter
@3 MOVE.L (A2)+,D2 ;get a power of 10
 MOVEQ  #’0',D1  ;init digit
@4 CMP.LD2,D0    ;is # > power of 10?
 BLT.S  @5
 ADDQ   #1,D1    ;increase digit
 SUB.L  D2,D0    ;subtract power of 10
 BNE.S  @4
@5 TST  D3;have we had a non-zero digit yet?
 BEQ.S  @6
 CMP.B  #’0',D1  ;is this a leading zero?
 BEQ.S  @7
 MOVEQ  #0,D3    ;print all zeros from now on
@6 MOVE.B D1,(A1)+
@7 DBRA D4,@3
@8 MOVE A1,D0    ;calc length of new string
 SUB    A0,D0
 SUBQ.B #1,D0    ;minus 1 for length byte
 MOVE.B D0,(A0)
 MOVEM.L(SP)+,A1-A2/D0-D4
 RTS

PowersTable:
 DC.L 1000000000
 DC.L 100000000
 DC.L 10000000
 DC.L 1000000
 DC.L 100000
 DC.L 10000
 DC.L 1000
 DC.L 100
 DC.L 10
 DC.L 1

; Resource File
RESOURCE ‘FRED’ 0 ‘IDENTIFICATION’
 DC.B 14, ‘Format Program’

.ALIGN 2
RESOURCE ‘BNDL’ 128 ‘BUNDLE’

 DC.L ‘FRED’;name
 DC.W 0,1‘;data
 DC.L ‘ICN#’;icon map
 DC.W 0 ;mapping-1
 DC.W 0,128 ;map 0 to 128
 
 DC.L ‘FREF’;file ref
 DC.W 0 ;maps-1
 DC.W 0,128 ;map 0 to 128
 
RESOURCE ‘FREF’ 128 ‘FREF 1’

 DC.B ‘APPL’,0,0,0

.ALIGN 2
RESOURCE ‘ICN#’ 128 ‘MY ICON’

 DC.L $00000000, $00000000, $07FFFFC0, $18000030
 DC.L $202038E8, $40604514, $80204412, $80204422
 DC.L $80204441, $80204481, $802139F1, $80000001
 DC.L $80000001, $80F81021, $80103061, $802010A1
 DC.L $80701121, $800811F1, $80881021, $80711021
 DC.L $80000001, $80201801, $80602001, $80204001
 DC.L $9E207802, $80204402, $40204404, $20213808
 DC.L $18000030, $07FFFFC0, $00000000, $00000000
 DC.L $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF
 DC.L $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF
 DC.L $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF
 DC.L $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF
 DC.L $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF
 DC.L $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF
 DC.L $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF
 DC.L $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF

.ALIGN 2
RESOURCE ‘MENU’ 1 ‘APPLE’
 DC.W 1 ;menu id
 DC.W 0 ;width holder
 DC.W 0 ;height holder
 DC.L 0 ;resource id holder
 DC.L $1FB;flags enable all except 2
 DC.B 1 ;title length
 DC.B 20;title apple symbol
 
 DC.B 22;menu item length
 DC.B ‘About this program... ‘
 DC.B 0 ;no icon
 DC.B 0 ;no keyboard equiv
 DC.B 0 ;marking char
 DC.B 0 ;style of item text
 
 DC.B 2 ;menu item length
 DC.B ‘--’
 DC.B 0 ;no icon
 DC.B 0 ;no keyboard equiv
 DC.B 0 ;marking char
 DC.B 0 ;style of item text
 
 DC.B 0 ;end of menu items
 
.ALIGN 2
RESOURCE ‘MENU’ 2 ‘FILE’
 DC.W 2 ;menu id
 DC.W 0 ;width holder
 DC.W 0 ;height holder
 DC.L 0 ;resource id
 DC.L $1FF;flags
 DC.B 4 ;title length
 DC.B ‘File’;title
 
 DC.B 6 ;menu item length
 DC.B ‘Quit/Q’
 DC.B 0 ;no icon
 DC.B 0 ;no keyboard
 DC.B 0 ;no marking
 DC.B 0 ;style
 
 DC.B 0 ;end of menu items
 
.ALIGN 2
RESOURCE ‘MENU’ 3 ‘MESSAGE’
 DC.W 3 ;menu id
 DC.W 0 ;width holder
 DC.W 0 ;height holder
 DC.L 0 ;resource id
 DC.L $1F8;flags - DISABLE
 DC.B 16;title length
 DC.B ‘Click in Window ‘  ;title
 
 DC.B 0 ;menu item length
 DC.B ‘’
 DC.B 0 ;no icon
 DC.B 0 ;no keyboard
 DC.B 0 ;no marking
 DC.B 0 ;style
 
 DC.B 0 ;end of menu items
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Ableton Live 9.7.1 - Record music using...
Ableton Live lets you create and record music on your Mac. Use digital instruments, pre-recorded sounds, and sampled loops to arrange, produce, and perform your music like never before. Ableton Live... Read more
FileZilla 3.23.0.2 - Fast and reliable F...
FileZilla (ported from Windows) is a fast and reliable FTP client and server with lots of useful features and an intuitive interface. Version 3.23.0.2: Bug Fixes and Minor Changes Speed up icon... Read more
Vivaldi 1.5.658.56 - An advanced browser...
Vivaldi is a browser for our friends. In 1994, two programmers started working on a web browser. Our idea was to make a really fast browser, capable of running on limited hardware, keeping in mind... Read more
Safari Technology Preview 10.1 - The new...
Safari Technology Preview contains the most recent additions and improvements to WebKit and the latest advances in Safari web technologies. And once installed, you will receive notifications of... Read more
TunnelBear 3.0.8 - Subscription-based pr...
TunnelBear is a subscription-based virtual private network (VPN) service and companion app, enabling you to browse the internet privately and securely. Features Browse privately - Secure your data... Read more
NeoFinder 7.0 - Catalog your external me...
NeoFinder (formerly CDFinder) rapidly organizes your data, either on external or internal disks, or any other volumes. It catalogs all your data, so you stay in control of your data archive or disk... Read more
Coda 2.6 - One-window Web development su...
Coda is a powerful Web editor that puts everything in one place. An editor. Terminal. CSS. Files. With Coda 2, we went beyond expectations. With loads of new, much-requested features, a few surprises... Read more
File Juicer 4.51 - Extract images, video...
File Juicer is a drag-and-drop can opener and data archaeologist. Its specialty is to find and extract images, video, audio, or text from files which are hard to open in other ways. In computer... Read more
PDFpenPro 8.3 - $124.95
PDFpenPro allows users to edit PDF's easily. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Create fillable forms and tables of content... Read more
PDFpen 8.3 - $74.95
PDFpen allows users to easily edit PDF's. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Even correct text and edit graphics! Features... Read more

Latest Forum Discussions

See All

Niantic teases new Pokémon announcement...
After rumors started swirling yesterday, it turns out there is an official Pokémon GO update on its way. We’ll find out what’s in store for us and our growing Pokémon collections tomorrow during the Starbucks event, but Niantic will be revealing... | Read more »
3 reasons why Nicki Minaj: The Empire is...
Nicki Minaj is as business-savvy as she is musically talented and she’s proved that by launching her own game. Designed by Glu, purveyors of other fine celebrity games like cult favorite Kim Kardashian: Hollywood, Nicki Minaj: The Empire launched... | Read more »
Clash of Clans is getting its own animat...
Riding on its unending wave of fame and success, Clash of Clans is getting an animated web series based on its Clash-A-Rama animated shorts.As opposed to the current shorts' 60 second run time, the new and improved Clash-A-Rama will be comprised of... | Read more »
Leaks hint at Pokémon GO and Starbucks C...
Leaked images from a hub for Starbucks employees suggests that a big Pokémon GO event with the coffee giant could begin this very week. The images appeared on Reddit and hint at some exciting new things to come for Niantic's smash hit game. | Read more »
Silent Depth Submarine Simulation (Game...
Silent Depth Submarine Simulation 1.0 Device: iOS Universal Category: Games Price: $7.99, Version: 1.0 (iTunes) Description: | Read more »
Enneas Saga lets you lead your own demon...
Defend the land of Enneas Continent from the forces of evil in the new fantasy MMORPG from Lyto Mobi: Enneas Saga. Can’t wait? No problem. It’s available to download now on Android devices. | Read more »
Great zombie games in the spirit of Dead...
Dead Rising 4 arrives tomorrow, giving enthusiasts a fresh chance to take selfies with zombies and get up to other ridiculous end-of-the-world shenanigans. To really get into the spirit of things, we've gone and gathered the best zombie games that... | Read more »
Amateur Surgeon 4 Guide: Advanced tips a...
Amateur Surgeon 4 is still tackling the competition at the top of the App Store charts, so if you haven't tried it out yet, you should probably do that right away. If you've been at it for a while, though, perhaps you're ready to start expanding... | Read more »
Amateur Surgeon 4 Guide: Become the worl...
It's time to wield your trusty pizza cutter again, as Amateur Surgeon has returned with a whole fresh set of challenges (and some old, familiar ones, too). Starting anew isn't easy, especially when all you have at your disposal is a lighter, the... | Read more »
Le Parker: Sous Chef Extraordinaire (Ga...
Le Parker: Sous Chef Extraordinaire 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: | Read more »

Price Scanner via MacPrices.net

Back in stock: Apple refurbished Mac minis fr...
Apple has Certified Refurbished Mac minis available starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: - 1.4GHz Mac mini: $419 $80 off MSRP - 2.6GHz Mac... Read more
Twenty-Five Years Of Apple Laptops – A person...
Among many other things, the often tumultuous 16th year of the new century marked the 25th anniversary of Apple laptop computers, not counting the optimistically named 16-pound Mac Portable of 1989.... Read more
Landlordy iOS App Adds Support For Appliances...
Riga, Latvia based E-protect SIA is releasing major update (version 1.8) to its Landlordy app for managing rental business financials on the go. Landlordy is iPhone and iPad app designed for self-... Read more
Holiday sale, Apple iMacs for up to $200 off...
B&H Photo has 21″ and 27″ Apple iMacs on sale for up to $200 off MSRP including free shipping plus NY sales tax only: - 27″ 3.3GHz iMac 5K: $2099 $200 off MSRP - 27″ 3.2GHz/1TB Fusion iMac 5K: $... Read more
Holiday sale: Mac minis for $50 to $100 off M...
B&H Photo has Mac minis on sale for up to $100 off MSRP free shipping plus NY sales tax only: - 1.4GHz Mac mini: $449 $50 off MSRP - 2.6GHz Mac mini: $629 $70 off MSRP - 2.8GHz Mac mini: $899 $... Read more
Mac Pros on sale for up to $300 off MSRP, ref...
B&H Photo has Mac Pros on sale for up to $300 off MSRP. Shipping is free, and B&H charges sales tax in NY only: - 3.7GHz 4-core Mac Pro: $2799, $200 off MSRP - 3.5GHz 6-core Mac Pro: $3699, $... Read more
12-inch WiFi Apple iPad Pros on sale for up t...
B&H Photo has 12″ WiFi Apple iPad Pros on sale for up to $50 off MSRP, each including free shipping. B&H charges sales tax in NY only: - 12″ Space Gray 32GB WiFi iPad Pro: $749 $50 off MSRP... Read more
9-inch Apple WiFi iPad Pros on sale for $20-$...
B&H Photo has 9.7″ Apple WiFi iPad Pros on sale for $20-$50 off MSRP, each including free shipping. B&H charges sales tax in NY only: - 9″ Space Gray 256GB WiFi iPad Pro: $779.95 $20 off MSRP... Read more
Apple refurbished 2015 15-inch MacBook Pros a...
Apple has Certified Refurbished 2015 15″ Retina MacBook Pros available starting at $1699. An Apple one-year warranty is included with each model, and shipping is free: - 15″ 2.2GHz Retina MacBook Pro... Read more
Back in stock! 13-inch 2.7GHz Retina MacBook...
Apple has Apple Certified Refurbished 2015 13″ 2.7GHz/128GB Retina MacBook Pros (MF839LL/A) available again for $1099 including free shipping. That’s $200 off MSRP, and it’s the lowest price... Read more

Jobs Board

*Apple* Retail - Multiple Positions- Philade...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions- San Ant...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Products Tester Needed - Apple (Unit...
…we therefore look forward to put out products to quality test for durability. Apple leads the digital music revolution with its iPods and iTunes online store, Read more
SW Engineer *Apple* TV Frameworks - Apple I...
The Apple TV team is looking for a software...create features that reflect the look and feel of Apple TV. Description: Were looking for someone who is Read more
Hardware Design Validation Engineer - *Apple...
The Apple Watch team is looking for a Hardware Design Validation Engineer. This person will be part of the Apple Watch hardware team with responsibilities for Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.