XCMD Shell
Volume Number: 9
Issue Number: 6
Column Tag: Object-programming
Think C Shell for XCMDs 
Incorporating XCMDs into your application without alteration
By Gerry H. Kenner, Magna, Utah
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
About the author
Gerry Kenner is a professional electrical and computer engineering consultant,
university re searcher and sometimes writer who specializes in image analysis
systems for investigative scientists.
INTRODUCTION
Recently, I submitted an article to MacTech Magazine entitled “Three Subclasses
for Screen Input/Output” in which I described the creation of three THINK C classes
which I use as general utilities when developing applications. These classes were
named BGetTCLInfo, BDisplayDoc and BBitMapDoc whose functions were to ask for data
input, output data and output bitmap dumps respectively. In this article, I am going to
show how BGetTCLInfo and BDisplayDoc can be used for development of XCMDs. The use
of two other classes, BEditDoc and BEditPane will also be demonstrated.
The idea is to write XCMDs in such a way that they can be incorporated in either
THINK C application or code resource projects without alteration. The XCMD can be
written in standard C or it can be object oriented. Once incorporated into a THINK C
object oriented application shell, standard debugging techniques can be used to follow
the execution of the code.
The code resource project consists of the standard main function for interfacing
with HyperCard. This function then calls the code for the XCMD which is in a separate
file.
The application project is somewhat more complicated in that it initially creates
an object of class BGetTCLInfo for getting whatever information is needed by the XCMD,
puts it in HyperCard usable form, executes the XCMD code and then uses a BDisplayDoc
object to pass the results back to the programmer.
If the programmer wants to use HyperTalk utility functions, he must create a
code file named something like HyperUtil.c (or HyperXcmd.c for that matter) and
provide alternate source code for any functions called. I have not done this because I
feel that HyperTalk utilities should be avoided in favor of THINK C library functions or
SANE toolbox calls.
I haven’t had occasion to try it but programming windoids may be a problem.
Descriptions of the classes BGetTCLInfo, BDisplayDoc, BEditDoc and BEditPane
are not included in this article. The reader will need to obtain the February, 1993
issue (page 18) of MacTech Magazine in which they are described and/or purchase a
copy of the MacTech Magazine disk for this issue to get the source code. [Or you can
download it from one of the online services. - Ed.]
Disclaimer
As in my previous article, I am only including the code necessary to understand
the project. This code is enough for an intermediate programmer to fill in what is
missing. Typically, I do not declare variables or state which header files must be
included. A copy of the complete project is available on the MacTech Magazine disk.
CODE RESOURCE PROJECT
Description
This is a regular code resource with the difference that code resource specific
code is included in the main function while a call is made to the XCMD code which is in a
separate file. In this example the code necessary for setting up A4 addressing will not
execute properly in a standalone application so it executed in the main function of the
XCMD.
Create a new project named Flash.π and two empty code files named FlashXCMD.c
and Flash.c. Incorporate these files as well as the libraries ANSI-A4 and MacTraps
into the project. Flash.c will contain the XCMD code that is common to both the code
resource project and the application project. FlashXCMD.c will contain the main
function of the Flash code resource.
Set up the project to build a code resource named FlashXCMD of type XCMD with a
resource number such as 30.
Implementation
The code of the main function is as follows:
/* 1 */
pascal void main(XCmdPtr pp)
{
RememberA0(); // Setup and save register A4
SetUpA4();
FlashMain(pp);
RestoreA4();
}
RememberA0 and SetUpA4 set up A4 addressing while RestoreA4 removes it.
FlashMain is a call to the XCMD code. For the above code to compile, it is necessary to
#include the files SetUpA4.h and Flash.h.
FlashMain is part of a file named Flash.c. It contains code for flashing the screen
and beeping the number of times the user specifies in the HyperCard stack where the
XCMD is called. It then returns this number to HyperCard. Its code is as follows. This
method is based on a HyperCard XCMD demonstration program originally written by
Apple Computer.
/* 2 */
#include
#include
#include “Flash.h”
pascal void FlashMain(XCmdPtr paramPtr)
{
short again;
long flashCount;
Handle returnHdl;
GrafPtr port;
Str255 str, tempStr;
// First param is flash count.
// Convert it to a pascal string
returnHdl = NewHandle(256L);
strcpy((char*)str,
(char*)*(unsigned char **)paramPtr->params[0]);
CtoPstr((char*)str);
// Convert the string to a number
StringToNum(str, &flashCount);
PtoCstr((char*)str);
// Invert the screen and sound the beep.
GetPort(&port);
for (again = 0; again < flashCount; again++)
{
InvertRect(&port->portRect);
InvertRect(&port->portRect);
SysBeep(5);
}
// Build the return string.
strcpy((char*)tempStr, “The number of flashes was “);
strcat((char*)tempStr, (char*)str);
strcat((char*)tempStr, “ “);
strcat((char*)tempStr, (char*)”\r”);
strcpy((char*)*returnHdl, (char*)tempStr);
paramPtr->returnValue = returnHdl;
}
Short, brief and simple as an example should be. The only other thing you need to
know is that Flash.h contains the prototype declaration of the function FlashMain and
Create a HyperCard stack named Flash Stack with one button which contains the
following script.
/* 3 */
on mouseUp
put FlashXCMD(5) into msg
end mouseUp
Compile the code resource and merge it with the above stack. Run the XCMD to
confirm that it is functional.
STANDALONE APPLICATION
Description
The purpose of this object oriented code is to provide a dialog box asking for
input, convert it to a HyperCard usable format, call the XCMD code and then display
return information.
The easiest way to get the necessary project is to make a copy of THINK C’s
Starter Project, compile it and then make the appropriate name changes, i.e.,
Starter.π to FlashObject.π, Starter.c to FlashObject.c, StarterApp.c to flApp.c, etc.
Remove the StarterDoc and StarterPane classes from the project and eliminate any
references to them as they are not necessary. In the StarterApp files change all
instances of the prefix Starter with fl. Add all the dialog box classes. Add CButton,
CCheckBox, CIconPane, CRadioControl and CRadioGroupPane of the control classes. The
ANSI and SANE libraries will be required before the project is finished. Finally, add
Flash.c from above to the project.
Implementation
In this case, the main function will look something like this when the changes
have been made.
/* 4 */
#include “flApp.h”
void main()
{
flApp *theApp;
theApp = new flApp;
theApp->IflApp();
theApp->XcmdRun();
theApp->Exit();
}
The flApp object is entered via the XcmdRun method to avoid complications which
would result from overriding the Run method of the CApplication class.
In the flApp class, the methods CreateDocument and OpenDocument must be
overridden to become donothing methods or else removed entirely. This is to pr event
the creation of unwanted windows.
Four new methods need to be added to the flApp class. These are named XcmdRun,
GetParams, FillParamPtr and DumpData. They have the following functions.
XcmdRun Access method. Launch XCMD.
GetParams Get input parameters.
FillParamPtr Convert input parameters to HyperCard readable form.
DumpData Dump results to a window.
XcmdRun gets the input, sends it out for conversion, calls the XCMD and then
outputs the result. Its code is as follows.
/* 5 */
void flApp::XcmdRun(void)
{
XCmdPtr paramPtr;
char returnStr[1024];
paramPtr = (XCmdPtr)NewPtr(136L); // Size of XCmdBlock.
GetParams(returnStr);
FillParamPtr(paramPtr, returnStr);
FlashMain(paramPtr);
DumpData(paramPtr->returnValue);
// A real program would dispose of paramPtr and its handles
// at this point.
}
The parameter data is input by creating an object of class BGetTCLInfo which
displays a dialog box containing an edit text box into which information can be entered.
The format used for entering the information is “First set of data”,”Second set of
data”, etc just as is done in HyperCard scripts. In the case of our example, we would
enter something like “3”. By enclosing it between quotes just about anything
including 32k text files can be read in this way.
/* 6 */
void flApp::GetParams(char *paramStr)
{
#define DLOGinfo 601 // Resource ID for DLOG template
BGetTCLInfo *theDocument = NULL;
Rect boxDescription;
SetRect(&boxDescription, 20, 20, 260, 60);
theDocument = new(BGetTCLInfo);
theDocument->IBGetTCLInfo(DLOGinfo, this);
theDocument->GetInfo(“Number of flashs”, paramStr);
theDocument->Dispose();
}
The FillParamPtr method is a conversion routine which takes data input in the
format given above and creates handles pointing to the text between each pair of
quotation marks.
/* 7 */
void flApp::FillParamPtr(XCmdPtr paramPtr, char *paramStr)
{
short count = 0;
size_t theLength;
char *tempPtr, *tokenPtr;
char tokenStr[256];
tempPtr = paramStr;
while (*tempPtr != 0x00)
{
tokenPtr = (char*)&tokenStr;
if (*tempPtr == 0x22)
{
++tempPtr;
while (*tempPtr != 0x22)
{
*tokenPtr = *tempPtr;
++tempPtr;
++tokenPtr;
}
++tempPtr;
if (*tempPtr == 0x2C)
++tempPtr;
}
else
{
while (*tempPtr != 0x2C)
{
*tokenPtr = *tempPtr;
++tempPtr;
++tokenPtr;
}
++tempPtr;
}
*tokenPtr = 0x00;
theLength = strlen(tokenStr);
paramPtr->params[count] = NewHandle(theLength + 1);
strcpy((char*)*(paramPtr->params[count]), tokenStr);
++count;
}
paramPtr->paramCount = count;
}
FlashMain was listed above as part of the code resource project. It is found in the
Flash.c file.
Once the program has returned from the FlashMain call, the DumpData method is
called to create an output window displaying the data returned by the XCMD code. This
is done by creating an object of class BDumpData. The code is as follows.
/* 8 */
void flApp::DumpData(Handle theData)
{
BDisplayOutput *theOutput;
gBartender->DisableMenuBar();
theOutput = new BDisplayOutput;
theOutput->IBDisplayOutput(this, TRUE);
theOutput->DisplayRun(theData);
theOutput->Dispose();
}
Use the above listings to add the methods to the flApp.c file. Add the following
#include statements.
/* 9 */
#include "flash.h
#include "CBartender.h
#include "BGetTCLInfo.h
#include "BDisplayOutput.h
#include "size_t.h
#include "string.h
Make the appropriate changes in the flApp.h file and add #include
“HyperXCmd.h”. Add BGetTCLInfo.c, BDisplayOutput.c, BEditDoc.c and BEditPane.c to
the project. Add the DLOG and DITL resources listed below to the resource file.
Compile and do whatever additional tweaking is necessary. One of the tweaks will be to
increase the project memory to about 500k if it hasn’t already been done.
RESOURCES
DLOG and DITL resources numbered 601 must be added to provide a template for
the prompt dialog box. This consists of an OK button centered at the bottom, one line of
static text at the top with a large edit text box in between. The exact size and layout of
the resource are determined by programmer tastes and requirements.
RUNNING
When the project is run, a dialog box will appear soliciting user input. Type in a
number in quotation marks such as “5” just as it would appear in the parameter list
for a Hypercard call. The computer will then beep for the listed number of times but
will not flash. Finally, a window will appear with the message “The number of flashes
was 5”. Although interesting, I did not consider it worth the effort for this paper to
determine why the screen did not flash on a Power Book 100.
FINAL REMARKS
I have been using this system for over a year. The principle advantages over
using compiler statements to alternate between creating XCMDs and applications is that
readability is not sacrificed and the input/output capabilities make it easy to keep
track of what is going on.
I can be reached on internet at ghkenner@cc.utah.edu and AppleLink at UUTL.