TweetFollow Us on Twitter

XCMD in Think C
Volume Number:5
Issue Number:5
Column Tag:HyperChat™

XCMD Corner: XCMDs in Think C

By Donald Koscheka, Arthur Young & Company, MacTutor Contributing Editor

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

Exploring XCMDs using just one development system is a lot like learning to play music on just one instrument. This is unfortunate because the Macintosh offers a virtual orchestra of development systems. As in learning to play a second instrument, learning a new development system often boils down to nothing more than learning how to transcribe the music.

Your programming environment is your instrument (writing a program is more like writing a piece of music than playing it). If you happen to own a copy of MPW you have no trouble using the code in this column because it’s all written for MPW. If you use a different development system , you’ll need to transcribe my listings to play on your particular development system.

In the past, I’ve been terribly guilty of catering to the MPW clique. My reasons were perhaps not so subtle: I use MPW at work; I’m comfortable with it, and I know that it directly supports an interface to XCMDs. After purchasing a copy of MPW 3.0, I realized that I might be making a mistake. For starters, MPW requires an expensive and time consuming learning curve; perhaps not everyone wants to spend several hundred dollars for sophistication they may never need.

Other development systems offer features that are not available in MPW such as a high quality source level debugger. Unfortunately several development systems lack key capabilities like support for XCMDs. Although you might expect LightspeedC to support XCMDs out of the box, it doesn’t. I’m not sure I understand the reason, but it doesn’t matter. Adding XCMD support to any compiler should be a very simple job.

Afterall, an XCMD is just another type of resource. If LightspeedC can create specialized resources such as window definitions and drivers, it already contains some of the support we need.

• Setting up the project

As luck, or design foresight, would have it, LightspeedC supports a generalized resource type called the “CODE” Resource. CODE resource projects are created like any other project in LightspeedC with the exception that you specify the project as a code resource in the set project type dialogue (see figure 1). You specify most of the information that the resource manger wants in this dialogue.

The custom header option requires a little elaboration. The standard interface to code resources branches to the entry point: main() . Selecting the Custom header option causes the entry point to be the first function in the file in which your main() is defined. XCMDs follow the second course as a matter of style.

Set the resource type to ‘XCMD’ or ‘XFCN’ according to the type of Hypercard interface you want.

Figure 1. Setting up a Code Resource using the Set Project Type Dialogue

• Writing the XCMD

In LightspeedC, a code resource has the same form as a “C” program. You define the entry point as:

 pascal void main( paramPtr ) 

ParamPtr is a pointer to a HyperTalk XCMDBlock. From there, your code looks like a vanilla “C” application. The same restrictions apply as on all CODE resources: no globals or statically initialized strings. CODE resources, of any kind, have no knowledge of globals at build time because they can’t make any assumptions about which application will load them! Strings suffer the same fate - “C” allocates statically defined strings in the application’s global pool. You’re not building an application so you don’t have a global pool - you must either define strings the hard way or load them in from the resource fork.

Listing 1 is a simple XCMD that returns the string “Hello World” to Hypercard. While the code itself is wholly unimaginative, it does demonstrate that the interface to Hypercard and the callback mechanism work satisfactorily. Anyhow there’s a time for imagination and a time to just get things done. Porting an interface falls to the latter category.

Include the header file, “HyperXCMD.h” (listing 2 ) in your code. This is the standard interface to Hypercard transposed for LightspeedC. There aren’t a lot of differences between the two as should be the case. Nonetheless this exercise proves quite useful in scoping out the idioms of a particular language implementation.

• The Hypercard “Glue”

You need to create a project which at the least includes MacTraps, your XCMD code and a special file called “XCMDGlue.c” (Listing 3) which interfaces (or glues) your XCMD to Hypertalk’s callback mechanism. I took the liberty of translating XCMDGlue.in.c from MPW “C” to LightspeedC. The major difference between the MPW and Think versions of the glue is that I use the CallPascal function available in LightspeedC to jump to the subroutine pointed to by paramPtr->entryPoint. Pascal routines push parameters from left to right and the subroutine is responsible for clearing the stack parameters. “C” pushes from right to left and the caller clears the stack.

