• Hello MLAers! We've re-enabled auto-approval for accounts. If you are still waiting on account approval, please check this thread for more information.

Convert THINK C 5.0 into Apple C for CodeWarrior?

Hi, does anybody know if it's possible to convert a Symantec THINK C 5.0 project into a CodeWarrior project? I tried to drag the .c files over to a new CodeWarrior project and adjusted the include paths and although it mostly wants the .c files, some of them contain code that CodeWarrior does not like. I think THINK C is a little bit different from Apple C or even ANSI C... Any way to convert it to Apple C so that CodeWarrior can compile/run it?
 
Hi, does anybody know if it's possible to convert a Symantec THINK C 5.0 project into a CodeWarrior project? I tried to drag the .c files over to a new CodeWarrior project and adjusted the include paths and although it mostly wants the .c files, some of them contain code that CodeWarrior does not like. I think THINK C is a little bit different from Apple C or even ANSI C... Any way to convert it to Apple C so that CodeWarrior can compile/run it?
That's a big question, you'll need to explain the kinds of things in your code CW doesn't like. For example, THINK C's version of C can include object-orientated C (not C++), which looks a lot like C++, but is mostly a subset. For example, you can call a super-class's method using super->methodName(params..). That's not valid with C++; you'd have to make it a C++ .cp file. Also, THINK C supports inline assembler, but CW doesn't.

You'll almost certainly have the same problems converting to Apple C though. I have successfully converted some of my THINK C projects to CW 10 or 11 Gold Academic (from about 1998 or 1999).
 
If it's just a couple syntax errors, then you can post them here if you can't figure out a work-around or to confirm a work-around. Posting replies here might be the most amount of work you might expect from fellow forum users. If they get interested enough, then they might try to load the project in CodeWarrior.

I use CodeWarrior Pro 4 for 68K. CodeWarrior Pro 6 max. I compile on newer Mac OS and test on older Mac OS if support for older Mac OS is desired.

There's a CW Porting Guide.pdf in CodeWarrior Pro 4 which has a small list of things to consider.
The CodeWarrior Pro 6 Porting Reference.pdf has similar info while removing references to specific compilers.
 
Well, let's do one concrete example. Here's a source code project that I would like to import into CodeWarrior. It runs and compiles fine under THINK C 5.0 but CodeWarrior will not compile it due to a couple syntax errors: https://amendhub.com/jcs/wikipedia
You can compile files individually on CW just like in THINK C. If you point us to the files we can probably answer the specific questions a bit quicker. I did notice an enum member called A in dnr.h. I'm not sure that's good practice.

C:
enum AddrClasses {
    A = 1,
    NS,
    CNAME = 5,
    lastClass = 65535
};
 
Well, if you consider this bad practice, then continue to read, as just a couple lines underneath that, you'll see even worse: One of the variable is named "class". I'm not kidding. But, apparently, the guy who made this is a genius and the app compiles very well under THINK C 5.0 and pulls DATA from Wikipedia on a Mac Plus. It's actually quite surprising. Sometimes, geniuses circumvent the hardest issues with what seems like nonsense or very unorthodox methods. Remember how the Atari Breakout game prototype was made (and worked) in a couple days with circuitry that nobody except Steve Wozniak understood. They had to redo the whole thing before manufacturing it because other engineers didn't understand how it even worked.

Screenshot 2025-03-06 at 5.21.50 AM.png
 
Last edited:
Well, if you consider this bad practice, then continue to read, just a couple lines underneath that, you'll see even worse: One of the variable is named "class". I'm not kidding. But, apparently, the guy who made this is a genius and the app compiles very well under THINK C 5.0 and pulls DATA from Wikipedia on a Mac Plus. It's actually quite surprising.

View attachment 84157
OK, you can do a search and replace for that. I tend to use the old Symbian convention (think Nokia Smartphones from the early 2000s) where instance variables are prefixed with 'i' for "instance".
 
