UCMDs & XCMDs 3.0.3

UserLand Software, Inc.

© copyright 1992-94, UserLand Software, Inc.

UserLand Software is the developer of the UserLand Frontier scripting system. The company is located at 555 Bryant #237, Palo Alto, CA 94301. 415-326-7791, 415-326-7793 (fax). UserLand, Frontier, Frontier Runtime and Frontier Extras are trademarks of UserLand Software, Inc. Other product names may be trademarks or registered trademarks of their owners.

Email: userland.dts@applelink.apple.com. If youÕre an AppleLink user, check out the UserLand Discussion Board under the Third Parties icon. CompuServe users enter GO USERLAND at any ! prompt. The UserLand Forum is in the Computing Support section on CompuServe. On America On-Line, enter the keyword USERLAND.

Comments, questions and suggestions are welcome!

Background

Frontier supports two kinds of code extensions: UCMDs and XCMDs.

In both models, you use a C or Pascal compiler to create a code resource in a Macintosh file, and then use a Frontier ŅdropletÓ to copy the code resource into the Frontier object database. Once the code is in the database, your scripts can call them, send parameters, and receive returned values. Several example code extensions are included in this folder.

XCMD support in Frontier allows script writers to tap into part of the large base of HyperCard 1.0-compatible code extensions. The architecture of XCMDs is well-understood, and for many programmers it represents a very easy way to extend the UserTalk language.

But we didnÕt want to stop there. We felt that there were limits to XCMDs that could easily be erased, and there were good reasons for us to invest in a new design for code extensions, one that is very compatible with the System 7 Apple Event Manager. Those are UCMDs. The ŅUÓ is for ŅUserTalk,Ó the scripting language that forms the heart of Frontier.

This folder, which is part of Frontier SDK, contains a set of tools, sample code and projects that can help get you started writing XCMDs and UCMDs that work with the upcoming release of Frontier.

System.extensions is a new standard table in Frontier 2.0 and 3.0. All UserLand-supplied code extensions are loaded into this table. You can load things into this table too, in fact we suggest that you do. It makes sense to keep all code extensions in one place in the userÕs object database.

As usual, the sample code is provided for Think C 6.0, but the techniques can be adapted for use with any Macintosh development system that can produce code resources.

As you browse thru the folders in the UCMDs & XCMDs folder, youÕll see Frontier install files for each of the extensions. To install one in your object database just double-click on its icon in the Finder.

UCMDs or XCMDs?

Tradeoffs

If youÕre writing a new code extension for Frontier, you can write either a UCMD or an XCMD. Naturally, UCMDs are a better fit for Frontier. But XCMDs can be faster and smaller, and a lot of people already know how to write XCMDs. In this section we list the advantages of each kind of code extension.

Advantages of XCMDs:

  XCMDs can be faster, ranging from 1.3 times faster to 1.9 times faster. See the benchmark script at system.extensions.stringOps.test2 for background.

  XCMDs are usually smaller. The minimum code size for a UCMD is approximately 2500 bytes, XCMDs can be as small as 500 bytes.

  XCMDs are a widely understood kind of code extension. For many people thereÕs nothing new to learn.

Advantages of  UCMDs:

  One code resource can implement many functions. See trigCmd for an example.

  Parameters and returned values can be of a many different types, unlike XCMDs which view all data as strings.

  They can return multiple values, and scripts can access these cleanly using FrontierÕs complexEvent built-in verb.

  They can have globals used to communicate between functions contained within the UCMD.

  They use the IAC Tools library, without modifications, so code can move easily from applications to code extensions and back very easily.

  Once you learn how to write a UCMD, youÕve learned how to program Apple Events. Since this is the form of interapplication communication that both UserLand and Apple are  evangelizing, this feature has tremendous appeal.

UCMDs

The UCMD Toolkit

A small toolkit is included in this package called the UCMD Toolkit.

The main () routine for your code extension is in ucmd.c. It sets up your globals, copies the event and reply pointers into the IACglobals record, and then calls your routine UCMDmain.

An additional routine, runscript, is provided in ucmdrunscript.c. If your UCMD wants to call back to Frontier, include this file in your project. An example is included in the scriptRunner UCMD.

Over time, the UCMD Toolkit may grow in size. If you have any suggestions for services that the UCMD Toolkit could provide, please let us know.

Your UCMD main file should #include ucmd.h. It contains prototypes for the two routines supplied in the UCMD Toolkit folder, and also brings in the header file for the IAC Tools library.

UCMDs and IAC Tools