We know that the callback engine uses the Pascal calling sequence because the parameters aren’t left on the stack after the call. Whether we push from right to left or left to right isn’t relevant here for an obvious reason that’s left as an exercise to the reader.

Add XCMDGlue.c to the project rather than including it at the end of the XCMDS source code as is the case with MPW. I like this feature of Think “C” - you keep track of the source modules at the project level and not at the source code level.

• Creating the resource

Once all modules compile,use the “Create Code Resource” menu option to create the code resource. LightspeedC presents a dialogue asking for the name of an output file. Enter the name of a file but not your output stack: LightspeedC completely erases the previous contents of both forks of the output file before writing out the code resource!

Select the “smart link” option when creating a code resource. Your links will be slower, but your XCMDs will be quite a bit smaller (The example in listing 3 compiles to 12.5K with smart link of and 2.5K with smart link on). Of course, you can speed up turnaround during development by leaving this option unselected.

That’s it! Use ResEdit or Rescopy to copy the XCMD into your stack. Perhaps LightspeedC will release a future version of “C” that will build code resources directly into the target file (if you try this now, the entire contents of the target file will be lost). In the meantime, the extra step needed to copy the resource into your stack is a small price to pay for an outstanding development system.

I hope the information in this article will help those of you who need to create an XCMD interface for another development system. The process is really rather simple and it provides you one of those rare opportunities in programming where you can get a lot done without doing a lot of work!

Listing 1:

/********************************/
/* File: SimpleXCMD.c*/
/* */
/* This is what a simple XCMD */
/* written in Lightspeed “C”*/
/* In order to build this code*/
/* resource, you will need the*/
/* two files “HyperXCMD.h” and*/
/* XCMDGlue.c.   */
/* */
/* ----------------------------  */
/* To Build:*/
/* */
/* (1) Create a project using */
/* this file as well as the */
/* XCMD.Glue.c file. (Set */
/* project type to XCMD (or */
/* XFCN) from the Project menu.  */
/* */
/* (2) Bring the project up to*/
/* date.*/
/* */
/* (3) Build Code Resource. */
/* */
/* (4) Use ResEdit to copy the   */
/* resource to your stack.*/
/********************************/

#include<MacTypes.h>
#include<OSUtil.h>
#include<MemoryMgr.h>
#include<FileMgr.h>
#include<ResourceMgr.h>
#include  “HyperXCmd.h”

pascal void main( paramPtr )
 XCmdBlockPtr  paramPtr;
{
 char theString[256];/* A “Pascal” String */

 theString[0] = ‘\0x0B’;  /* Remember, static*/
 theString[1] = ‘H’; /* strings are placed*/
 theString[2] = ‘E’; /* in the global pool*/
 theString[3] = ‘L’; /* CODE resources such */
 theString[4] = ‘L’; /* as XCMDS and XFCNS*/
 theString[5] = ‘O’; /* don’t have access to */
 theString[6] = ‘ ‘; /* globals so you have*/
 theString[7] = ‘W’; /* to discretely set the*/
 theString[8] = ‘O’; /* string’s value */
 theString[9] = ‘R’;
 theString[10]= ‘L’;
 theString[11]= ‘D’;

 /* A sample callback example */
 paramPtr->returnValue = PasToZero( paramPtr, &theString );
}
Listing 2:

/************************************/
/* File:HyperXCmd.h  */
/* */
/* Interface for standard */ 
/* HyperCard callback routines.    */
/* */
/* Based on original work by*/
/* Dan Winkler of Apple Computer */
/* */
/************************************/

typedef struct Str31 {
 char data[32];
 } Str31;
typedef  Str31 * Str31Ptr;

