PocketC Native Libraries

Creating native libraries allows a PocketC developer to write code that executes faster than similar PocketC code. It also allows a user to expose functionality to a PocketC applet that PocketC's built-in library does not provide. Such libraries can be released for use by other developers, which helps the PocketC and Palm community.

This document does not cover aspects of PalmOS system libraries. In theory, all that you need to know about system libraries to create a PocketC native library is either included in the document, or is already written in the sample library. For more information, check the PalmOS SDK.

Assuming you have a copy of CodeWarrior installed, creating native libraries is almost trivial. Users who wish to use other tools, such as GCC, will need to do a little more work. At this time, OrbWorks will provide no support for GCC developers since we have not used or tested it. (If anyone is able to compile the sample with GCC, let us know so that we can help others).

There a few basic steps to create a PocketC library:

  1. Copy the PocketCLib project to a new directory into your CodeWarrior tree. Rename it whatever you like, and open it.
  2. Open the settings of the PocketCLib project, and change the output name and creator id. Creator ID's must be unique, so if you plan to release your library to the public, you must choose and register a unique ID with 3com. You may also need to change some of the include/lib paths.
  3. In PocketCLib.h:
  4. In PocketCLib.cpp:
  5. No changes are needing in PocketCLibDispatch.cpp
  6. In PocketCLib.lib (description file for PocketC Desktop Edition):
  7. Compile and enjoy!

General Info

Value

A value is the C++ datatype that represents all PocketC datatypes in the form of a union. A value has a type field, which describes the type of the value. Only one of the other fields is used (based on the type). A type can be one of vtInt, vtFloat, vtChar, or vtString.

Important: A string is stored somewhere in dynamic memory, and a value holds a handle to it, not a pointer. Once a value containing a string is no longer needed, it must be deleted using the cleanup() function.

Function Prototypes

A function declaration (created with a call to addFunc() ) consists of a name, a number of arguments, and a list of up to ten argument types. The arguments may be one of the standard types or can be of type vmVoid. A parameter of type vmVoid means that the compiler will not cast the parameter that is passed. In other words, the user can pass in any type of value, and no conversion is automatically performed.

The Stack

PocketC pushes all parameters on the the stack in the order they appear in the function declaration. So, a function declared with two parameters [func(int x, int y)] will have the x pushed on the stack first, followed by the y. Therefore, the first value popped off the stack will be the y.

Return Values

A function set the return value by setting the global variable retVal. When PocketC calls the library, the return value is set to type=vtInt, vtInt=0.

The C++ function

The C++ function that implements your PocketC library function will take only one parameter, a pointer to the global data. It will obtain the PocketC parameters by using the pop() function and will call cleanup() on all string parameters.


Standard Library Exports

PocketCLibOpen()

This function is called both at compile and run time. This function should set up your globals and return a pointer to you locked globals. The function pointers in the global structure are filled in after this call, so they are not yet available.

PocketCLibClose()

This function is called both at compile and run time. This function should free the global structure.

PocketCLibAddFunctions()

This function is called only at compile time. This function should add function prototypes by calling addFunc(). The first function added is given an index of 0.

PocketCLibExecuteFunction()

This function is called only at runtime. The function should contain a switch statement which calls your C++ functions to process the PocketC function call. The index of the functions must match the order in which they were added in PocketCLibAddFunctions().


Global Functions

pop(Value&)

pops a value off the stack. If it is a string value, you must call cleanup() on it when you are finished using it.

push(Value&)

pushes a value on the stack. The value is copied to the stack. If it is a string, the string is also copied, so you must call cleanup() on the original value after you push it on the stack.

cleanup(Value&)

Frees the memory held by a string value. If the value is not a string, no processing is done. (i.e. it is always safe to call cleanup(), even when not needed).

typeCast(Value&, VarType)

Casts a value to the given type. If the new value is a string, it must be freed when no longer needed. If the original value is a string which is converted to another type, the string is freed automatically.

typeMatch(Value&, Value&)

Casts both values to a matching type. For example, when this function is called with a float and an int, the int is cast to a float. If one is a string, the other is cast to a string.

UIYield(bool blocking)

Allows the system to process PalmOS events. This function also sets up the return values for the PocketC event() function and processing PalmOS events on behalf of PocketC. You must call this if your operation will take a while. If the blocking parameter is true, a single PalmOS event will be processed. If none are available, the system will wait for one. If blocking is false, the system will process all waiting messages and return.

callFunc(int location)

Calls the PocketC function at address location. Before this call, you must push the parameters on the stack (in the order of the function's parameter list). You can obtain the address of a function by accessing it in your PocketC source code without parentheses. (e.g. puts(main); will print the address of the function main). This function cannot be used to call PocketC's built in functions. Calling this function recursively is not very smart.

Important: The function's return value is placed on the stack. You must pop it off the stack after it has been called. A call to this function will modify retVal

callBI(char* name)

Calls the built-in PocketC function with the given name. Before this call, you must push the parameters on the stack (in the order of the function's parameter list). The function's return value is placed in retVal. So if it returns a string, you must clean it up (by calling cleanup()) before you overwrite retVal. This function returns false if the function is not found.

deref(int ptr)

Dereferences a PocketC pointer, returning a Value* which points to the memory to which the pointer refers. Remember, this is a pointer to the actual value, not a copy of it.


Using Native Libaries

To use a native library in a PocketC applet, you must instruct the compiler to load the library's functions. This is done through the library keyword.

Example:

// My Applet
library "PocketCLib"

main() {
   int x;
   x = times5(7);
}

The name of a library function cannot be the same as a user function. However, it may be the same as the name of a builtin function. In this case, the compiler will generate calls to the native library function rather than the builtin function.