G_Signals handling non-Gobject types? - c

The only example I was able to find for creating and emitting new signals was on the gnome developer site which provides the following example:
file = g_object_new (MAMAN_FILE_TYPE, NULL);
g_signal_connect (file, "changed", G_CALLBACK (changed_event), NULL);
maman_file_write (file, buffer, strlen (buffer));
/* ------------------ */
file_signals[CHANGED] =
g_signal_newv ("changed",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
NULL /* closure */,
NULL /* accumulator */,
NULL /* accumulator data */,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE /* return_type */,
0 /* n_params */,
NULL /* param_types */);
/* ------------------ */
void maman_file_write (MamanFile *self, const guchar *buffer, gssize size)
{
/* First write data. */
/* Then, notify user of data written. */
g_signal_emit (self, file_signals[CHANGED], 0 /* details */);
}
One thing I'm wondering is whether it's possible to emit signals which don't have a GObject as a source -- and whether it's possible to pass non-Gobject structures.
For simplicity sake suppose I have a function that creates point objects and I want to emit a signal when a point has been created (suppose there is some GtkWidget that displays something when a point is created):
struct point {
int x,y;
};
struct point *new_point(int x, int y) {
struct point *my_point = malloc(sizeof(point));
my_point->x= x;
my_point->y= y;
/* ???
g_signal_emit "point-created"
send pointer to my_point as a parameter to listeners
*/
return my_point;
}
Is there a way to make something akin to the lower work without all of the boiler plate that goes into creating a new G_OBJECT_TYPE ?

Related

Get the name of a coll object in Max C API

I am writing a Max MSP external.
I am lost in Max C API documentation since hours and couldn't find a way to get the name of a coll object from Max C API.
https://cycling74.com/sdk/max-sdk-8.0.3/html/index.html
If the object is | coll foo | , foo is the symbol I want to get.
I am able to iterate over a patcher and get pointers to all boxes and then to objects by calling jbox_get_object() with pointers to boxes. I tried getting many attributes of the objects I got and everything works ok.
I can't seem to find where the data I want to get is stored and what is it called.
I would appreciate some help.
Thank you.
[coll] is very sparsely documented, you should ask on the Cycling74 dev-forum. Below is what I do in [posit] after traversing the patcher to find a coll’s box. hth /*j
#include “coll.h”
<snip>
t_object *o;
t_coll *collob;
t_object *jb;
t_symbol *collname;
<snip>
o = jbox_get_object(jb);
collob = (t_coll *)o;
collname = (t_symbol *)collob->c_x->c_sym;
</snip>
Thank you user12106422! This is how I have implemented this in my iterator function and it works perfectly.
#include "coll.h"
//in your iterator function ..
long patcher_iterator(<replace this with your external type> *x, t_object *b) {
//check if object is a coll
if(strncmp(object_classname( jbox_get_object(b) )->s_name, "coll",4) == 0){
t_coll *collobject;
t_symbol *collname;
collob = (t_coll *)jbox_get_object(b);
collname = (t_symbol *)collobject->c_x->c_sym;
post("--The name of the coll is (%s) ", collname->s_name);
}
}
I would also like to share coll.h here for common benefit.
/* -------- coll.c -- the collection object --------------- */
#include "ext.h"
// #include "edit.h"
#include "ext_wind.h"
#include "ext_common.h"
#include "ext_strings.h"
#include "ext_critical.h"
#define C_EMBED 1
/* ddz 06/09/94:
* fixed interspersed (entremele) use of next and prev messages
* added assistance for third outlet
* prototyped functions and removed voids
* fixed truncating on sorts
*/
/* sde use to fill the read and write flags */
#define FILE_DIALOG 1 /* use dialogs to get file name */
#define FILE_NAMED 2 /* symbol specifies file name */
#define Index_Integer 1
#define Index_Symbol 2
typedef struct celem { /* doubly linked list element */
short e_size;
short e_extra;
long e_index;
t_symbol *e_assoc;
struct celem *e_next;
struct celem *e_prev;
t_atom e_data[1]; /* dummy */
} t_celem;
typedef struct xcoll {
t_object c_ob;
void *c_data; // linklist
//t_celem c_head; /* head of list elements */
t_celem *c_next; /* element to be returned by "next" */
t_celem *c_prev; /* element to be returned by "prev" */
void *c_out2; /* next "end" signal outlet */
char c_read,c_write; /* flags for reading & writing */
char c_freeing,c_saveme;
char c_embed; /* embed in owning patcher? */
t_symbol *c_sym; /* associated symbol? */
struct ed *c_edit; /* edit window */
short c_refcount; /* reference count */
struct coll *c_refcoll; /* list of "colls" that reference this xcoll */
/* sde filename, volume, and MAX type */
t_symbol *c_fn;
short c_vol;
short c_bin;
long c_type; /* type of the file that was read in */
short c_modified;
long c_filetype; /* for filetype message -- allowed types */
long c_modcount;
} t_xcoll;
typedef struct coll {
t_object c_ob;
t_xcoll *c_x;
t_symbol *c_sym;
void *c_out2;
/* sde third outlet bangs after reading data */
void *c_out3;
void *c_out4;
struct coll *c_nextref; /* next in the list of colls that share this coll's xcoll */
void *c_owner;
long c_nosearch;
} t_coll;