typedef struct XCmdBlock {
 short  paramCount;       
    Handle  params[16];
    Handle  returnValue;      
    Boolean passFlag; 
    
    void  (*entryPoint)();    
    short request;  
    short result;  
    longinArgs[8];
    longoutArgs[4];
} XCmdBlock;
typedef XCmdBlock*XCmdBlockPtr; 

  /* Callback codes  */
#define xresSucc 0
#define xresFail 1 
#define xresNotImp 2 
  
  /* Callback request codes */
#define xreqSendCardMessage 1 
#define xreqEvalExpr 2 
#define xreqStringLength  3 
#define xreqStringMatch   4 

#define xreqZeroBytes         6 
#define xreqPasToZero7 
#define xreqZeroToPas8 
#define xreqStrToLong9 
#define xreqStrToNum 10 
#define xreqStrToBool11 
#define xreqStrToExt 12 
#define xreqLongToStr13 
#define xreqNumToStr 14 
#define xreqNumToHex 15 
#define xreqBoolToStr16 
#define xreqExtToStr 17 
#define xreqGetGlobal18 
#define xreqSetGlobal19 
#define xreqGetFieldByName20 
#define xreqGetFieldByNum 21 
#define xreqGetFieldByID  22 
#define xreqSetFieldByName23 
#define xreqSetFieldByNum 24 
#define xreqSetFieldByID  25 
#define xreqStringEqual       26 
#define xreqReturnToPas       27 
#define xreqScanToReturn      28 
#define xreqScanToZero        39  

/* 
 “Prototypes” for the Callbacks.  Project 
 must include XCmdGlue.c.  
*/

 
pascal void SendCardMessage();     
pascal Handle  EvalExpr();
pascal long StringLength(); 
pascal Ptr  StringMatch();
pascal void ZeroBytes();
pascal Handle  PasToZero();
pascal void ZeroToPas();
pascal long StrToLong();
pascal long StrToNum();
pascal Boolean   StrToBool();
pascal void StrToExt();
pascal void LongToStr();
pascal void NumToStr();
pascal void NumToHex();
pascal void BoolToStr();
pascal void ExtToStr();
pascal Handle  GetGlobal();
pascal void SetGlobal();
pascal Handle  GetFieldByName();
pascal Handle  GetFieldByNum();
pascal Handle  GetFieldByID();
pascal void SetFieldByName();
pascal void SetFieldByNum();
pascal void SetFieldByID();
pascal Boolean   StringEqual();
pascal void ReturnToPas();
pascal void ScanToReturn();
pascal void ScanToZero();
Listing 3:

/************************************/
/* File: XCMDGlue.c*/
/* */
/* Callback routines for XCMDs*/
/* and XFCNs.  This file should  */
/* be included in your project*/
/* */
/* Based on original work by*/
/* Dan Winkler of Apple Computer */
/* */
/************************************/

#include<MacTypes.h>
#include<OSUtil.h>
#include<MemoryMgr.h>
#include<FileMgr.h>
#include<ResourceMgr.h>
#include  “HyperXCmd.h”
#include<math.h>

pascal void SendCardMessage(paramPtr,msg)
 XCmdBlockPtr  paramPtr;  
 StringPtrmsg;
/***********************
* Send a message back to 
* hypercard.  The input message
* is a Pascal String
***********************/
{
 paramPtr->inArgs[0] = (long)msg;
 paramPtr->request = xreqSendCardMessage;
    CallPascal( paramPtr->entryPoint );
}

pascal Handle EvalExpr(paramPtr,expr)
 XCmdBlockPtr  paramPtr;  
 StringPtrexpr;
/***********************
* Evaluate a Hypertalk expression
* returning the result as a “C” 
* string
***********************/
{
 paramPtr->inArgs[0] = (long)expr;
 paramPtr->request = xreqEvalExpr;
    CallPascal( paramPtr->entryPoint );
 return (Handle)paramPtr->outArgs[0];
}

