[comp.sys.mac.programmer] Standard File and Desk Accessories

thitt@yacht.cis.ohio-state.edu (Todd A Hitt) (06/05/89)

Has anybody used a non-standard dialog box with SFPPutFile?  I would like
to add a check box to the bottom of my PutFile dialog box.  In my dlgHook
procedure I can toggle this item, but...how does one get the status of
whether the check box was checked after SFPPutFile returns?

I can't use a global variable in a Desk Accessory.  I've tried using the
dialog's refCon - which causes Standard File to crash.

Any ideas?

Thanks.

Todd Hitt
(614)424-3297
thitt@cis.ohio-state.edu
hitt%36.114@ohstpy.mps.ohio-state.edu

siegel@endor.harvard.edu (Rich Siegel) (06/05/89)

In article <50967@tut.cis.ohio-state.edu> Todd A Hitt <thitt@cis.ohio-state.edu> writes:
>
>I can't use a global variable in a Desk Accessory.  I've tried using the
>dialog's refCon - which causes Standard File to crash.

	If you're using LightspeedC 3.0 or later, or Lightspeed Pascal 2.0 or
later, then DA's can have globals. Otherwise, you can allocate storage
in the dCtlStorage handle field of the DA's DCE.

		--Rich



~~~~~~~~~~~~~~~
 Rich Siegel
 Staff Software Developer
 Symantec Corporation, Language Products Group
 Internet: siegel@endor.harvard.edu
 UUCP: ..harvard!endor!siegel

 "She told me to make myself comfortable, so I pulled down my pants
 and sat in the pudding." -Emo Phillips
~~~~~~~~~~~~~~~

tim@hoptoad.uucp (Tim Maroney) (06/06/89)

In article <50967@tut.cis.ohio-state.edu> Todd A Hitt
<thitt@cis.ohio-state.edu> writes:
>Has anybody used a non-standard dialog box with SFPPutFile?  I would like
>to add a check box to the bottom of my PutFile dialog box.  In my dlgHook
>procedure I can toggle this item, but...how does one get the status of
>whether the check box was checked after SFPPutFile returns?
>
>I can't use a global variable in a Desk Accessory.  I've tried using the
>dialog's refCon - which causes Standard File to crash.

Yes, strangely enough, Standard File sets its dialog's refCon to one
and then crashes if it's changed.  Maybe someone at Apple could
enlighten us as to the reasons.

Globals can be used in desk accessories.  It's pretty easy with
LightSpeed C, but fairly tricky with MPW C.  If you really can't do
this, then there are some other tricks.  One thing would be to save the
contents of one byte of ApplScratch or ToolScratch before going into
Standard File, then setting it from inside Standard File, then
extracting it after leaving and restoring the old value.  Another way
is to write directly into your DA's code space, using PC-relative
instructions.  This is pretty easy in assembly.

The above approaches also have a decent chance of breaking on future
systems....

Probably the best way is to use your DA's dCtlStorage field, or your DA
window's refCon.  The dCtlStorage field will be a bit tricky to get at
inside the Standard File hook, but you should be able to find your
dialog window very easily, and so find its refCon -- it's the
nextWindow field of the Standard File dialog.  (Some sophisticated
approaches to DA windows might change that, but for most DAs, you will
always be bringing up Standard File right in front of the DA window.)
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"Women's wages are 56% of men's -- but that's not necessarily evidence
 of discrimination in employment."
  -- Clayton Cramer in news.groups and soc.women

zben@umd5.umd.edu (Ben Cranston) (06/07/89)

Re: Standard File's putting a 1 in the dialog's RefCon and blowing up if it
has changed: the version I am looking at puts the local frame (A6) value of
Standard File's main routine into the RefCon; the dialog hook routine and
other callback routines then use this to access Standard File's globals.

I suggested to the original poster (offline, via mail) that one solution
would be to extend the item list handle by one word and plant a pointer
back to the DA's globals there.  Then the dialog hook routine could link
from the dialog record to the item list and pick up the pointer.

Too bad the dialoghook routine doesn't get the SFReply record as an argument.
Then one could just extend that record in a straightforward manner to
accomodate this sort of extension...
-- 
Ben Cranston <zben@umd2.UMD.EDU>    (Kingdom of Merryland UniSys 1100/92)
Copyright 1989 (you may redistribute ONLY if your recipients can).

thitt@schooner.cis.ohio-state.edu (Todd A Hitt) (06/07/89)

Thanks for all your ideas on Desk Accessories & (non)Standard-File.  For a few
of you who have asked why I can't use globals it's because I have a DA that's
mostly in MPW Pascal and somewhat in MPW C.  Neither one of these environments
provide "official" support for globals in DA's.  I'm sure someone from
Symantec can enlighten us but I think they get around this problem by using
another register (maybe A4?) to "anchor" the global variables.  I believe
that applications have their globals referenced by A5.

But enough of that.  Here's the solution or part of it, I used (and it works)
that was sent to me by Krzysztof Kozminski:

>In article <50967@tut.cis.ohio-state.edu> you write:
>>Has anybody used a non-standard dialog box with SFPPutFile?  I would like
>>to add a check box to the bottom of my PutFile dialog box.  In my dlgHook
>>procedure I can toggle this item, but...how does one get the status of
>>whether the check box was checked after SFPPutFile returns?
>>
>>I can't use a global variable in a Desk Accessory.  I've tried using the
>>dialog's refCon - which causes Standard File to crash.
>
>I am not sure how you are going to use dialog's refCon - I don't think
>you can get at your DialogPtr before or after calling CFPPutFile ...
>
>Anyway, just an idea, based on what I do:
>
>	long **h = NewHandle(4);
>	int checkBoxValue;
>
>	**h = (long) &checkBoxValue;
>	AddResource(h,'pvte',0,"\p");
>
>	/* Now you have a private resource (in whatever is the current
>	   resource file) that stores the address of your result. */
>	
>	SFPPutfFile( ..., myHook, ...);
>
>	/* my Hook calls GetResource(...'pvte',0...) to find out where to
>	   put the value of the check box control. */
>	
>	RmveResource(h);	/* Don't want it added to, e.g., System */
>
[stuff deleted]

I've modified it a little to suit me but it works like a champ.  I do feel
a little funny using the resource manager like this, but it doesn't look like
there is any particularly clean way to do this.

Thanks Krzysztof!

=	=	=	=	=	=	=	=	=	=
Todd Hitt				 thitt@cis.ohio-state.edu
Battelle Columbus/Ohio State University	 hitt%36.114@ohstpy.mps.ohio-state.edu
(614)424-3297
"You were not put on this earth to 'Get It'"
	- "Lo Pan" in Big Trouble in Little China

-=-


=	=	=	=	=	=	=	=	=	=
Todd Hitt				 thitt@cis.ohio-state.edu

siegel@endor.harvard.edu (Rich Siegel) (06/07/89)

In article <51276@tut.cis.ohio-state.edu> Todd A Hitt <thitt@cis.ohio-state.edu> writes:

	[adding a resource (!!) to a resource file to hold storage]

	Yeeeech. I would throw away any program that added resources
to a running application without my explicit command. The idea of adding
a resource in this manner has some big holes in it:

	1. The file is modified.
		1a. Doing so changes the mod date, which means that
			the next time I do an incremental backup,
			the file has to get backed up for no particularly
			good reason.

		1b. Doing so will set of virus detectors left and right.

	2. What if the AddResource fails, perhaps because the disk is
	write-protected or full? If that happens, you're hosed.

	3. As I said, modifying applications without explicit command
	is repugnant to me.

