Convert THINK C 5.0 into Apple C for CodeWarrior?

MarcTremblay

Active member
AH, now that worked! I guess you have to explicitly write (struct browser*) because if you don't, then it's going to cast to a pointer instead of a struct.

OK, next are a bunch of undefined identifier screenBits. SHHH! Don't tell me this one, because I know already. You told me before...

Screenshot 2025-03-06 at 12.27.44 PM.png

That's right. I learn fast ;-) qd.screenBits !

Screenshot 2025-03-06 at 1.16.20 PM.png

OK, for that one, I'm not sure what it wants. It's defined like this: char title[256];
I guess I could just do this?
browser->win = NewWindow(0L, &bounds, (unsigned char*) title, false, noGrowDocProc, (WindowPtr)-1L, true, 0);
...yep, it seems to work.

Then, there's this, but don't tell me! I just did this one 10 minutes ago so I know what it is :)

Screenshot 2025-03-06 at 1.24.52 PM.png

I'm going to do: focusable = (struct focusable*) xmalloczero(sizeof(struct focusable));
...yep, it worked.

So after those 10 errors fixed, we're down from 127... to 127 lol... I think 127 is the max amount of errors that can be stacked in CW9. Maybe I'm at like 573 errors right now and I don't know yet XD
 
Last edited:

Snial

Well-known member
AH, now that worked! I guess you have to explicitly write (struct browser*) because if you don't, then it's going to cast to a pointer instead of a struct.
Close, it's because browser by itself isn't a thing and 'C's silly syntax rule here requires the struct.
OK, next are a bunch of undefined identifier screenBits. SHHH! Don't tell me this one, because I know already. You told me before... I learn fast ;-) qd.screenBits !
Yep :) !
OK, for that one, I'm not sure what it wants. It's defined like this: char title[256];
I guess I could just do this?
browser->win = NewWindow(0L, &bounds, (unsigned char*) title, false, noGrowDocProc, (WindowPtr)-1L, true, 0);
...yep, it seems to work.
Correct. Unsigned chars (range 0..255) don't have the same properties as signed chars (range -128 to 127). e.g:

C:
char ch=-128;
unsigned uch=128; // same internal representation, 1 byte containing 0x80.
int x=100+ch, y=100+uch; // x=-28, y=228.


I'm going to do: focusable = (struct focusable*) xmalloczero(sizeof(struct focusable));
...yep, it worked.
Yay!
So after those 10 errors fixed, we're down from 127... to 127 lol... I think 127 is the max amount of errors that can be stacked in CW9.
Good point!
Maybe I'm at like 573 errors right now and I don't know yet XD
But you still might find you fix something and it suddenly drops to way under 127 errors.
 

MarcTremblay

Active member
But you still might find you fix something and it suddenly drops to way under 127 errors.
This is exactly what just happened. I replaced a ton of white patterns from "white" to "&qd.white" and I'm now down to only 100 errors to fix! (but let's not party just yet, even when I reach 0 error later today, the app might compile and then crash... I'm not out of the woods just yet)

OK now I've got what the compiler says is a "ListRec" object, it's instantiated like this:
Screenshot 2025-03-06 at 1.53.06 PM.png

But then a little bit down the code, CodeWarrior is complaining that the ListRec cannot be HLock() or HUnlock() because it can't convert it from ListRec** to Char**. I know that earlier today, you educated me to look in the Inside Macintosh PDF book to find the structure of TERec (Text Edit Record) so now I'm looking at https://vintageapple.org/inside_o/pdf/Inside_Macintosh_Volume_IV_1986.pdf to inspect ListRec and find a handle, but I'm not 100% sure. What do you think?

Screenshot 2025-03-06 at 2.00.59 PM.png
 

joevt

Well-known member
I took a break and came back at it. It went well today! Now only 63 errors left to fix. This one is giving me a hard time though.
aNotifyProc appears to be defined as a C function but callbacks in Mac OS 68K usually need to be pascal functions (different calling conventions or ABI).

Where is TCPNotifyProc defined? Shouldn't it already be defined as pascal if it's in the include files used by CodeWarrior? You're not using Think C include files, right? What version of CodeWarrior are you using?
 

Snial

Well-known member
I took a break and came back at it. It went well today! Now only 63 errors left to fix. This one is giving me a hard time though. Any idea @Snial ?