pascal long StringLength(paramPtr,strPtr)
 XCmdBlockPtr  paramPtr;
 StringPtrstrPtr;
/***********************
* Counts the number of 
* characters in the input 
* string from StrPtr to end
* of string (zero byte)
***********************/
{
 paramPtr->inArgs[0] = (long)strPtr;
 paramPtr->request = xreqStringLength;
    CallPascal( paramPtr->entryPoint );
 return (long)paramPtr->outArgs[0];
}

pascal Ptr StringMatch(paramPtr,pattern,target)
 XCmdBlockPtr  paramPtr;  
 StringPtrpattern;
 Ptr    target;
/***********************
* Case-insensitive match 
* for pattern anywhere in
* target, 
* 
* Returns a pointer to first
* character of the first match,
* in target or NIL if no match
* found.  pattern is a Pascal string,
* and target is a zero-terminated string.
***********************/
{
 paramPtr->inArgs[0] = (long)pattern;
 paramPtr->inArgs[1] = (long)target;
 paramPtr->request = xreqStringMatch;
    CallPascal( paramPtr->entryPoint );
 return (Ptr)paramPtr->outArgs[0];
}

pascal void ZeroBytes(paramPtr,dstPtr,longCount)
 XCmdBlockPtr  paramPtr;  
 Ptr    dstPtr;  
 long   longCount;
/***********************
* Clear memory starting at destPtr
* through destPtr+longCount
***********************/
{
 paramPtr->inArgs[0] = (long)dstPtr;
 paramPtr->inArgs[1] = longCount;
 paramPtr->request = xreqZeroBytes;
    CallPascal( paramPtr->entryPoint );
}

pascal Handle PasToZero(paramPtr,pasStr)
 XCmdBlockPtr  paramPtr;
 StringPtrpasStr;
/***********************
* Convert a Pascal string (STR255)
* to a zero-terminated string.  
* Returns a handle to a zero-terminated
* string.  The caller must dispose the handle.
*
* Useful for setting the result or
* an argument you send from 
* an XCMD to HyperTalk.
***********************/
{
 paramPtr->inArgs[0] = (long)pasStr;
 paramPtr->request = xreqPasToZero;
    CallPascal( paramPtr->entryPoint );
 return (Handle)paramPtr->outArgs[0];
}

pascal void ZeroToPas(paramPtr,zeroStr,pasStr)
 XCmdBlockPtr  paramPtr;  
 char   *zeroStr;
 StringPtrpasStr;
/***********************
* Copy the zero-terminated
* string into the Pascal String.
*
* You create the Pascal string 
* and pass it by reference.
*
***********************/
{
 paramPtr->inArgs[0] = (long)zeroStr;
 paramPtr->inArgs[1] = (long)pasStr;
 paramPtr->request = xreqZeroToPas;
    CallPascal( paramPtr->entryPoint );
}

pascal long StrToLong(paramPtr,strPtr)
 XCmdBlockPtr  paramPtr;  
 Str31  *strPtr;
/***********************
* Convert a string of ASCII
* characters to an unsigned 
* long integer.
***********************/
{
 paramPtr->inArgs[0] = (long)strPtr;
 paramPtr->request = xreqStrToLong;
    CallPascal( paramPtr->entryPoint );
 return (long)paramPtr->outArgs[0];
}

pascal long StrToNum(paramPtr,str)
 XCmdBlockPtr  paramPtr;  
 Str31  *str;
/***********************
* Convert a string of ASCII
* characters to a signed 
* long integer.
***********************/
{
 paramPtr->inArgs[0] = (long)str;
 paramPtr->request = xreqStrToNum;
    CallPascal( paramPtr->entryPoint );
 return paramPtr->outArgs[0];
}

pascal Boolean StrToBool(paramPtr,str)
 XCmdBlockPtr  paramPtr;
 Str31  *str;
