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.
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
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
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
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 recordyou 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
Label must match the enterproc fn name:
long if 0 "MyCommandProcessHandler" enterproc fn MyCommandProcessHandler( ...
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
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
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
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 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 #endifor
#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.
#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
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:
 float/float [e.g. 2.42/4.29]
 float/integer [e.g. 2.42/4]
 integer/float [e.g. 2/4.29]
 dim as double floatResult : floatResult = integer/integer [e.g. 8/9]
In , "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.