greitman@abel.ifistg.uucp (08/09/90)
I'm writing interface classes between Eiffel and Sun's XView-Toolkit (part of Open Windows Version 2.0 Beta). I'm working with a SPARC Station 1 under the Operating System SunOS Version 4.0.3c. There appeared some problems which are described in the following. 1. I have to pass the address of Eiffel features to "C". Here is my Eiffel feature with the appropriate "c"-call: left_mouse_down_add_me(button: XV_BUTTON) is external c_left_mouse_down_add_me(button: XV_BUTTON): INTEGER language "C"; do self := button; dummy := c_left_mouse_down_add_me(@self); -- pass the address of self to the "C" function. end; -- left_mouse_down_add_me In "C" the variable containing this address has the type OBJPTR. Then in the "C" -file I have the definition: static OBJPTR static_obj; and in file c_left_mouse_down_add_me in this file the assignment: static_obj = (OBJPTR) *obj; /* The notify procedure should be added to the Eiffel event left_mouse_down. It should be possible to write the action which should be executed at the event entry in Eiffel. int c_left_mouse_down_add_me(obj) int *obj; { int result; Xv_object *handle; static_obj = (OBJPTR) *obj; handle = (Xv_object *)eif_attr((OBJPTR)static_obj, "handle"); result = (int)xv_set(handle, PANEL_NOTIFY_PROC, left_mouse_down, NULL); return(result); } The function eif_attr in file _eifc.c doesn't return a correct value at the assignment index = search(Objptr, a_name, 0); int32 eif_attr (Objptr, a_name) OBJPTR Objptr; char *a_name; { DATUM index; index = search (Objptr, a_name, 0); if (index) return ((int32)(*(Access (Objptr)+index-1))); else ATTR_ERROR; } Function search in file _eifc.c stops with segmentation fault after the position: if (!strcmp (a_name, Attr_names [dtype][i])) return i+1. It looks like an initialization of Attr_names to "0" although it seems to be an array. Before this position I have following values: Objptr = (OBJPTR)0x6e2d0 a_name = (char *)0x58127 "handle" flag = 0 (!Objptr ||!a_name) = 0 dtype = 4 Object_size[dtype] = 1048577 nb_attr = 3 !flag = 1 i = 0 Attr_names[4][0]] =I/O Error, Cannot read memory, address 0x4 out of bounds. Attr_names[dtype][i] =I/O Error, Cannot read memory, address 0x4 out of bounds. Attr_names is of type int and it is initialized with value "0". I've got all these values running the debugger gdb on my root class. static unsigned int search (Objptr, a_name, flag) OBJPTR Objptr; char *a_name; int flag; { extern int16 obj_nb; register int16 i; char *tmp; char field_name [825]; int32 nb_attr, pos; int16 dtype; RESET; if (!Objptr || !a_name) return ((int32) 0); dtype = DType (Objptr); nb_attr = Object_size [dtype]; if (!flag) { for (i = 0; i < nb_attr; i++) if (!strcmp (a_name, Attr_names [dtype][i])) return i+1; } else { for (i =0; i < nb_attr; i++) { strcpy (field_name, Attr_names [dtype][i]); if (field_name [strlen (field_name)-1] == ' ') { tmp = Strtok (field_name, " "); for (pos=1; tmp != NULL; pos++) { if (!strcmp (a_name, tmp)) return ((i<<7) + pos + 1); tmp = Strtok (NULL, " "); } } } } } 2. Where do I find the definition of such types like OBJPTR, DATUM, DType, Attr_names, Attr_names[dtype][i], Strotok, etc ? 3. If you compile the file _eifc.c with Debug-Option (-g) you get two warnings (illegal combination of pointer and integer, op = ) in function search. static unsigned int search (Objptr, a_name, flag) OBJPTR Objptr; char *a_name; int flag; { extern int16 obj_nb; register int16 i; char *tmp; char field_name [825]; int32 nb_attr, pos; int16 dtype; RESET; if (!Objptr || !a_name) return ((int32) 0); dtype = DType (Objptr); nb_attr = Object_size [dtype]; if (!flag) { for (i = 0; i < nb_attr; i++) if (!strcmp (a_name, Attr_names [dtype][i])) return i+1; /* line 77 warning: illegal combination of pointer and integer, op = */ } else { for (i =0; i < nb_attr; i++) { strcpy (field_name, Attr_names [dtype][i]); if (field_name [strlen (field_name)-1] == ' ') { tmp = Strtok (field_name, " "); for (pos=1; tmp != NULL; pos++) { if (!strcmp (a_name, tmp)) return ((i<<7) + pos + 1); tmp = Strtok (NULL, " "); /* line 80 warning: illegal combination of pointer an dinteger, op = */ } } } } } 4. The documentation in the book "Eiffel: The Language Version2.2" about interfacing between Eiffel and "C" is absolutely insufficient. With only this information it is nearly impossible to write such interface classes. But we are dependant on such self written classes because the Eiffel Graphics Library Classes are not sufficient for our needs. Furthermore some parts like menus don't work at all. 5. Furtheron the graphical browser "GOOD" does not run at all. We have tested "GOOD" using Sun Open Windows Version 1.0 (X11 R3) and Open Windows Version 2.0 Beta (X11 R4) as well as MIT X11 R4. With all versions of X Windows "GOOD" crashed with segmentation fault. As "GOOD" is a very interesting tool especially to inspect the library classes delivered with the Eiffel system we hope that the next release of Eiffel will contain a running browser. 6. Another question during writing our interface classes is, wheather there are mechanisms to free data structures allacotated in "C" language parts based on the Eiffel garbage collection mechanism. This is a major problem because Eiffel has no facilities to write user defined destructor mechanisms. I hope that someone out there in netland or maybe at ISE can help us to solve the problems stated above. My request to ISE: If this is a known bug please patch it immediately and send us these patches. Many thanks in advance. Best regards Christiane Greitmann und Michael Ryba Stuttgart University Research Institut for Parallel and Distributed Supercomputers Department of Integrated Systems Design
nosmo@eiffel.UUCP (Vince Kraemer) (08/14/90)
Drs. Greitmann and Ryba at University of Stuttgart, in their article <3953@ifi.informatik.uni-stuttgart.de>, have stumbled across a common problem in the documentation concerning interfacing Eiffel to C via the eif_... routines. We are working to improve the documentation by producing an addendum for "Eiffel: the Language" and our other documentation. This addendum will be part of the documentation for the 2.3 release. The following extracts from the addendum concern (1) Eiffel to C interfacing (2) Passing objects to C and (3) Handling externally allocated resources, including memory, in the presence of garbage collection. These are all issues that were raised in their article. (1) Dealing with Eiffel objects from C Five routines are provided by the Eiffel run-time library to allow external C routines, which are linked into an Eiffel based executable, to manipulate Eiffel objects: eif_create, eif_rout, eif_attr, eif_rattr and eif_battr. The first routine, eif_create, is used to create an Eiffel object from C. Its return type is OBJPTR (an object pointer). A call to eif_create requires one argument: a lower case class name, which this object will be a member of. If the create routine for the named class requires arguments, these should be passed as additional arguments to eif_create, in the same order as they are required for the Create routine of the Eiffel class. Two important caveats apply to eif_create: * First, when you call eif_create, the class that you try to create must be part of the set of classes that make up a system. Put simply, this means that you cannot eif_create an object of a class that is not used as a feature or entity in the Eiffel code for the system. * The second caveat applies to Eiffel code as well: you may not create an instance of a deferred class. The following code segment illustrates the use of eif_create to create an Eiffel string object from C. (The ellipsis denote code which has been deleted for brevity.) #include "$EIFFEL/files/_eiffel.h" /* $EIFFEL should be replaced by the path to the base of the Eiffel installation tree. */ ... my_c_routine (..) { OBJPTR obj; ... obj = eif_create ("string", 20); /* Class string needs length argument. */ ... } Next, eif_rout provides access to Eiffel routines from C. Calling the routine is actually a two step process: first you need to find the correct routine to call and then you need to call it. Eif_rout handles the first task. The role of eif_rout is incorrectly documented in "Eiffel: the Language". Eif_rout takes two arguments, an OBJPTR and the name of a routine as a lower case string. It returns a ROUT_PTR, which is a pointer to a function returning a DATUM. If the object's class does not implement the routine named, a NULL pointer is returned. Since a ROUT_PTR is a pointer to a function, you must dereference it to call the corresponding function. The first argument to the dereferenced ROUT_PTR is an OBJPTR, which points at the target object, which comes before the period in an Eiffel, as in a.f (...). Any other arguments required by the Eiffel routine should be passed in the order specified in the Eiffel class text. Be sure that the OBJPTR passed as the first argument points to an object of exactly the same type as the OBJPTR used as the first argument to eif_rout. An example of the use of eif_rout is given below: /* assume that str1 and str2 are Eiffel objects (OBJPTR's) of class STRING either created by C or passed to C from Eiffel */ merge (str1, str2) OBJPTR str1, str2; { ROUT_PTR rout; rout = eif_rout (str1, "append"); (*rout)(str1, str2); } Note: The result of dereferencing the ROUT_PTR with the wrong number of arguments, an argument of the incorrect type or other possible abuses is undefined. To obtain the value of an attribute of an object, you can use the functions eif_rattr, eif_battr and eif_attr, provided by the run-time library. Each requires two arguments, an object instance (an OBJPTR) and the name of the attribute to access (a lower case string). The function eif_rattr returns a float, eif_battr returns an int that can be interpreted as a boolean value and eif_attr returns an int32, which can be used as an integer or a OBJPTR. One thing to note about the use of these three routines: they are applicable only to "true" attributes. Trying to access the value of functions that are playing the role of attributes is an undefined operation. (2) Passing Eiffel objects to External routines The easiest way to pass objects from Eiffel to external C routines is by naming the objects you wish to pass as part of the call. For example, if you want to pass the object referred to by the variable `my_obj' to an external routine `external_rout', write the call from Eiffel in the following fashion: external_rout (my_obj); The C function, external_rout, would be declared as follows: void external_rout (obj) OBJPTR obj; You can also use the "@" operator to perform this type of passing, but it is a bit more tedious. (Note: The "@" operator was originally intended for passing the address of routines only. In its original implementation, the application of the "@" to some non-routines, like local variables, was an unundetected error. This has been fixed in the 2.3 release so you may use "@" to pass the address of objects, known through both local entities and attributes, as well as routines). (3) Handling external resources in the presence of garbage collection. It is often necessary to access external resources from Eiffel systems, such as windowing systems, data-bases, etc. While it is often easy to determine when to allocate resources from Eiffel, it is more difficult to determine when to release these resources. The simple solution is to allow an object to release the resources when the object is guaranteed to be finished with them: when it is collected as garbage. To facilitate this, the class MEMORY, which is an interface to the garbage collector, defines the empty routine `dispose'. Classes which require explicit actions to be performed before they are collected should inherit from this class and redefine `dispose'. This is very applicable to situations where resources need to be de-allocated as the corresponding Eiffel objects are being disposed of. Consider the following code: class X_WINDOW export inherit ... MEMORY redefine dispose; ... feature window_ref: INTEGER; Create (parent: X_WINDOW) is -- Create an X_window object and allocate its -- corresponding X server entity. external create_x_window: INTEGER name "XCreateSimpleWindow" language "C" do window_ref := create_x_window (display.ref, parent.window_ref, 0, 0, 100, 200, 1, black, white); ... end; -- Create dispose is -- De-allocate the window on the X server external destroy_x_window name "XDestroyWindow" language "C" do destroy_x_window (display.ref, window_ref); end; -- dispose ... end -- Class X_WINDOW ---------------------- End of Addendum extracts ----------------------- From <3953@ifi.informatik.uni-stuttgart.de>: >2. >Where do I find the definition of such types like OBJPTR, DATUM, DType, >Attr_names, Attr_names[dtype][i], Strotok, etc ? The definition of types, variables and other entities used in the Eiffel run-time are in Eiffel/files/_eiffel.h and its parent ".h" files. >5. >Furtheron the graphical browser "GOOD" does not run at all. >We have tested "GOOD" using Sun Open Windows Version 1.0 (X11 R3) and >Open Windows Version 2.0 Beta (X11 R4) as well as MIT X11 R4. With all versions >of X Windows "GOOD" crashed with segmentation fault. We were aware that there were problems running GOOD on the Sun X11/NeWS merged server that is the basis for OpenWindows. We have just recently gotten OW 1.0.1 and OW 2.0 in house. We have found the problems with GOOD that were exercising invalid assumptions about colors, fonts, etc. and causing GOOD to fail due to the graphics library. These areas have been addressed and are part of the next release. We have not had problems with GOOD (2.2B) on the MIT server. If others have had problems like this, we are appreciate hearing more about it, through our customer support e-mail (eiffel@eiffel.com) or via phone (805) 685-1006 or fax (805) 685-6869. Vince Kraemer ISE Tech. Support (technical correspondence to: eiffel@eiffel.com)