/***********************
* Convert the Pascal strings
* ‘true’ and ‘false’ to booleans.
***********************/
{
 paramPtr->inArgs[0] = (long)str;
 paramPtr->request = xreqStrToBool;
    CallPascal( paramPtr->entryPoint );
 return (Boolean)paramPtr->outArgs[0];
}

pascal void StrToExt(paramPtr,str,myext)
 XCmdBlockPtr  paramPtr;
 Str31  *str;  
 long   *myext;
/***********************
* Convert a string of ASCII digits 
* to an extended long integer.
*
* The return value is passed
* by reference and you must
* asllocate the space before 
* calling this routine.
***********************/
{
 paramPtr->inArgs[0] = (long)str;
 paramPtr->inArgs[1] = (long)myext;
 paramPtr->request = xreqStrToExt;
    CallPascal( paramPtr->entryPoint );
}

pascal void LongToStr(paramPtr,posNum,mystr)
 XCmdBlockPtr  paramPtr;  
 long   posNum;  
 Str31  *mystr;
/***********************
* Convert an unsigned long integer
* to a pascal string representation
* Useful for sending numbers back 
* to Hypercard.
*
*  You create mystr and pass
* it by reference.
***********************/
{
 paramPtr->inArgs[0] = (long)posNum;
 paramPtr->inArgs[1] = (long)mystr;
 paramPtr->request = xreqLongToStr;
    CallPascal( paramPtr->entryPoint );
}

pascal void NumToStr(paramPtr,num,mystr)
 XCmdBlockPtr  paramPtr;  
 long   num;
 Str31  *mystr;
/***********************
* Convert a signed long integer
* to a pascal string representation
* Useful for sending numbers back 
* to Hypercard.
*
*  You create mystr and pass
* it by reference.
***********************/
{
 paramPtr->inArgs[0] = num;
 paramPtr->inArgs[1] = (long)mystr;
 paramPtr->request = xreqNumToStr;
    CallPascal( paramPtr->entryPoint );
}

pascal void NumToHex(paramPtr,num,nDigits,mystr)
 XCmdBlockPtr  paramPtr;  
 long   num;
 short  nDigits; 
 Str31  *mystr;
/***********************
* Convert an unsigned long integer
* to a hexadecimal number and put it
* into a Pascal string.
*
* The “output” string is passed
* by reference.
***********************/
{
 paramPtr->inArgs[0] = num;
 paramPtr->inArgs[1] = nDigits;
 paramPtr->inArgs[2] = (long)mystr;
 paramPtr->request = xreqNumToHex;
    CallPascal( paramPtr->entryPoint );
}

pascal void BoolToStr(paramPtr,bool,mystr)
 XCmdBlockPtr  paramPtr;  
 Booleanbool;  
 Str31  *mystr;
/***********************
* Convert a boolean to 
* ‘true’ or ‘false’.  
*
* The “output” string is passed
* by reference.
***********************/
{
 paramPtr->inArgs[0] = (long)bool;
 paramPtr->inArgs[1] = (long)mystr;
 paramPtr->request = xreqBoolToStr;
    CallPascal( paramPtr->entryPoint );
}

pascal void ExtToStr( paramPtr, myext, mystr)
 XCmdBlockPtr  paramPtr;  
 char   *myext;  
 Str31  *mystr;
/***********************
* Convert an extended long
* to its string representation
*
* The “output” string is passed
* by reference.
***********************/
{
 paramPtr->inArgs[0] = (long)myext;
 paramPtr->inArgs[1] = (long)mystr;
 paramPtr->request = xreqExtToStr;
    CallPascal( paramPtr->entryPoint );
}

pascal Handle GetGlobal(paramPtr,globName)
 XCmdBlockPtr  paramPtr;  
 StringPtrglobName;
/***********************
* Return a handle to a zero-terminated
* string containing the value of 
* the specified HyperTalk global variable.
***********************/
{
 paramPtr->inArgs[0] = (long)globName;
 paramPtr->request = xreqGetGlobal;
    CallPascal( paramPtr->entryPoint );
 return (Handle)paramPtr->outArgs[0];
}

