[net.micro.mac] Using the Macintosh Toolbox with C

chuq@sun.uucp (Chuq Von Rospach) (11/22/85)

Are you programming the Macintosh with C? Are you tired of readings books and
trying to translate contructs like "foo^^baz.bar[buf]" into useful terms in
your head? Are you tired of having a stack of reference books on your desk
larger than the computer you're referencing?

Well, have I got a deal for you. It's called "Using the Macintosh Toolbox with
C", published by Sybex books ($22.95), 559 pages with 8 appendices and 13
chapters. 

This book tries to do a lot of things. It tries to act as a standalone
programming reference to the Mac. It tries to show you how to program the Mac.
It delves into a number of areas (such as scroll bars and glue routines) that
are very difficult to translate out of a Pascal reference (or are ignored
completely).

The authors (who are out there on the net somewhere) have put a lot of work
into translating the constructs and concepts of Inside Mac into C. The book is
written around Mac C by Consulair, but they've tried to avoid as much compiler
dependent material as possible, or to point at ways around it. For a book like
this, Mac C is probably the best compiler because it doesn't hide parts of the
system (as Megamax does with the pascal function type, for example). It is a
lot easier for a Megamax programmer to convert a glue routine to a pascal
procedure than the other way around.

The authors build their way, chapter by chapter, to a complete basic
application that includes DA's, text windows with full scrollbar capability,
filesystem hooks for reading and writing files, and multiple windows. In
comparing what they did with Chernicoff's book, they seem to have the same
information, a more complete application, and it doesn't have to be translated
out of Lisa Pascal. They also got it into one volume.

Source code is available on disk from the authors (three guys with computers
in Berkeley), or you can (of course) type it in from the book. They don't
have a single place where the entire application is listed, but it is built
piece by piece as you work through the chapters.

There are some things that are not covered in the book. Sound generation,
working with the printer, and writing desk accessories come immediately to
mind. I would have liked to see some reasonable code having to do with working
with the printer, but the others aren't really needed to deal with 'everyday'
applications. Beyond the lack of printer drivers, I really don't have any
gripes with the book. I definitely recommend it over any other book I've seen
on the market, including the Chernicoff pair and inside mac. If you program in
C, this is a must.
-- 
:From catacombs of Castle Tarot:        Chuq Von Rospach 
sun!chuq@decwrl.DEC.COM                 {hplabs,ihnp4,nsc,pyramid}!sun!chuq

Let us now take the sacred oath. As of now, he is no longer an elephant!

shebanow@ernie.BERKELEY.EDU (Mike Shebanow) (11/25/85)

(Beware the line eater)

For all of you who want an example of printing from C, I have
posted a substantial application to net.sources.mac. It does
just about everything except printing from the Finder.

The example was used for a talk on the subject of Mac printing
given to the BMUG Developers Group by myself a few weeks ago.

I agree with your assessment of "Using the Mac Toolbox with C". Its
a real nice book. Of course, I know the authors, so I am not the most
unbiased source in the world.

Have fun...

Andrew Shebanow
shebanow@ucbernie

tim@ISM780B.UUCP (11/25/85)

> this, Mac C is probably the best compiler because it doesn't hide
> parts of the system (as Megamax does with the pascal function
> type, for example).  It is a lot easier for a Megamax programmer

Huh?  What are you talking about?

burnard@lll-crg.ARpA (David Burnard) (11/27/85)