One thing that I cannot find anywhere in any of the source or header files, even from within THINK C 5.0 where this project compiles is the "Ticks" variable. Nowhere does this look to be defined. It's like some kind of THINK C magic variable or something... or it's part of some library that the mass find function does not pick up.
 
One thing that I cannot find anywhere in any of the source or header files, even from within THINK C 5.0 where this project compiles is the "Ticks" variable. Nowhere does this look to be defined. It's like some kind of THINK C magic variable or something... or it's part of some library that the mass find function does not pick up.
It's real, it's one of the system global variables. It's better to use the function TickCount() than rely on the global variable though, especially with post-68K compilers. For reference, you can find it in the listing of global variables here:

 
Oh, I see, but will TickCount() work on 68000 still?

And what about TERec ? Is that a variable type that you recognize?
 

Attachments

  • Screenshot 2025-03-06 at 7.21.20 AM.png
    Screenshot 2025-03-06 at 7.21.20 AM.png
    172.7 KB · Views: 3
TERec is also in Inside Macintosh Vol 1, it's the type definition for the Text Edit record. See Vol 1 page 377.
OK, so according to https://developer.apple.com/library/archive/documentation/mac/pdf/Text.pdf there is a "hText" member variable, which is a handle to the text in that TextEdit control so I guess if I feed that to the HLock and HUnlock it... could... work, maybe? I don't know. The compiler seems happy with it (we'll see if it crashes once I get all 127 other errors sorted out!)

Screenshot 2025-03-06 at 7.47.42 AM.png

Next are two SetCursor(&arrow); statements for which CodeWarrior doesn't know what the "arrow" variable is. It's not in your linked almanac either. It's clear to me that "arrow" should reference the default Mac OS arrow cursor since I also see this:
SetCursor(*(GetCursor(watchCursor)));
...But "arrow" is not defined anywhere. Any idea to make it work in CodeWarrior?

Screenshot 2025-03-06 at 7.54.49 AM.png
 
<snip> "hText" <snip> a handle to the text in that TextEdit control <snip> HLock and HUnlock it... could... work <snip> all 127 other errors sorted out!
Correct and it might not be as bad as 127 errors, often one error will cause a cascade of others.
<snip> SetCursor(&arrow); <snip>
In early Mac programming it used to be possible to directly address QuickDraw vars, but later on, you need to refer to them via a struct:

C:
void Initialize(void)
{
    WindowPtr    mainPtr;
    OSErr        error;
    SysEnvRec    theWorld;
       
    //
    //    Test the computer to be sure we can do color. 
    //    If not we would crash, which would be bad. 
    //    If we can’t run, just beep and exit.
    //

    error = SysEnvirons(1, &theWorld);
    if (theWorld.hasColorQD == false) {
        SysBeep(50);
        ExitToShell();                    /* If no color QD, we must leave. */
    }
   
    /* Initialize all the needed managers. */
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    InitCursor();

Note how it says &qd.thePort ? All of the QuickDraw globals are now referenced from a struct called qd instead of just global globals:

Code:
struct QDGlobals {
    char                        privates[76];
    long                        randSeed;
    BitMap                        screenBits;
    Cursor                        arrow;
    Pattern                        dkGray;
    Pattern                        ltGray;
    Pattern                        gray;
    Pattern                        black;
    Pattern                        white;
    GrafPtr                        thePort;
};

typedef struct QDGlobals QDGlobals;

extern QDGlobals qd;

So you should find that &qd.arrow works. Inside Macintosh: I-204, or Inside Macintosh: Imaging With QuickDraw: 2-36.

Hope this helps.
 
But "arrow" is not defined anywhere. Any idea to make it work in CodeWarrior?
qd.arrow.GIF

Try:
SetCursor(&(qd.arrow));

As C and compilers matured, they corrected mistakes and used more "C standard" ways of accessing Mac features. Unfortunately, this broke some earlier source code. In the example above, rather than faking that arrow is a global variable, they define qd in the startup library. So now, you can reference all of those variable as members of the qd object.
 
Guys, you're geniuses. The compiler is happy about the arrow cursor now. Alright, so after fixing those 2 errors, we're down from 127 to.... 127 ?! ... *SIGH* XD ... OK now the compiler is unhappy about this line:

Screenshot 2025-03-06 at 12.03.46 PM.png
 
Guys, you're geniuses. The compiler is happy about the arrow cursor now.
Thanks, and great - that's progress!
Alright, so after fixing those 2 errors, we're down from 127 to.... 127 ?! ... *SIGH* XD ... OK now the compiler is unhappy about this line:
Sometimes errors just mask other errors. Here, it should be (browser*)xmalloczero... It can't automatically cast from a void * to a specific type.
 
@Snial types faster than I do.
LOL! I was three grades under the entrance requirements for UEA (BCE instead of BBC 'A' level grades, 'E' is still a pass). But they still offered me a place. To try and compete better, I learned to touch-type just so that when we were programming in labs I could look across to a fellow student in a conversation while typing and they'd be impressed. It worked! And, I'm much faster after 38 years of touch-typing! And I learned to touch type on a Sinclair QL with its strangely Scandinavian, 80's era membrane+keycaps keyboard.

1741281749441.png
The QL keyboard is unusual for a UK keyboard in that single and double-quotes are US-style rather than a typical UK PC keyboard style (which swaps '@' and '''). But I prefer it, UK Mac keyboards don't swap those characters. You may know that the QL, despite running on a puny 68008 had a sophisticated preemptive, multithreaded OS. You could rotate through all the current processes (called jobs) using <ctrl><F5>.
 
That doesn't seem to do the trick:

View attachment 84168
Sorry, I keep forgetting that people don't typedef every struct. Try (struct browser *) , it ought to work.

My general opinion is that pascal's approach is better. It rarely makes sense to define a struct declaration if you're going to use it more than once.

For example,

C:
struct sMyXY {
    int iX,iY;
};

struct {
    uint8_t iLen;
    char iText[100]; // up to 100 chars..
} gMyStr100;

Both of these forms are almost always frustrating. You can't refer to sMyXY by itself, instead you always have to refer to struct sMyXY so it involves extra typing and at some point a programmer will forget to prefix sMyXY with a struct. In the case of gMyStr100, you're stuck with that single variable of that kind: you can't pass it as a parameter for use in other functions, it's a standalone declaration that can't be reused. Super annoying IMHO. It should be:

C:
typedef struct {
    int iX,iY;
}tMyXY; // the type, you just need this.

typedef struct {
    uint8_t iLen;
    char iText[100]; // up to 100 chars..
}tMyStr100; // now we can re-use tMyStr100 for more vars or params.

tMyStr100 gMyStr100;

There's one case where it does make sense though, where you need to refer to the structure from within the struct (e.g. a list definition).

C:
typedef struct {
    int iX, iY;
    tMyList *iNext; // point to next in list. *Doesn't Work!*.
}tMyList;

typedef struct sMyList {
    int iX, iY;
    struct sMyList *iNext; // You need to use this form, tMyList doesn't exist yet.
}tMyList; // only now tMyList exists.

So, in 'C' the name of the type isn't known in a typedef until the end. It's a dumb syntax decision which derived from the pre-1978 era of 'C' where you could define a struct, but you couldn't define a type (typedef didn't exist, programmers used #define instead). So, they made struct definitions first take the same syntax as a variable definition, e.g. int x; becomes struct { int a,b,c,d; } x; and then since you usually wanted to re-use it, they bodged on a name for the struct after 'struct'... struct FourInts { int a,b,c,d; } x; [which is a struct template + a variable based on the template].

C++ fixes that. simply typing struct tFourInts { int a,b,c,d; }; defines it as a type rather than a template. Anyway, 'C' rant over ;-) !
 
Last edited:
Back
Top