UCMDs are built on top of the IAC Tools library. Each project file should include as many of the iacxxx.c files as necessary to build the project. In our sample code we include all the IAC Tools files; we depend on THINK CÕs smart linking to exclude the code for modules that we donÕt call.

When itÕs time to release your UCMD, you might want to copy the IAC Tools routines you depend on into a separate file to make the resulting UCMD as small as possible.

Using a compiled IAC Tools Library

If youÕre using a compiled form of IAC Tools as a library in your project, make sure itÕs built with A4 addressing, not A5 addressing. One of our test sites mistakenly built a UCMD with A5 addressing. Things didnÕt work too well!

There is no specific switch to turn on A4 addressing in THINK C. In the Set Project Type dialog, be sure that ŅCode ResourceÓ is checked off before building the IAC Tools library.

The Apple Event refcon

Each Apple Event comes with three parameters: a pointer to the incoming Apple Event record, a pointer to the reply record, and a 4-byte refcon. In Frontier 2.0 and 3.0, this refcon is always 0. ItÕs reserved for future versions of Frontier. If you have any ideas for how we should use this refcon, please let us know.

Writing a new UCMD

1.  In the Finder, copy one of the folders in the UCMD folder using the FinderÕs Duplicate command. Change the name of the project file and the C source file to reflect the name of your UCMD.

2.  Open the project file. Choose the Set Project Type command in THINK CÕs Project menu. Change the name item to reflect the name of your UCMD.

3.  When youÕre ready to build the project, select the Build Code Resource command from the Project menu. Name the file xxx.ucmd, where xxx is the name of your UCMD.

4.  To load the UCMD into your Frontier object database, drag and drop the xxx.ucmd file onto the Load CMD Droplet.

UCMD glue scripts

The glue scripts for UCMDs work much the same way as glue scripts for Apple Event-aware programs, with one important exception. Instead of the target of the appleEvent call being the creator id of a program, the target is the address of the object database cell that holds the UCMD code.

The stringOps UCMD implements a single Apple Event, it converts its string parameter to upper case. There are two entries in the system.extensions.stringOps table, allUpper and code.

 

HereÕs how the allUpper script connects outside callers to the UCMD:

You can call it from the Quick Script window as follows:

By convention, all UCMD and XCMD code objects are loaded into a sub-table in system.extensions with the same name as the code resource. Inside the sub-table, the name of the XCMD or UCMD is Ņcode.Ó For UCMDs there are one or more glue scripts that call the appleEvent built-in to talk to the UCMD code. The only difference for XMCDs is that their single glue script uses the callXCMD Frontier kernel call.

These conventions are supported by the Load CMD droplet.

XCMDs

XCMDs versus XFCNs

We use the term ŅXCMDÓ to refer to all X-things, as seems to be the convention in the Hyper world.

Why use XCMDs instead of XFCNs? There doesnÕt seem to be a good reason. All Frontier scripts are expected to return a value, even if itÕs just a boolean true. Therefore, if youÕre writing a new XCMD code extension, we suggest that you return a value, and use the XFCN shells we provide as a starting point.

XCMD callbacks

HyperCard 1.0 callbacks are supported to the extent that they make sense in the Frontier environment, including most of the HyperTalk Utilities and all of the String Utilities and String Conversions. In addition, the HyperCard 2.0 SendHCEvent callback is supported.

RunHandler and the Field Utilities are not currently supported. Unsupported callbacks are well-behaved; they return NIL and set the return code to xresNotImp.

When calling EvalExpr, SendCardMessage, or SendHCMessage, the message or expression must be a valid UserTalk script. All three of these callbacks execute the script, but only EvalExpr returns the result.

When getting or setting a global, any value in the current scriptÕs scope can be named. If SetGlobal is called with a name that isnÕt defined and isnÕt a dotted database path, the value is placed in the scratchpad table. If GetGlobal is called with a name that isnÕt defined, an error is returned.

In general, we do not recommend that you call WaitNextEvent in your XCMD, but if you do itÕs important that you use the SendHCEvent callback to allow Frontier to processes events that you donÕt respond to.

Writing a new XCMD

1.  In the Finder, copy one of the folders in the XCMD folder using the FinderÕs Duplicate command. Change the name of the project file and the C source file to reflect the name of your XCMD.

2.  Open the project file. Choose the Set Project Type command in THINK CÕs Project menu. Change the name item to reflect the name of your XCMD.

3.  When youÕre ready to build the project, select the Build Code Resource command from the Project menu. Name the file xxx.xcmd, where xxx is the name of your XCMD.

4.  To load the XCMD into your Frontier object database, drag and drop the xxx.xcmd file onto the Load CMD Droplet.

The callXCMD built-in

