Adapting your code for FBtoC

In theory, FBtoC translates any and all FB code correctly without requiring you to make any changes. As they say, theory and practice are the same in theory, but in practice they are different.

You're going to have to make changes. Some are straightforward, and don't affect the ability of your code to run on FB, such as replacing compile long if by #if.

Some are invasive, meaning that the altered code no longer works in FB. To keep your project compatible, you provide two code paths, one for FB and the other for FBtoC. The special constant _FBtoC described below serves to conditionalise the two branches.


autoXREFCurr&
To obtain the next index for a dynamic array:

begin globals
dynamic myDynArray(1000) as long
end globals
myDynArray(567) = 1
#if def _FBtoC
nextIndex = fn DynamicNextElement( dynamic( myDynArray ) ) // FBtoC syntax
#else
dim as pointer address
address = @myDynArray               // FB...
nextIndex = address.autoXREFCurr&   // ...syntax
#endif
// nextIndex is 568

def DynamicRemoveItems
The syntax for FBtoC is different from FB.

// Delete item 1 in dynamic array
#if ndef _FBtoC
def DynamicRemoveItems( gMyDynArray, 1, 1, 0 )            // FB syntax
#else
def DynamicRemoveItems( dynamic( gMyDynArray ), 1, 1, 0 ) // FBtoC syntax
#endif

for/next loops
Owing to historical aberration, for/next loops in FB were always executed at least once. This aberration has been removed in FBtoC.

dim as long  j, n
n = 0
for j = 1 to n
 // get here in FB but not in FBtoC
next

HandleEvents
The default behaviour of HandleEvents is to block (i.e. not return) unless an event is dispatched. The original behaviour of returning 30 times a second, if required for old polling code, can be restored by:

poke long event - 8, 2 // null events every 2 ticks, like FB4
do
  fn PollForSomething
  HandleEvents
until gFBQuit

HMHelpContent and ControlButtonContentInfo
The HMHelpContent and ControlButtonContentInfo structs in C (and FBtoC ) contain a named union (whose name is 'u'), whereas in FB the union is anonymous.
To avoid the error

... Field not a member of record
you must use the new syntax for all statements in your code that reference fields within the union.
dim as HMHelpContent  helpText
#if def _FBtoC
helpText.u.tagString = "My window help tag"
#else
helpText.tagString = "My window help tag"
#endif

dim as ControlButtonContentInfo   cbcInfo
cbcInfo.contentType = _kControlContentIconSuiteRes
#if ndef _FBtoC
// your old FB code using field references such as:
... cbcInfo.resID ... // or cIconHandle, iconSuite, iconRef...
#else
// FBtoC equivalent union field references:
... cbcInfo.u.resID ... // or u.cIconHandle, u.iconSuite, u.iconRef...
#endif

enterproc
Label must match the enterproc fn name:

long if 0
"MyCommandProcessHandler"
enterproc fn MyCommandProcessHandler( ...

FSCatalogInfo.finderInfo
Defined differently in C and FB.

This works in FB only:

include "Tlbx MoreFilesX.incl"
local mode
local fn FSRefSetTypeAndCreator( ref as ^FSRef, type as OSType, creator as OSType )
'~'1
dim as FSCatalogInfo info
dim as OSErr err

err = fn FSGetCatalogInfo( #ref, _kFSCatInfoFinderInfo, @info, #0, #0, #0 ) 
long if ( err == _noErr )
info.finderInfo.file.fileType = type // ................. compile error
info.finderInfo.file.fileCreator = creator // ........... compile error
err = fn FSSetCatalogInfo( #ref, _kFSCatInfoFinderInfo, info )
end if
end fn = err

This (exact equivalent) works in both FB and FBtoC:

include "Tlbx MoreFilesX.incl"
local mode
local fn FSRefSetTypeAndCreator( ref as ^FSRef, type as OSType, creator as OSType )
'~'1
dim as FSCatalogInfo info
dim fInfo as ^FileInfo
dim as OSErr err

err = fn FSGetCatalogInfo( #ref, _kFSCatInfoFinderInfo, @info, #0, #0, #0 ) 
long if ( err == _noErr )
fInfo = @info.finderInfo
fInfo.fileType = type
fInfo.fileCreator = creator
err = fn FSSetCatalogInfo( #ref, _kFSCatInfoFinderInfo, info )
end if
end fn = err

LongDateRec
Different syntax required for FBtoC.

In order to simulate the union structure in C, the definition of LongDateRec in Tlbx Structures.incl (in FBtoC headers folder) is different from that used in standard FB. Assuming there is a variable defined as:

dim as LongDateRec   cDate

The conditional code to access month, day , year is as follows:

#if def _FBtoC
cDate.ld.year      = whatever
cDate.ld.month     = whatever
cDate.ld.day       = whatever
#else
cDate.year         = whatever
cDate.month        = whatever
cDate.day          = whatever
#endif

picFrame
Intel native code for the picFrame field of a PicHandle gives byte-reversed garbage. The fix is to use QDGetPictureBounds().

dim as Rect  r
dim picH as ^^Picture
picH = fn GetPicture( _myPICTResID )
#if def _FBtoC
fn QDGetPictureBound( picH, @r )
#else
r = picH..picFrame // r fields are wrong on Intel
// r;8 = [picH] + _picFrame // old FBII syntax; r fields are wrong on Intel
#endif

Proc function
The syntax for FBtoC is different from FB.

#if ndef _FBtoC
sRFilter = fn NewControlKeyFilterUPP( [proc "MyFilterProc" + _FBprocToProcPtrOffset] )  // FB
#else
sRFilter = fn NewControlKeyFilterUPP( @fn MyFilterProc )   // FBtoC
#endif

FBtoC also accepts another form: proc "MyRecurFilterProc"

Special constants

FBtoC special constant
FBtoC maintains a special constant _FBtoC for use in conditional compilation. It is defined in FBtoC but not in FB. Even in FBtoC, its value is of no interest. The constant should be used only in the definition-query forms #if def ... or #if ndef ... Typically, two alternative code paths are specified:

#if def _FBtoC
// FBtoC sees this; FB does not
#else
// FB sees this; FBtoC does not
#endif
or
#if ndef _FBtoC
// FB sees this; FBtoC does not
#else
// FBtoC sees this; FB does not
#endif

Other special constants
There are five special constant in addition to _FBtoC (described above). All are undefined in FB.
Like _FBtoC, they should be used only in the definition-query forms #if def ... or #if ndef ...
Unlike _FBtoC, they temporarily affect FBtoC's internal translation state. They are used mainly, but not exclusively, in Headers files.

For reference:

#if def _LITTLEENDIAN
// FBtoC sees this; FB does not
// the compiler sees this only when compiling for Intel
#else
// FBtoC and FB both see this
// the compiler sees this only when compiling for PowerPC
#endif


#if ndef _DEFINEDINCARBON
// FBtoC and FB both see this
// FBtoC suppresses C code for #define and record definitions
#endif


// Example (from Tlbx CFString.h):
#if ndef _DEFINEDINCARBON
#define CFStringEncoding as UInt32
#endif


#if def _PASSTHROUGH
// FBtoC sees this; FB does not
// FBtoC passes everything, except comments, untranslated to the compiler
// passed C code goes in current function or main()
#endif


#if def _PASSTHROUGHFUNCTION
// FBtoC sees this; FB does not
// FBtoC passes everything, except comments, untranslated to the compiler
// the C code, typically a function definition, goes before main()
#else
// FB sees this; FBtoC does not
#endif


#if def _DEFINEDINCRUNTIME
// FBtoC and FB both see this
// FBtoC suppresses C code for var declarations (typically globals already defined in the C runtime)
#endif

Working directories

History
Under MFS on the first Macs, files were identified by two parameters: name and volume reference number. When HFS superseded MFS, the directory structure required an additional parameter: the parID. The official way to identify a file then became the FSSpec, which contains all three parameters. To allow MFS code to work under the new file system, Apple devised an hack known as a working directory. An unfortunate consequence was that many programs, even newly written ones, continued to use the old MFS API instead of switching to the new-in-1985 FSSpecs. See http://developer.apple.com/documentation/mac/Files/Files-85.html

Working directories are history
If your code attempts to identify a file by name and 1 number, that number is a working directory refNum.

As noted above, working directories date from HFS and were abandoned by Apple in Carbon. Working directory reference numbers(WDs), and any WDs generated by FB functions/keywords, like system(_aplVol), system( _sysVol) and FOLDER, are not implemented, and will never be implemented, in FBtoC.

In Carbon, a file may be identified by:

What do I use instead of FOLDER and other WD verbs?
FindFolder (or the FSRef version FSFindFolder) is your friend here.

How do I access files in the application folder?
err = fn FSMakeFSSpec( system( _aplVRefNum ), system( _aplParID ), "Test", @theFileSpec )

How do I get a FileSpec from a file on the boot volume at the root level?

dim as FSSpec fs
dim as OSStatus err

#if you_know_the_vol_name // "MyDrive"

err = fn FSMakeFSSpec( 0, 0, "MyDrive:MyFileName", @fs )

#else

dim as short @ vRefNum
dim as long @ dirID
err = fn FindFolder( _kOnSystemDisk, _kSystemFolderType, _kDontCreateFolder, @vRefNum, @dirID )
dim as FSSpec fs
err = fn FSMakeFSSpec( vRefNum, _fsRtDirID, ":MyFileName", @fs )

#endif

Division operator usage rules
' / ' and ' \\ ' are synonyms for integer divide.
' \ ' means floating-point divide.

These divisions are floating-point, no matter what division symbol is used:
[1] float/float [e.g. 2.42/4.29]
[2] float/integer [e.g. 2.42/4]
[3] integer/float [e.g. 2/4.29]
[4] dim as double floatResult : floatResult = integer/integer [e.g. 8/9]

In [4], "floatness" implied by the destination of the expression overrules the "integerness" of the right hand side. Numerator and denominator are converted to doubles and divided on the fpu.