Sozobon library of AES and VDI bindings This library is based on gemfast lib version 1.5 by Ian Lepore. It is called xgemfast, cause of some changes we did on it. The header file you have to include using this library is called xgemfast.h accordingly. So you can make use of other (original) versions of GEMFAST, too. 1. header files Use 'xgemfast.h' as header file for this extended gemlib version. 2. xvdifast.a It is based on vdifast library. optimized (Holger Weets) and bugs fixed (he and me) version number added: extern int _xvdifast lowbyte is revision, highbyte is version number. 2 functions added: int vq_gdos() returns FALSE if no GDOS is present (this was in gemlib.a) void c_vdi(int *pb[5]) interface for your own vdi functions (because they are not in this standard binding, etc.) all touched registers but D0 are saved by this function; it is not called vdi() cause it has an argument; usage: cause all vdi arrays are some dynamic binding (on stack) you have to create your own arrays when using this function: int contrl[12]; int intin[1]; /* see what you need */ int intout[1]; /* see what you need */ int ptsin[1]; /* see what you need */ int ptsout[1]; /* see what you need */ int *PB[5]; /* where: */ PB[0] = contrl; PB[1] = intin; PB[2] = ptsin; PB[3] = intout; PB[4] = ptsout; /* fill in the values from parameters */ contrl[0] = opcode contrl[1] = #ptsin /* (number of values in ptsin) */ contrl[2] = 0 contrl[3] = #intin /* (number of values in intin) */ contrl[4] = 0 contrl[5] = sub_opcode contrl[6] = vdi_handle /* contrl[7] = ... maybe some more values */ c_vdi(PB); /* maybe some code for getting values */ /* the function tells you : */ /* in contrl[2] #ptsout */ /* in contrl[4] #intout */ return(intout[0]); /* this is default */ 3. xaesfast.a It is based on aesfast library, version 1.5. optimized (Holger Weets) and bugs fixed (he and me) The following variables defined by AES are visible to your source code, after including 'xgemfast.h'. These AES-defined variables are documented in any manual or textbook on GEM programming. The gl_ names in this group are just aliases for the items in the global array. (That is, gl_apversion is just another name for global[0], etc.) int global[15]; aliased by following names... int gl_apversion; the AES version number (BCD) global[0] != 0 if any AES is present(after appl_init()) int gl_apcount; max # of concurrent AES applications global[1] == -1 if MultiTOS or another multitasking TOS is running int gl_apid; id of the current application global[2] the value appl_init() returned long gl_apprivate; anything application wants to store global[3,4] OBJECT **gl_apptree; pointer to array of object tree ptrs global[5,6] RSHDR *gl_aprshdr; pointer to head of rsc data global[7,8] (new name for gl_ap1resv) RSHDR *gl_ap1resv; address of resource file memory global[7,8] (Digital Research calls it ap_pmem) int gl_ap2resv[6]; more entries in global array Digital Research documented additionally following fields: global[9] ap_lmem global[10] ap_nplanes global[11] to global[14] reserved version number added: extern int _xaesfast lowbyte is revision, highbyte is version number. int fsel_emulation(char *PATH, char *name, int *button, char *title) This function is the original AESFAST function in which tested for the presence of >= TOS 1.4 and (if not found) simulated the modern file selector. SEE: fsel_sm(), fsel_input(), fsel_emulation() in GEMLIB.A: fsel(), fsel_e() and fsel_ex() which is the same like fsel_sm() function int fsel_sm(char *PATH, char *name, int *button, char *title) This function (small emulation) replaces the AES call fsel_exinput(), testing for the presence of >= TOS 1.4 and (if not found) simulated the modern file selector. This function does the same thing, like fsel_emulation() but has a new binding and is considerably smaller. It should reduce the size of any program using the old binding by 700 bytes. int fsel_exinput(char *PATH, char *name, int *button, char *title) This function replaces the function in AESFAST which tested for the presence of >= TOS 1.4 and (if not found) simulated the modern file selector. This function @{B}only@{b} tests wether to call fsel_exinput() or fsel_input() depending on the AES version. int fsel_input(char *PATH, char *name, int *button) Just a call of AES fsel_input() function. int evnx_multi(XMULTI *xm); Call evnt_multi() passing just a single pointer. Input: The xm parameter is a pointer to an XMULTI structure. Returns: The mask of events which occurred; xm->mwhich. Details: This function keeps all the input and output parms for an evnt_multi() call in a single structure. This is more efficient than stacking and unstacking 50-some bytes of parameters on each call, and it also allows you to "pass off" event handling to a series of event handlers by passing a single pointer to each handler. GemFast 2.0 will make heavy use of the latter technique. void rsc_treefix(OBJECT *ptree) Performs xywh fixup on all objects in a tree. Input: The ptree parameter is a pointer to the tree which needs resolution fixup. Details: This function calls rsrc_obfix() for every object in the tree. It's just a shortcut for calling the GEM object fixup for all objects in a tree, and does not provide any custom resolution fixup, scaling, etc. Use this function to do fixup on resource trees which are embedded in your source code. Do NOT use this function on trees loaded via rsrc_load(), since that function automatically applies resolution fixup as it loads the resource data. void rsc_gstrings(OBJECT *ptree, int object, char **ppstr, ...) Get the string pointers for one or more string-related objects in a dialog tree. Input: The ptree parameter is a pointer to the dialog tree containing the string-related objects. The object parameter is the index of the first object for which you want to retrieve the string pointer. The ppstr parameter is a pointer to your variable (char* type). The string pointer for the object is stored here. The ... parameters are additional object/ppstr pairs. Use an object number of -1 to indicate the end of the list. Details: This allows you to easily initialize your local string pointers to point at string-related objects in a dialog tree. The description of the obj_ppstring() function contains details on what objects are string-related. You must specify at least one object/ppstr pair following the tree pointer in the call. You can specify any number of pairs following the first one to retrieve the pointers for more than one object with a single call. Specify -1 for the index following the last pair. (There's no need to supply a pointer to go with the -1 object index.) This function understands how to find the real string pointer for each of string-related object type. It copes with the INDIRECT flag. It understands extended G_USERDEF objects, where ob_spec has been moved into the XUSERBLK. This function gives you pointers which point into the resource data area. If you modify the strings using these pointers, please remember that your resource editor has only allocated enough space in the resource data to hold the strings as you typed them when you built the object. In other words, you can define a button as "OK", and then at runtime use this function to get a pointer to the button text. But, if you do something like strcpy(buttonptr, "Not Okay"); then you end up corrupting the resource data, because you copied an 8-character string into a space only 2 characters wide. You can avoid this modify-in-place problem by defining your strings big enough in the resource editor, or by using rsc_sstrings() to make the objects point to strings allocated within your program rather than working with the strings directly in the resource data area. In this case, you can define dummy strings (I use "x") in the resource editor to avoid wasting space, since the strings you define are not used at runtime anyway after you use rsc_sstrings() to point objects at your program-defined strings. void rsc_sstrings(OBJECT *ptree, int object, char *pstr, ...) Set the string pointers for one or more string-related objects in a dialog tree. Input: The ptree parameter is a pointer to the dialog tree containing the string-related objects. The object parameter is the index of the first object for which you want to set the string pointer. The pstr parameter is a pointer to your string variable (char [] or "" type). This pointer is copied into the string object's string pointer field (ob_spec, te_ptext, etc). The ... parameters are additional object/pstr pairs. Use an object number of -1 to indicate the end of the list. Details: This allows you to easily initialize string-related objects in a dialog tree to point at strings defined within your program. The description of the obj_ppstring() function contains details on what objects are string-related. You must specify at least one object/pstr pair following the tree pointer in the call. You can specify any number of pairs following the first one to retrieve the pointers for more than one object with a single call. Specify -1 for the index following the last pair. (There's no need to supply a pointer to go with the -1 object index.) This function understands how to find the real string pointer for each of string-related object type. It copes with the INDIRECT flag. It understands extended G_USERDEF objects, where ob_spec has been moved into the XUSERBLK. This function attaches string data defined in your program to string-related objects in your dialog trees. This is especially handy for editable text objects, because some resource editors don't allocate enough space for the object in the resource data. If you define an editable text object and supply a te_pvalid string that allows 20 chars of input, but you define an initial string of "abc" for the field, some resource editors will only allocate 3 bytes of resource string space for the field. When the user enters 20 chars of data into the 3-byte field, other resource data gets corrupted. To avoid this, you can allocate a 20-byte character array in your program, and use this function to make the editable field's te_ptext pointer point at your array instead of the 3-byte area in the resource data. long rsc_gspec(tree, object); Get ob_spec value from an object within a tree. Input: Details: This function gets one string ob_spec from within a resource tree. It knows the difference between text and non-text objects, and gets the ob_spec value as appropriate. It also understands INDIRECT objects. char *rsc_gpointer (tree, object); Get pointer to single string within a tree. Input: Details: This function gets one string pointerfrom within a resource tree. It knows the difference between text and non-text objects, and gets the te_ptext value as appropriate. It also understands INDIRECT objects. void rsc_sspec(tree, object, obspec_value); This function sets one ob_spec from an object within a resource tree. Input: This function sets one ob_spec from within a resource tree. It knows the difference between text and non-text objects, and sets the ob_spec value as appropriate. It also understands INDIRECT objects. void rsc_spointer(tree, object, pointer); This function sets one string pointer from an object within a resource tree. Input: This function sets one string pointer from within a resource tree. It knows the difference between text and non-text objects, and sets the te_ptext value as appropriate. It also understands INDIRECT objects. GRECT * rc_gadjust(GRECT *prect, int hadjust, int vadjust) Adjust the size of a GRECT rectangle. Input: The prect parameter is a pointer to the rectangle to be adjusted. The hadjust parameter is the number of pixels to adjust by in the horizontal direction. Positive values enlarge the rectangle; negative values shrink it. The vadjust parameter is the number of pixels to adjust by in the vertical direction. Positive values enlarge the rectangle; negative values shrink it. Returns: The pointer to the rectangle. Details: This function makes a GRECT rectangle describe a larger or smaller area. The rectangle remains centered on its original location, and grows or shrinks equally on each side in the adjusted dimension(s). The x/y locations are never allowed to go negative (they are clipped to zero). The w/h sizes are never allowed to fall below 1. VRECT * rc_vadjust(VRECT *prect, int hadjust, int vadjust) Adjust the size of a VRECT rectangle. Input: The prect parameter is a pointer to the rectangle to be adjusted. The hadjust parameter is the number of pixels to adjust by in the horizontal direction. Positive values enlarge the rectangle; negative values shrink it. The vadjust parameter is the number of pixels to adjust by in the vertical direction. Positive values enlarge the rectangle; negative values shrink it. Returns: The pointer to the rectangle. Details: This function makes a VRECT rectangle describe a larger or smaller area. The rectangle remains centered on its original location, and grows or shrinks equally on each side in the adjusted dimension(s). The x/y locations are never allowed to go negative (they are clipped to zero). The w/h sizes are never allowed to fall below 1. GRECT *rc_vtog(VRECT *pvrect, GRECT *pgrect) Convert a VRECT rectangle to a GRECT rectangle. Input: The pvrect parameter is a pointer to the source VRECT. The pgrect parameter is a pointer to the destination GRECT. Details: The source VRECT is converted to the equivalent GRECT. Do NOT specify the same rectangle for source and destination. A VRECT describes an area by the x and y coordinates of diagonally opposite corners. A GRECT describes an area by x, y, width and height. This function translates a VRECT to a GRECT as follows: pgrect->g_x = pvrect->v_x1; pgrect->g_y = pvrect->v_y1; pgrect->g_w = pvrect->v_x1 - pvrect->g_x2 + 1; pgrect->g_h = pvrect->v_y1 - pvrect->g_y2 + 1; VRECT *rc_gtov(GRECT *pgrect, VRECT *pvrect) Convert a GRECT rectangle to a VRECT rectangle. Input: The pgrect parameter is a pointer to the source GRECT. The pvrect parameter is a pointer to the destination VRECT. Returns: The pointer to the destination VRECT. Details: The source GRECT is converted to the equivalent VRECT. Do NOT specify the same rectangle for source and destination. A GRECT describes an area by x, y, width and height. A VRECT describes an area by the x and y coordinates of diagonally opposite corners. This function translates a GRECT to a VRECT as follows: pvrect->v_x1 = pgrect->g_x; pvrect->v_y1 = pgrect->g_y; pvrect->v_x2 = pgrect->g_x + pgrect->g_w - 1; pvrect->v_y2 = pgrect->g_y + pgrect->g_h - 1; void rc_union(GRECT *sourcerect, GRECT *destrect) Computes a single rectangle that encompasses the area of both the original rectangles. Input: The sourcerect parameter is a pointer to the source rectangle. The destrect parameter is a pointer to the destination rectangle. The destination rectangle is used for input and output. Details: This function calculates the single large rectangle that encompasses all the area of both rectangles. This function does NOT clip to the physical screen automatically. Negative values in the returned x and y coordinates are possible if negative values existed in the inputs. int rc_intersect(GRECT *sourcerect, GRECT *destrect) Calculate the intersecting portion of two rectangles. Input: The sourcerect parameter is a pointer to the source (or clipping) rectangle. The destrect parameter is a pointer to the destination rectangle. The destination rectangle is used for input and output. Returns: TRUE (1) if the two rectangles intersect, or FALSE (0) if they do not intersect. When the return value is FALSE, the contents of the destination rectangle are undetermined. Details: You can think of this function as clipping the destination rectangle against the area of the source. On entry, the destination rectangle describes an area that may or may not have pixels in common with the source (or clipping) rectangle. This function modifies the destination rectangle to describe the area where the two rectangles intersect. If they don't intersect at all, this function returns FALSE, and the destination rectangle is left in an undetermined state. This function is typically used in window redraw loops, to process the window rectangle list. It can also be used in general-purpose drawing situations, especially to generate a clip rectangle to keep a blit from going outside the window work area or off the screen. This function does NOT clip to the physical screen automatically. Negative values in the returned x and y coordinates are possible if negative values existed in the inputs. void objcl_calc (OBJECT *tree, short object, GRECT *grect, VRECT *vrect); This routine simultaneously calculates the GRECT and VRECT clipping rectangles that describe an object. Input: grect: A pointer to a GRECT structure or NULL. vrect: A pointer to a VRECT structure or NULL. Details: If object has outside borders or is OUTLINED and/or SHADOWED, clipping sizes are calc'd accordingly. (This routine started out short and gracefull...) These routines have been re-classified as rectangle calcs, and are now found in AESUTRC5.S as rc_gadjust and rc_vadjust. Also, the docs for v1.3 utils state that objcl_calc is being phased out. void obj_flchange(OBJECT *ptree, int object, int newflags, int drawflag [ ,GRECT *cliprect ]) Change an object's flags, with optional redraw. Input: The ptree parameter is a pointer to the tree containing the object to change. The object parameter is the index of the object to change. The newflags parameter specifies which object flag bits to change; details below. The drawflag parameter specifies whether the object is to be visually updated on the screen, use one of the following: OBJ_NODRAW (0) - Don't update the screen. OBJ_WITHDRAW (1) - Update the screen. OBJ_CLIPDRAW (2) - Update the screen with clipping. The cliprect parameter is an optional pointer to a rectangle which will be used to clip the redraw of the object. This parameter is only used when the drawflag parameter is equal to OBJ_CLIPDRAW. Details: This function provides a simple way to change the object flag bits for any object. If the high bit of the newflags parameter is set, an AND is used to mask off bits in the object flags. If the high bit is not set, an OR is used to set bits in the object flags. This allows a newflags value of DEFAULT to set the default bit, and a value of ~DEFAULT to unset it. When the drawflag parameter is non-zero, an objc_draw() call is automatically done after the flags are changed. The objc_draw() is always done starting at the root object and drawing to MAX_DEPTH, and the draw is clipped to the on- screen rectangle of the object being changed. This allows a change that sets HIDETREE to properly hide the object visually, because the parent of the object is redrawn, but the object itself is not. When your dialog is in a window or another situation in which you might need to clip the redraw, use the OBJ_CLIPDRAW option, and provide a pointer to the clipping rectangle. If the draw option is not CLIPDRAW, the clip pointer need not be specified. void obj_stchange(OBJECT *ptree, int object, int newstate, int drawflag [, GRECT *cliprect ]) Change an object's state, with optional redraw. Input: The ptree parameter is a pointer to the tree containing the object to change. The object parameter is the index of the object to change. The newstate parameter specifies which object state bits to change; details below. The drawflag parameter specifies whether the object is to be visually updated on the screen, use one of the following: OBJ_NODRAW (0) - Don't update the screen. OBJ_WITHDRAW (1) - Update the screen. OBJ_CLIPDRAW (2) - Update the screen with clipping. The cliprect parameter is an optional pointer to a rectangle which will be used to clip the redraw of the object. This parameter is only used when the drawflag parameter is equal to OBJ_CLIPDRAW. Details: This function provides a simple way to change the object state bits for any object. If the high bit of the newstate parameter is set, an AND is used to mask off bits in the object flags. If the high bit is not set, an OR is used to set bits in the object flags. This allows a newstate value of SELECTED to set the bit, and a value of ~SELECTED to unset it. When the drawflag parameter is non-zero, an objc_draw() call is automatically done after the flags are changed. The objc_draw() is always done starting at object and drawing to MAX_DEPTH, and the draw is clipped to the on-screen rectangle of the dialog that contains it. When your dialog is in a window or another situation in which you might need to clip the redraw, use the OBJ_CLIPDRAW option, and provide a pointer to the clipping rectangle. If the draw option is not CLIPDRAW, the clip pointer need not be specified. void obj_offxywh(OBJECT *ptree, int object, GRECT *prect) Get the screen-adjusted xywh values for an object. Input: The ptree parameter is a pointer to the object tree. The object parameter is the index of the object. The prect parameter is a pointer to the rectangle into which the object's xywh values are returned. Details: This function gets the screen-adjusted xywh values for the object. It does NOT take into account that some objects are visually larger than their xywh values imply (ie, OUTLINED objects). Use the obj_clcalc() function if you need to account for the actual visual area an object occupies on the screen. void obj_xywh(OBJECT *ptree, int object, GRECT *prect) Get the xywh values for an object. Input: The ptree parameter is a pointer to the object tree. The object parameter is the index of the object. The prect parameter is a pointer to the rectangle into which the object's xywh values are returned. Details: This function gets the xywh values for the object. The values returned are straight from the object; they are relative to the object's parent, not to the screen. See Also: obj_offxywh() obj_clcalc() void rc_copy(void *sourcerect, void *destrect) Copy the source rectangle to the destination rectangle. Input: The sourcerect parameter is a pointer to the source rectangle. The destrect parameter is a pointer to the destination rectangle. Details: This copies a rectangle, or more accurately, 8 bytes of word-aligned data. int rc_equal(void *rect1, void *rect2) Returns TRUE if two rectangles are identical. Input: The rect1 and rect2 parameters are pointers to the rectangles to be compared. Returns: TRUE (non-zero) if the rectangles are identical, FALSE (0) if they're not. Details: For the rectangles to be identical, all four values (xywh) must be equal. More accurately, this function compares 8 bytes of word-aligned data. int obj_xtfind(OBJECT *ptree, int parent, int xtype) Finds the object with the specified extended object type. Input: The ptree parameter is a pointer to the tree. The parent parameter is the index of the parent which contains the objects to be scanned. The xtype parameter specifies the extended object type to search for. Returns: The index of the object having the specified extended type, or NO_OBJECT (-1) if nothing was found. Details: This function scans the children of the specified parent object. It compares the extended object type in each child to the specified xtype, and returns the index of the first object which matches. If none of the children have the specified extended type, NO_OBJECT is returned. Extended object types are stored in the upper byte of the ob_type word. GEM only uses the lower 8 bits of the ob_type value, and ignores any value in the upper 8 bits. All GemFast library routines which look at or set the ob_type field also work with the lower 8 bits, and ignore (or preserve) the upper 8 bits. So, you can stuff any 8-bit value you want into the upper 8 bits of the ob_type word. There's a zillion things you can do with it. See Also: obj_bmbuttons() rsc_sxtypes() int obj_rbfind(OBJECT *ptree, int parent, int rbstate) Finds the selected button in a group of radio buttons. Input: The ptree parameter is a pointer to the object tree. The parent parameter is the index of the parent which contains the radio buttons. The rbstate parameter is the ob_state mask to look for. Returns: The index of the selected object, or NO_OBJECT (-1) if no radio buttons are in the desired state. Details: This function walks through the children of the specified parent. For each child object with the RBUTTON bit set in the ob_flags, it does an AND of the child's ob_state against the rbstate parameter. It returns the index of the first child object which has a non-zero result from the AND. It returns NO_OBJECT if the result was zero for all children. The most common use of this function is to pass SELECTED for the rbstate parameter. Sometimes it's handy to use OUTLINED or another state to indicate selection of an object, so this function allows any state bit(s) to be specified. If you pass a combination of bits, (ie, (SELECTED|OUTLINED)), then this function finds the first radio button with either (not both) of those bits set. See Also: obj_rbselect() int obj_rbselect(OBJECT *ptree, int selobj, int selstate) De-selects current radio button, selects a new one. Input: The ptree parameter is a pointer to the object tree. The selobj parameter is the index of the new radio button to be selected. The selstate parameter specifies the ob_state bits which are turned off in the current radio button and turned on in the new one. Returns: The index of the radio button that was selected before the call, or NO_OBJECT if no buttons were previously selected. Details: This function is the easiest way to set a given radio button to a selected state. If a button in the group is already selected, this function de-selects it before selecting the new button. Note that this function does NOT update the buttons on- screen, it only changes the ob_state words. Use this for setting up a dialog before displaying it. After that, the GEM forms manager updates the ob_state and the on-screen object during dialog processing. See Also: obj_rbfind() int obj_parent(OBJECT *ptree, int object) Return the parent object for the specified object. Input: The ptree parameter is a pointer to the object tree. The object parameter is the index of the object. Returns: The index of the parent object. Details: By definition, the root object has no parent. If you try to get the parent of the root, zero is returned, as if the root were its own parent. int frmx_center(OBJECT *ptree, GRECT *prect) Call form_center() passing a single pointer for the return values. Input: The ptree parameter is a pointer to the object tree to be centered. The prect parameter is a pointer to a GRECT structure into which the on-screen sizes of the dialog are returned. Returns: TRUE (1) always. Details: This function allows you to pass a single pointer to an output rectangle, instead of the four pointers required by the standard form_center() function. See Also: frm_sizes() int winx_calc(int type, int kind, GRECT inrect, GRECT *outrect) Call wind_calc() passing a single pointer to the output. Input: The type, kind, and inrect parameters are identical to the corresponding wind_calc() parameters. The outrect parameter is a pointer to the output rectangle where the results of the calculation are stored. Returns: Zero on error, or non-zero on success. Details: Please note that the inrect parameter is a structure passed by value (4 values stacked) not a pointer to a rectangle. int winx_get(int whandle, int field, GRECT *outrect) Call wind_get() passing a single output pointer. Input: The whandle and field parameters are identical to the corresponding wind_get() parameters. The outrect parameter is a pointer to the output rectangle where the results of the query are stored. Returns: Zero on error or non-zero on success. Details: Please note that this function will always write 8 bytes of output to the memory location indicated by outrect even if the type of query you're doing normally returns less information that. (IE, don't use &integer_variable for this parameter, or the memory following the integer variable will be overwritten as well.) new AES functions added (MultiTOS) appl_search( short ap_smode, char *ap_sname, short *ap_stype, short *ap_sid); call: appl_search( ap_smode, ap_sname, &ap_stype, &ap_sid ); appl_getinfo( short ap_gtype, short *ap_gout1, short *ap_gout2, short *ap_gout3, short *ap_gout4 ); call: short ap_gtype, ap_gout1, ap_gout2, ap_gout3, ap_gout4; appl_getinfo( ap_gtype, &ap_gout1, &ap_gout2, &ap_gout3, &ap_gout4 ); menu_popup( MENU *me_menu, short me_xpos, short me_ypos, MENU *me_mdata); call: MENU me_menu, me_mdata; menu_popup( &me_menu, me_xpos, me_ypos, &me_mdata); menu_attach( short me_flag, OBJECT *me_tree, short me_item, MENU *me_mdata ); call: OBJECT *me_tree; MENU me_mdata; menu_attach( me_flag, me_tree, me_item, &me_mdata ); menu_istart( short me_flag, OBJECT *me_tree, short me_imenu, short me_item ); call: object *me_tree; menu_istart( me_flag, me_tree, me_imenu, me_item ); menu_settings( shrot me_flag, MN_SET *me_values ); call: MN_SET me_values; menu_settings( me_flag, &me_values ); rsrc_rcfix( RSHDR *rc_header ); call: RSHDR *rc_header; rsrc_rcfix( rc_header ); objc_sysvar( short ob_smode, short ob_swhich, short ob_sival1, short ob_soval1, short *ob_soval1, short *ob_soval2 ); call: short ob_smode, ob_swhich, ob_sival1, ob_soval1, short *ob_soval1, *ob_soval2; objc_sysvar( ob_smode, ob_swhich, ob_sival1, ob_soval1, &ob_soval1, &ob_soval2 ); Jerry Geiger, Berlin, July 1994