Convert THINK C 5.0 into Apple C for CodeWarrior?

David Cook

Well-known member
is there a SetMBarHeight(0);

Yes. At some point, Apple realized that global variables complicated the transition to multiple threads/CPUs and protected memory spaces. As a first step, they renamed all of the global variables to look like routines starting with "LM". One of these is named LMSetMBarHeight();

Had the MacOS continued, presumably these would have been replaced by actual operating system routines that were thread safe and memory safe. Simply recompiling the code would switch from "defines" to OS routines without the programmer being the wiser.
 

MarcTremblay

Active member
@David Cook , I confirm that CodeWarrior likes LMSetMBarHeight(0);
However, is this still going to work under System 6.0.8 ? This is what this app is going to be running on later.

Then, any idea what those are, especially __va() ? This sounds more low level. Maybe in one of the standard THINK C libraries?
Screenshot 2025-03-07 at 7.42.56 PM.png
 
Last edited:

David Cook

Well-known member
However, is this still going to work under System 6.0.8 ?

Yes. As far as I know, Apple never actually got to the point of adding operating system calls for this. All the compilers should still be replacing the LM calls with direct access to low memory global variables.
 

joevt

Well-known member
@David Cook , I confirm that CodeWarrior likes LMSetMBarHeight(0);
However, is this still going to work under System 6.0.8 ? This is what this app is going to be running on later.

Then, any idea what those are, especially __va() ? This sounds more low level. Maybe in one of the standard THINK C libraries?
View attachment 84211
The MSL C 68K library should have it's own snprintf and vsnprintf functions defined in cstdio (#include <stdio.h>) so you can probably surround these by #if !defined(__MWERKS__) to remove these. Do the same in the util.h file.
 

Snial

Well-known member
@David Cook , I confirm that CodeWarrior likes LMSetMBarHeight(0);
However, is this still going to work under System 6.0.8 ? This is what this app is going to be running on later.

Then, any idea what those are, especially __va() ? This sounds more low level. Maybe in one of the standard THINK C libraries?
__va() stands for Variable Arguments. If this is from the THINK C code, then it's their pre-VARARGS mechanism for doing it.
 

MarcTremblay

Active member
Yes, it did it the trick while maintaining compatibility with THINK C (which feels redundant, since the original source code is for THINK C 5.0, but oh well) ... Even though the compiler initially was happy and that I have #include <stdio.h> at the top of my main.c file, after fixing other errors, it's complaining that snprintf is an undefined identifier. I'll have to keep it defined in the .c file somehow.

Speaking of which, after a minute scratching my head, I realized that THINK C 5.0 recognizes "OK" as a hit in a Mac dialog window, but CodeWarrior expects "ok" in lowercase. Is there a way to adapt the code so that no matter if the compiler expects "OK" or "ok", both are accepted?
Screenshot 2025-03-08 at 8.08.54 AM.png

I did it like this and wonder what it's worth to you guys?
Screenshot 2025-03-08 at 8.12.10 AM.png
 
Last edited:

Snial

Well-known member
Yes, it did it the trick while maintaining compatibility with THINK C (which feels redundant, since the original source code is for THINK C 5.0, but oh well) ... Even though the compiler initially was happy and that I have #include <stdio.h> at the top of my main.c file, after fixing other errors, it's complaining that snprintf is an undefined identifier. I'll have to keep it defined in the .c file somehow.

Speaking of which, after a minute scratching my head, I realized that THINK C 5.0 recognizes "OK" as a hit in a Mac dialog window, but CodeWarrior expects "ok" in lowercase. Is there a way to adapt the code so that no matter if the compiler expects "OK" or "ok", both are accepted?
View attachment 84226

I did it like this and wonder what it's worth to you guys?
View attachment 84227
It works, but you'd have to replicate it every time you had a dialog that returned OK or ok. One solution, if you're going from THINK C to Metrowerks would be to have

#if defined(__MWERKS__)
#define ok OK
#endif

Defined in a project .h your app always uses. Then you can stick to the MW version.
 

MarcTremblay

Active member
I modified 2 places in the whole project, but it's true that a define would maybe be a better approach, although, for some reason, I also came across 1 "ok" which is very strange because then, it means that THINK C 5.0 recognizes both. Either way, it's solved.

I've been trying to fix the variable argument function that CodeWarrior did not like from THINK C 5.0 and I think I got it not too bad. CodeWarrior seems to like that, what do you think? So instead of __va(fmt) I make a new variable (p) and assign it the DATA that is after fmt and that's what I send to vsnprintf() instead of __va() which is undefined in CodeWarrior.
Screenshot 2025-03-08 at 9.22.13 AM.png

In another .c file I also see this, which seems like yet another way of dealing with variable arguments. CodeWarrior does not seem to complain about that way of doing it, so it might be more standard to do it like this with va_start() and va_end() ?
Screenshot 2025-03-08 at 9.47.30 AM.png

Anyway, so all that's left to fix is the vsnprintf() function which seemingly wants nothing to do with this FILE typed variable. Every single f.something is undefined. I tried to make a new FILE and it's the same. Any idea? That must be from a THINK C 5.0 library that is not standard or that does not exist in CodeWarrior?
Screenshot 2025-03-08 at 9.43.12 AM.png
 
Last edited:

Snial

Well-known member
I modified 2 places in the whole project, but it's true that a define would maybe be a better approach, although, for some reason, I also came across 1 "ok" which is very strange because then, it means that THINK C 5.0 recognizes both. Either way, it's solved.