An alternate solution involves some assembly language, and works something like
this:

	Define a 4-byte spot in your code where you can store a handle.
Then, allocate the handle with NewHandle, and put it there. Whenever
you need your global storage, retrieve the handle from this location
and use the handle. The code looks something like this (I'm writing
off the top of my head, so forgive me if this doesn't assemble).

;this is where the handle goes
HStorage:
	dc.l	0

; this routine saves away the handle for you.
;
;	procedure SaveAway(h : Handle);
;
SaveAway:	
	movea.l	(a7)+, a0	; pop the return address
	movea.l	(a7)+, a1	; pop the argument
	move.l	a0, -(a7)	; push the return address back.

	; a1 now contains the handle we want to store
	
	lea	@HStorage, a0	; get the address of our storage
	move.l	a1, (a0)	; put the handle there

	; we're done, so return. A more efficient routine might have
	;left the return address in a register and done an indirect JMP,
	;but this is quickie code.
	
	rts

; this routine returns the handle that was saved away.
;	procedure GetBack(var h : Handle);
;
        movea.l (a7)+, a0       ; pop the return address
        movea.l (a7)+, a1       ; pop the argument
        move.l  a0, -(a7)       ; push the return address back.

	; a1 now contains the address of the variable to hold our
	; handle

	lea 	@HStorage, a0	; get the address of our store handle
	move.l	a0, (a1)	; store it in our variable

	; we're done, so return.

	rts

	You can assemble this into a .O file, and it should
work substantially as written. This scheme is similar to the way that
THINK C and THINK Pascal save away A4, but to do globals from A4 requires
a little assistance from the compiler and linker.

	TLSC and TLSP also have jump-table support which allows you to write
multi-segment DA's and drivers, and (in TLSP) to write DA's or drivers in
Object Pascal. (A rather unique capability, if I may say so myself. :-)

		--Rich


~~~~~~~~~~~~~~~
 Rich Siegel
 Staff Software Developer
 Symantec Corporation, Language Products Group
 Internet: siegel@endor.harvard.edu
 UUCP: ..harvard!endor!siegel

 "She told me to make myself comfortable, so I pulled down my pants
 and sat in the pudding." -Emo Phillips
~~~~~~~~~~~~~~~

zben@umd5.umd.edu (Ben Cranston) (06/08/89)

Re: using one of the development packages that implements local variables for
DAs and other data-less code resources by using A4 as an ersatz global pointer.

Standard File saves A4 on entry and uses it to point to other things!  For
much of the routine it points to the SFReply record, however several of the
subroutines save it and use it for local purposes!

Therefore it would not work to access DA globals from hook routines...


I though of these other ways to solve the original poster's problems:

1. Run the device chain looking for DA's entry, link back to device's control
   data (see Tim's posting).

2. Use the A6 value from the windows RefCon, knowing that the SFReply record
   pointer can be found at 8(A6).

3. Use the A4 value, expecting Standard File to have it pointing at SFReply.

4. Build, in a small non-relocatable block, a separate A5 world for the DA.
   (See the init-time-icon display code recently posted here for examples).
   At a known offset in that block would be the handle to the main DA data.

"Work is the drink of the cursing class..."
-- 
Ben Cranston <zben@umd2.UMD.EDU>    (Kingdom of Merryland UniSys 1100/92)
Copyright 1989 (you may redistribute ONLY if your recipients can).

tim@hoptoad.uucp (Tim Maroney) (06/08/89)

In article <51276@tut.cis.ohio-state.edu> Todd A Hitt
<thitt@cis.ohio-state.edu> writes:
>But enough of that.  Here's the solution or part of it, I used (and it works)
>that was sent to me by Krzysztof Kozminski:
>
>>Anyway, just an idea, based on what I do:
>>
>>	long **h = NewHandle(4);
>>	int checkBoxValue;
>>
>>	**h = (long) &checkBoxValue;
>>	AddResource(h,'pvte',0,"\p");

I don't mean to be the bad guy, but this is a horrible solution.
Adding resources to someone else's resource file?  Can you say massive
potential for conflicts?  Can you say forget about network
compatibility if you write into an application file?  Can you say every
sense of programming elegance revolts?

There are a number of other solutions that work much better.  Ben
Cranston pointed out that the dialog item list could have a pointer to
globals appended to the end of it.  I pointed out that you could use
the refCon of your main DA window behind the SF dialog; I also pointed
out that you could write into your DA's code space.  Rich Siegel
suggested using the private storage field of your DA's device control
entry, which you can find by looping through the unit table as
described in a Tech Note.  I'm sure you got other reasonable answers as
well, answers that don't require writing into other people's files
without even knowing what files they are!

>>	RmveResource(h);	/* Don't want it added to, e.g., System */

That's for sure!  Not even for a second!

>I've modified it a little to suit me but it works like a champ.  I do feel
>a little funny using the resource manager like this, but it doesn't look like
>there is any particularly clean way to do this.

There are much cleaner ways that that, believe me....
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"When errors are found in old research, the relevant theories are
 re-examined.  When facts contradict theory, theory gets dumped.  Is
 that why the NLP people are unwilling to research their facts?"
	-- Jerry Hollombe on sci.psychology

siegel@endor.harvard.edu (Rich Siegel) (06/08/89)

In article <4975@umd5.umd.edu> zben@umd5.umd.edu (Ben Cranston) writes:
>Re: using one of the development packages that implements local variables for
>DAs and other data-less code resources by using A4 as an ersatz global pointer.
>
>Standard File saves A4 on entry and uses it to point to other things!  For
>much of the routine it points to the SFReply record, however several of the
>subroutines save it and use it for local purposes!

	In principle, you're correct. In practice, TLSP and TLSC provide
SetupA4() and RestoreA4(), which are to be used in routines which are
callbacks from the Toolbox or other places that don't know about the
A4 global conventions.

	This works quite well - a number of DA's have been written using
A4 globals in TLSC, and they work, and they do use Standard file.

>	[outlines other methods, like using the refcon and expecting it
>	to point to SF's frame pointer]

	It's best to use the standard callback mechanism, since you never
know when the people who wrote Standard File may decide to keep SF's A6 some-
where else. As I said above, callbacks written using TLSC and TLSP will work
fine, provided you use SetupA4() and RestoreA4().

		--Rich
~~~~~~~~~~~~~~~
 Rich Siegel
 Staff Software Developer
 Symantec Corporation, Language Products Group
 Internet: siegel@endor.harvard.edu
 UUCP: ..harvard!endor!siegel

 "She told me to make myself comfortable, so I pulled down my pants
 and sat in the pudding." -Emo Phillips
~~~~~~~~~~~~~~~

thitt@hydroplane.cis.ohio-state.edu (Todd A Hitt) (06/08/89)

Just to set the record straight ... I'm not advocating using resources
for temporary purposes.  I agree whole-heartedly with Rich Siegel and I do
think his assembly language based solution is the most bullet-proof.

However ... some people out there may not be using Lightspeed products and not
have access to an assembler.  In these cases, they may be stuck with using
resources as temporary holders.

-=-
Todd Hitt			thitt@cis.ohio-state.edu
Battelle Columbus/Ohio State	hitt%36.114@ohstpy.mps.ohio-state.edu
(614)424-3297			"You were not put on this earth to 'Get It'"
				 - "Lo Pan" in Big Trouble in Little China

siegel@endor.harvard.edu (Rich Siegel) (06/08/89)

In article <51402@tut.cis.ohio-state.edu> Todd A Hitt <thitt@cis.ohio-state.edu> writes:
>
>However ... some people out there may not be using Lightspeed products and not
>have access to an assembler.  In these cases, they may be stuck with using
>resources as temporary holders.

	My advice to such people is that if they are doing any kind of
work that is intended for publication (be it freeware to the net, shareware, or
commercial product), they should expend the effort to do the work correctly,
and if they expect any kind of return on their efforts, then spending the
money ($100 for the MDS system, at last count) for a tool to get the job
done is worthwhile.

	I've found that for some tasks, a macro assembler is absolutely
essential. I'm sure that others will agree with me.

	If you're hacking in the privacy of your own home, far be it from
me to tell you what to do. :-)

		--Rich




~~~~~~~~~~~~~~~
 Rich Siegel
 Staff Software Developer
 Symantec Corporation, Language Products Group
 Internet: siegel@endor.harvard.edu
 UUCP: ..harvard!endor!siegel

 "She told me to make myself comfortable, so I pulled down my pants
 and sat in the pudding." -Emo Phillips
~~~~~~~~~~~~~~~

wdh@well.UUCP (Bill Hofmann) (06/08/89)

In article <4975@umd5.umd.edu> zben@umd5.umd.edu (Ben Cranston) writes:
>Re: using one of the development packages that implements local variables for
>DAs and other data-less code resources by using A4 as an ersatz global pointer.
>
>Standard File saves A4 on entry and uses it to point to other things!  For
>much of the routine it points to the SFReply record, however several of the
>subroutines save it and use it for local purposes!
>
>Therefore it would not work to access DA globals from hook routines...

Not so.  I've been using a4 in standard file hooks and dialog filter procs
for years.  All one has to do is save a4 first, then restore at completion.
Really, folks, it's a solved problem, at least in any environment other
than MPW.  Lightspeed makes it quite easy, with SetUpA4() and RestoreA4(),
and Manx (typically for Manx) requires a bit of hacking, but look at the
sample code in the explorer da, and generalize the save and restore routines.

Note that the Dialog manager uses A4 when it calls user item routines (another
gotcha).

-Bill Hofmann
      Flashpoint

kk@mcnc.org (Krzysztof Kozminski) (06/08/89)

In article <2015@husc6.harvard.edu> siegel@endor.UUCP (Rich Siegel) writes:
>In article <51276@tut.cis.ohio-state.edu> Todd A Hitt <thitt@cis.ohio-state.edu> writes:
>> [adding a resource (!!) to a resource file to hold storage]
>
>	Yeeeech. [followed by bashing of the idea, admittedly deserved]

OK, OK, so I won't suggest any more ideas generated at 3 am ... but it
worked perfectly in that at least Todd got some sound suggestions from
Ben Cranston.  I am not sure if Rich's solution is applicable - remember
that Todd has mentioned that for some reasons he cannot use global variables.

:-):-):-):-):-):-):-):-)
BTW, an idea that I had at 3:15 am was to use the NULL location:
	*((Handle*) 0L) = HStorage;
	