'cannot convert from...' error during callback assignations (migrated code from C)

I'm migrating some lines coded on C to C++/CLI (UI Windows Form based on .NET). One of my problems comes when I try to do this kind of assignation:
myCallbacks.cbf_data_write = this->dataWriteFunc;
In this case, dataWriteFunc is defined as:
PNIO_IOXS dataWriteFunc(PNIO_UINT32, PNIO_DEV_ADDR *, PNIO_UINT32, PNIO_UINT8 *, PNIO_IOXS);
And myCallbacks is declared as
PNIOD_CBF_FUNCTIONS myCallbacks;
with
typedef struct {
PNIO_UINT32 size; /* size of struct = sizeof(PNIO_CBF_FUNCTIONS) */
PNIO_CBF_DATA_WRITE cbf_data_write; /* mandatory */
PNIO_CBF_DATA_READ cbf_data_read; /* mandatory */
PNIOD_CBF_ASYNC_REC_READ cbf_async_rec_read; /* mandatory */
PNIOD_CBF_ASYNC_REC_WRITE cbf_async_rec_write; /* mandatory */
PNIOD_CBF_SYNC_ALARM_DONE cbf_sync_alarm_done; /* mandatory */
PNIOD_CBF_ASYNC_CONNECT_IND cbf_async_connect_ind; /* mandatory */
PNIOD_CBF_ASYNC_OWNERSHIP_IND cbf_async_ownership_ind; /* mandatory */
PNIOD_CBF_ASYNC_INDATA_IND cbf_async_indata_ind; /* mandatory */
PNIOD_CBF_SYNC_DISCONNECT_IND cbf_sync_disconnect_ind; /* mandatory */
PNIOD_CBF_SYNC_DATA_STATUS_IND cbf_sync_data_status_ind; /* mandatory */
PNIOD_CBF_ASYNC_PRM_END_IND cbf_async_prm_end_ind; /* mandatory */
PNIOD_CBF_SYNC_STOPPED cbf_sync_device_stopped; /* mandatory */
PNIOD_CBF_ASYNC_IRT_INIT_INPUTS cbf_async_irt_init_inputs; /* mandatory for IRT top */
PNIOD_CBF_SYNC_CP_STOP_REQ cbf_sync_cp_stop_req; /* optional */
PNIOD_CBF_SYNC_START_LED_FLASH cbf_sync_start_led_flash; /* optional */
PNIOD_CBF_SYNC_STOP_LED_FLASH cbf_sync_stop_led_flash; /* optional */
PNIOD_CBF_RESERVED
} ATTR_PACKED PNIOD_CBF_FUNCTIONS;
Also:
typedef PNIO_IOXS (*PNIO_CBF_DATA_WRITE) /* write data to IO stack (local ==> remote) */
(PNIO_UINT32 DevHndl, /* Handle for Multidevice */
PNIO_DEV_ADDR * pAddr, /* geographical address */
PNIO_UINT32 BufLen, /* length of the submodule input data */
PNIO_UINT8 * pBuffer, /* Ptr to data buffer to write to */
PNIO_IOXS Iocs); /* remote (io controller) consumer status */
So, what exactly I'm doing wrong? VS2012 gives me next error:
Error 4 error C2440: '=' : cannot convert from 'PNIO_IOXS (__thiscall CP1626::* )(PNIO_UINT32,PNIO_DEV_ADDR *,PNIO_UINT32,PNIO_UINT8 *,PNIO_IOXS)' to 'PNIO_CBF_DATA_WRITE' c:\users\hp\documents\visual studio 2012\projects\ui_cp1626\ui_cp1626\Profinet_IDevice.h 513 1 UI_CP1626
What's the correct form to associate callbacks in this case?
Thank you in advance.
You're trying to convert thiscall function (non-static class member function) to ordinary function. The problem is non-static class members take extra implicit argument, the pointer to class object aka this, so dataWriteFunc's implicit signature is:
PNIO_IOXS dataWriteFunc(CP1626 *this, PNIO_UINT32, PNIO_DEV_ADDR *,
PNIO_UINT32, PNIO_UINT8 *, PNIO_IOXS);
, note the 1st argument, it's implicit presence is what gives function "__thiscall" attribute. If you declare this function as
static PNIO_IOXS dataWriteFunc(PNIO_UINT32, PNIO_DEV_ADDR *,
PNIO_UINT32, PNIO_UINT8 *, PNIO_IOXS);
then the error will go away. Note that inside static methods this is not available.