(-----Who's afraid of the big bad line-eater?-----)

   Thanks to Chuq for his initial review of our book, "Using the
Macintosh Toolbox with C". I think he does a reasonable job of
pointing out some of the strong (and weak) points of our book.
We really would have liked to include the topics he mentions (Sound,
DA's, printing, ..., devices, drivers, serial I/O) but the pressures
of getting back to school/work kept us from including these topics.
Still, we are considering another book covering these subjects, if
people are interested, let us know...

   In response to Chuq's review, was a question about what he meant by
the phrase "hiding parts of the system with the pascal function or
subroutine declaration" (or words to this effect). For those of you
who haven't compared the grundge-level features of the available C
compilers, let me summarize the situation...

   Lets begin with how the various systems generate "normal" Toolbox
calls. Two different approaches have emerged to the simple problem of
dealing with the Toolbox. The problem results from the fact that the
routines of the Toolbox have different calling conventions. Roughly
half of the routines expect their parameters to be passed on the stack
(most of the high level managers) while the other half expect their
parameters in registers (low-level managers like File and Memory). How
can the compiler deal with this?

   Approach 1: Smart Compiler - Consulair (and Aztec) have built the
   necessary smarts into their compilers to generate the correct
   linkage to each of the 400 or so traps. This of course leads to a
   larger somewhat slower compiler than the following...

   Approach 2: Glue - MegaMax and the SUmacc systems take the opposite
   approach of hiding all of the linkage routines in object libraries.
   So instead of calling the trap directly, the call is routed through
   a tiny routine which sets up the stack/registers appropriately for
   the Toolbox call. This makes for an ultrafast compiler but leads to
   long link times since the Glue must be attached by the Linker. (Now
   you know why MegaMax had a linker that removed unused subroutines long
   before Consulair did...)

   Either of these methods is OK by me. I'm not trying to compare
which is better or worse, just let people know whats going on. (I was a
little surprised when I fired up TMON the other day to look at some of
the code in MacKermit, and couldnt find any Traps anywhere...except
all smashed together at the end. Much less understandable when you're
debugging - no wonder people are screaming for symbolic debugging).


   Now lets look at the other situation, when one of the routines in
the Toolbox calls a routine supplied by the programmer. Some familiar
examples are TextEdit's TEClick (ClikLoop and WordBreak routines), the
action procs for TrackControl and the filter procs for the Standard
File Package. Again there are two different situations that arise: the
parameters can either be passed in registers or on the stack. 

   If the parameters are passed on the stack, then some compilers
   (soon, even Consulair) allow you to declare your action proc, or
   whatever, to have a pascal linkage:

        pascal MyActionProc(arg1, arg2,...,argn)
 
   this insures that the arguments are passed correctly to your
   procedure. In fact some compilers declare the Toolbox routines to
   be of type pascal.

   The nasty case, which prompted Chuq's original comment, occurs when
   the Toolbox routine passes the parameters to your routine in
   registers. Here, everyone is equal...you have no choice but to get out your
   Motorola assembly manuals and write the dreaded "Glue Routine" to
   take the parameters out of the registers and stuff them where your
   compiler wants to find them. (which again can be either on the
   stack, or in some other registers).

   So lets suppose that I write a book about using the Toolbox with C
(you'd have to be crazy!), how should I present these special cases?
Unfortunately there will be absolutely no chance of portability here.
Worse, if I use the pascal directive, readers using systems with no
pascal directive will be left in the dark. So we tried to explain a
little about what was going on, and included the glue routines needed
for Consulair. Then, at least we have shown the worst case, if you can
use the pascal directive then so much the better.

   Remember to take pity on Consulair users, until Andy Shebanow's
   IMLib came along we had to write glue just to use any of the
   packages!!! That reminds me, I should post a note about MDSMake...


   Does this answer anyone's questions? Or has everyone hit the 'n'
key to move on to the flammable "discussion" regarding how to make Mac
programs portable (about the most ridiculous thing I have ever heard).

                                               Until next time,

                                               Dave Burnard

                                     (also speaking on behalf of 
                                      Fred Huxham and Jim Takatsuka)

                                               burnard@lll-crg.ARPA


   The standard disclaimers...Hey wait a minute that's our book!

bhyde@inmet.UUCP (11/30/85)

It is nice to have some technical discussion in this silly news group.

Another case that gives the shakes to C compilers is when you have 
snarfed a pointer to a pascal subprogram out of some data structure.
The cases I'm familar with, having written glue to handle them,
are filtering calls to the bottle neck procedures or to control
def procs.  Such a filter wants to spend a few moments considering
the call and then just let the real procedure handle the normal
case.

One plausable solution in the Megamax tradition would be to allow
the "pascal" modifier to be placed on procedure variable declarations.

In some cases you can avoid assembler language in such cases by using
your C compiler's willingness to pass structure values.  This is done
by writing a structure that mimics the Pascal call site.

ben hyde, cambridge.

tim@k.cs.cmu.edu (Tim Maroney) (12/01/85)

Two approaches to Macintosh toolbox interfaces for C compilers were
mentioned.  The summary was fairly good, so I'll just reprint it:

>   Approach 1: Smart Compiler - Consulair (and Aztec) have built the
>   necessary smarts into their compilers to generate the correct
>   linkage to each of the 400 or so traps. This of course leads to a
>   larger somewhat slower compiler than the following...
> 
>   Approach 2: Glue - MegaMax and the SUmacc systems take the opposite
>   approach of hiding all of the linkage routines in object libraries.
>   So instead of calling the trap directly, the call is routed through
>   a tiny routine which sets up the stack/registers appropriately for
>   the Toolbox call. This makes for an ultrafast compiler but leads to
>   long link times since the Glue must be attached by the Linker.

For some reason, Dave avoided getting into comparisons of these approaches,
and in fact seemed to imply they were equally good.  To me, the issue seems
very clear cut: the smart compiler approach is far better.  You have to
consider the different effective costs of compile-time memory and speed, and
run-time memory and speed.  It is better to have 10K of additional space in
a compiler (to generate smart toolbox interfaces) than 2K of additional
space in hundreds of programs generated by that compiler (for machine code
of glue routines).  It is better to use an extra few minutes in a compiler
(for generation of smart interfaces) than a few extra seconds in hundreds of
thousands of executions of programs generated by the compiler (for executing
the glue routines).  Space and memory are far cheaper at compile time than
at run time, because code will be compiled far less frequently than it is
run.  Using intelligently-generated interfaces is a major win.
-=-
Tim Maroney, Electronic Village Idiot, CMU Center for Art and Technology
tim@k.cs.cmu.edu       | uucp: {seismo,decwrl,ucbvax,etc.}!k.cs.cmu.edu!tim
CompuServe: 74176,1360 | CMU. Tomorrow's networking nightmares -- today!

tim@ISM780B.UUCP (12/02/85)

[ talking about when your routines are called by the toolbox, such as
  filter proc for getfile, etc ]


>   The nasty case, which prompted Chuq's original comment, occurs
>   when the Toolbox routine passes the parameters to your routine
>   in registers.  Here, everyone is equal...you have no choice
>   but to get out your Motorola assembly manuals and write the
>   dreaded "Glue Routine" to take the parameters out of the
>   registers and stuff them where your compiler wants to find
>   them.  (which again can be either on the stack, or in some
>   other registers).

Which Toolbox routines do this?

joel@gould9.UUCP (Joel West) (12/05/85)

In article <687@k.cs.cmu.edu>, tim@k.cs.cmu.edu (Tim Maroney) writes:
> Two approaches to Macintosh toolbox interfaces...
> >   Approach 1: Smart Compiler - Consulair (and Aztec) 
> >   Approach 2: Glue - MegaMax and the SUmacc 
> 
> For some reason, Dave avoided getting into comparisons of these approaches,
> and in fact seemed to imply they were equally good.  To me, the issue seems
> very clear cut: the smart compiler approach is far better.  
(Maroney goes on to justify his case)

While I understand this point of view, there are many who claim 
that "Optimum Run-time Speed and Size" are the only valid measure
of a compiler's performance.  This is a very simplistic view
of things.

The overall life-cycle cost issues are more complex.  For example, it
may be that a system with "glue" routines will support a new feature
(e.g. Appletalk) 6 months before one where the compiler has to be
modified.  It may also mean that the interfaces are less buggy because
they're easier to implement.  (I'm not saying this is necessarily true...)

I would also note that the Megamax has been near the top or at the
top on every speed benchmark I've seen.  And they were the first
with the smart linker, so their programs were faster.

I'm not saying speed and size aren't important.  But flexibility
and reliability have to be factored into the equation, as well
as the list of features (post-K&R, in-line assembler, development
tools, etc. etc.).  For my part, I'll take the extra compile time
and use it to hand-code 5 key routines in assembler.
-- 
	Joel West	 	(619) 457-9681
	CACI, Inc. Federal, 3344 N. Torrey Pines Ct., La Jolla, CA  92037
	{cbosgd,ihnp4,pyramid,sdcsvax,ucla-cs}!gould9!joel
	gould9!joel@nosc.ARPA

mike@smu (12/10/85)

Re: Interfacing to Toolbox with C (Mechanisms)

I not so sure about the claim that in-line traps are neccessarily better.
Remember that C-style strings must be converted to Pascal strings, and
vice-versa.  When toolbox routines are called through glue routines, 
the conversion code is isolated.  With inline traps, the calls to the
conversion routines are scattered throughout the program.

On the other hand, if the programmer is able to preserve Pascal style
strings in order to save conversion time, that might be an advantage 
to the in-line trap system.  Conversion time doesn't seem to be much
of a problem, however.  A profile report of a Megamax program shows
that the string conversion is usually less than a tenth of a percent 
of the total time.  The bulk of the time is spent in the ROM.

Oh well, I really don't have too much conviction either way on this
issue.


Mike McNally            SMU     -----------------------------------------
mike@smu                        "Is there Christmas in the hippie world?"
...{convex|texsun}!smu!mike     -----------------------------------------

tim@k.cs.cmu.edu (Tim Maroney) (12/11/85)

Thanks to Joel West for his reasoned response.  However, I think that there
were some flaws in his analysis of the issue of "smart" (compiler-generated)
toolbox interfaces versus "glue" (linker-generated) toolbox interfaces.

> it
> may be that a system with "glue" routines will support a new feature
> (e.g. Appletalk) 6 months before one where the compiler has to be
> modified.  It may also mean that the interfaces are less buggy because
> they're easier to implement.  (I'm not saying this is necessarily true...)

But even in a "smart" compiler, glue routines can still be used, so the
first point doesn't apply.  Glue routines can be created as a temporary fix
in this case, pending later compiler modification.

Also, this makes an assumption which is understandable and probably is the
case for all existing compilers; but it is not necessary that a smart
compiler store object code with which it generates toolbox interfaces.  It
would be easy enough to keep specifications of the interfaces in an external
file, editable using an ASCII text editor.  The language of the file would
be quite small, and could be parsed and stored in the compiler symbol table
at compiler startup.  It would take a few seconds, but parsing small
languages like this is pretty fast; the file could even be kept in a binary
format, with an associated editor program, so not even parsing would be
needed, only file I/O.  Any compiler implementor worth his pay should be
able to put something like this together in less than a week.  This would
mean that no compiler modifications would be needed, ever.  It would also
mean that bug fixes could be easily done, and that the interfaces would be
MORE reliable, not less, being specified non-procedurally (that is, you
don't write code to put out the interface, but just specify the interface's
format).

By the way, Appletalk was a bad example.  The low-level interface is through
device driver control calls, requiring no new interfaces.  The high-level
interface is not in ROM and so is always a "glue routine", though it does a
lot more than just providing a nice calling sequence.

> I would also note that the Megamax has been near the top or at the
> top on every speed benchmark I've seen.  And they were the first
> with the smart linker, so their programs were faster.

Right, but this is not important.  Toolbox interface speed is not the only
factor in run-time speed and size.  Megamax C seems to produce fairly good
code for control constructs (loops, conditionals, etc.) and to do a small
amount of optimization; it produces good object code.  Its speed is DESPITE,
not BECAUSE, of its glue routines.  There is no way that glue routines which
reconstrct stack frames and increase the number of instructions executed
with each toolbox call can be faster than smart interfaces generated in
line.  (Unless, that is, they read the trap addresses at program startup and
use those rather than trapping -- this would require modifying
SetTrapAddress to also update the glue routine, but it could be done....)  I
was only discussing the effects of one compiler design decision, not making
a general judgment on which compilers are better overall.  Sorry if this was
unclear (which, judging from my mail, it was.)
-=-
Tim Maroney, Electronic Village Idiot, CMU Center for Art and Technology
tim@k.cs.cmu.edu       | uucp: {seismo,decwrl,ucbvax,etc.}!k.cs.cmu.edu!tim
CompuServe: 74176,1360 | Offense is an inevitable consequence of honesty.