[comp.sys.mac.hypercard] Is PasToZero necessary?

moore@cs.washington.edu (Charles Moore) (07/06/90)

Is a call to PasToZero necessary in order to return a result to Hypercard
from an XCMD?  The appendix to the HyperCard Script Language Guide is
pretty cagey about this saying only that the returnValue field of the
XCmdBlock can contain a handle to a zero-terminated string.  But where
is the space for this string allocated?  I allocated space within my
XCMD with the declaration:

char resultStr[80];

and then tried to return this value with the assignment:

paramPtr->returnValue = (Handle)&resultStr;

The result was a system error.  Does this mean that PasToZero, in 
addition to converting between string types, also commands HyperCard
to allocate space for the converted string?  If so, why must I use
PasToZero?  I already have a zero-terminated string.  I don't need to
convert it; I just need to return it.  Where is the glue routine that
has HyperCard allocate some space and copies your string into that 
space but that doesn't waste time doing unnecessary conversions?

Charles Moore

gb2a+@andrew.cmu.edu (George J. Baxter) (07/06/90)

I think you should be using ZerotoPas..  This is if you're programming
in 'C' or something.. and you have to convert your zero terminated
string to a Pascal string so that Hypercard, which is written in Pascal,
can read it.  It would also explain the system error.

mcguire@cs.utexas.edu (Tommy Marcus McGuire) (07/07/90)

I believe that PasToZero does allocate the space for the handle and the
string for returnValue.  Your problem might be with the
char resultStr[80];
declaration.  Doesn't the space allocated for the string itself go away
when your XCMD returns?  Rather than calling PasToZero, though, you could
allocate the space for the string on the heap yourself.

Tommy McGuire

gibson@tut.cis.ohio-state.edu (William Kerr Gibson) (07/09/90)

In article <12477@june.cs.washington.edu> moore@cs.washington.edu (Charles Moore) writes:
>Is a call to PasToZero necessary in order to return a result to Hypercard
>from an XCMD?  The appendix to the HyperCard Script Language Guide is
...
>is the space for this string allocated?  I allocated space within my
>XCMD with the declaration:
>
>char resultStr[80];
>
>and then tried to return this value with the assignment:
>
>paramPtr->returnValue = (Handle)&resultStr;
>
>The result was a system error.  Does this mean that PasToZero, in 
...
>
>Charles Moore

Howdy,
    my name is seann i am Kerr's brother. You have a couple of problems here:
    1st, I assume that you have declared resultStr in your main as one of the
local variables. This means that the 80 bytes of space that you have declared
are on the Stack; thus when you return to hypercard, you have NO GAURANTEE
at all with what hypercard will do to the stack, and since hypercard does not
know that this result parameter is on the stack, it could easily overwrite this
area. As a general RULE, NEVER return a pointer to anything
that you have declared as local storage in a 'c' function.

   Your second problem, and perhaps a worse one is that you HAVE NOT returned
a handle at all! what you have returned is merely a pointer. In fact, you have
not really even returned a pointer to a pointer, which is as i believe, what
you are trying to return. Because, since resultStr is on the stack (the space
is on the stack) refering to resultStr without any brackets [] is the same
as refering to &resultStr.

in other words:

char resultStr[80];
char *a;

    a = resultStr;
is the same as...
    a = &resultStr;

 but at any rate even if you do return a pointer
to a pointer this will NOT help you at all because a pointer to a pointer is
NOT the same as a handle. A handle will be explicitly declared as such in
hypercards heap zone so that it knows the size and can move it around and
compact the heap and do whatever it likes. In other words, paramPtr->
returnValue is a space of 4 bytes and you have put 4 bytes in there that happen
to be a pointer to a group of 80 bytes. now when hypercard tries to dispose
of this handle or set the size different, or do any memory operations with it,
the results are unpredictable, and could easily destroy hypercards heap which
will eventually cause any number of system errors to occur.

and now my brother (the hypercard XCMD whizz boy) will tell you what you
should really do...

sorry Charlie, but you are going to have to declare a handle somewhere.
Fortunately this is not too difficult.  When you use paramPtr->returnValue
you have two options.  

1. you can assign paramPtr->returnValue to an existing handle (much like you
have tried to do in your code).   In this case you need to have actually
declared space for your handle with NewHandle(). Once you have assigned
returnValue you must NOT dispose of the old handle as HyperCard will
dispose of it for you. E.g.

{	
Handle resultStr;

resultStr = NewHandle((long) 80); /* declare space for the handle */

...

strcpy(*resultStr,"This is my return message"); /* perform string operations */
 
...

paramPtr->returnValue = resultStr; /* returnValue is now same as resultStr */
 
/* WARNING! Do not dispose of resultStr.  Hypercard will dispose of */
/* paramPtr->returnValue on its own, which amounts to the same thing */

return();

}

2. The other thing you can do is to declare space for returnValue at the
time you assign your string to it.

{

char resultStr[80];

...

paramPtr->returnValue = CopyStrToHand(resultStr);

return();
}

/* CopyStrToHand function is below */
/* This is taken from "XCMD's For HyperCard" by Gary Bond */

Handle CopyStrToHand(str)
 char *str;
{
  Handle newHndl;

  newHndl = (Handle) NewHandle((long) strlen(str) + 1);
  strcpy((char *) (*newHndl), str);
  return(newHndl);
}

 

That's it....

Hope this helps you out!

Kerr Gibson CIS Dept OSU. (614)292-0915               __---------------------__
gibson@tut.cis.ohio-state.edu          _____________ /   >-------------------
att-cb!osu-cis!tut.cis.oh...!gibson   `-~~~~~~~~~"--'---/       /
OSU 2036 neil av. Col. Oh. 43210-1277    `---`==________/    Engage!

stm@apple.com (Steve Maller) (07/10/90)

The name "PasToZero" is misleading. It should be PasToZeroHandle. It 
allocates the space necessary and returns a regular Memory Manager Handle 
to a null-terminated string. You can roll your own version of it, but you 
have to go through the memory manager.

I yam what I yam...