relay: add type "hashtable" in relay protocol and hdata, add signals "buffer_localvar_xxx" in protocol

This commit is contained in:
Sebastien Helleu 2011-12-20 10:51:01 +01:00
parent 8cd9845804
commit 443b8fc033
4 changed files with 213 additions and 81 deletions

View File

@ -424,37 +424,47 @@ There are two different identifiers ('id'):
WeeChat reserved identifiers:
[width="100%",cols="4m,3,2,15",options="header"]
[width="100%",cols="5m,5,3,15",options="header"]
|=====================================================
| Identifier | Description | Hdata type | Hdata content
| Identifier | Description | Hdata type | Hdata content
| _buffer_opened | Buffer opened | buffer |
| _buffer_opened | Buffer opened | buffer |
'number' (integer), 'full_name' (string), 'short_name' (string), +
'nicklist' (integer), 'title' (string), +
'nicklist' (integer), 'title' (string), 'local_variables' (hashtable), +
'prev_buffer' (pointer), 'next_buffer' (pointer)
| _buffer_moved | Buffer moved | buffer |
| _buffer_moved | Buffer moved | buffer |
'number' (integer), 'full_name' (string), +
'prev_buffer' (pointer), 'next_buffer' (pointer)
| _buffer_merged | Buffer merged | buffer |
| _buffer_merged | Buffer merged | buffer |
'number' (integer), 'full_name' (string), +
'prev_buffer' (pointer), 'next_buffer' (pointer)
| _buffer_renamed | Buffer renamed | buffer |
'number' (integer), 'full_name' (string), 'short_name' (string)
| _buffer_renamed | Buffer renamed | buffer |
'number' (integer), 'full_name' (string), 'short_name' (string),
'local_variables' (hashtable)
| _buffer_title_changed | Buffer moved | buffer |
| _buffer_title_changed | Buffer moved | buffer |
'number' (integer), 'full_name' (string), 'title' (string)
| _buffer_line_added | Line added in buffer | line |
| _buffer_localvar_added | Local variable added | buffer |
'number' (integer), 'full_name' (string), 'local_variables' (hashtable)
| _buffer_localvar_changed | Local variable changed | buffer |
'number' (integer), 'full_name' (string), 'local_variables' (hashtable)
| _buffer_localvar_removed | Local variable removed | buffer |
'number' (integer), 'full_name' (string), 'local_variables' (hashtable)
| _buffer_line_added | Line added in buffer | line |
'buffer' (pointer), 'date' (time), 'displayed' (char), 'prefix' (string),
'message' (string)
| _buffer_closing | Buffer closing | buffer |
| _buffer_closing | Buffer closing | buffer |
'number' (integer), 'full_name' (string)
| _nicklist | Nicklist for a buffer | nicklist_item |
| _nicklist | Nicklist for a buffer | nicklist_item |
'group' (char), 'visible' (char), 'level' (integer), +
'name' (string), 'color' (string), +
'prefix' (string), 'prefix_color' (string)
@ -477,22 +487,19 @@ available:
| buf | Buffer of bytes | 4 bytes + length of data
| ptr | Pointer | 1 byte + length of pointer as string
| tim | Time | 1 byte + length of time as string
| htb | Hashtable | Variable
| hda | Hdata content | Variable
| inf | Info: name + content | Variable
| lis | Infolist content | Variable
| inl | Infolist content | Variable
|=====================================================
[NOTE]
Only types 'hda', 'inf' and 'lis' are used for objects in message. The other
types are used inside hdata and infolist for type of keys.
[[object_char]]
Char
^^^^
A signed char is 1 byte.
Example of byte with value 65 (0x41: "A"):
Example:
.......................................
┌────┐
@ -507,7 +514,7 @@ Integer
A signed integer is 4 bytes, encoded as big-endian format (most significant byte
first).
Example of integer with value 260 (0x104):
Example:
.......................................
┌────┬────┬────┬────┐
@ -521,7 +528,7 @@ Long integer
A signed long integer is encoded as a string, with length on one byte.
Example of long integer with value 260:
Example:
.......................................
┌────╥────┬────┬────┐
@ -537,7 +544,7 @@ String
A string is a length (integer on 4 bytes) + content of string (without final '\0').
Example of string with value 'hello':
Example:
.......................................
┌────┬────┬────┬────╥────┬────┬────┬────┬────┐
@ -579,12 +586,12 @@ Pointer
A pointer is encoded as string (hex), with length on one byte.
Example of pointer with value 0x1a2b3c4d5:
Example:
.......................................
┌────────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 09 31 │ 61 │ 32 │ 62 │ 33 │ 63 │ 34 │ 64 │ 35 │ ────► 0x1a2b3c4d5
└────────┴────┴────┴────┴────┴────┴────┴────┴────┘
┌────────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 09 31 │ 61 │ 32 │ 62 │ 33 │ 63 │ 34 │ 64 │ 35 │ ────► 0x1a2b3c4d5
└────────┴────┴────┴────┴────┴────┴────┴────┴────┘
└──┘ └──────────────────────────────────────────┘
length '1' 'a' '2' 'b' '3' 'c' '4' 'd' '5'
.......................................
@ -592,9 +599,9 @@ length '1' 'a' '2' 'b' '3' 'c' '4' 'd' '5'
A 'NULL' pointer has value 0:
.......................................
┌────────┐
│ 01 00 │ ────► NULL (0x0)
└────────┘
┌────────┐
│ 01 00 │ ────► NULL (0x0)
└────────┘
└──┘ └──┘
length 0
.......................................
@ -605,7 +612,7 @@ Time
A time (number of seconds) is encoded as a string, with length on one byte.
Example of time 1321993456:
Example:
.......................................
┌────╥────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
@ -615,6 +622,30 @@ Example of time 1321993456:
length '1' '3' '2' '1' '9' '9' '3' '4' '5' '6'
.......................................
[[object_hashtable]]
Hashtable
^^^^^^^^^
A hashtable contains type for keys, type for values, number of items in
hashtable (integer on 4 bytes), and then keys and values of items.
.......................................
┌───────────┬─────────────┬───────╥───────┬─────────╥─────╥───────┬─────────┐
│ type_keys │ type_values │ count ║ key 1 │ value 1 ║ ... ║ key N │ value N │
└───────────┴─────────────┴───────╨───────┴─────────╨─────╨───────┴─────────┘
.......................................
Example:
.......................................
┌─────┬─────┬───╥──────┬─────╥──────┬─────┐
│ str │ str │ 2 ║ key1 │ abc ║ key2 │ def │ ────► { 'key1' => 'abc', 'key2' => 'def' }
└─────┴─────┴───╨──────┴─────╨──────┴─────┘
└───┘ └───┘ └─┘ └──────────┘ └──────────┘
type type count item 1 item 2
keys values
.......................................
[[object_hdata]]
Hdata
^^^^^
@ -623,9 +654,9 @@ A 'hdata' contains a path with hdata names, list of keys, number of set of
objects, and then set of objects (path with pointers, then objects).
.......................................
┌─────╥────────┬──────┬───────╥────────┬─────────────────────╥────────┬─────────────────────╥─────┐
│ hda ║ h-path │ keys │ count ║ p-path │ value 1 ... value N ║ p-path │ value 1 ... value N ║ ... │
└─────╨────────┴──────┴───────╨────────┴─────────────────────╨────────┴─────────────────────╨─────┘
┌────────┬──────┬───────╥────────┬─────────────────────╥────────┬─────────────────────╥─────┐
│ h-path │ keys │ count ║ p-path │ value 1 ... value N ║ p-path │ value 1 ... value N ║ ... │
└────────┴──────┴───────╨────────┴─────────────────────╨────────┴─────────────────────╨─────┘
.......................................
* 'name' (string): name of hdata ('buffer', 'window', 'bar', ...)
@ -647,11 +678,11 @@ Example of hdata with 2 buffers (weechat core and freenode server) and two keys
hdata buffer:gui_buffers(*) number,full_name
# response
┌─────╥────────┬──────────────────────────┬───╥─────────┬───┬──────────────╥─────────┬───┬────────────────────┐
hda ║ buffer │ number:int,full_name:str │ 2 ║ 0x12345 │ 1 │ core.weechat ║ 0x6789a │ 2 │irc.server.freenode │
└─────╨────────┴──────────────────────────┴───╨─────────┴───┴──────────────╨─────────┴───┴────────────────────┘
└───┘ └──────┘ └────────────────────────┘ └─┘ └──────────────────────────┘ └────────────────────────────────┘
type hpath keys count buffer 1 buffer 2
┌────────┬──────────────────────────┬───╥─────────┬───┬──────────────╥─────────┬───┬────────────────────┐
│ buffer │ number:int,full_name:str │ 2 ║ 0x12345 │ 1 │ core.weechat ║ 0x6789a │ 2 │irc.server.freenode │
└────────┴──────────────────────────┴───╨─────────┴───┴──────────────╨─────────┴───┴────────────────────┘
└──────┘ └────────────────────────┘ └─┘ └──────────────────────────┘ └────────────────────────────────┘
hpath keys count buffer 1 buffer 2
.......................................
Example of hdata with lines of core buffer:
@ -661,11 +692,11 @@ Example of hdata with lines of core buffer:
hdata buffer:gui_buffers(*)/lines/first_line(*)/data
# response
┌─────╥─────────────────────────────┬─────┬────╥──
hda ║ buffer/lines/line/line_data │ ... │ 50 ║ ...
└─────╨─────────────────────────────┴─────┴────╨──
└───┘ └───────────────────────────┘ └───┘ └──┘
type h-path (hdata names) keys count
┌─────────────────────────────┬─────┬────╥──
│ buffer/lines/line/line_data │ ... │ 50 ║ ...
└─────────────────────────────┴─────┴────╨──
└───────────────────────────┘ └───┘ └──┘
h-path (hdata names) keys count
──╥───────────┬───────────┬───────────┬───────╥───────────┬───────────┬───────────┬───────╥──────────────┐
... ║ 0x23cf970 │ 0x23cfb60 │ 0x23d5f40 │ ..... ║ 0x23cf970 │ 0x23cfb60 │ 0x23d6110 │ ..... ║ ............ │
@ -683,11 +714,11 @@ Example of hdata with nicklist:
nicklist
# response
┌─────╥───────────────────┬────────────────────────────────────────────────────────────────────────────────┬────╥──
hda ║ buffer/nick_group │ group:chr,visible:chr,name:str,color:str,prefix:str,prefix_color:str,level:int │ 12 ║ ...
└─────╨───────────────────┴────────────────────────────────────────────────────────────────────────────────┴────╨──
└───┘ └─────────────────┘ └──────────────────────────────────────────────────────────────────────────────┘ └──┘
type h-path keys count
┌───────────────────┬────────────────────────────────────────────────────────────────────────────────┬────╥──
│ buffer/nick_group │ group:chr,visible:chr,name:str,color:str,prefix:str,prefix_color:str,level:int │ 12 ║ ...
└───────────────────┴────────────────────────────────────────────────────────────────────────────────┴────╨──
└─────────────────┘ └──────────────────────────────────────────────────────────────────────────────┘ └──┘
h-path keys count
──╥─────────┬─────────┬───┬───┬──────┬─┬─┬─┬───╥─────────┬─────────┬───┬───┬───────┬─┬─┬─┬───╥──
... ║ 0x12345 │ 0x6789a │ 1 │ 0 │ root │ │ │ │ 0 ║ 0x123cf │ 0x678d4 │ 1 │ 0 │ 000|o │ │ │ │ 1 ║ ...
@ -713,9 +744,9 @@ Info
A 'info' contains a name and a value (both are strings).
.......................................
┌─────╥──────┬───────┐
inf ║ name │ value │
└─────╨──────┴───────┘
┌──────┬───────┐
│ name │ value │
└──────┴───────┘
.......................................
* 'name' (string): name of info
@ -724,9 +755,9 @@ A 'info' contains a name and a value (both are strings).
Exemple of info 'version':
.......................................
┌─────╥─────────┬───────────────────┐
inf ║ version │ WeeChat 0.3.7-dev │
└─────╨─────────┴───────────────────┘
┌─────────┬───────────────────┐
│ version │ WeeChat 0.3.7-dev │
└─────────┴───────────────────┘
.......................................
[[object_infolist]]
@ -737,9 +768,9 @@ A 'infolist' contains a name, number of items, and then items (set of
variables).
.......................................
┌─────╥──────┬───────╥────────╥─────╥────────┐
lis ║ name │ count ║ item 1 ║ ... ║ item N │
└─────╨──────┴───────╨────────╨─────╨────────┘
┌──────┬───────╥────────╥─────╥────────┐
│ name │ count ║ item 1 ║ ... ║ item N │
└──────┴───────╨────────╨─────╨────────┘
.......................................
An item is:
@ -765,11 +796,11 @@ Example of infolist with 2 buffers (weechat core and freenode server):
infolist buffer
# response
┌─────╥────────┬───╥────┬─────────┬─────┬─────────┬─────╥────┬─────────┬─────┬─────────┬─────┐
lis ║ buffer │ 2 ║ 42 │ pointer │ ptr │ 0x12345 │ ... ║ 42 │ pointer │ ptr │ 0x6789a │ ... │
└─────╨────────┴───╨────┴─────────┴─────┴─────────┴─────╨────┴─────────┴─────┴─────────┴─────┘
└───┘ └──────┘ └─┘ └──────────────────────────────────┘ └──────────────────────────────────┘
type name count item 1 item 2
┌────────┬───╥────┬─────────┬─────┬─────────┬─────╥────┬─────────┬─────┬─────────┬─────┐
│ buffer │ 2 ║ 42 │ pointer │ ptr │ 0x12345 │ ... ║ 42 │ pointer │ ptr │ 0x6789a │ ... │
└────────┴───╨────┴─────────┴─────┴─────────┴─────╨────┴─────────┴─────┴─────────┴─────┘
└──────┘ └─┘ └──────────────────────────────────┘ └──────────────────────────────────┘
name count item 1 item 2
.......................................
[[typical_session]]

