THINK Pascal & CodeWarrior Pascal
Steve Makohin, Water's Edge Software



THINK Pascal & CodeWarrior Pascal

June 1997
by Steve Makohin

Water's Edge Software
2441 Lakeshore Rd., West #70022
Oakville, Ontario, Canada, L6L 6M9

Contents

Section 1 - Comparing THINK Pascal to CodeWarrior Pascal
Section 2 - Migrating To CodeWarrior Pascal





Comparing THINK Pascal to CodeWarrior Pascal


Water's Edge Software, creators of Tools Plus, has extensive experience using CodeWarrior compilers (C/C++/Pascal for 680x0 & PPC). We originally came from a THINK Pascal background and we've spent a lot of time with CW Pascal specifically, so we can make a fare comparison between the two. Here are our thoughts:



Migrating To CodeWarrior Pascal


If you are thinking about making the transition from THINK Pascal to CodeWarrior, or if you want to use THINK Pascal for your 68K work and CodeWarrior for your PowerPC work and have both use the same source code, here are the areas when you need to be aware of the differences:

  1. CW Pascal projects expect your application file to be first in your projects's build order whereas THINK expects it to be last.

  2. CW expects the unit name and its source file to be the same. For example, a unit named MyUnit must be in a source file named MyUnit.p. This means your source _files_ must be named in a way that is consistent with the unit's name. For example, you can't have a file named "1Thing.p" because a Pascal unit can't start with a number. You also can't include spaces or other characters in your file names that would not be allowed in a Pascal unit.

  3. THINK Pascal assumes a "uses" statement for all the standard toolbox units. CodeWarrior makes no assumptions, so you will likely need to include a uses clause that looks like this:
    Uses
    	Controls, Dialogs, Fonts, Lists, Menus, Packages, Processes,
    	QuickDraw, Resources, SegLoad, TextEdit, ToolUtils, Windows;

    Fortunately, CW also lets you turn on "Used Propagation" so you can have all these items listed once in your application's "globals" unit which in turn will be used by each unit in your project.

  4. CW supports only Universal Headers and Universal Pascal Interfaces (UPIs). As you compile your THINK Pascal source code under CW, every time CW runs across a routine that has been renamed in the new UPIs, you must rename it in your app. The same applies for some constants that have been renamed in the UPIs.

    NOTE: If your source code must be compiled by both THINK Pascal and CW, you'll want to take a different approach:

  5. The original Apple interfaces and headers are for 680x0 Macs only whereas the new UPIs let you use the same source code for both 680x0 Macs and PowerPC Macs. A problem arises in callback routines. For example, in the old interfaces, you could say:
    SetClikLoop(@myProc, hTE);

    @myProc is simply a pointer to a Pascal routine. When using the new UPIs, they take PowerPC differences into account, and with a PowerPC, it is possible to call a routine that is made of either 68K or PowerPC native executable code. The caller has to know this, so PowerPC introduces the Mixed Mode Manager.

    When using the UPIs, you have to create something called a Universal Procedure Pointer (UPP). When compiled into 680x0 code, it is nothing more than a pointer to the routine, just like it has been in the past. When compiled into PowerPC native code, creating a UPP actually allocates a structure that tells the calling routine what kind of code it will call (68K or PowerPC) and how the parameters are passed.

    Remember that on PowerPC, a UPP is an _allocated_ _structure_ that points to a routine. It's not just a pointer. The same UPP can be used throughout your application, so it's a smart idea to allocate the UPP only once early in your app, then use that one UPP throughout your app as required. Here's the code you can use to allocate the UPP early in your app:

    {$IFC THINK_Pascal}
    	DragProcPtr := @myProc;
    {$ELSEC}
    	DragProcPtr := NewTEClickLoopProc(@myProc);
    {$ENDC}


    Later, you can use the DragProcPtr as follows:

    {$IFC THINK_Pascal}
    	SetClikLoop(DragProcPtr, hTE);
    {$ELSEC}
    	TESetClickLoop(DragProcPtr, hTE);
    {$ENDC}


    If you ever need to deallocate the UPP so save memory, use the following code:

    {$IFC NOT THINK_Pascal}
    	DisposeRoutineDescriptor(DragProcPtr);
    {$ENDC}
    
  6. Your app references QuickDraw globals through the "qd" global. For example, use "qd.Gray" instead of "Gray" for the gray pattern. More common is the use of qd.screenBits.Bounds to determine the boundary of your monitor.

  7. In CW your projects must initialize the Mac toolbox:
    InitGraf(@qd.thePort);
    InitFonts;
    InitWindows;
    InitMenus;
    TEInit;
    InitDialogs(nil);
    MaxApplZone;

    By default, this is done automatically in THINK Pascal. If your code must run on both THINK Pascal and CW, write your main program as follows:

    {$IFC THINK_Pascal}
    {Don't do automatic toolbox initialization}
    {$I-}
    {$ENDC}
    BEGIN
    {$IFC THINK_Pascal}
    	InitGraf(thePort);
    {$ELSEC}
    	InitGraf(@qd.thePort);
    {$ENDC}
    	InitFonts;
    	InitWindows;
    	InitMenus;
    	TEInit;
    	InitDialogs(nil);
    	MaxApplZone;

    If you are using Tools Plus, you can skip the InitGraf through MaxApplZone code by including initMacToolbox in the Spec parameter of Tools Plus' InitToolsPlus routine.

  8. At initialization, THINK Pascal does a bunch of calls to MoreMasters. CW does not. Here is the equivalent code you need to add to your CW app.
    for x := 1 to 12 do
    	MoreMasters;
  9. Make sure you turn the "copy strings using length byte" option ON in CW's preferences. THINK Pascal does, MPW Pascal does not. CodeWarrior lets you go either way.

  10. CW does not always evaluate a line from left to right like THINK Pascal does. The following example works in THINK Pascal but gives you an incorrect answer in CW Pascal:
    IF SectRect(ButtonRect, Bounds, IntersectingRect) and 
    	EqualRect(ButtonRect, IntersectingRect) THEN

    EqualRect depends on a correct answer from SectRect being evaluated first. In CW Pascal, you must use short circuit evaluation to guarantee a correct left-to-right evaluation, such as:

    IF SectRect(ButtonRect, Bounds, IntersectingRect) & 
    	EqualRect(ButtonRect, IntersectingRect) THEN
  11. Look out if you work with packed records where a 2 byte or 4 byte record is made up of various bit patterns. For example, the low 9 bits being a number from 0 to 511, the next bit up being a boolean, etc. We've experienced problems in CW 6, 8 and 9. As far as we can see, CW10 and later work correctly with packed record.

Water's Edge Software Voice: 1-416-219-5628
2441 Lakeshore Rd. West #70022 Fax: 1-905-847-1638
Oakville, Ontario Internet: WaterEdg@interlog.com
Canada, L6L 6M9 CIS: 73424,2507


Visit our developer web site at http://www.interlog.com/~wateredg


Copyright ©1997 Steve Makohin, Water's Edge Software

Web page by Bill Catambay
Updated: 11-July-1997