View attachment 84174
Well, it looks more complex than previous casting issues, but it's probably very similar. At the beginning of the function, _TCPCreate has a TCPNotifyProc aNotifyProc parameter. And it'll be some kind of function pointer (i.e. whose value is the address of a function). For example, you may find that TCPNotifyProc is defined in a header as something like:

typedef long (*TCPNotifyProc)();

And maybe it's done that way, because it could take different kinds of actual parameters in a real situation, so the typedef definition is just as general as possible.

However, later you're trying to assign it to pb->csParse.create.notifyProc . So, that's somewhere in the definition of pb which is a TCPiopb (this time, the original author used a typedef, hurrah!). If you look up the TCPiopb struct, you'll see it has a csParse member, which is whatever type it is; that has a create member of another type; which in turn has a notifyProc member. Great, so you need to find the type of the notifyProc member within the create structure that's part of the csParse's struct type which is part of TCPiopb. Once you've found notifyProc's type, you'll need to change the line to:

pb->csParse.create.notifyProc = ([I]whateverNotifyProcsTypeIs[/I])aNotifyProc;

That's the right way of doing it - you could of course reproduce a cast to whatever the type appears to be in the error, and the error would go away, but if someone changed whateverNotifyProcsTypeIs , then it'd fail again.

And it looks like you've either solved it in the meantime or someone else has given a hint.

-cheers from Julz
 

joevt

Well-known member
OK now I've got what the compiler says is a "ListRec" object, it's instantiated like this:
View attachment 84172

But then a little bit down the code, CodeWarrior is complaining that the ListRec cannot be HLock() or HUnlock() because it can't convert it from ListRec** to Char**. I know that earlier today, you educated me to look in the Inside Macintosh PDF book to find the structure of TERec (Text Edit Record) so now I'm looking at https://vintageapple.org/inside_o/pdf/Inside_Macintosh_Volume_IV_1986.pdf to inspect ListRec and find a handle, but I'm not 100% sure. What do you think?
If search_results is a ListHandle (or ListRec**) then to lock it or unlock it, you need to typecast to a Handle.
 
Last edited:

joevt

Well-known member
OK, for that one, I'm not sure what it wants. It's defined like this: char title[256];
I guess I could just do this?
browser->win = NewWindow(0L, &bounds, (unsigned char*) title, false, noGrowDocProc, (WindowPtr)-1L, true, 0);
...yep, it seems to work.
A window title is a pascal string. It uses unsigned char because the first byte is the length (0-255).

I'm going to do: focusable = (struct focusable*) xmalloczero(sizeof(struct focusable));
...yep, it worked.

browser is a variable of type struct browser. It's kind of horrible to have a variable and struct with the same name.
Same for focusable and struct focusable.

I guess they're not the same name since the type is struct browser and the variable is just browser, but it means you can't do
typedef struct browser browser.
unless you rename the variable.
 

MarcTremblay

Active member
Ah, I was eating dinner and forgot to post, but I fixed both the UDP and the TCP notifications by casting the variables with an appropriate pointer type.

Where is TCPNotifyProc defined?

It's like a collection of objects that was defined in MacTCP.h which is part of the standard MPW interfaces/libraries:

Screenshot 2025-03-06 at 7.21.57 PM.png

Here's how I fixed the notification for CodeWarrior. This is the UDP one but the TCP one is the same except TCP instead of UDP in the cast pointer name:
Screenshot 2025-03-06 at 7.17.07 PM.png

I must say, it's going very well. I think tomorrow I will have it fixed enough to try and compile it. Not sure that it will run, but it might compile at least, we'll see. I'm glad you guys are trying to help me and educate me on this retro Mac archeology journey. It seems like a nice community here. Anyway, here's where I stop for tonight:

Screenshot 2025-03-06 at 7.25.15 PM.png

Good night all.
 
Last edited:

joevt

Well-known member
Ah, I was eating dinner and forgot to post, but I fixed both the UDP and the TCP notifications by casting the variables with an appropriate pointer type.



It's like a collection of objects that was defined in MacTCP.h which is part of the standard MPW interfaces/libraries:

View attachment 84181

Here's how I fixed the notification for CodeWarrior. This is the UDP one but the TCP one is the same except TCP instead of UDP in the cast pointer name:
View attachment 84180