Why not? All applications should avoid writing into NULL location, so
your data should be perfectly safe there (However, standard file dlogs
used to dump 0x00FFFFFF into *NULL in older Sysytem versions)
:-):-):-):-):-):-):-):-)

For the record, my full letter to Todd included an outline of another technique
(using refCon in an existing, privately owned CNTL resource that is already
in memory - so that it wouldn't cause any problems that AddResource is
likely to create) - similar to Ben Cranston's idea of extending the dialog
item list.  (I use it to pass data to a custom CDEF that is invoked from a
CNTL that is appended to the DITL number -3999 after having increased the
window size in DLOG number -3999 to show my extra CNTL)

Now, modifying a system DITL in memory is also not that great idea (other
applications may want to use it) and having a duplicated, modified DITL 
in the application calls for updates each time Apple changes theirs... so
my application compares its DITL with the system DITL upon startup and updates
the modified DITL if necessary (and DLOG, too).

Any holes or potential problems there?

------------------------------
Now my turn in idea - bashing:

>An alternate solution involves some assembly language, and works something like
>this:
>	Define a 4-byte spot in your code where you can store a handle.

Yeeechh.  A "spot in your code"? Tim Maroney also suggested writing into
the code space ... Is self-modifying code OK nowadays? Anyway, I have this
impression that a spot in memory, the address of which is known to more
than one routine, is called a global variable ...

> [Two procedures in assembly]

It seems to me that what Rich wrote is essentially equivalent to the following:

	Handle HStorage;

	SaveAway(h) Handle h;
	{ HStorage = h; }

	GetBack(hp) Handle *hp;
	{ *hp = Hstorage; }

That's *not* the answer to the original question (no globals, remember?).
Perhaps this modification would work:

	SaveAndGetBack(saveIt, hp)
	Boolean saveIt; Handle *hp;
	{ static Handle HStorage;
	  if (saveIt) HStorage = *hp;
	  else *hp = HStorage;
	}

but then, if a development system does not allow globals, then why would it
allow static variables?

KK

svc@well.UUCP (Leonard Rosenthol) (06/08/89)

In article <2015@husc6.harvard.edu>, siegel@endor.harvard.edu (Rich Siegel) writes:
> In article <51276@tut.cis.ohio-state.edu> Todd A Hitt <thitt@cis.ohio-state.edu> writes:
> 
> 	[adding a resource (!!) to a resource file to hold storage]
> 
> 	Yeeeech. I would throw away any program that added resources
> to a running application without my explicit command. The idea of adding
> a resource in this manner has some big holes in it:
> 
	I agree that adding a resource FOR THIS reason is VERY bad and I agree
that it using resources 'freely' for this type of purpose is not always the
way to go - BUT there are VERY good reason to add resources to a file WITHOUT
user intervention.  One of the best reason that I know of, and that both MPW
and MicroPhone II v3.0 do, is autosaving of window sizes/positions. Since the
user could reposition/resize his windows WITHOUT changing any settings/text
you must STILL retain that window change and the best way that I have found to
do that is to simply add a resource to the datafile when it is closed which
contains the window info.

> 	1. The file is modified.
> 		1a. Doing so changes the mod date, which means that
> 			the next time I do an incremental backup,
> 			the file has to get backed up for no particularly
> 			good reason.
> 
	I agree that this does change that mod date, but you HAVE changed the
file if you HAVE moved windows.  If the mod date problem you felt strongly
about you COULD get the curModDate, make the resChange, and then reset the date.

> 		1b. Doing so will set of virus detectors left and right.
> 
	Maybe.  We have not found any that get upset about it yet...

> 	2. What if the AddResource fails, perhaps because the disk is
> 	write-protected or full? If that happens, you're hosed.
> 
	For the original concept, yes you are - but for saving window pos it
just means that user doesn't get his positions saved.  You could, of course,
alert the user to the situation just like you do when you try to do ANY write.

> 	3. As I said, modifying applications without explicit command
> 	is repugnant to me.
> 
	I, again, ask you to reconsider - though I AGREE that APPLICATION
modification is A LOT worse then datafile mods.

-- 
+--------------------------------------------------+
Leonard Rosenthol        |  GEnie : MACgician
Lazerware, inc.          |  MacNet: MACgician
UUCP: svc@well.UUCP      |  ALink : D0025

zben@umd5.umd.edu (Ben Cranston) (06/09/89)

