Global Data in Magic Cap Packages


Is it legal and safe for an object/package to have a static array? We want to create an static array when the device is turned on and use it while we are logging. We need to have fast access to an array so the user doesn't take a performance hit.


Packages cannot have globals, such as static arrays. Neither can you specify an array as a field of an object. You can use the extra data portion of an object to simulate an unbounded array. You can get a pointer to the beginning of the extra data portion of an object by calling ExtraSize() on that object. You can also allocate a buffer (the Buffer class is nothing but extra data) by calling NewTransientBuffer(). You can associate this buffer with an object by assigning it to an object field of type Pointer.

You need to be careful about what type of information you put into buffers and extra data portions of objects. Normally, Magic Cap's garbage collection will destroy objects that are not being referenced by any other objects. Because the extra data of an object can be anything, this reference search does not normally look in the extra data of an object unless that object's class overrides EachExtraField() to interpret the data. If you plan to keep ObjectIDs in your array and you use extra data or a Buffer object to implement the array, you'll need to override EachExtraField() to help Magic Cap interpret your array data.


I want to be able to have global, initialized data. I get an error when I try to link the following code:

static long inkColorsRGB[numInkColors] =
{
   inkColorRGBBlack,
   inkColorRGBDarkGray,
   inkColorRGBLightSilver,
   inkColorRGBWhite,
   inkColorRGBRed,
   inkColorRGBGreen,
   inkColorRGBBlue,
   inkColorRGBCyan,
   inkColorRGBMagenta,
   inkColorRGBYellow,
   inkColorRGBDarkRed,
   inkColorRGBDarkGreen,
   inkColorRGBDarkBlue,
   inkColorRGBDarkCyan,
   inkColorRGBDarkMagenta,
   inkColorRGBDarkYellow
};

What's the right way to specify global data in Magic Cap?


Global data, initialized or not, is not supported in Magic Cap packages. You'll need to use objects in your Objects.Def for this sort of static data.

Here's how your table might look:

Instance FixedList 'Colors' 3;
    length: 8;
    entry1: 0xFFFFFFFF;
    ....
    entry8: 0x88888888;
End Instance;
You can refer to this object in your code with an indexical.


How can I use a private routine from a different segment than it's implemented in?


You can't use the same private non-method routine from more than one segement. You can get around the problem in a couple of ways. One thing you could do is to put all of your code in a single segment. Then for each class in your files you would only #define CURRENTCLASS, and not bother with the #pragma segment. The other thing you could do is collect all these private routines and make them intrinsic methods of your classes. You might even collect them all into a single class and call it MyPrivateRoutines, or something like that. Intrinsic methods are dispatched pretty quickly, and are just like "regular" methods except that the implied self parameter in a norma operation is not present in an intrinsic.


Can I use the MPW libraries from my package?


No. This is because the MPW and standard C libraries are written assuming they will be used in a Macintosh runtime environment, where global variables are allowed and multiple code segments can call each other via register A5. The runtime error you got when you implemented your own version of strlen is probably because you put the private function in one segment and called it from a different segment. This sort of inter-segment calling, one of the core elements of the Macintosh runtime environment, is not supported in Magic Cap packages.

Some of the functions you might want to use can be found in the Utilities class and the Debug class. (Most of the operations in the Debug class are only available when you are building "debug" versions of your packages. Be careful not to use a "debug-only" operation in your final package, because when you build a "nodebug" version the operation will be undefined in the interfaces and unavailable on shipping Magic Cap devices.) Look in :Interfaces:DefFiles:Utilities.Def for the class descriptions of Utilities and Debug (or use Bowser to browse them). For example, strlen(), is implemented in the Debug class:

intrinsic CStringLength(cString: Literal): Unsigned;
If you want to implement more of the standard C library to use in your package, you should define a class with a bunch of intrinsic operations that implement the functions (very much like the Utilities and Debug classes). This way you may call them from anywhere in your package and not worry about inter-segment calling because all operations (even intrinsic ones) are dispatched by Magic Cap instead of simply branching to a subroutine. Intrinsic operations are dispatched very quickly, and the C interfaces of the methods look just like ordinary function calls (without the implied self parameter that regular operations have).