Wireshark C dissector error when filling subtree

I have a simple Wireshark dissector which throws the following bug warning when it is run against a capture:
13:04:12 Warn Dissector bug, protocol usbserial, in packet 353: /wireshark/epan/proto.c:5504:
failed assertion "idx >= 0 && idx < num_tree_types"
The protocol registration function looks like this:
static gint ett_myproto = -1;
void
proto_register_myproto(void)
{
/* Set up field array */
static hf_register_info hf[] = {
{ &hf_myproto_payload,
{"Payload", "myproto.payload", FT_BYTES, BASE_NONE, NULL,
0x0, NULL, HFILL }},
};
/* Register protocol */
proto_myproto = proto_register_protocol("My Protocol", "myproto", "myproto");
/* Register protocol fields */
proto_register_field_array(proto_myproto, hf, array_length(hf));
/* Register the dissector */
register_dissector("myproto", dissect_myproto, proto_myproto);
}
The dissector does some general munging of data, but the core of the problem area seems to be:
static int
dissect_myproto(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
void *data _U_)
{
proto_item *ti;
proto_tree *myproto_tree;
/* Create top tree and add to the item */
ti = proto_tree_add_protocol_format(tree, proto_myproto, tvb, 0, -1,
"My Protocol");
myproto_tree = proto_item_add_subtree(ti, ett_myproto);
proto_tree_add_bytes_format(myproto_tree, hf_myproto_payload,
tvb, 0, payload_len,
NULL, "Payload");
}
What do I need to do to get the protocol to fill the subtree correctly?
The problem here is a failure to register the subtree as part of a subtree array (hint from here).
This is done in the protocol registration function, and requires "packaging" the subtree variables (of which there is only one here: ett_myproto) into an array, and then registering that array using proto_register_subtree_array:
static gint ett_myproto = -1;
void
proto_register_myproto(void)
{
/* Set up field array */
static hf_register_info hf[] = {
....
};
/* Register protocol */
proto_myproto = proto_register_protocol("My Protocol", "myproto", "myproto");
/* Register protocol fields */
proto_register_field_array(proto_myproto, hf, array_length(hf));
/* Setup and register all protocol subtrees */
static gint *ett[] = {
&ett_myproto,
};
proto_register_subtree_array(ett, array_length(ett));
/* Register the dissector */
register_dissector("myproto", dissect_myproto, proto_myproto);
}
The ett variables are indices used to refer to GUI information about the state of the subtree (e.g. expanded or not).

Change Struct module pointer