The callXCMD verb returns the value returned by the XCMD or XFCN Ń a string. If an XCMD doesnÕt return a value, callXCMD will return true. If an XFCN doesnÕt return a value, callXCMD returns the empty string.

The first parameter to callXCMD is the address of the XCMD binary object. It is followed by the XCMDÕs parameters, all of which are implicitly coerced to strings.

HyperCard 1.0 callbacks are supported to the extent that they apply to the Frontier environment. This includes EvalExpr, SendCardMessage, SendHCMessage, the memory and string utilities, and the string conversions. RunHandler and the field utilities are not currently supported. Unsupported callbacks are well-behaved; that is, they have no effect or return null values as appropriate.

Using the GetGlobal and SetGlobal callbacks, an XCMD can get or set the value of any variable defined in the context of the call, including local variables. Using EvalExpr, SendCardMessage, or SendHCMessage, an XCMD can execute any valid UserTalk script.

XCMD glue scripts

Glue scripts for XCMDs work much the same way as glue scripts for UCMDs with two exceptions:

1.  Usually there is only one glue script for each XCMD.
2.  XCMD glue scripts use the callXCMD built-in.

HereÕs what the stringupper XCMD glue script looks like:

You can call it from the Quick Script window as follows:

See ŅUCMD glue scripts,Ó above, for more information. For background on glue scripts, see the ŅFrontier Install File CreatorÓ sub-folder in the Utilities & Scripts folder.

HereÕs the complete list of supported XCMD callbacks:

  EvalExpr

  SendCardMessage

  SendHCMessage

  SendHCEvent

  GetGlobal

  SetGlobal

  ZeroBytes

  ScanToReturn

  ScanToZero

  StringEqual

  StringLength

  StringMatch

  ZeroTermHandle

  BoolToStr

  ExtToStr

  LongToStr

  NumToHex

  NumToStr

  PasToZero

  PointToStr

  RectToStr

  ReturnToPas

  StrToBool

  StrToExt

  StrToLong

  StrToNum

  StrToPoint

  StrToRect

  ZeroToPas

Sample UCMDs & XCMDs

stringOps UCMD

This UCMD implements a single Apple Event, it converts the single string parameter to upper case.

Enter the following into the Quick Script window. It displays HELLO WORLD! in the main window.

msg (stringOps.allUpper ("Hello World!"))

scriptRunner UCMD

Demonstrates the use of the runscript routine in the UCMD Toolkit.

The scriptRunner.do glue script takes one parameter, a string containing a UserTalk script which will be executed.

Enter the following into the Quick Script window. It displays a random number between 1 and 100 in FrontierÕs main window.

scriptRunner.do ("msg (random (1, 100))")

trigCmd UCMD

This is the UCMD version of the Trig sample application.

Check out trigCmd.examples for performance testing script and a oneLiners outline.

wordInfo UCMD

This UCMD implements three Apple Events that locate and count words in a string of text. Check out wordInfo.examples for a oneLiners outline and a script that tests UCMDs for memory leakage.

Note: weÕve also included wordInfo as an XCMD so you can easily compare the two different approaches.

stringupper XCMD

This XCMD converts the single string parameter to uppercase.

Enter the following into the Quick Script window. It displays HELLO WORLD! in the main window.

msg (stringupper.get ("Hello World!"))

This XCMD duplicates the stringOps UCMD. We used it in determining the performance differences between XCMDs and UCMDs.

syslargestblock XCMD

This XCMD returns the size of the largest block in the Macintosh system heap. ItÕs the same number thatÕs displayed by the About This Macintosh command in the FinderÕs š menu.

To call this XCMD from a script, weÕve provided a glue script thatÕs called as follows:

syslargestblock.get ()

sysfreemem XCMD

This XCMD returns the total number of free bytes in the Macintosh system heap.

To call this XCMD from a script, weÕve provided a glue script thatÕs called as follows:

sysfreemem.get ()

UCMDs & XCMDs 3.0.3 -- 7/27/94 dmb

Universal Headers, PowerPC compatibility

UCMDs and XCMDscan now be built using AppleÕs Universal Headers under Symantec C/C++ 7.0 or Metrowerks C/C++ 1.0 68K or PPC (UCMDs only). Native UCMDs can be generated in the Code Warrior environment. Also, ANSI-conformant function prototypes are used thoughout the code, so strict error checking can be enforced in your projects.

UCMDs & XCMDs 2.1 -- 11/3/93 DW

Convert the Load CMD Droplet to be faceless

Using the new Droplet Developer kit.

Test all sample UCMDs and XCMDs with Frontier 2.1

They work!