-SUBDIRS= base adns hbytes cdb crypto
-# dgram tuntap
+SUBDIRS= base adns hbytes cdb crypto dgram
+# tuntap
default: all
void cht_objfreeir(Tcl_Obj *o);
int cht_get_urandom(Tcl_Interp *ip, Byte *buffer, int l);
-void cht_obj_updatestr_array(Tcl_Obj *o, const Byte *array, int l);
-void cht_obj_updatestr_array_prefix(Tcl_Obj *o, const Byte *byte,
- int l, const char *prefix);
-
void cht_obj_updatestr_vstringls(Tcl_Obj *o, ...);
/* const char*, int, const char*, int, ..., (const char*)0 */
void cht_obj_updatestr_string_len(Tcl_Obj *o, const char *str, int l);
initd= 1; \
return TCL_OK; \
}
-
+
#define CHTI_OTHER(e) \
{ extern void cht_prepare_##e(Tcl_Interp *ip); cht_prepare_##e(ip); }
#define CHTI_TYPE(ot) { Tcl_RegisterObjType(&(ot)); }
+
#define CHTI_COMMANDS(cl) { cht_setup__commands(ip,cl); }
#endif /*CHIARK_TCL_H*/
# implement the function. If the `=> RESULT-TYPE' is omitted, so
# is the result argument to the function. Each argument to the
# function is of the C type corresponding to the specified type.
+# TYPE may be `...', in which case the C function will be passed
+# two args (int objc, Tcl_Obj *const *objv) for the remaining
+# arguments.
+#
# The cht_do_... function should not eat any memory associated with
# the arguments. The result buffer (if any) will be initialised
# using the `Init' and should on success contain the relevant
# result. On failure it should leave the result unmodified (or at
# least, not in need of freeing).
#
+# As an alternative, the arguments can be replaced with just
+# dispatch(TYPE-ARGS-FOR-ENUM)
+# which is a shorthand for
+# subcmd enum(TYPE-ARGS-FOR-ENUM)
+# args ...
+# and also generates and uses a standard dispatch function.
+#
# There will be an entry in C-ARRAY-NAME for every table entry.
# The name will be ENTRYNAME, and the func will be a function
# suitable for use as a Tcl command procedure, which parses the
$tables{$c_table}{$c_entry}{A} = [ ];
} elsif (@i==2 && m/^\.\.\.\s+(\w+)$/ && defined $c_entry) {
$tables{$c_table}{$c_entry}{V}= $1;
+ } elsif (@i==2 && m:^dispatch\(((.*)/(.*)\,.*)\)$: && defined $c_entry) {
+ my $enumargs= $1;
+ my $subcmdtype= $2.$3;
+ $tables{$c_table}{$c_entry}{D}= $subcmdtype;
+ $tables{$c_table}{$c_entry}{V}= 'obj';
+ push @{ $tables{$c_table}{$c_entry}{A} },
+ { N => 'subcmd', T => 'enum', A => $enumargs, O => '' };
} elsif (@i==2 && m/^(\??)([a-z]\w*)\s*(\S.*)/
&& defined $c_entry) {
($opt, $var, $type) = ($1,$2,$3);
$r_entry= $r_table->{$c_entry};
$pa_decl= "int pa_${c_table}_${c_entry_c}(ClientData cd,".
" Tcl_Interp *ip, int objc, Tcl_Obj *const *objv)";
- $do_decl= "int cht_do_${c_table}_${c_entry_c}(";
+ $pa_func= "cht_do_${c_table}_${c_entry_c}";
+ if (exists $r_entry->{D}) {
+ $pa_func= "cht_dispatch_$r_entry->{D}";
+ }
+ $do_decl= "int $pa_func(";
@do_al= ('ClientData cd', 'Tcl_Interp *ip');
@do_aa= qw(cd ip);
$pa_init= '';
$pa_rslt .= "));\n";
}
$pa_body .= "\n";
- $pa_body .= " rc= cht_do_${c_table}_${c_entry_c}(";
+ $pa_body .= " rc= $pa_func(";
$pa_body .= join ', ', @do_aa;
$pa_body .= ");\n";
$pa_body .= " if (rc) goto rc_err;\n";
$pa_fini);
$do_decl .= join ', ', @do_al;
$do_decl .= ")";
- o('h',100, $do_decl.";\n") or die $!;
-
+
+ if (exists $r_entry->{D}) {
+ my $subcmdtype= $r_entry->{D};
+ if (!exists $dispatch_done{$subcmdtype}) {
+ my $di_body='';
+ $di_body .= "static $do_decl {\n";
+ $di_body .= " return subcmd->func(0,ip,objc,objv);\n";
+ $di_body .= "}\n";
+ o('c',50, $di_body) or die $!;
+ }
+ } else {
+ o('h',100, $do_decl.";\n") or die $!;
+ }
$op_tab .= sprintf(" { %-20s %-40s%s },\n",
"\"$c_entry\",",
}
static void key_t_ustr(Tcl_Obj *o) {
- obj_updatestr_array(o, OBJ_CIPHKEY(o)->value, OBJ_CIPHKEY(o)->valuelen);
+ cht_obj_updatestr_array(o, OBJ_CIPHKEY(o)->value, OBJ_CIPHKEY(o)->valuelen);
}
static int key_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
Table hbcrypto HBCrypto_SubCommand
pad
- op enum(PadOp/, "hbytes pad subcommand")
+ op enum(PadOp/, "hbcrypto pad subcommand")
v hbv
blocksz obj
meth enum(PadMethodInfo/, "pad method")
chiark-tcl (1.0.1) unstable; urgency=low
+ * dgram: New extension for datagram sockets; dgram-socket command.
+ * New way of doing toplevels with tcmdifgen dispatch() primitive.
* Replace #include <tcl8.3/tcl.h> with <tcl.h> and in build system find
Tcl version and pass appropriate -I option. (Closes: #362806.)
* Declare versioned build-dependency on libadns1-dev >= 1.2
--- /dev/null
+*+tcmdif.[ch]
+*.d
--- /dev/null
+# dgram - Tcl extension for udp datagrams
+# Copyright 2006 Ian Jackson
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+
+BASE_DIR = ../base
+EXTBASE = dgram
+CFILES = dgram misc sockaddr hook
+OTHER_TCTS = ../hbytes/hbytes-base.tct
+OTHER_EXTS = hbytes/hbytes
+
+include ../base/extension.make
+
--- /dev/null
+/* dgram - Tcl extension for udp datagrams
+ * Copyright 2006 Ian Jackson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#include "hbytes.h"
+#include "dgram.h"
+#include "dgram+tcmdif.h"
* if script not supplied, cancel
*/
-#include "tables.h"
-#include "hbytes.h"
+#include "dgram.h"
typedef struct DgramSocket {
int ix; /* first ! */
int addr_buflen, msg_buflen;
} DgramSocket;
-int do_dgram_socket_create(ClientData cd, Tcl_Interp *ip,
+int cht_do_dgramsocket_create(ClientData cd, Tcl_Interp *ip,
SockAddr_Value local, void **sock_r) {
int fd, al, r;
DgramSocket *sock;
const struct sockaddr *sa;
- sa= sockaddr_addr(&local);
- al= sockaddr_len(&local);
+ sa= cht_sockaddr_addr(&local);
+ al= cht_sockaddr_len(&local);
fd= socket(sa->sa_family, SOCK_DGRAM, 0);
- if (fd<0) return posixerr(ip,errno,"socket");
- r= bind(fd, sa, al); if (r) return newfdposixerr(ip,fd,"bind");
- r= setnonblock(fd, 1); if (r) return newfdposixerr(ip,fd,"setnonblock");
+ if (fd<0) return cht_posixerr(ip,errno,"socket");
+ r= bind(fd, sa, al); if (r) return cht_newfdposixerr(ip,fd,"bind");
+ r= cht_setnonblock(fd, 1); if (r) return cht_newfdposixerr(ip,fd,"setnonblock");
sock= TALLOC(sizeof(DgramSocket));
sock->ix= -1;
sock->addr_buf= TALLOC(sock->addr_buflen);
sock->msg_buflen= 0;
sock->msg_buf= 0;
- scriptinv_init(&sock->script);
+ cht_scriptinv_init(&sock->script);
*sock_r= sock;
return TCL_OK;
}
-int do_dgram_socket_transmit(ClientData cd, Tcl_Interp *ip,
+int cht_do_dgramsocket_transmit(ClientData cd, Tcl_Interp *ip,
void *sock_v, HBytes_Value data,
SockAddr_Value remote) {
DgramSocket *sock= sock_v;
int l, r;
r= sendto(sock->fd,
- hbytes_data(&data), l=hbytes_len(&data),
+ cht_hb_data(&data), l=cht_hb_len(&data),
0,
- sockaddr_addr(&remote), sockaddr_len(&remote));
- if (r==-1) return posixerr(ip,errno,"sendto");
- else if (r!=l) return staticerr(ip,"sendto gave wrong answer",0);
+ cht_sockaddr_addr(&remote), cht_sockaddr_len(&remote));
+ if (r==-1) return cht_posixerr(ip,errno,"sendto");
+ else if (r!=l) return cht_staticerr(ip,"sendto gave wrong answer",0);
return TCL_OK;
}
static void cancel(DgramSocket *sock) {
- if (sock->script.obj) {
- scriptinv_cancel(&sock->script);
+ if (sock->script.script) {
+ cht_scriptinv_cancel(&sock->script);
Tcl_DeleteFileHandler(sock->fd);
}
}
static void recv_call(ClientData sock_cd, int mask) {
DgramSocket *sock= (void*)sock_cd;
- Tcl_Interp *ip= sock->script.ip;
+ Tcl_Interp *ip= sock->script.ipq;
int sz, rc, peek;
HBytes_Value message_val;
SockAddr_Value peer_val;
struct msghdr mh;
struct iovec iov;
- hbytes_empty(&message_val);
- sockaddr_clear(&peer_val);
+ cht_hb_empty(&message_val);
+ cht_sockaddr_clear(&peer_val);
mh.msg_iov= &iov;
mh.msg_iovlen= 1;
sz= recvmsg(sock->fd, &mh, peek);
if (sz==-1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) rc=0;
- else rc= posixerr(ip,errno,"recvmsg");
+ else rc= cht_posixerr(ip,errno,"recvmsg");
goto x_rc;
}
sock->msg_buf= TALLOC(sock->msg_buflen);
}
- hbytes_array(&message_val, iov.iov_base, sz);
- sockaddr_create(&peer_val, mh.msg_name, mh.msg_namelen);
+ cht_hb_array(&message_val, iov.iov_base, sz);
+ cht_sockaddr_create(&peer_val, mh.msg_name, mh.msg_namelen);
- args[0]= ret_hb(ip, message_val); hbytes_empty(&message_val);
- args[1]= ret_sockaddr(ip, peer_val); sockaddr_clear(&peer_val);
- args[2]= ret_iddata(ip, sock, &dgram_socks);
- scriptinv_invoke(&sock->script,3,args);
+ args[0]= cht_ret_hb(ip, message_val); cht_hb_empty(&message_val);
+ args[1]= cht_ret_sockaddr(ip, peer_val); cht_sockaddr_clear(&peer_val);
+ args[2]= cht_ret_iddata(ip, sock, &cht_dgram_socks);
+ cht_scriptinv_invoke(&sock->script,3,args);
rc= 0;
Tcl_BackgroundError(ip);
}
-int do_dgram_socket_on_receive(ClientData cd, Tcl_Interp *ip,
+int cht_do_dgramsocket_on_receive(ClientData cd, Tcl_Interp *ip,
void *sock_v, Tcl_Obj *newscript) {
DgramSocket *sock= sock_v;
int rc;
cancel(sock);
if (newscript) {
- rc= scriptinv_set(&sock->script, ip, newscript, 0);
+ rc= cht_scriptinv_set(&sock->script, ip, newscript, 0);
if (rc) return rc;
}
destroy(sock_v);
}
-int do_dgram_socket_close(ClientData cd, Tcl_Interp *ip, void *sock_v) {
- tabledataid_disposing(ip,sock_v,&dgram_socks);
+int cht_do_dgramsocket_close(ClientData cd, Tcl_Interp *ip, void *sock_v) {
+ cht_tabledataid_disposing(ip,sock_v,&cht_dgram_socks);
destroy(sock_v);
return TCL_OK;
}
-const IdDataSpec dgram_socks= {
+const IdDataSpec cht_dgram_socks= {
"dgramsock", "dgramsock-table", destroy_idtabcb
};
* 02110-1301, USA.
*/
+#ifndef DGRAM_H
+#define DGRAM_H
+
+#include "hbytes.h"
/* from sockaddr.c */
extern Tcl_ObjType sockaddr_type;
-void sockaddr_clear(SockAddr_Value*);
-void sockaddr_create(SockAddr_Value*, const struct sockaddr *addr, int len);
-int sockaddr_len(const SockAddr_Value*);
-const struct sockaddr *sockaddr_addr(const SockAddr_Value*);
-void sockaddr_free(const SockAddr_Value*);
+void cht_sockaddr_clear(SockAddr_Value*);
+void cht_sockaddr_create(SockAddr_Value*, const struct sockaddr *addr, int al);
+int cht_sockaddr_len(const SockAddr_Value*);
+const struct sockaddr *cht_sockaddr_addr(const SockAddr_Value*);
+void cht_sockaddr_free(const SockAddr_Value*);
/* from dgram.c */
-extern const IdDataSpec dgram_socks;
+extern const IdDataSpec cht_dgram_socks;
/* from misc.c */
-int setnonblock(int fd, int isnonblock);
+int cht_setnonblock(int fd, int isnonblock);
+
+#include "dgram+tcmdif.h"
+#endif /*DGRAM_H*/
Type sockaddr: SockAddr_Value @
-Init sockaddr sockaddr_clear(&@);
+Init sockaddr cht_sockaddr_clear(&@);
-Table *toplevel TopLevel_Command
+Table *dgramsockettoplevel TopLevel_Command
dgram-socket
- subcmd enum(DgramSocket_SubCommand,"dgram-socket subcommand")
- ... obj
- tuntap-socket-raw
- subcmd enum(TunSocket_SubCommand,"tuntap-socket-raw subcommand")
- ... obj
+ dispatch(DgramSocket/_SubCommand,"dgram-socket subcommand")
-Table dgram_socket DgramSocket_SubCommand
+Table dgramsocket DgramSocket_SubCommand
create
local sockaddr
- => iddata(&dgram_socks)
+ => iddata(&cht_dgram_socks)
close
- sock iddata(&dgram_socks)
+ sock iddata(&cht_dgram_socks)
transmit
- sock iddata(&dgram_socks)
+ sock iddata(&cht_dgram_socks)
data hb
remote sockaddr
on-receive
- sock iddata(&dgram_socks)
+ sock iddata(&cht_dgram_socks)
?script obj
* 02110-1301, USA.
*/
+#include "dgram.h"
- Tcl_RegisterObjType(&sockaddr_type);
+CHT_INIT(dgram, CHTI_TYPE(sockaddr_type),
+ CHTI_COMMANDS(cht_dgramsockettoplevel_entries))
/**/
-#include "hbytes.h"
+#include "dgram.h"
-int setnonblock(int fd, int isnonblock) {
+int cht_setnonblock(int fd, int isnonblock) {
int r;
r= fcntl(fd,F_GETFL);
* ./rel/path/to/socket AF_UNIX
*/
-#include "hbytes.h"
-#include "tables.h"
+#include "dgram.h"
#define SOCKADDR_LEN(sa) ((sa)->end - (sa)->begin)
/* parsing */
-int pat_sockaddr(Tcl_Interp *ip, Tcl_Obj *o, SockAddr_Value *val) {
+int cht_pat_sockaddr(Tcl_Interp *ip, Tcl_Obj *o, SockAddr_Value *val) {
int rc;
rc= Tcl_ConvertToType(ip,o,&sockaddr_type);
return TCL_OK;
}
-Tcl_Obj *ret_sockaddr(Tcl_Interp *ip, SockAddr_Value val) {
+Tcl_Obj *cht_ret_sockaddr(Tcl_Interp *ip, SockAddr_Value val) {
Tcl_Obj *o;
o= Tcl_NewObj();
/* native type methods */
-void sockaddr_clear(SockAddr_Value *v) { v->begin= v->end= 0; }
+void cht_sockaddr_clear(SockAddr_Value *v) { v->begin= v->end= 0; }
-void sockaddr_create(SockAddr_Value *v, const struct sockaddr *addr, int len) {
+void cht_sockaddr_create(SockAddr_Value *v, const struct sockaddr *a, int al) {
Byte *begin;
- v->begin= begin= TALLOC(len);
- memcpy(begin, addr, len);
- v->end= begin + len;
+ v->begin= begin= TALLOC(al);
+ memcpy(begin, a, al);
+ v->end= begin + al;
}
-int sockaddr_len(const SockAddr_Value *v) {
+int cht_sockaddr_len(const SockAddr_Value *v) {
return SOCKADDR_LEN(v);
}
-const struct sockaddr *sockaddr_addr(const SockAddr_Value *v) {
+const struct sockaddr *cht_sockaddr_addr(const SockAddr_Value *v) {
return (const void*)v->begin;
}
-void sockaddr_free(const SockAddr_Value *v) {
+void cht_sockaddr_free(const SockAddr_Value *v) {
TFREE(v->begin);
}
/* Sockaddr Tcl type */
static void sockaddr_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
- sockaddr_create(OBJ_SOCKADDR(dup),
- sockaddr_addr(OBJ_SOCKADDR(src)),
- sockaddr_len(OBJ_SOCKADDR(src)));
- dup->typePtr= &hbytes_type;
+ cht_sockaddr_create(OBJ_SOCKADDR(dup),
+ cht_sockaddr_addr(OBJ_SOCKADDR(src)),
+ cht_sockaddr_len(OBJ_SOCKADDR(src)));
+ dup->typePtr= &cht_hbytes_type;
}
static void sockaddr_t_free(Tcl_Obj *o) {
- sockaddr_free(OBJ_SOCKADDR(o));
+ cht_sockaddr_free(OBJ_SOCKADDR(o));
}
static void sockaddr_t_ustr(Tcl_Obj *o) {
int al;
const char *string, *prepend;
- sa= sockaddr_addr(OBJ_SOCKADDR(o));
- al= sockaddr_len(OBJ_SOCKADDR(o));
+ sa= cht_sockaddr_addr(OBJ_SOCKADDR(o));
+ al= cht_sockaddr_len(OBJ_SOCKADDR(o));
switch (sa->sa_family) {
case AF_INET:
break;
default: /* ouch ! */
- obj_updatestr_array_prefix(o,(const void*)sa,al,"?");
+ cht_obj_updatestr_array_prefix(o,(const void*)sa,al,"?");
return;
}
- obj_updatestr_vstringls(o,
+ cht_obj_updatestr_vstringls(o,
prepend, strlen(prepend),
string, strlen(string),
(char*)0);
const char *comma, *path;
str= Tcl_GetStringFromObj(o,0); assert(str);
- objfreeir(o);
+ cht_objfreeir(o);
memset(&s,0,sizeof(s));
if (str[0]=='/' || (str[0]=='.' && str[1]=='/')) {
else { assert(str[0]=='/' && str[1]!='/'); path=str; }
if (strlen(str) >= sizeof(s.sun.sun_path))
- return staticerr(ip, "AF_UNIX path too long", "SOCKADDR AFUNIX LENGTH");
+ return cht_staticerr(ip, "AF_UNIX path too long", "SOCKADDR AFUNIX LENGTH");
strcpy(s.sun.sun_path, path);
TFREE(copy);
if (!iprv)
- return staticerr(ip, "bad IPv4 address syntax", "SOCKADDR SYNTAX IPV4");
+ return cht_staticerr(ip, "bad IPv4 address syntax", "SOCKADDR SYNTAX IPV4");
comma++;
if (!strcmp(comma,"*")) {
} else {
errno=0; port_l=strtoul(comma,&ep,10);
if (errno || *ep)
- return staticerr(ip, "bad IPv4 port", "SOCKADDR SYNTAX IPV4");
+ return cht_staticerr(ip, "bad IPv4 port", "SOCKADDR SYNTAX IPV4");
if (port_l > 65535)
- return staticerr(ip, "IPv4 port out of range", "SOCKADDR SYNTAX IPV4");
+ return cht_staticerr(ip, "IPv4 port out of range", "SOCKADDR SYNTAX IPV4");
s.sin.sin_port= htons(port_l);
}
} else {
- return staticerr(ip, "bad socket address syntax", "SOCKADDR SYNTAX OTHER");
+ return cht_staticerr(ip, "bad socket address syntax", "SOCKADDR SYNTAX OTHER");
}
- sockaddr_create(OBJ_SOCKADDR(o), (void*)&s, sl);
+ cht_sockaddr_create(OBJ_SOCKADDR(o), (void*)&s, sl);
o->typePtr = &sockaddr_type;
return TCL_OK;
/* from hook.c */
-void obj_updatestr_array(Tcl_Obj *o, const Byte *array, int l);
-void obj_updatestr_array_prefix(Tcl_Obj *o, const Byte *byte,
+void cht_obj_updatestr_array(Tcl_Obj *o, const Byte *array, int l);
+void cht_obj_updatestr_array_prefix(Tcl_Obj *o, const Byte *byte,
int l, const char *prefix);
/* from parse.c */
Table *hbytestoplevel TopLevel_Command
hbytes
- subcmd enum(HBytes/_SubCommand, "hbytes subcommand")
- ... obj
+ dispatch(HBytes/_SubCommand, "hbytes subcommand")
ulong
- subcmd enum(ULong/_SubCommand, "ulong subcommand")
- ... obj
+ dispatch(ULong/_SubCommand, "ulong subcommand")
Table ulong ULong_SubCommand
ul2int
cht_hb_free(OBJ_HBYTES(o));
}
-void obj_updatestr_array_prefix(Tcl_Obj *o, const Byte *byte,
+void cht_obj_updatestr_array_prefix(Tcl_Obj *o, const Byte *byte,
int l, const char *prefix) {
char *str;
int pl;
*str= 0;
}
-void obj_updatestr_array(Tcl_Obj *o, const Byte *byte, int l) {
- obj_updatestr_array_prefix(o,byte,l,"");
+void cht_obj_updatestr_array(Tcl_Obj *o, const Byte *byte, int l) {
+ cht_obj_updatestr_array_prefix(o,byte,l,"");
}
static void hbytes_t_ustr(Tcl_Obj *o) {
- obj_updatestr_array(o,
+ cht_obj_updatestr_array(o,
cht_hb_data(OBJ_HBYTES(o)),
cht_hb_len(OBJ_HBYTES(o)));
}
/* toplevel functions */
-int cht_do_hbytestoplevel_hbytes(ClientData cd, Tcl_Interp *ip,
- const HBytes_SubCommand *subcmd,
- int objc, Tcl_Obj *const *objv) {
- return subcmd->func(0,ip,objc,objv);
-}
-
-int cht_do_hbytestoplevel_ulong(ClientData cd, Tcl_Interp *ip,
- const ULong_SubCommand *subcmd,
- int objc, Tcl_Obj *const *objv) {
- return subcmd->func(0,ip,objc,objv);
-}
-
CHT_INIT(hbytes,
CHTI_TYPE(cht_hbytes_type) CHTI_TYPE(cht_ulong_type),
CHTI_COMMANDS(cht_hbytestoplevel_entries))