Good day all, I'd like some help to change a small section in this C program which I have licensed back in the early 90's. Some of you may be familiar with it, it's called MajorBBS and as you probably have guess it is bbs software.
In the header file majorbbs.h we have
extern
struct module { /* module interface block */
char descrp[MNMSIZ]; /* description for main menu */
int (*lonrou)(); /* user logon supplemental routine */
int (*sttrou)(); /* input routine if selected */
void (*stsrou)(); /* status-input routine if selected */
int (*injrou)(); /* "injoth" routine for this module */
int (*lofrou)(); /* user logoff supplemental routine */
void (*huprou)(); /* hangup (lost carrier) routine */
void (*mcurou)(); /* midnight cleanup routine */
void (*dlarou)(); /* delete-account routine */
void (*finrou)(); /* finish-up (sys shutdown) routine */
} **module;
Also in the majorbbs.h we have some code that defines the menu variables
extern
struct usrmnu { /* user's menuing-specific variables */
char curpag[PNMSIZ]; /* current menu page */
char parpag[PNMSIZ]; /* parent menu page */
char selchrs[MAXSEL]; /* select characters currently available */
char pages[MAXSEL][PNMSIZ]; /* pages or file names for select chars */
char optdsp[MAXSEL]; /* instructions on how to display options */
int keyreq[MAXSEL]; /* key required for each select character */
FILE *fp; /* pointer to file currently being viewed */
char mnuttl[TITLSZ]; /* menu page title */
} *mnuusr;
Then in the majorbbs.c file we have
struct module module00={ /* module interface block */
"Menuing System", /* description for main menu */
NULL, /* user logon supplemental routine */
mainu, /* input routine if selected */
musthn, /* status-input routine if selected */
NULL, /* "injoth" routine for this module */
NULL, /* user logoff supplemental routine */
loscar, /* hangup (lost carrier) routine */
midnit, /* midnight cleanup routine */
NULL, /* delete-account routine */
mjrfin /* finish-up (sys shutdown) routine */
};
What I'd like is to change the value of the descrp here which is defined as "Menuing System" to something more dynamic like the Menu the user is currently on.
From the code here I think it would be mnuusr->curpag which is where the pointer is pointing to I think.
So I'm thinking of a routine. I am by no means a programmer and I've been there many sites to look for examples of how to do such a thing. I've searched here for the last couple days (before posting this). I saw some things
that sparked a "Hey this might work" but I ended up with compiler errors (more on that in a bit)
What I did was make a routine like
char *
mydescrp
{
if (strcmp(module00.descrp,"Menuing System" ) == 0 ) {
mnuusr=mnuoff(usrnum);
return(mnuusr->mnuttl);
}
}
Then if I change the module00 call above to
struct module module00={
mydescrp, /* My change */
NULL,
mainu,
musthn,
NULL,
NULL,
loscar,
midnit,
NULL,
mjrfin
};
When I compile I get some error that says:
Initalization not fully bracketed
the list goes on from there. There are some further initialization later on in majorbbs.c and will gladly supply them if you need. I am sure one would be.
int
register_module( /* register a module for online use */
struct module *mod) /* pointer to a module block */
{
if (strlen(mod->descrp) > MNMSIZ-1) {
catastro("MODULE NAME \"%s\" TOO LONG!",mod->descrp);
}
if (mod->stsrou == NULL) {
mod->stsrou=dfsthn;
}
if (nmods == 0) {
module=(struct module **)alcmem(sizeof(struct module *));
mdstats=(struct mdstats *)alcmem(sizeof(struct mdstats));
}
else {
module=(struct module **)alcrsz(module,sizeof(struct module *)*nmods,
sizeof(struct module *)*(nmods+1));
mdstats=(struct mdstats *)alcrsz(mdstats,sizeof(struct mdstats)*nmods,
sizeof(struct mdstats)*(nmods+1));
}
module[nmods]=mod;
setbtv(mstbb);
if (qeqbtv(mod->descrp,0)) {
gcrbtv(&mdstats[nmods],0);
}
else {
setmem(&mdstats[nmods],sizeof(struct mdstats),0);
strcpy(mdstats[nmods].mdname,mod->descrp);
}
rstbtv();
return(nmods++);
}
From MENUING.C mnuoff routine
struct usrmnu *
mnuoff( /* get pointer to user's menu info */
int unum) /* user number to grab */
{
#ifdef PHARLAP
return((struct usrmnu *)((long)(eclmnubas+(unum<<3))<<16));
#else
#ifdef ECLIPSE
return((struct usrmnu *)((long)(eclmnubas+(unum<<3))<<16));
#else
return((struct usrmnu *)(muusrs+(unum*(long)sizeof(struct usrmnu))));
#endif
#endif
}
Is this the routine to change for some newly code? I am simply at a loss on how to go about this. If you need more code let me know.
I even went as far as asking for help from other majorbbs programmers on usenet but this software is 20 years + old so I don't think anyone uses it anymore let alone modify code anymore. I would think since it's still C someone might have an idea to help me out. I am trying to create a new revive with some small modifications. This being one of two.
Thanks for any help.
It looks like the descrp field in struct module is expecting a char[] (or a string), and you're giving it a char *() (function returning a string) instead.
Perhaps what you want to do is not call the mydescrp function in the declaration of module00, but manually perform the check in register_module:
int register_module(struct module *mod) {
if (strcmp(mod->descrp, "Menuing System") == 0) {
struct usrmnu *menu = mnuoff(usrnum);
// Copy as much of the title to the menu description as possible.
strncpy(mod->descrp, menu->mnuttl, MNMSIZ-1);
// Terminate the string in case the title was too long.
mod->descrp[MNMSIZ-1] = '\0';
}
// Rest of method.
}

