[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.2.2.1 Passed Arguments

All interesting extensions take arguments passed from the main program so that they can do different things depending on how they were called. In the case of picture generators, these arguments are passed from the Create Pictures from CXR (%I) command.

Here we would like our SHAPE extension to take several arguments. The first argument will be an integer which specifies which shape to draw: say 1 means circle, and 2 means square. Let's say that all squares will be drawn of the same size, 50x50 pixels. A circle, however, will have another argument, a radius. If the radius is nonzero, then a circle with a radius of that many pixels is drawn.

If the radius is zero, then the circle is drawn with the radius of the picture number. Remember that first argument you pass to %I is the number of pictures you want drawn. So, by specifying %I[50,1,0] we are asking Cogsys to generate 50 pictures, where the first picture has a circle of radius 1, the second of radius 2, and so on. By using the Multiframe Picture Display commands, you can show these 50 pictures in succession and create the animated effect of a growing circle.

So, let's see how we would write our shape.c file. We start with the standard extension header for a picture generator:

 
static void extension(unsigned char *A, unsigned char *arg) 

The header must be written exactly like this for all picture generators. The function is called extension, and it takes two arguments (that are filled in by Cogsys): 1) a playground, called A, and 2) an argument buffer, arg. Both are pointers to unsigned char. For maximum flexibility, they are untyped data blocks that can be interpreted any way that's necessary.

The playground is the block of data that holds the picture data. Essentially, all our extension will do is modify the array pointed to by A.

The argument buffer arg is the important one. By default, the argument buffer is exactly 1 kilobyte (1,024 bytes). This can be changed by the Cogsys developer via the Cogsys constant ARGBUF_SIZE (see section Setting Cogsys Constants). The argument buffer comes with 4 values (totalling 10 bytes) already filled in:

0000: 00 000002: 00 00 00 000006: 00 000008: 00 00
DATASEG external function's data segment
SIZE size of playground
NUMPICS total number of pictures requested
NUM this picture's number

The first value is discussed below under Data Segments. The next three values tell the extension important information about how it is being called. SIZE is a long integer that gives the size of the playground; it tells us how big A is. In all of the picture generating extensions included with Cogsys, Type 2 pictures are being displayed, which are 320x200 pixels, 1 byte per pixel, so SIZE is usually 64,000. NUMPICS is a short integer that indicates how many pictures were requested. This correpsonds directly to the first argument the user gave to %I. Finally, NUM tell us which of those NUMPICS pictures we are currently generating.

Starting at the 10th byte, the contents of arg are the values that the user passed in the %I command. Values are always one of three types: 1) a four byte long integer, or 2) a four byte float (not double), or 3) a null-terminated string. Note specifically that user-passed arguments are never short integers.

So in the case of our shape extension, the array has at least one more entry:

0010: 00 00 00 00
SHAPETYPE circle or square subfunction selector

Furthermore, if circle is selected, there is another entry for radius:

0014: 00 00 00 00
RADIUS raidus

These values are all embedded in the arg array, where they are hard to access. Thus the first variables we declare in the extension are usually size, numpics, and num. We then assign theese variables from the arg buffer by casting the unsigned char * to a type * (where type is the type of the argument we're extracting) and then dereferencing:

 
static void extension(unsigned char *A, unsigned char *arg)
{
  long  size;
  short numpics, num;

  /* Read in the standard arguments. */
  size    = *((long *)  (arg+2));
  numpics = *((short *) (arg+6));
  num     = *((short *) (arg+8));
}

(If that looks scary, don't worry about it, just copy those lines into the start of every extension you write and use size, numpics, and num as you would any integer.) We can use similar code to access our shapetype argument, and set up the switch structure. Inside the CIRCLE case, we get the radius argument, and if it's zero, adjust it to be the picture number instead:

 
#define CIRCLE 1
#define SQUARE 2

static void extension(unsigned char *A, unsigned char *arg)
{
  /* Standard arguments */
  long  size;
  short numpics, num;

  /* Custom arguments */
  long shapetype, radius;

  /* Read in the standard arguments. */
  size    = *((long *)  (arg+2));
  numpics = *((short *) (arg+6));
  num     = *((short *) (arg+8));

  shapetype = *((long *) (arg+10));

  switch shapetype 
    { 
    case CIRCLE:
      radius = *((long *) (arg+14));
      if (radius == 0)
        radius = num;
      break;
    case SQUARE:
      break;
    }

}

Strings can be handled similarly: let's say the first argument wasn't an integer code that represented what type of shape to draw, but instead a null-terminated ASCII string. The user would invoke the extension with something like this: %I[1,CIRCLE,5]. In the extension, we'd extract the arguments like this:

 
char *shapestr;
int  len;
...
shapestr = arg+10; /* no need for cast, arg is already ptr-to-char */
len      = strlen(shapestr);
radius   = *((long *) (arg+10+len));

if (strcmp(shapestr,"CIRCLE"==0)) ...
    

Of course, this technique isn't recommended for this case, because it takes more space and more time to process. But it is very important for extensions that display text, for example.

There is only one more important detail about argument passing that merits special attention:

The contents of the playground and the argument buffer are never reset by Cogsys.

This means that unless you want your image to be superimposed on the last thing in the playground (which could very well be garbage), you (that is, your extension) must explicitly reset all element of the A array to zero. It also means that you can deliberately not reset the array to create cool superimposition effects.

Similarly, the argument buffer is only updated with values most recently passed. For example, if a user creates a circle of radius 10 with our shape extension with the command %I[1,1,10], and then creates a square with %I[1,2], the value 10 is still present at location arg+14. This provides a neat means of passing values from one call of the extension to the next. A common technique is to save values near the high end of the buffer, where they won't ever get overwritten by a call to %I which has longer arguments.

More importantly, even though error checking for extensions is not implemented in Cogsys 3.0.15, when it is, it will be through this mechanism. If the extension catches an error, it writes error information in the high end of the argument buffer, and exits. Create Pics from CXR will check the argument buffer for error status after every call to the extension. If it finds an error, it will raise a main Cogsys error, and the list will terminate cleanly.

Here, then is the almost-complete shape extension source file (it won't work until the code described in Data Segments, is added).

 


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated by Usman Muzaffar on June, 28 2000 using texi2html