pascal void SetGlobal(paramPtr,globName,globValue)
 XCmdBlockPtr  paramPtr;  
 StringPtrglobName;
 Handle globValue;
/***********************
* Set the value of the specified 
* HyperTalk global variable to be
* the zero-terminated string in globValue.
* The contents of globValue
* are copied, you dispose the
* handle
***********************/
{
 paramPtr->inArgs[0] = (long)globName;
 paramPtr->inArgs[1] = (long)globValue;
 paramPtr->request = xreqSetGlobal;
    CallPascal( paramPtr->entryPoint );
}

pascal Handle GetFieldByName(paramPtr,cardFieldFlag,fieldName)
 XCmdBlockPtr  paramPtr;  
 BooleancardFieldFlag;
 StringPtrfieldName;
/***********************
* Return a handle to a zero-terminated
* string containing the value of 
* field fieldName on the current 
* card.  You must dispose the handle.
*
* Set cardfieldFlag to ture if
* you want the contents of a card
* field or to false if you want
* the contents of a bkgnd field
***********************/
{
 paramPtr->inArgs[0] = (long)cardFieldFlag;
 paramPtr->inArgs[1] = (long)fieldName;
 paramPtr->request = xreqGetFieldByName;
    CallPascal( paramPtr->entryPoint );
 return (Handle)paramPtr->outArgs[0];
}

pascal Handle GetFieldByNum(paramPtr,cardFieldFlag,fieldNum)
 XCmdBlockPtr  paramPtr;  
 BooleancardFieldFlag;
 short  fieldNum;
/***********************
* Returns a copy of the contents of the field whose number is
* fieldnum on the current card.
* You dispose the handle when you are done.
***********************/
{
 paramPtr->inArgs[0] = (long)cardFieldFlag;
 paramPtr->inArgs[1] = fieldNum;
 paramPtr->request = xreqGetFieldByNum;
    CallPascal( paramPtr->entryPoint );
 return (Handle)paramPtr->outArgs[0];
}

pascal Handle GetFieldByID(paramPtr,cardFieldFlag,fieldID)
 XCmdBlockPtr  paramPtr;  
 BooleancardFieldFlag;
 short  fieldID;
/***********************
* Returns a copy of the contents of the field whose id is
* fieldID on the current card.
* You dispose the handle when you are done.
***********************/
{
 paramPtr->inArgs[0] = (long)cardFieldFlag;
 paramPtr->inArgs[1] = fieldID;
 paramPtr->request = xreqGetFieldByID;
    CallPascal( paramPtr->entryPoint );
 return (Handle)paramPtr->outArgs[0];
}

pascal void SetFieldByName(paramPtr,cardFieldFlag,fieldName,fieldVal)
 XCmdBlockPtr  paramPtr;  
 BooleancardFieldFlag;
 StringPtrfieldName; 
 Handle fieldVal;
/***********************
* Set the value of the field whose name is fieldName on 
* the current card.
* You dispose the handle when you are done.
***********************/
{
 paramPtr->inArgs[0] = (long)cardFieldFlag;
 paramPtr->inArgs[1] = (long)fieldName;
 paramPtr->inArgs[2] = (long)fieldVal;
 paramPtr->request = xreqSetFieldByName;
    CallPascal( paramPtr->entryPoint );
}

pascal void SetFieldByNum(paramPtr,cardFieldFlag,fieldNum,fieldVal)
 XCmdBlockPtr  paramPtr;  
 BooleancardFieldFlag;
 short  fieldNum;
 Handle fieldVal;
/***********************
* Set the value of the field whose number is fieldnum on 
* the current card.
* You dispose the handle when you are done.
***********************/
{
 paramPtr->inArgs[0] = (long)cardFieldFlag;
 paramPtr->inArgs[1] = fieldNum;
 paramPtr->inArgs[2] = (long)fieldVal;
 paramPtr->request = xreqSetFieldByNum;
    CallPascal( paramPtr->entryPoint );
}