Actually, of all the ideas presented, I like the store-into-our-code idea the
best.  Yes, self-modifying code is not a good thing.  But, it is the ONLY way
to properly manage A5 in the MultiFinder world, given that CurrentA5 may be
swapped out by MF.  The only problem I have with the technique is that the
people who designed the MC680x0 had the same tunnel vision.  "Storing into
our own code is a *BAD* thing!", they thought, so they omitted any kind of
PC relative store instruction!  So you gotta do something like this:

      LEA     blappo,A1
      Move.L  A5,(A1)

Oh, well, it's only one extra instruction...  My suggestion of using A4 or
A6 was not real.  Nobody should depend on the structure of another program
like that.  The point about SetupA4 and RestoreA4 is well taken.  I wonder
how they are implemented, though.  The old SetupA5 and RestoreA5 used a
reserved low memory location (CurrentA5) and I wonder if there is some kind
of reservation for A4 in low memory (deal between Apple and developers?) and
if there is a similar MultiFinder problem with the low-core location.  This
would show up in background event handling in MF-aware programs, also in
handling raw IO interrupts etc...

Q. How many computer professionals does it take to change a lightbulb?
A. Three
   One customer engineer to decide the problem is software.
   One systems programmer to decide the problem is applications software.
   One applications programmer to reprogram the light switch...
-- 
Ben Cranston <zben@umd2.UMD.EDU>    (Kingdom of Merryland UniSys 1100/92)
Copyright 1989 (you may redistribute ONLY if your recipients can).

siegel@endor.harvard.edu (Rich Siegel) (06/09/89)

In article <1241@speedy.mcnc.org> kk@mcnc.org.UUCP (Krzysztof Kozminski) writes:
>BTW, an idea that I had at 3:15 am was to use the NULL location:
>	*((Handle*) 0L) = HStorage;
>	
>Why not? All applications should avoid writing into NULL location, so
>your data should be perfectly safe there (However, standard file dlogs
>used to dump 0x00FFFFFF into *NULL in older Sysytem versions)

	Some Radius products do (or used to, at least) use location zero
for their own purposes. On the memory map, location 0 is noted as being
"part of the system heap", and is usually smashed by applications, whether
they're supposed to or not.


>>	Define a 4-byte spot in your code where you can store a handle.
>
>Yeeechh.  A "spot in your code"? Tim Maroney also suggested writing into
>the code space ... Is self-modifying code OK nowadays? Anyway, I have this
>impression that a spot in memory, the address of which is known to more
>than one routine, is called a global variable ...

	This is not self-modifying code, because the location that's modified
is never executed. It's actually storing data in code space; this particular
trick WILL fail once an OS comes out that has separate code and data spaces,
but it's reasonably far off.

>> [Two procedures in assembly]
>
>It seems to me that what Rich wrote is essentially equivalent to the following:
	[An incorrect translation of my assembler source into C].

	Taken literally, you're correct; the saved-away handle IS known
to more than one routine. However, the routines that DO know about the
handle are exactly two in number, and any other routine which wants the
handle must access it as an argument to a procedure.
	
	Furthermore, "true" global variables are accessed as offsets from
a globals base register, such as A5. The saved-away handle is not a global
in this sense, since it's accessed via PC-relative offsets, which means
that it's independent of the value of ANY base register, which provides
an easy and reliable to fetch and store the value. 

	Which was the problem in the first place: not that ANY globals
weren't allowed; the code just couldn't use "True" globals (ones that
would be addressed relative to a base register).

		--Rich





~~~~~~~~~~~~~~~
 Rich Siegel
 Staff Software Developer
 Symantec Corporation, Language Products Group
 Internet: siegel@endor.harvard.edu
 UUCP: ..harvard!endor!siegel

 I classify myself as a real developer because my desk is hip-deep in
 assembly-language listings and I spend more than 50% of my time in TMON.

~~~~~~~~~~~~~~~

tim@hoptoad.uucp (Tim Maroney) (06/09/89)

I agree with Rich; to do serious programming on the Mac, you *need* an
assembler.  I think it was a terribly foolish decision to stop bundling
the excellent MPW Assembler with the MPW Shell.  I can't imagine a
serious programming project on the Mac that uses absolutely no assembly
language.  Very little, possibly, but none?  No way.

And again, I agree with Rich that you need to *not* write resources
into other people's files.  It's not a solution, period.  Don't do it.
There are tons of other ways to do what you need without stepping on
people's resource files.  How often do both Rich and I spontaneously
clutch our throats and make loud exaggerrated gagging noises?  Not very
often?  That should tell you something!

So what's wrong with using the DCE private storage field or the refCon
of the main DA window?  You can get at both without globals, and they
both have the ability to store whatever you need.  Unlike writing into
code space, they won't break on future systems.
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"Jesus died for somebody's sins, but not mine." -- Patti Smith

tim@hoptoad.uucp (Tim Maroney) (06/09/89)

In article <1241@speedy.mcnc.org> kk@mcnc.org.UUCP (Krzysztof Kozminski) writes:
>>An alternate solution involves some assembly language, and works something like
>>this:
>>	Define a 4-byte spot in your code where you can store a handle.
>
>Yeeechh.  A "spot in your code"? Tim Maroney also suggested writing into
>the code space ... Is self-modifying code OK nowadays?

No, which is fine, since this is not self-modifying code.  No
instructions are being written.  Writing to a DC.L in your code is not
in any way self-modifying code unless the PC hits that location at some
point.  Nothing that's being written is ever executed, that is, no code
is modified.

(Actually some self-modifying code is OK -- the jump tables used by the
Segment Loader are an example.  The modification is very simple and
well-defined: a LoadSeg trap is replaced by a JMP instruction.  The
superstition against self-modifying code originates in more complicated
self-modifying software, which is like Dijkstra spaghetti after you run
it through a blender.)

>Anyway, I have this
>impression that a spot in memory, the address of which is known to more
>than one routine, is called a global variable ...

Then you have a mistaken impression.  A global variable on the Macintosh
is an offset from register A5 or register A4.  The kind of storage Rich
and I are suggesting is an offset from the PC.

>It seems to me that what Rich wrote is essentially equivalent to the following:
>
>	Handle HStorage;
>	SaveAway(h) Handle h;   { HStorage = h; }
>	GetBack(hp) Handle *hp; { *hp = Hstorage; }
>
>That's *not* the answer to the original question (no globals, remember?).

You're being silly, Krsysztof.  They are not equivalent.  For your code
to run on the Mac, there has to be a properly initialized globals
register, which is what Tom can't cope with from MPW C in a DA.  For
the code Rich gave (similar to code myself and others have frequently
used in our trap patches etc.) there is no such requirement.  Tom
didn't object to globals on metaphysical grounds, but on pragmatic
ones.  This is a technical programming problem, not a brain teaser
from a puzzle book.

>Perhaps this modification would work:
>
>	SaveAndGetBack(saveIt, hp)
>	Boolean saveIt; Handle *hp;
>	{ static Handle HStorage;
>	  if (saveIt) HStorage = *hp;
>	  else *hp = HStorage;
>	}
>
>but then, if a development system does not allow globals, then why would it
>allow static variables?

It won't.  This code also requires a globals register, unlike Rich's.
I can't see why you think there might be a difference.

I should point out that the SetUpA4 (etc.) macros in Lightspeed C
actually work by a code-space write.  They can be expected to break on
a memory-protected OS, as can the code-space write Rich and I
proposed.  So when there's an alternative, as there is for what Tom is
trying to do, it should be taken.  (No use enumerating the alternatives
once again.)  Nonetheless, in situations where nothing else will do,
then the code-space write technique is legitimate.
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"The pride of the peacock is the glory of God.
 The lust of the goat is the bounty of God.
 The wrath of the lion is the wisdom of God.
 The nakedness of woman is the work of God."
    - Blake, "The Marriage of Heaven and Hell"

