Hi Jimmy,
I've been wrestling with similar issues for the past 3 weeks. Three
weeks does not a C/C++ expert make, but here's what I've done:
> In C if the signature was (... tStatus *status) would it make a
difference?
Your "tStatus *status" parameter is an address, so I assume that the
C/C++ function may/probably will change the value of the declared
variable. IOW, if you declared
tStatus status
and then in C called the function like this
result = cpp_get_next(..., &status) /* C function call */
then I'd assume that "status" will change. Sorry if I'm stating the
obvious.
The question then is, what to do about "status"? It gets changed, and
the function also returns a value "result" (some sort of POINTER in your
example). You need to do something meaningful with 2 values returned by
the function, one as a parameter, and one as its return value. This is
common practice in C, but, as I've been reminded recently by Roger and
Helmut (very nicely and thoroughly convincingly), it's not recommended
in Eiffel to change the value of a parameter passed to a function in an
Eiffel feature. (It's probably not a good idea to do it in C either, but
it's seems to be universal.)
So what I've done is to take advantage of the new "inline" syntax, and
write C code in an Eiffel "external" routine that calls an Eiffel
"setter" command for the C parameter that changed. Let's assume, to keep
things simple, that your "status" is a C "int" (and not the more
complicated "tStatus"). In the Eiffel class MY_EIFFEL_WRAPPER you could
create an Eiffel attribute called "status":
status: INTEGER
and a setter routine:
feature {NONE} -- don't allow other objects to change "status"
set_status (s: INTEGER)
You would also need to make "set_status" visible (in the Project
Settings window, select the cluster in which the class appears, open the
"Advanced" element, select the value box of "Visible Classes", and in
the resulting dialog enter both the Eiffel class name and the
"set_status" feature name).
Now, for the Eiffel "external" routine. Add the Current object to the
parameter list of the external routine:
cpp_get_next (obj: MY_EIFFEL_WRAPPER)
external
"C++ inline use <c_header_file.h>"
alias
"[
// C++ code goes here
]"
end
MY_EIFFEL_WRAPPER is the Eiffel class with the "status" and "set_status"
features. You will need a C pointer to the Eiffel function "set_status"
in order to call it. That can be done this way:
// Insert following between the "[ and ]" tokens
in the alias part
// along with other C code
EIF_PROCEDURE ep_ss; // Pointer to Eiffel
function "set_status"
EIF_TYPE_ID tid;
tid = eif_type(arg1); // "arg1" is the
parameter whose type
// is
MY_EIFFEL_WRAPPER
ep_ss = eif_procedure("set_status",tid);
if(ep_ss == NULL) // for debugging only,
unnecessary once it's working
{
cout << "ep_ss not found/visible\n";
return EIF_<sometype>;
}
Now declare C/C++ variables, call the C/C++ function, and return the
"status" to the Eiffel class:
int status; // your case is more complicated
but the principle is the same
get_next (/* possible parameters */, &status);
(ep_ss) (eif_access(arg1),status); // call
"set_status" and pass "status"
In this way the "status" is returned to the Eiffel class and is visible
as an Eiffel attribute. The external function is free to return a result
as well, which may or may not also need to be assigned to an Eiffel
attribute.
I've simplified things--your "tStatus" type is doubtless more
complicated than an "int"--but you get the general idea. This approach
is working great for me, and conforms to the CQS convention.
Real Eiffel/C/C++ experts, please jump in!
David Jenkins