Run C Code Block in Erlang

How to Run C Code Block from Erlang? ( Or Call a C function from erlang? )
This is for creating a driver
Firstly you'll need to create the C/C++ files to do it.
They will need to include
#include "erl_driver.h"
#include "ei.h"
Then you'll need to set up the driver mapping
/* mapping of the drivers functions */
static ErlDrvEntry driver_entry = {
NULL, /* init */
startup_function_name, /* startup */
shutdown_function_name, /* shutdown */
NULL, /* output */
NULL, /* ready_input */
NULL, /* ready_output */
driver_name, /* the name of the driver */
NULL, /* finish */
NULL, /* handle */
NULL, /* control */
NULL, /* timeout */
outputv_function_name, /* outputv */
NULL, /* ready_async */
NULL, /* flush */
NULL, /* call */
NULL, /* event */
ERL_DRV_EXTENDED_MARKER, /* ERL_DRV_EXTENDED_MARKER */
ERL_DRV_EXTENDED_MAJOR_VERSION, /* ERL_DRV_EXTENDED_MAJOR_VERSION */
ERL_DRV_EXTENDED_MAJOR_VERSION, /* ERL_DRV_EXTENDED_MINOR_VERSION */
ERL_DRV_FLAG_USE_PORT_LOCKING /* ERL_DRV_FLAGs */
};
DRIVER_INIT(driver_name){
return &driver_entry;
}
Note: if you are trying to run C++ code instead of C you'll need
extern "C" {
DRIVER_INIT(driver_name){
return &driver_entry;
}
}
And you will need to cast any literal string with (char *)
Then it's good to define a struct that'll contain the port information
typedef struct
{
ErlDrvPort port;
} port_data;
Lastly, you'll want to set up all the functions
static ErlDrvData startup_function_name(ErlDrvPort port, char *doc)
{
/* Plus any other start up methods you need */
port_data* d = (port_data*)driver_alloc(sizeof(port_data));
d->port = port;
return (ErlDrvData)d;
}
/* Plus any other shutdown methods you need */
static void shutdown_function_name(ErlDrvData handle)
{
driver_free((char*)handle);
}
static void outputv_function_name(ErlDrvData handle, ErlIOVec *ev)
{
port_data* d = (port_data*)handle;
char* inputstring = ev->binv[1]->orig_bytes;
ErlDrvTermData spec[] = {
ERL_DRV_ATOM, driver_mk_atom("ok"),
ERL_DRV_BUF2BINARY, inputstring, strlen(inputstring)
ERL_DRV_TUPLE, 2
};
driver_send_term(d->port,driver_caller(d->port),spec,sizeof(spec)/sizeof(spec[0]));
}
You'll want to compile this C/C++ code into a shared object and link it with the erl interface
g++ -fpic -rdynamic -shared file_name -lerl_interface -lei
Now from erlang you'll want to do a couple things:
You'll need to load the driver
erl_ddll:load_driver("./location/of/driver", driver_name).
Then you'll open a port to the driver
Port = open_port({spawn, driver_name}, [binary]).
And lastly you can sent data to the port
port_command(Port, <<"String to Echo Back"),
receive
{ok, String} -> io:format("Received ~p back from the driver")
end.
The newest approach would consider NIFs http://www.erlang.org/doc/man/erl_nif.html (be careful, it can crash VM). Regular way to do it involves linked in drivers (google up the link, because anti-spam holds it)

Resources