earleh@eleazar.dartmouth.edu (Earle R. Horton) (06/09/89)

     This looks like fun!  May I throw in my two cents worth?

In article <2024@husc6.harvard.edu> siegel@endor.UUCP (Rich Siegel) writes:
>In article <1241@speedy.mcnc.org> kk@mcnc.org.UUCP
	(Krzysztof Kozminski) writes:
>>BTW, an idea that I had at 3:15 am was to use the NULL location:
>>	*((Handle*) 0L) = HStorage;
...
>	Some Radius products do (or used to, at least) use location zero
>for their own purposes. On the memory map, location 0 is noted as being
>"part of the system heap", and is usually smashed by applications, whether
>they're supposed to or not.

     The 68000 reference I use says location zero holds the initial
supervisor stack pointer when the machine is first powered up.  This
makes it a theoretically safe location to use for temporary storage
from within a desk accessory.  Aesthetically, however, it's a real bad
idea.  It produces the same problem that you get using ToolScratch,
ApplScratch, or any other lowmem location--conflicts with other pieces
of code.

>>>	Define a 4-byte spot in your code where you can store a handle.
>>
>>Yeeechh.  A "spot in your code"? Tim Maroney also suggested writing into
>>the code space ... Is self-modifying code OK nowadays? Anyway, I have this
>>impression that a spot in memory, the address of which is known to more
>>than one routine, is called a global variable ...
>
>	This is not self-modifying code, because the location that's modified
>is never executed. It's actually storing data in code space; this particular
>trick WILL fail once an OS comes out that has separate code and data spaces,
>but it's reasonably far off.

     Aha!  So one of you A4-relative types admits that the trick will
fail someday!  This makes my day.  If Apple is real careful about
compatibility of OS releases and the Toolbox, then much current
software will still be in operational condition when separate code and
data spaces are implemented.  It would be real sad for any software to
fail then, JUST BECAUSE it writes to its own code space.

     It's just not real nice to write computer software which has a
shorter lifetime than it could have, had you coded it differently.
Modifying code space to store variables or Handles to variables seems
to save a lot of work in writing code for desk accessories and other
code resources today, but is the work saved worth the inevitable
aggravation that users will experience if and when the OS makes that
technique invalid?  Will you be around to make sure the software you
have written gets re-coded properly at that time, and will you be able
to make sure that users receive upgrades in a timely manner?  Perhaps
not...

     Please think carefully before using any technique which can be
demonstrated to have a high probably of failure under a future
operating system, no matter how convenient it might be to use it
today.
...
> I classify myself as a real developer because my desk is hip-deep in
> assembly-language listings and I spend more than 50% of my time in TMON.

     84+ hours a week, wow!

Earle R. Horton
"People forget how fast you did a job, but they remember how well you
did it."  Salada Tag Lines

siegel@endor.harvard.edu (Rich Siegel) (06/09/89)

In article <13855@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu (Earle R. Horton) writes:
>
>     This looks like fun!  May I throw in my two cents worth?

	It IS fun. By the way, Tim Maroney and I really ARE two different
people, even though our postings have similar content. I guess we just 
think the same way.... :-)

>     Aha!  So one of you A4-relative types admits that the trick will
>fail someday!  This makes my day.  If Apple is real careful about

	Hey, I never said it would work forever. It's actually an
educated bet, because it's highly possible that when separate code
and data spaces are implemented in the OS, the support structure
desk accessories may be radically different, and may well support
base-register-relative globals for DA's. Who knows?

>     It's just not real nice to write computer software which has a
>shorter lifetime than it could have, had you coded it differently.

	I challenge you to solve this problem for the PRESENT incarnation
of the operating system, given the contstraints of not being allowed
to use a base register, and not being allowed to use any low-memory
system space.

	For example, suppose you have an INIT and a cdev that need to
share information with one another? How do you propose to have them
communicate? Remember, there's no low memory you can use, and there's
no place to place a base register. Well, you could put a block in the
system heap with your unique signature in it, and crawl the system
heap for it, BUT that (a) won't work when the format of heap blocks
changes, and (b) won't work when the system heap becomes protected.

	As I said, this is just an example. Sometimes, expediency is
necessary. It's a risk, but it beats the alternatives (bogus solutions,
or no solutions at all).

>     Please think carefully before using any technique which can be
>demonstrated to have a high probably of failure under a future
>operating system, no matter how convenient it might be to use it
>today.

	And please think carefully for attacking proven techniques, without
also providing a workable solution of your own.....

		--Rich



~~~~~~~~~~~~~~~
 Rich Siegel
 Staff Software Developer
 Symantec Corporation, Language Products Group
 Internet: siegel@endor.harvard.edu
 UUCP: ..harvard!endor!siegel

 I classify myself as a real developer because my desk is hip-deep in
 assembly-language listings and I spend more than 50% of my time in TMON.

~~~~~~~~~~~~~~~

earleh@northstar.dartmouth.edu (Earle Horton) (06/09/89)

I had to hack the references line, because either my news reader or my
news poster had an "interp buffer overflow."  Sorry if this breaks
anyone's train of thought.

In article <2026@husc6.harvard.edu> siegel@endor.harvard.edu
	(Rich Siegel) writes
>In article <13855@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu
>	(Earle R. Horton) writes:
...
>>     It's just not real nice to write computer software which has a
>>shorter lifetime than it could have, had you coded it differently.
>
>	I challenge you to solve this problem for the PRESENT incarnation
>of the operating system, given the contstraints of not being allowed
>to use a base register, and not being allowed to use any low-memory
>system space.
>
>	For example, suppose you have an INIT and a cdev that need to
>share information with one another? How do you propose to have them
>communicate?

     Whoa!  I thought we were talking about desk accessories here!
Desk accessories have an officially sanctioned place where they are
allowed to store information.  This is the dCtlStorage field of the
Device Control Entry.  This field is accessible from anywhere in the
code of the 'DRVR' resource, even in a filterproc (I know how to find
it, anyway).  It is, therefore, not necessary to write to the driver's
code space in order to implement private storage for a desk accessory
or device driver.

     You are quite right in saying that there do exist applications
where writing to code space and low memory seems to be the only
solution presently available.  I don't believe that a Desk Accessory
or Device Driver is one of these.

...
>>     Please think carefully before using any technique which can be
>>demonstrated to have a high probably of failure under a future
>>operating system, no matter how convenient it might be to use it
>>today.
>
>	And please think carefully for attacking proven techniques, without
>also providing a workable solution of your own.....

     There are existing working solutions for device drivers under the
present system, which do not write into the driver's code space.
(Device drivers include Desk Accessories.)  What I mean to say is that
the safe solution should be used for these, even though it is perhaps
more cumbersome than the A4-stashed-in-code method.  Desk Accessories
should not write to code space because they don't really have to, and
because the technique may cause them to break someday.  In regard to
INIT/cdev combinations, well you have to do what you have to do, and I
don't suppose I can argue with that.

Earle R. Horton
"People forget how fast you did a job, but they remember how well you
did it."  Salada Tag Lines

jmunkki@santra.UUCP (Juri Munkki) (06/09/89)

siegel@endor.harvard.edu (Rich Siegel) writes:
> earleh@eleazar.dartmouth.edu (Earle R. Horton) writes:
> >     This looks like fun!
> 	It IS fun.
I have to agree.