I must say, it's going very well. I think tomorrow I will have it fixed enough to try and compile it. Not sure that it will run, but it might compile at least, we'll see. I'm glad you guys are trying to help me and educate me on this retro Mac archeology journey. It seems like a nice community here. Anyway, here's where I stop for tonight:

View attachment 84182

Good night all.
I'm not sure type casting aNotifyProc is the correct thing to do. I would change the type of aNotifyProc instead.
Is the function pointer that is passed as aNotifyProc for a function declared with pascal?

For PBOpen, maybe declare pb as a ParamBlockRec instead of a IOParam. Then access the IOParam members like this: pb.ioparam.ioNamePtr
 

MarcTremblay

Active member
I understand, but I was not planning on rewriting the Wikipedia Reader app's source code that I got on GitHub the other day, since it works perfectly fine when compiled with THINK C 5.0 so I'm sure it's just because CodeWarrior is more strict about variable typing and that it will compile at the end of the day when all variables are explicitely typed. Not only would it be a lot of work to rewrite the Wikipedia Reader app, but I'm certainly not qualified to write better C code than Joshua Stein.

That being said, if you feel qualified to rewrite it for CodeWarrior 9 Gold and would like to share your work, then I'd be the first one to jump on it!
 

MarcTremblay

Active member
Not 'inline' per se, but yes, it can include assembly subroutines.
It worked, thanks!

MBarHeight = 0;
It's complaining about MBarHeight being unidentified. I think the code is trying to hide the menu bar or something like that. Is MBarHeight some kind of global variable? If so, how would I reference it? I'm trying to find something about this in Inside Macintosh, but all I've got so far is this: https://developer.apple.com/library/archive/documentation/mac/pdf/MacintoshToolboxEssentials.pdf

Screenshot 2025-03-07 at 11.19.24 AM.png
 

Snial

Well-known member
It worked, thanks!

MBarHeight = 0;
It's complaining about MBarHeight being unidentified. I think the code is trying to hide the menu bar or something like that. Is MBarHeight some kind of global variable? If so, how would I reference it? I'm trying to find something about this in Inside Macintosh, but all I've got so far is this: https://developer.apple.com/library/archive/documentation/mac/pdf/MacintoshToolboxEssentials.pdf

View attachment 84201
The global variable MBarHeight you found is only for pure assembler code, it's not defined as such for 'C'. Instead, a few pages back from where you saw the Assembler info above, page 3-164, there's the 'C' version, which is:

GetMBarHeight()

In fact, it defines it, so you can see where it really comes from:

#define GetMBarHeight() (*(short*)0x0BAA)

It's not a proper function as such, but a #define. The 16-bit word at RAM location 0x0BAA (2986 in decimal) contains the menu bar height, so if you cast the location to a (short *) and take the contents of it (*(short*)location), it reads the 16-bit word at that location.

All you need to do is use the function: GetMBarHeight(), because for all I know, it was abstracted into a proper function at some point during the PowerPC era.

-cheers from Julz
 

Snial

Well-known member
Not 'inline' per se, but yes, it can include assembly subroutines.

asm pascal void NullCaretHook(void)
{
move.l (a7)+, d0
preturn
}
Aaah, I didn't know that. For the PPC compiler can you write PowerPC assembly subroutines?
 

MarcTremblay

Active member
It's not a proper function as such, but a #define. The 16-bit word at RAM location 0x0BAA (2986 in decimal) contains the menu bar height, so if you cast the location to a (short *) and take the contents of it (*(short*)location), it reads the 16-bit word at that location.

But Julz! The issue is that they're trying to assign 0 to it, not to read from it. See this paragraph of code:

Screenshot 2025-03-07 at 5.16.23 PM.png
 

Snial

Well-known member
But Julz! The issue is that they're trying to assign 0 to it, not to read from it.
Aaaah, I didn't notice that, D'oh!
See this paragraph of code:

View attachment 84208
Ironically, the way it's defined in the new Inside Macintosh means you can do GetMBarHeight()=0; .

But in case that doesn't work, is there a SetMBarHeight(0); ?

And if that doesn't work, double-click on GetMenuBarHeight then can you use the menu operation in CW, to find the definition and reference?

Oops I misspelled GetMBarHeight. It turns out you can do GetMBarHeight()=0; in CW. I did a search, it's defined in Menus.h, as #define GetMBarHeight() (*(short*)0x0BAA) as described earlier. So, you can assign it; though I don't know why the code wants to do that.
 
Last edited:
Top