pascal void SetFieldByID(paramPtr,cardFieldFlag,fieldID,fieldVal)
 XCmdBlockPtr  paramPtr;  
 BooleancardFieldFlag;
 short  fieldID; 
 Handle fieldVal;
/***********************
* Set the value of the field whose id is fieldID on 
* the current card.
* You dispose the handle when
* you are done.
***********************/
{
 paramPtr->inArgs[0] = (long)cardFieldFlag;
 paramPtr->inArgs[1] = fieldID;
 paramPtr->inArgs[2] = (long)fieldVal;
 paramPtr->request = xreqSetFieldByID;
    CallPascal( paramPtr->entryPoint );
}

pascal Boolean StringEqual(paramPtr,str1,str2)
 XCmdBlockPtr  paramPtr;  
 Str31  *str1; 
 Str31  *str2;
/***********************
* Returns true if the strings match, false otherwise.
* Compare is case insensitive
***********************/
{
 paramPtr->inArgs[0] = (long)str1;
 paramPtr->inArgs[1] = (long)str2;
 paramPtr->request = xreqStringEqual;
    CallPascal( paramPtr->entryPoint );
 return (Boolean)paramPtr->outArgs[0];
}

pascal void ReturnToPas(paramPtr,zeroStr,pasStr)
 XCmdBlockPtr  paramPtr;  
 Ptr    zeroStr; 
 StringPtrpasStr;
/***********************
* Collect characters from zeroStr
* to the next carriage Return and return 
* them in the Pascal string pasStr. 
* If no Return found, collect chars
* until the end of the string (zero)
***********************/
{
 paramPtr->inArgs[0] = (long)zeroStr;
 paramPtr->inArgs[1] = (long)pasStr;
 paramPtr->request = xreqReturnToPas;
    CallPascal( paramPtr->entryPoint );
}

pascal void ScanToReturn(paramPtr,scanHndl)
 XCmdBlockPtr  paramPtr;  
 Ptr    *scanHndl;
/***********************
* Position the pointer, scanPtr,at a Return character
* or a zero byte. 
***********************/
{
 paramPtr->inArgs[0] = (long)scanHndl;
 paramPtr->request = xreqScanToReturn;
    CallPascal( paramPtr->entryPoint );
}

pascal void ScanToZero(paramPtr,scanHndl)
 XCmdBlockPtr  paramPtr;  
 Ptr    *scanHndl;
/***********************
* Position the pointer, scanPtr,
* at a  zero byte. 
***********************/
{
 paramPtr->inArgs[0] = (long)scanHndl;
 paramPtr->request = xreqScanToZero;
    CallPascal( paramPtr->entryPoint );
}

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, don’t remind me I could currently buy him this month I’m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »
MoreFun Studios has announced Season 4,...
Tension has escalated in the ever-volatile world of Arena Breakout, as your old pal Randall Fisher and bosses Fred and Perrero continue to lob insults and explosives at each other, bringing us to a new phase of warfare. Season 4, Into The Fog of... | Read more »
Top Mobile Game Discounts
Every day, we pick out a curated list of the best mobile discounts on the App Store and post them here. This list won't be comprehensive, but it every game on it is recommended. Feel free to check out the coverage we did on them in the links below... | Read more »
Marvel Future Fight celebrates nine year...
Announced alongside an advertising image I can only assume was aimed squarely at myself with the prominent Deadpool and Odin featured on it, Netmarble has revealed their celebrations for the 9th anniversary of Marvel Future Fight. The Countdown... | Read more »
HoYoFair 2024 prepares to showcase over...
To say Genshin Impact took the world by storm when it was released would be an understatement. However, I think the most surprising part of the launch was just how much further it went than gaming. There have been concerts, art shows, massive... | Read more »