View File

@ -251,6 +251,77 @@ relay_weechat_msg_add_time (struct t_relay_weechat_msg *msg, time_t time)
relay_weechat_msg_add_bytes (msg, str_time, length);
}
/*
* relay_weechat_msg_hashtable_map_cb: callback used to add hashtable items in
* message
*/
void
relay_weechat_msg_hashtable_map_cb (void *data, struct t_hashtable *hashtable,
const void *key, const void *value)
{
struct t_relay_weechat_msg *msg;
char *types[2] = { "type_keys", "type_values" };
const void *pointers[2];
const char *type;
int i;
msg = (struct t_relay_weechat_msg *)data;
pointers[0] = key;
pointers[1] = value;
for (i = 0; i < 2; i++)
{
type = weechat_hashtable_get_string (hashtable, types[i]);
if (strcmp (type, WEECHAT_HASHTABLE_INTEGER) == 0)
relay_weechat_msg_add_int (msg, *((int *)pointers[i]));
else if (strcmp (type, WEECHAT_HASHTABLE_STRING) == 0)
relay_weechat_msg_add_string (msg, (const char *)pointers[i]);
else if (strcmp (type, WEECHAT_HASHTABLE_POINTER) == 0)
relay_weechat_msg_add_pointer (msg, (void *)pointers[i]);
else if (strcmp (type, WEECHAT_HASHTABLE_BUFFER) == 0)
relay_weechat_msg_add_pointer (msg, (void *)pointers[i]);
else if (strcmp (type, WEECHAT_HASHTABLE_TIME) == 0)
relay_weechat_msg_add_time (msg, *((time_t *)pointers[i]));
}
}
/*
* relay_weechat_msg_add_hashtable: add a hashtable to a message
*/
void
relay_weechat_msg_add_hashtable (struct t_relay_weechat_msg *msg,
struct t_hashtable *hashtable)
{
char *types[2] = { "type_keys", "type_values" };
const char *type;
int i, count;
for (i = 0; i < 2; i++)
{
type = weechat_hashtable_get_string (hashtable, types[i]);
if (strcmp (type, WEECHAT_HASHTABLE_INTEGER) == 0)
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_INT);
else if (strcmp (type, WEECHAT_HASHTABLE_STRING) == 0)
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_STRING);
else if (strcmp (type, WEECHAT_HASHTABLE_POINTER) == 0)
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_POINTER);
else if (strcmp (type, WEECHAT_HASHTABLE_BUFFER) == 0)
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_POINTER);
else if (strcmp (type, WEECHAT_HASHTABLE_TIME) == 0)
relay_weechat_msg_add_type (msg, RELAY_WEECHAT_MSG_OBJ_TIME);
}
/* number of items */
count = weechat_hashtable_get_integer (hashtable, "items_count");
relay_weechat_msg_add_int (msg, count);
/* add all items */
weechat_hashtable_map (hashtable,
&relay_weechat_msg_hashtable_map_cb, msg);
}
/*
* relay_weechat_msg_add_hdata_path: recursively add hdata for a path
* return number of hdata objects added in
@ -385,6 +456,12 @@ relay_weechat_msg_add_hdata_path (struct t_relay_weechat_msg *msg,
pointer,
list_keys[i]));
break;
case WEECHAT_HDATA_HASHTABLE:
relay_weechat_msg_add_hashtable (msg,
weechat_hdata_hashtable (hdata,
pointer,
list_keys[i]));
break;
}
}
}
@ -548,6 +625,9 @@ relay_weechat_msg_add_hdata (struct t_relay_weechat_msg *msg,
case WEECHAT_HDATA_TIME:
strcat (keys_types, RELAY_WEECHAT_MSG_OBJ_TIME);
break;
case WEECHAT_HDATA_HASHTABLE:
strcat (keys_types, RELAY_WEECHAT_MSG_OBJ_HASHTABLE);
break;
}
}
}

View File

@ -23,16 +23,17 @@
#define RELAY_WEECHAT_MSG_INITIAL_ALLOC 4096
/* object ids in binary messages */
#define RELAY_WEECHAT_MSG_OBJ_CHAR "chr"
#define RELAY_WEECHAT_MSG_OBJ_INT "int"
#define RELAY_WEECHAT_MSG_OBJ_LONG "lon"
#define RELAY_WEECHAT_MSG_OBJ_STRING "str"
#define RELAY_WEECHAT_MSG_OBJ_BUFFER "buf"
#define RELAY_WEECHAT_MSG_OBJ_POINTER "ptr"
#define RELAY_WEECHAT_MSG_OBJ_TIME "tim"
#define RELAY_WEECHAT_MSG_OBJ_HDATA "hda"
#define RELAY_WEECHAT_MSG_OBJ_INFO "inf"
#define RELAY_WEECHAT_MSG_OBJ_INFOLIST "lis"
#define RELAY_WEECHAT_MSG_OBJ_CHAR "chr"
#define RELAY_WEECHAT_MSG_OBJ_INT "int"
#define RELAY_WEECHAT_MSG_OBJ_LONG "lon"
#define RELAY_WEECHAT_MSG_OBJ_STRING "str"
#define RELAY_WEECHAT_MSG_OBJ_BUFFER "buf"
#define RELAY_WEECHAT_MSG_OBJ_POINTER "ptr"
#define RELAY_WEECHAT_MSG_OBJ_TIME "tim"
#define RELAY_WEECHAT_MSG_OBJ_HASHTABLE "htb"
#define RELAY_WEECHAT_MSG_OBJ_HDATA "hda"
#define RELAY_WEECHAT_MSG_OBJ_INFO "inf"
#define RELAY_WEECHAT_MSG_OBJ_INFOLIST "inl"
struct t_relay_weechat_msg
{

View File

@ -275,7 +275,7 @@ relay_weechat_protocol_signal_buffer_cb (void *data, const char *signal,
struct t_gui_line_data *ptr_line_data;
struct t_gui_buffer *ptr_buffer;
struct t_relay_weechat_msg *msg;
char cmd_hdata[64];
char cmd_hdata[64], str_signal[128];
/* make C compiler happy */
(void) signal;
@ -285,20 +285,22 @@ relay_weechat_protocol_signal_buffer_cb (void *data, const char *signal,
if (!ptr_client || !relay_client_valid (ptr_client))
return WEECHAT_RC_OK;
snprintf (str_signal, sizeof (str_signal), "_%s", signal);
if (strcmp (signal, "buffer_opened") == 0)
{
ptr_buffer = (struct t_gui_buffer *)signal_data;
if (!ptr_buffer)
return WEECHAT_RC_OK;
msg = relay_weechat_msg_new ("_buffer_opened");
msg = relay_weechat_msg_new (str_signal);
if (msg)
{
snprintf (cmd_hdata, sizeof (cmd_hdata),
"buffer:0x%lx", (long unsigned int)ptr_buffer);
relay_weechat_msg_add_hdata (msg, cmd_hdata,
"number,full_name,short_name,"
"nicklist,title,"
"nicklist,title,local_variables,"
"prev_buffer,next_buffer");
relay_weechat_msg_send (ptr_client, msg, 0);
relay_weechat_msg_free (msg);
@ -310,7 +312,7 @@ relay_weechat_protocol_signal_buffer_cb (void *data, const char *signal,
if (!ptr_buffer)
return WEECHAT_RC_OK;
msg = relay_weechat_msg_new ("_buffer_moved");
msg = relay_weechat_msg_new (str_signal);
if (msg)
{
snprintf (cmd_hdata, sizeof (cmd_hdata),
@ -328,7 +330,7 @@ relay_weechat_protocol_signal_buffer_cb (void *data, const char *signal,
if (!ptr_buffer)
return WEECHAT_RC_OK;
msg = relay_weechat_msg_new ("_buffer_merged");
msg = relay_weechat_msg_new (str_signal);
if (msg)
{
snprintf (cmd_hdata, sizeof (cmd_hdata),
@ -346,13 +348,14 @@ relay_weechat_protocol_signal_buffer_cb (void *data, const char *signal,
if (!ptr_buffer)
return WEECHAT_RC_OK;
msg = relay_weechat_msg_new ("_buffer_renamed");
msg = relay_weechat_msg_new (str_signal);
if (msg)
{
snprintf (cmd_hdata, sizeof (cmd_hdata),
"buffer:0x%lx", (long unsigned int)ptr_buffer);
relay_weechat_msg_add_hdata (msg, cmd_hdata,
"number,full_name,short_name");
"number,full_name,short_name,"
"local_variables");
relay_weechat_msg_send (ptr_client, msg, 0);
relay_weechat_msg_free (msg);
}
@ -363,7 +366,7 @@ relay_weechat_protocol_signal_buffer_cb (void *data, const char *signal,
if (!ptr_buffer)
return WEECHAT_RC_OK;
msg = relay_weechat_msg_new ("_buffer_title_changed");
msg = relay_weechat_msg_new (str_signal);
if (msg)
{
snprintf (cmd_hdata, sizeof (cmd_hdata),
@ -374,6 +377,23 @@ relay_weechat_protocol_signal_buffer_cb (void *data, const char *signal,
relay_weechat_msg_free (msg);
}
}
else if (strncmp (signal, "buffer_localvar_", 16) == 0)
{
ptr_buffer = (struct t_gui_buffer *)signal_data;
if (!ptr_buffer)
return WEECHAT_RC_OK;
msg = relay_weechat_msg_new (str_signal);
if (msg)
{
snprintf (cmd_hdata, sizeof (cmd_hdata),
"buffer:0x%lx", (long unsigned int)ptr_buffer);
relay_weechat_msg_add_hdata (msg, cmd_hdata,
"number,full_name,local_variables");
relay_weechat_msg_send (ptr_client, msg, 0);
relay_weechat_msg_free (msg);
}
}
else if (strcmp (signal, "buffer_line_added") == 0)
{
ptr_line = (struct t_gui_line *)signal_data;
@ -404,7 +424,7 @@ relay_weechat_protocol_signal_buffer_cb (void *data, const char *signal,
weechat_buffer_get_string (ptr_buffer,
"full_name")))
{
msg = relay_weechat_msg_new ("_buffer_line_added");
msg = relay_weechat_msg_new (str_signal);
if (msg)
{
snprintf (cmd_hdata, sizeof (cmd_hdata),
@ -423,7 +443,7 @@ relay_weechat_protocol_signal_buffer_cb (void *data, const char *signal,
if (!ptr_buffer)
return WEECHAT_RC_OK;
msg = relay_weechat_msg_new ("_buffer_closing");
msg = relay_weechat_msg_new (str_signal);
if (msg)
{
snprintf (cmd_hdata, sizeof (cmd_hdata),