> 	For example, suppose you have an INIT and a cdev that need to
> share information with one another? How do you propose to have them
> communicate? Remember, there's no low memory you can use, and there's
> no place to place a base register. Well, you could put a block in the
> system heap with your unique signature in it, and crawl the system
> heap for it, BUT that (a) won't work when the format of heap blocks
> changes, and (b) won't work when the system heap becomes protected.

That's the technique that is described in the QuicKeys manual. I've
also used it on one occasion, but I know of a better way to do it.
There's only one problem with the better way and it's that it isn't
always possible (and it doesn't work with old systems).

The solution is to use AppleTalk. If you Mac isn't connected to a
network, this doesn't work, but in my case I was writing a program
that already required an AppleTalk network. My INIT registered itself
with name binding protocol and it also had it's own DDP socket listener.
My cdev could have set the selfsend flag, found any entity of the correct
type on the local node and sent a ddp packet to this socket. After this
the two programs can communicate by sharing memory.

There are some problems with writing socket listeners under multifinder
or using them from INITs. While writing a VBL task to control the sound
driver, I came up with a pretty good solution that works just as well
for socket listeners. The solution is LSC specific, since it uses the
inline assembler. Here are some code fragments to get you started:

/*		Note: VVars is just any structure you need
>>	If A5 points to a VVars structure, the following macro will become
>>	xx(A5), where xx is the offset into that structure element.
*/
#define VBV(field)	((int) &((VVars *) 0)->field)(A5)

VVars	Vv;	/*  Vertical blanking variables				*/

/*
>>	Setup vertical blanking variables &
>>	install vertical blanking task.
*/
void	InstallMyVBL()
{
	long	vbltask;
	
	asm	{
		lea	@myvbltask,A0	;Get address of vbltask
		move.l	A0,vbltask	;Store in local variable
		lea	@mybase,A0	;Get addr of variable base storage
		lea	Vv,A1		;Get addr of Vv record
		move.l	A1,(A0)		;Store base in base storage
		}
	
	Vv.VBL.qType=vType;		/*  Vertical blanking queue.	*/
	Vv.VBL.vblAddr=(ProcPtr)vbltask;/*  Address of task		*/
	Vv.VBL.vblCount=1;		/*  Every 1/60 seconds		*/
	Vv.VBL.vblPhase=0;		/*  0 is ok..			*/
	VInstall(&Vv.VBL);		/*  Install task in queue	*/
	if(0)				/*  Skip the following :-)	*/
asm	{	
@myvbltask
		move.l	A5,-(SP)		;Save A5
		move.l	@mybase,A5		;Get Vv address into A5
		move.w	#1,VBV(VBL.vblCount)	;Call again in 1/60 seconds

	[ Some code deleted... 
		Vv structure elements are accessed as:
		sub.w	#1,VBV(CountB)	;Decrement channel B count
		In C you would have written Vv.CountB
	]

@endvbl
		move.l	(SP)+,A5	;Restore A5
		rts			;Return from vbl routine
@mybase
		dc.l	0		;Vv record address stored here.
	}
}

To install the VBL task, you call this routine and to control what it does
you just change its variables. (Remember that this is "multitasking" so that
you have to use some sort of locking to prevent the vbl task from seeing
changes that aren't complete.)


-- 
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
|     Juri Munkki jmunkki@hut.fi  jmunkki@fingate.bitnet        I Want   Ne   |
|     Helsinki University of Technology Computing Centre        My Own   XT   |
~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~

svc@well.UUCP (Leonard Rosenthol) (06/10/89)

In article <7596@hoptoad.uucp>, tim@hoptoad.uucp (Tim Maroney) writes:
> I agree with Rich; to do serious programming on the Mac, you *need* an
> assembler.  I think it was a terribly foolish decision to stop bundling
> the excellent MPW Assembler with the MPW Shell.  I can't imagine a
> serious programming project on the Mac that uses absolutely no assembly
> language.  Very little, possibly, but none?  No way.
> 
	I will agree with both Tim and Rich that an assembler is a VERY useful
item and that no programmer should be without one - HOWEVER I disagree that just
because a program does not have any assembly in it, means it is not a SERIOUS
programming project.  I can name a NUMBER of major commericial Macintosh
software which does not contain ONE SINGLE ASSEMBLY instruction. (this even
includes defprocs!)
	
-- 
+--------------------------------------------------+
Leonard Rosenthol        |  GEnie : MACgician
Lazerware, inc.          |  MacNet: MACgician
UUCP: svc@well.UUCP      |  ALink : D0025

tim@hoptoad.uucp (Tim Maroney) (06/10/89)

In article <13855@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu
(Earle R. Horton) writes:
>Aesthetically, however, it's a real bad
>idea.  It produces the same problem that you get using ToolScratch,
>ApplScratch, or any other lowmem location--conflicts with other pieces
>of code.

Unless, as I pointed out when I proposed it, you save the old state and
restore it before anyone else gets a chance to use it.  If you save the
value, call Standard File, extract the value stashed by your filter
procs, and restore the old value, there's no way any code that would
use the scratch storage will be interfered with.  Only system software,
interrupt driven code, and trap patches would have a chance to see it,
and it's clear that such software is not allowed to use the scratch
areas.

Like storing the information in the refCon of the DA window, using
ApplScratch or ToolScratch with a state save/restore seems to have been
a useful and *easy* technique that was dismissed out of hand for some
unknown reason.  It's stuff like this that makes me wonder why I put so
much work into this newsgroup.  It's frustrating.
-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com
Postal: 424 Tehama, SF CA 94103; Phone: (415) 495-2934

"I slept with Faith, and found a corpse in my arms on awaking; I drank and
 danced all night with Doubt, and found her a virgin in the morning."
    -- Aleister Crowley, THE BOOK OF LIES

paul@taniwha.UUCP (Paul Campbell) (06/10/89)

In article <22694@santra.UUCP> jmunkki@santra.UUCP (Juri Munkki) writes:
>To install the VBL task, you call this routine and to control what it does
>you just change its variables. (Remember that this is "multitasking" so that
>you have to use some sort of locking to prevent the vbl task from seeing
>changes that aren't complete.)

This brings up one of my chief beefs about the MacOS, if you are doing
something like this involving:

	VBL's
	DDP socket listeners
	IO completion routines
	Deferred Tasks
	Device interrupt handlers

in short anything asynchronous - there are no primitives short of
'or.w #$0700, sr' that you can use to do synchronization between application
code and asynchronous code. I don't think that 'normal' applications should 
ever have to turn interrupts off, instead I think that the correct solution
is to have a trap that defers the delivery of 'Deferred Tasks' untill 
the trap is called again to turn them on again.  Since all the other above 
asynchronous operations can Q deferred tasks this is a lowest common
denominator, and since the queueing of deferred tasks is relatively
cheap it is also a relatively inexpensive solution. APPLE ARE YOU LISTENING?

This brings up another issue I've never really pursued, I use the deferred
task manager to process incoming DDP packets. (My DDP listener Q's a 
deffered task). IM V really only mentions DTs being delivered on the
return from level 1 and 2 interrupts, it doesn't mention Appletalk ...
however it does work - my question is: Does it work because Appletalk
calls out queued deferred tasks on return from interrupts (to IPL 0)
or do my tasks get called out after the next clock tick? I suspect
the latter ....


	Paul
-- 
Paul Campbell
Taniwha Systems Design			UUCP:		..!mtxinu!taniwha!paul 
Oakland CA				AppleLink:	D3213
Achtung! Ve are from ze Interface Police! Ve vant to look und feel!

earleh@eleazar.dartmouth.edu (Earle R. Horton) (06/10/89)

In article <7610@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>In article <13855@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu
>(Earle R. Horton) writes:
	[This is in reference to using location zero as a scratch area.]
>>Aesthetically, however, it's a real bad
>>idea.  It produces the same problem that you get using ToolScratch,
>>ApplScratch, or any other lowmem location--conflicts with other pieces
>>of code.
>
>Unless, as I pointed out when I proposed it, you save the old state and
>restore it before anyone else gets a chance to use it.  If you save the
>value, call Standard File, extract the value stashed by your filter
>procs, and restore the old value, there's no way any code that would
>use the scratch storage will be interfered with.  Only system software,
>interrupt driven code, and trap patches would have a chance to see it,
>and it's clear that such software is not allowed to use the scratch
>areas.

  "Scratch20, Scratch8, and ToolScratch will not be preserved across
   calls to the routines in the Macintosh ROM.  ApplScratch will be
   preserved; it should be used only by application programs and not
   by desk accessories or other drivers."
                     Phonebook: Assembly Language Programming Chapter

     Standard File makes a whole bunch of ROM calls.  This means that
the three scratch areas dedicated to tool use cannot be used.  Saving
and restoring the value at location zero (an interrupt vector) will
not work across Standard File, because background tasks are allowed to
run while Standard File is active, and lots of tasks will have a
chance to see it.  (I'm assuming MultiFinder here.)

     It's not nice to use ApplScratch, even though you think it
extremely unlikely that the application will need it during the
Standard File call.  What if the call to Standard File causes the
application's grow zone function to be called, and the grow zone
function uses ApplScratch?  Grow zone functions are just an example;
my point is that it is possible for the code of the current
application to get control in the midst of a call to Standard File.

>Like storing the information in the refCon of the DA window, using
>ApplScratch or ToolScratch with a state save/restore seems to have been
>a useful and *easy* technique that was dismissed out of hand for some
>unknown reason.  It's stuff like this that makes me wonder why I put so
>much work into this newsgroup.  It's frustrating.

     ToolScratch is definitely out, given what IM says about its
volatility.  ApplScratch is out, too, because it is just barely
possible for the application code to need or modify it during the call
to Standard File.  Murphy's Law equates "just barely possible" with
"will happen," as I am sure you know already.  There are aesthetic
problems with the use of low memory globals for this sort of thing,
too.  Many people will just not use them if there is another method.

Earle R. Horton
"People forget how fast you did a job, but they remember how well you
did it."  Salada Tag Lines

lsr@Apple.COM (Larry Rosenstein) (06/10/89)

In article <1241@speedy.mcnc.org> kk@mcnc.org (Krzysztof Kozminski) writes:
> BTW, an idea that I had at 3:15 am was to use the NULL location:
>         *((Handle*) 0L) = HStorage;
>         
> Why not? All applications should avoid writing into NULL location, so

Two reasons why not:

(1) Some applications or DAs do write into location 0.  Most do this by 
mistake, but some do it on purpose.  I ran across one piece of code that 
passed NULL as one of the VAR parameters to a Dialog Manager code, which 
meant that the Dialog Manager would change location 0.

(2) Some programs incorrectly dereference a NIL pointer.  If location 0 
happens to contain an invalid address, the program will crash. 

Larry Rosenstein, Apple Computer, Inc.
Object Specialist

Internet: lsr@Apple.com   UUCP: {nsc, sun}!apple!lsr
AppleLink: Rosenstein1

cep@apple.com (Christopher Pettus) (06/10/89)

In article <1241@speedy.mcnc.org> kk@mcnc.org (Krzysztof Kozminski) writes:
> BTW, an idea that I had at 3:15 am was to use the NULL location:
>         *((Handle*) 0L) = HStorage;
>         
> Why not? All applications should avoid writing into NULL location, so

What happens when the _next_ piece of code comes along, assuming that all 
applications will avoid writing to zero?  And, what happens when you can't 
write to location zero (as under A/UX, I believe)?

-- Christopher Pettus                   | "Ganesha Said: 'Done!  The very 
   Network Systems Development          | day I was born I made my first
   Apple Computer, Inc.                 | mistake, and by that path have
   cep@apple.com   {nsc, sun}!apple!cep | I sought wisdom ever since.'"
   AppleLink: PETTUS.C                  | - The Mahabharata
   (408) 974-0004                       |   I: A Mine of Jewels and Gems

ech@cbnewsk.ATT.COM (ned.horvath) (06/13/89)

> In article <2024@husc6.harvard.edu> siegel@endor.UUCP (Rich Siegel) writes:
>	This is not self-modifying code, because the location that's modified
>is never executed. It's actually storing data in code space; this particular
>trick WILL fail once an OS comes out that has separate code and data spaces,
>but it's reasonably far off.

From article <13855@dartvax.Dartmouth.EDU>, by earleh@eleazar.dartmouth.edu (Earle R. Horton):
>      Aha!  So one of you A4-relative types admits that the trick will
> fail someday!  This makes my day...

>      It's just not real nice to write computer software which has a
> shorter lifetime than it could have, had you coded it differently.
> Modifying code space to store variables or Handles to variables seems
> to save a lot of work in writing code for desk accessories and other
> code resources today, but is the work saved worth the inevitable
> aggravation that users will experience if and when the OS makes that
> technique invalid?  Will you be around to make sure the software you
> have written gets re-coded properly at that time, and will you be able
> to make sure that users receive upgrades in a timely manner?  Perhaps
> not...

Are you having fun, Earle?  Smugness ill-becomes you, unless you have
a solution to the problem...if you do, please share it.

The "A4-relative" bit is a perfectly wonderful technique for a non-app
to maintain access to its global variables.  All I need now is someplace
for A4 to point at -- that's easy, there are two heaps to do NewHandle in --
and some mechanism in the OS to preserve the value of A4 when I'm not
executing.

Apple provides no such mechanism.  For APPLs, there's A5.  For DRVRs,
there's the Device control block, and the Handle to data storage.  For
everything else, there's nada.  Not even owned resources for most things.

What Aztec, and lately Think, have done is to store the handle to the
globals in the only place that belongs to a CODE resource: in the resource
itself.  Someday Apple may want to separate data from code, so the latter
can be write-protected.  Presumably, at least 90 days prior to that day,
Apple will give us the means to tell the OS just where one ends and the
other begins.  And if there's anybody sane in charge, along with that,
will go some way for the code to find the data.

Unless you can propose a mechanism that both works with the benevolent
neglect the OS provides today, and is also going to work when the OS grows up.

=Ned Horvath=

tim@hoptoad.uucp (Tim Maroney) (06/13/89)

In article <13870@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu
(Earle R. Horton) writes:
>  "Scratch20, Scratch8, and ToolScratch will not be preserved across
>   calls to the routines in the Macintosh ROM.  ApplScratch will be
>   preserved; it should be used only by application programs and not
>   by desk accessories or other drivers."
>                     Phonebook: Assembly Language Programming Chapter
>
>     Standard File makes a whole bunch of ROM calls.  This means that
>the three scratch areas dedicated to tool use cannot be used.

Thanks for the correction.  (But are you really still using the phone book?)

>Saving
>and restoring the value at location zero (an interrupt vector) will
>not work across Standard File, because background tasks are allowed to
>run while Standard File is active, and lots of tasks will have a
>chance to see it.  (I'm assuming MultiFinder here.)

I'm satisfied with saying that you can't use location zero because it's
blecchy, but as someone else pointed out, what if other software also
wants to use it?  Anyway, I think it goes without saying that any
location in the first page belongs to the OS and should be used only in
explicitly sanctioned ways.  (By the way, it's not an interrupt vector,
exactly.  It's the reset vector, but due to the way the Mac maps
memory, it will never be consulted from RAM.  I can't find a reference,
but during reset, the ROM is mapped in at address 0.)

>     It's not nice to use ApplScratch, even though you think it
>extremely unlikely that the application will need it during the
>Standard File call.  What if the call to Standard File causes the
>application's grow zone function to be called, and the grow zone
>function uses ApplScratch?

True, but pretty obscure.  I think I could live with this level of
compatibility.  Grow zone routines ought to use globals anyway;
they are guaranteed to find the proper A5 in CurrentA5.

>Grow zone functions are just an example;
>my point is that it is possible for the code of the current
>application to get control in the midst of a call to Standard File.

Other than the grow zone routine, how?

>     ToolScratch is definitely out, given what IM says about its
>volatility.

Yes.

>ApplScratch is out, too, because it is just barely
>possible for the application code to need or modify it during the call
>to Standard File.  Murphy's Law equates "just barely possible" with
>"will happen," as I am sure you know already.

Murphy's Law is a joke.  If everything bad that could happen did
happen, no one would ever finish a hundred lines of code.  I think a
realistic assessment shows that the chances that the grow zone routine
will need ApplScratch are so small that they can be neglected.  I mean,
if you want to get absolutely technical, Standard File can't even be
called from a desk accessory, because DAs aren't allowed to allocate
more than 3K of RAM.  If you violate this, it's possible you will
crash.  But in real life, it's not a problem.

>There are aesthetic
>problems with the use of low memory globals for this sort of thing,
>too.  Many people will just not use them if there is another method.

Oh sure, I'm not saying this is the best method by any means.  The best
method is still to use the refCon of the main DA window; the second
best, to use the private storage field of the DCE in the unit table; the
third, to write into code space.  None of these involve low-memory
globals, except for walking the unit table, a process described
officially in one of the tech notes.

>"People forget how fast you did a job, but they remember how well you
>did it."  Salada Tag Lines

Not in my experience....
-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com
Postal: 424 Tehama, SF CA 94103; Phone: (415) 495-2934

"Do what you wanna, do what you will;
 Just don't mess up your neighbor's thrill.
 And when you pay the bill, kindly leave a little tip
 To help the next poor sucker on his one-way trip."
    - Frank Zappa, "You Are What You Is"

kaufman@polya.Stanford.EDU (Marc T. Kaufman) (06/13/89)

From article <13855@dartvax.Dartmouth.EDU>, by earleh@eleazar.dartmouth.edu (Earle R. Horton):
.      Aha!  So one of you A4-relative types admits that the trick will
. fail someday!  This makes my day...

.      It's just not real nice to write computer software which has a
. shorter lifetime than it could have, had you coded it differently.
. Modifying code space to store variables or Handles to variables seems
. to save a lot of work in writing code for desk accessories and other
. code resources today, but is the work saved worth the inevitable
. aggravation that users will experience if and when the OS makes that
. technique invalid?  Will you be around to make sure the software you
. have written gets re-coded properly at that time, and will you be able
. to make sure that users receive upgrades in a timely manner?  Perhaps
. not...

It is EXTREMELY unlikely that Apple will try to separate code and data
spaces in the Mac OS.  The 680x0 paging system is just not well suited to
short, variable length segments.  It seems likely (to me) that processes will
be protected from one another... but we're unlikely to see protection within
a process.

Marc Kaufman (kaufman@polya.stanford.edu)

tim@hoptoad.uucp (Tim Maroney) (06/14/89)

In article <9983@polya.Stanford.EDU> kaufman@polya.Stanford.EDU
(Marc T. Kaufman) writes:
>It is EXTREMELY unlikely that Apple will try to separate code and data
>spaces in the Mac OS.  The 680x0 paging system is just not well suited to
>short, variable length segments.  It seems likely (to me) that processes will
>be protected from one another... but we're unlikely to see protection within
>a process.

I think this is an oversimplification.  It may turn out to be a correct
guess, and certainly it is less important that applications be
protected from overwriting their own code space than it is that they be
protected from writing into system space or other applications.

However, it is not neccessary to protect short, variable-length
segments to protect code resources from writing.  The Resource Manager
can readily be hacked so that code resources of various types turn up
in a separate, write-protected area, rather than in the main heap as
they do at present.  This entire code area would be protected against
writing by application code; there would be no need to lock individual
code segments.
-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com
Postal: 424 Tehama, SF CA 94103; Phone: (415) 495-2934

"Satanic is merely the name they give to the behavior of those who would
 disrupt the orderly way in which men want to live."
    -- Gabrielle, THE VAMPIRE LESTAT, Anne Rice

earleh@eleazar.dartmouth.edu (Earle R. Horton) (06/16/89)

In article <446@cbnewsk.ATT.COM> ech@cbnewsk.ATT.COM (ned.horvath) writes:
>> In article <2024@husc6.harvard.edu> siegel@endor.UUCP (Rich Siegel) writes:
>>	This is not self-modifying code, because the location that's modified
>>is never executed. It's actually storing data in code space; this particular
>>trick WILL fail once an OS comes out that has separate code and data spaces,
>>but it's reasonably far off.
>
>From article <13855@dartvax.Dartmouth.EDU>, by earleh@eleazar.dartmouth.edu (Earle R. Horton):
>>      Aha!  So one of you A4-relative types admits that the trick will
>> fail someday!  This makes my day...
...
>Are you having fun, Earle?  Smugness ill-becomes you, unless you have
>a solution to the problem...if you do, please share it.

     I have been accused of condemning the use of A4-based code resource
globals, while providing no alternate solution of my own.  This was not
my intent.  I merely hoped to point out that for any problem, there usually
exist multiple solutions.  In the case of code resources which are not
provided with an external means of keeping global data around, the use
of A4-relative data is only one solution.  The technique, while seeming
to provide a universal solution to the globals problem, has the serious
drawback that it sometimes requires the programmer to write the A4 value
into a part of her code space.

     For many code resources, such as desk accessories and cdevs, there
already exist mechanisms for saving a Handle to data.  My point is that
where such a mechanism exists, it should be used in preference to writing
to code space.  For desk accessories, when it is necessary to reference
A4-based globals from within a routine where the DA's A4 is invalid, it
is preferable to use the driver's dCtlStorage Handle for this purpose,
rather than using Think's SetupA4().  For some applications it may be
possible, or even preferable, to forego globals entirely.

     Rewriting code to accomodate an OS change can be an expensive
proposition.  If you can find a way to avoid doing so, then you may save
yourself or someone else a lot of trouble in the future.  Although I
propose no universal solution to this problem, I do suggest that anyone
who is involved in writing code which writes to code space ("Class II
self-modifying code") make sure that this is the only solution which
is practical.

     If you detect a note of sarcasm in my characterization of
"A4-relative bozos," then it is there.  The reason is that from my
experience with Aztec, I find that the A4-relative method is presented
as a solution to the code resource globals problem, but that the
potential problems which exist are not discussed in the documentation.
I am not condemning the technique, because there appear to be cases
where it is perfectly safe.  It is the one percent or less where it is
not that worries me.  Code with a time bomb in it can blow up anytime.

Earle R. Horton
"People forget how fast you did a job, but they remember how well you
did it."  Salada Tag Lines