Price Scanner via MacPrices.net

Apple Watch Ultra 2 now available at Apple fo...
Apple has, for the first time, begun offering Certified Refurbished Apple Watch Ultra 2 models in their online store for $679, or $120 off MSRP. Each Watch includes Apple’s standard one-year warranty... Read more
AT&T has the iPhone 14 on sale for only $...
AT&T has the 128GB Apple iPhone 14 available for only $5.99 per month for new and existing customers when you activate unlimited service and use AT&T’s 36 month installment plan. The fine... Read more
Amazon is offering a $100 discount on every M...
Amazon is offering a $100 instant discount on each configuration of Apple’s new 13″ M3 MacBook Air, in Midnight, this weekend. These are the lowest prices currently available for new 13″ M3 MacBook... Read more
You can save $300-$480 on a 14-inch M3 Pro/Ma...
Apple has 14″ M3 Pro and M3 Max MacBook Pros in stock today and available, Certified Refurbished, starting at $1699 and ranging up to $480 off MSRP. Each model features a new outer case, shipping is... Read more
24-inch M1 iMacs available at Apple starting...
Apple has clearance M1 iMacs available in their Certified Refurbished store starting at $1049 and ranging up to $300 off original MSRP. Each iMac is in like-new condition and comes with Apple’s... Read more
Walmart continues to offer $699 13-inch M1 Ma...
Walmart continues to offer new Apple 13″ M1 MacBook Airs (8GB RAM, 256GB SSD) online for $699, $300 off original MSRP, in Space Gray, Silver, and Gold colors. These are new MacBook for sale by... Read more
B&H has 13-inch M2 MacBook Airs with 16GB...
B&H Photo has 13″ MacBook Airs with M2 CPUs, 16GB of memory, and 256GB of storage in stock and on sale for $1099, $100 off Apple’s MSRP for this configuration. Free 1-2 day delivery is available... Read more
14-inch M3 MacBook Pro with 16GB of RAM avail...
Apple has the 14″ M3 MacBook Pro with 16GB of RAM and 1TB of storage, Certified Refurbished, available for $300 off MSRP. Each MacBook Pro features a new outer case, shipping is free, and an Apple 1-... Read more
Apple M2 Mac minis on sale for up to $150 off...
Amazon has Apple’s M2-powered Mac minis in stock and on sale for $100-$150 off MSRP, each including free delivery: – Mac mini M2/256GB SSD: $499, save $100 – Mac mini M2/512GB SSD: $699, save $100 –... Read more
Amazon is offering a $200 discount on 14-inch...
Amazon has 14-inch M3 MacBook Pros in stock and on sale for $200 off MSRP. Shipping is free. Note that Amazon’s stock tends to come and go: – 14″ M3 MacBook Pro (8GB RAM/512GB SSD): $1399.99, $200... Read more

Jobs Board

*Apple* Systems Administrator - JAMF - Syste...
Title: Apple Systems Administrator - JAMF ALTA is supporting a direct hire opportunity. This position is 100% Onsite for initial 3-6 months and then remote 1-2 Read more
Relationship Banker - *Apple* Valley Financ...
Relationship Banker - Apple Valley Financial Center APPLE VALLEY, Minnesota **Job Description:** At Bank of America, we are guided by a common purpose to help Read more
IN6728 Optometrist- *Apple* Valley, CA- Tar...
Date: Apr 9, 2024 Brand: Target Optical Location: Apple Valley, CA, US, 92308 **Requisition ID:** 824398 At Target Optical, we help people see and look great - and Read more
Medical Assistant - Orthopedics *Apple* Hil...
Medical Assistant - Orthopedics Apple Hill York Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Now Read more
*Apple* Systems Administrator - JAMF - Activ...
…**Public Trust/Other Required:** None **Job Family:** Systems Administration **Skills:** Apple Platforms,Computer Servers,Jamf Pro **Experience:** 3 + years of Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.