I've been trying to fix the variable argument function that CodeWarrior did not like from THINK C 5.0 and I think I got it not too bad. CodeWarrior seems to like that, what do you think? So instead of __va(fmt) I make a new variable (p) and assign it the DATA that is after fmt and that's what I send to vsnprintf() instead of __va() which is undefined in CodeWarrior.
View attachment 84235
I think that would probably work, but it's non-portable. It would be better to use the same method as below. Also, I wouldn't put the return type on a line before the name of a function definition even though that's common practice. The reason is that if you're looking for a function (e.g. using grep) based on its prototype, then conceptually you'd think of all 3 components together: the return type + functionname '(' parameters ')'.

But if people stick the return type on a previous line, grep won't find it as easily: it can find lots of places where there's an 'int' on a line by itself; then lots of function definitions where it doesn't look like it has a return type until you look at the previous line. So, I don't think that's great practice. The correction then amounts to:

C:
int snprintf(char *s, size_t size, const char *fmt, ...)
{
    va_list argptr;
    int retVal;
    va_start(argptr, format);
    retVal=vsnprintf(s, size, fmt, argptr);
    va_end(argptr);
    return retVal;
}

In another .c file I also see this, which seems like yet another way of dealing with variable arguments. CodeWarrior does not seem to complain about that way of doing it, so it might be more standard to do it like this with va_start() and va_end() ?
View attachment 84236
Yes, this is better!
Anyway, so all that's left to fix is the vsnprintf() function which seemingly wants nothing to do with this FILE typed variable. Every single f.something is undefined. I tried to make a new FILE and it's the same. Any idea? That must be from a THINK C 5.0 library that is not standard or that does not exist in CodeWarrior?
View attachment 84237
It will be, because FILE is a standard 'C' file type, but the code is trying to use the hidden parameters present in THINK C's FILE type. And also I think it means that f.refnum=-1; means a predefined stream, e.g. error or what THINK C uses for stdout.
 

MarcTremblay

Active member
Also, I wouldn't put the return type on a line before the name of a function definition even though that's common practice. The reason is that if you're looking for a function (e.g. using grep) based on its prototype, then conceptually you'd think of all 3 components together: the return type + functionname '(' parameters ')'.
Yes, I have no idea why some programmers do that. Personally, I hate it and I find the code less readable and it uses more lines for no reason which is a pain to scroll through on older Macs. The whole app was programmed like this in 2022 (not by me!).

It will be, because FILE is a standard 'C' file type, but the code is trying to use the hidden parameters present in THINK C's FILE type.
Right, so now I have to find that .c file and try to import it into CodeWarrior. I hope it's not in some proprietary, compressed lib file or I'm screwed.

I found this "file.c" source file in the THINK C 5.0 folder, but I'm not sure yet if it's related or not:
Screenshot 2025-03-08 at 11.28.37 AM.png

Wait, this looks more promising. I see all the class members that are referenced in the Wiki Reader app in there. That looks like Symantec's own stdio implementation or something? This was in the THINK C 5.0 folder under "C Libraries":
Screenshot 2025-03-08 at 11.46.04 AM.png

This is interesting because CodeWarrior complains that the FILE struct that it's got is a "_Filet" and not a "__FILE" so clearly, CodeWarrior is using a different stdio.h
Screenshot 2025-03-08 at 11.51.16 AM.png
 
Last edited:

Snial

Well-known member
Yes, I have no idea why some programmers do that. Personally, I hate it and I find the code less readable and it uses more lines for no reason which is a pain to scroll through on older Macs. The whole app was programmed like this in 2022 (not by me!).


Right, so now I have to find that .c file and try to import it into CodeWarrior. I hope it's not in some proprietary, compressed lib file or I'm screwed.

I found this "file.c" source file in the THINK C 5.0 folder, but I'm not sure yet if it's related or not:
View attachment 84240

Wait, this looks more promising. I see all the class members that are referenced in the Wiki Reader app in there. That looks like Symantec's own stdio implementation or something? This was in the THINK C 5.0 folder under "C Libraries":
View attachment 84241

This is interesting because CodeWarrior complains that the FILE struct that it's got is a "_Filet" and not a "__FILE" so clearly, CodeWarrior is using a different stdio.h
View attachment 84242
I think what you need to do rather is just find out where vsnprintf is normally in MetroWerks. It looks like a standard library routine to me. It's part of <stdio.h>


So, you should just be able to use it without worrying about an underlying implementation. Maybe it's a source code file you simply don't need in your MW project?
 

MarcTremblay

Active member
I cheated a little bit and copy/pasted the struct from the THINK C stdio.h and forced the variable to be cast to a "_filet" type and CodeWarrior is happy. I'm not sure the app will run, but at least this will probably compile.

The only thing left is the following... In the .h we have this declared function:

OSErr DNSResolveName(char **name, unsigned long *ipAddress, void (*yielder)(void));

I just realized that although it's declared in the .h file, that function is not coded anywhere. I used grep to find it in the THINK C 5.0 libs and sources but it's nowhere to be seen. That must be some kind of Symantec magic I guess? I'll have to circumvent this issue by using something else in the standard MacTCP.c that I have here in CodeWarrior to resolve the domain name I guess.
 
Last edited:

MarcTremblay

Active member
Never mind! I found it in a file that I had seemingly forgot to drag into the CodeWarrior project! Kind of a fail moment right here haha!

So good news is that the app compiles and runs. Bad news is that some things are not working. For example, some of the functions never get called. I will take a look tomorrow, but at least the app runs, a window is created with controls, menu bar works, but yeah, some things are not quite right and just silently failing or not doing anything.
 
Top