aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2025-02-19 23:06:02 +0100
committerMattias Andrée <m@maandree.se>2025-02-19 23:06:02 +0100
commit24ebd3c309c5d6cad63bbf1b40de8c17aead0366 (patch)
tree7deab3ddadf241ccfaefc31e65916b6036689285
parentAdd tests for new escape sequences (diff)
downloadlibterminput-24ebd3c309c5d6cad63bbf1b40de8c17aead0366.tar.gz
libterminput-24ebd3c309c5d6cad63bbf1b40de8c17aead0366.tar.bz2
libterminput-24ebd3c309c5d6cad63bbf1b40de8c17aead0366.tar.xz
Add state marshalling and unmarshalling functions
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r--Makefile31
-rw-r--r--common.h23
-rw-r--r--libterminput.h46
l---------libterminput_clear_flags.31
-rw-r--r--libterminput_marshal_input.c27
-rw-r--r--libterminput_marshal_keypress__.c16
-rw-r--r--libterminput_marshal_mouseevent__.c20
-rw-r--r--libterminput_marshal_position__.c9
-rw-r--r--libterminput_marshal_state.c9
-rw-r--r--libterminput_marshal_text__.c12
-rw-r--r--libterminput_parse_csi_m_mouse_tracking__.c2
-rw-r--r--libterminput_parse_sequence__.c4
-rw-r--r--libterminput_read.c7
-rw-r--r--libterminput_read_bracketed_paste__.c2
-rw-r--r--libterminput_unmarshal_input.c30
-rw-r--r--libterminput_unmarshal_keypress__.c19
-rw-r--r--libterminput_unmarshal_mouseevent__.c23
-rw-r--r--libterminput_unmarshal_position__.c10
-rw-r--r--libterminput_unmarshal_state.c9
-rw-r--r--libterminput_unmarshal_text__.c13
20 files changed, 296 insertions, 17 deletions
diff --git a/Makefile b/Makefile
index 552a2e3..a6c1472 100644
--- a/Makefile
+++ b/Makefile
@@ -15,11 +15,26 @@ LIB_MINOR = 0
LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR)
+MAN3 =\
+ libterminput_read.3\
+ libterminput_is_ready.3\
+ libterminput_set_flags.3\
+ libterminput_clear_flags.3
+
OBJ =\
- libterminput_read.o\
- libterminput_is_ready.o\
- libterminput_set_flags.o\
- libterminput_clear_flags.o\
+ $(MAN3:.3=.o)\
+ libterminput_marshal_input.o\
+ libterminput_marshal_state.o\
+ libterminput_unmarshal_input.o\
+ libterminput_unmarshal_state.o\
+ libterminput_marshal_keypress__.o\
+ libterminput_marshal_text__.o\
+ libterminput_marshal_mouseevent__.o\
+ libterminput_marshal_position__.o\
+ libterminput_unmarshal_keypress__.o\
+ libterminput_unmarshal_text__.o\
+ libterminput_unmarshal_mouseevent__.o\
+ libterminput_unmarshal_position__.o\
libterminput_encode_utf8__.o\
libterminput_check_utf8_char__.o\
libterminput_utf8_decode__.o\
@@ -81,8 +96,7 @@ install: libterminput.a libterminput.$(LIBEXT)
$(FIX_INSTALL_NAME) "$(DESTDIR)$(PREFIX)/lib/libterminput.$(LIBMINOREXT)"
ln -sf -- libterminput.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/libterminput.$(LIBMAJOREXT)"
ln -sf -- libterminput.$(LIBMAJOREXT) "$(DESTDIR)$(PREFIX)/lib/libterminput.$(LIBEXT)"
- cp -- libterminput_read.3 libterminput_set_flags.3 libterminput_is_ready.3 "$(DESTDIR)$(MANPREFIX)/man3"
- ln -sf -- libterminput_set_flags.3 "$(DESTDIR)$(MANPREFIX)/man3/libterminput_clear_flags.3"
+ cp -P -- $(MAN3) "$(DESTDIR)$(MANPREFIX)/man3"
cp -- libterminput.7 "$(DESTDIR)$(MANPREFIX)/man7"
uninstall:
@@ -91,10 +105,7 @@ uninstall:
-rm -f -- "$(DESTDIR)$(PREFIX)/lib/libterminput.$(LIBEXT)"
-rm -f -- "$(DESTDIR)$(PREFIX)/lib/libterminput.a"
-rm -f -- "$(DESTDIR)$(PREFIX)/include/libterminput.h"
- -rm -f -- "$(DESTDIR)$(MANPREFIX)/man3/libterminput_read.3"
- -rm -f -- "$(DESTDIR)$(MANPREFIX)/man3/libterminput_set_flags.3"
- -rm -f -- "$(DESTDIR)$(MANPREFIX)/man3/libterminput_clear_flags.3"
- -rm -f -- "$(DESTDIR)$(MANPREFIX)/man3/libterminput_is_ready.3"
+ -cd -- "$(DESTDIR)$(MANPREFIX)/man3/" && rm -f -- $(MAN3)
-rm -f -- "$(DESTDIR)$(MANPREFIX)/man7/libterminput.7"
clean:
diff --git a/common.h b/common.h
index ba96f50..a1c385f 100644
--- a/common.h
+++ b/common.h
@@ -17,6 +17,19 @@
/**
+ * Mark that there is no input available or pending
+ *
+ * @param INPUT_OUT:union libterminput_input *input The input output
+ */
+#define NOTHING(INPUT_OUT)\
+ do {\
+ union libterminput_input *input__ = (INPUT_OUT);\
+ input__->type = LIBTERMINPUT_NONE;\
+ input__->keypress.key = LIBTERMINPUT_SYMBOL;\
+ } while (0);
+
+
+/**
* Singlar read symbol
*/
struct input {
@@ -130,5 +143,15 @@ HIDDEN void libterminput_parse_sequence__(union libterminput_input *input, struc
*/
HIDDEN int libterminput_read_symbol__(int fd, struct input *input, struct libterminput_state *ctx);
+/* TODO doc, test */
+HIDDEN int libterminput_marshal_keypress__(struct libterminput_marshaller *how, const struct libterminput_keypress *what);
+HIDDEN int libterminput_marshal_text__(struct libterminput_marshaller *how, const struct libterminput_text *what);
+HIDDEN int libterminput_marshal_mouseevent__(struct libterminput_marshaller *how, const struct libterminput_mouseevent *what);
+HIDDEN int libterminput_marshal_position__(struct libterminput_marshaller *how, const struct libterminput_position *what);
+HIDDEN int libterminput_unmarshal_keypress__(struct libterminput_unmarshaller *how, struct libterminput_keypress *what);
+HIDDEN int libterminput_unmarshal_text__(struct libterminput_unmarshaller *how, struct libterminput_text *what);
+HIDDEN int libterminput_unmarshal_mouseevent__(struct libterminput_unmarshaller *how, struct libterminput_mouseevent *what);
+HIDDEN int libterminput_unmarshal_position__(struct libterminput_unmarshaller *how, struct libterminput_position *what);
+
#undef HIDDEN
diff --git a/libterminput.h b/libterminput.h
index 46d47e2..d69cb0d 100644
--- a/libterminput.h
+++ b/libterminput.h
@@ -85,6 +85,7 @@ enum libterminput_flags {
LIBTERMINPUT_MACRO_ON_BLOCK = 0x0080
};
+
/**
* Modifier keys
*
@@ -108,6 +109,7 @@ enum libterminput_mod {
LIBTERMINPUT_CTRL = 0x04
};
+
/**
* Keyboard buttons
*
@@ -178,6 +180,7 @@ enum libterminput_key {
LIBTERMINPUT_KEYPAD_ENTER
};
+
/**
* Mouse buttons
*
@@ -264,6 +267,7 @@ enum libterminput_button {
LIBTERMINPUT_XBUTTON4
};
+
/**
* Input event type
*/
@@ -316,6 +320,7 @@ enum libterminput_type {
LIBTERMINPUT_CURSOR_POSITION /* response to CSI 6 n */
};
+
/**
* Mouse event subtype
*/
@@ -346,6 +351,7 @@ enum libterminput_event {
LIBTERMINPUT_HIGHLIGHT_OUTSIDE
};
+
/**
* Keypress event
*
@@ -395,6 +401,7 @@ struct libterminput_keypress {
char symbol[7];
};
+
/**
* Text from a bracketed paste
*/
@@ -424,6 +431,7 @@ struct libterminput_text {
char bytes[512];
};
+
/**
* Mouse event
*/
@@ -498,6 +506,7 @@ struct libterminput_mouseevent {
size_t end_y;
};
+
/**
* Cursor position response
*/
@@ -522,6 +531,7 @@ struct libterminput_position {
size_t y;
};
+
/**
* Input event
*/
@@ -529,7 +539,7 @@ union libterminput_input {
/**
* Input event type, used to determine which
* other member to read
- *
+ *
* The following values have no corresponding
* member to read data from:
* `LIBTERMINPUT_NONE`,
@@ -537,6 +547,12 @@ union libterminput_input {
* `LIBTERMINPUT_BRACKETED_PASTE_END`,
* `LIBTERMINPUT_TERMINAL_IS_OK`,
* `LIBTERMINPUT_TERMINAL_IS_NOT_OK`
+ *
+ * Internal comment:
+ * When `.type == LIBTERMINPUT_NONE`, `.keypress.key`
+ * is normally set to `LIBTERMINPUT_SYMBOL`, however
+ * if it is set to anything else, there is a queued
+ * keypress
*/
enum libterminput_type type;
@@ -590,6 +606,28 @@ struct libterminput_state {
};
+/* TODO doc */
+struct libterminput_marshaller {
+ int (*store)(struct libterminput_marshaller *this, const void *data, size_t size);
+ union {
+ void *ptr;
+ int i;
+ size_t zu;
+ } user;
+};
+
+
+/* TODO doc */
+struct libterminput_unmarshaller {
+ int (*load)(struct libterminput_unmarshaller *this, void *data, size_t size);
+ union {
+ void *ptr;
+ int i;
+ size_t zu;
+ } user;
+};
+
+
/**
* Get input from the terminal
*
@@ -652,5 +690,11 @@ int libterminput_set_flags(struct libterminput_state *ctx, enum libterminput_fla
*/
int libterminput_clear_flags(struct libterminput_state *ctx, enum libterminput_flags flags);
+/* TODO doc, man */
+int libterminput_marshal_input(struct libterminput_marshaller *how, const union libterminput_input *what);
+int libterminput_marshal_state(struct libterminput_marshaller *how, const struct libterminput_state *what);
+int libterminput_unmarshal_input(struct libterminput_unmarshaller *how, union libterminput_input *what);
+int libterminput_unmarshal_state(struct libterminput_unmarshaller *how, struct libterminput_state *what);
+
#endif
diff --git a/libterminput_clear_flags.3 b/libterminput_clear_flags.3
new file mode 120000
index 0000000..62881e4
--- /dev/null
+++ b/libterminput_clear_flags.3
@@ -0,0 +1 @@
+libterminput_set_flags.3 \ No newline at end of file
diff --git a/libterminput_marshal_input.c b/libterminput_marshal_input.c
new file mode 100644
index 0000000..9949838
--- /dev/null
+++ b/libterminput_marshal_input.c
@@ -0,0 +1,27 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_marshal_input(struct libterminput_marshaller *how, const union libterminput_input *what) /* TODO test */
+{
+ enum libterminput_type type = what->type;
+ if (how->store(how, &type, sizeof(type)))
+ return -1;
+ if (type == LIBTERMINPUT_NONE) {
+ if (what->keypress.key == LIBTERMINPUT_SYMBOL)
+ type = LIBTERMINPUT_KEYPRESS;
+ if (how->store(how, &type, sizeof(type)))
+ return -1;
+ }
+ if (type == LIBTERMINPUT_KEYPRESS)
+ return libterminput_marshal_keypress__(how, &what->keypress);
+ else if (type == LIBTERMINPUT_TEXT)
+ return libterminput_marshal_text__(how, &what->text);
+ else if (type == LIBTERMINPUT_MOUSEEVENT)
+ return libterminput_marshal_mouseevent__(how, &what->mouseevent);
+ else if (type == LIBTERMINPUT_CURSOR_POSITION)
+ return libterminput_marshal_position__(how, &what->position);
+ else
+ return 0;
+}
diff --git a/libterminput_marshal_keypress__.c b/libterminput_marshal_keypress__.c
new file mode 100644
index 0000000..1ffba01
--- /dev/null
+++ b/libterminput_marshal_keypress__.c
@@ -0,0 +1,16 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_marshal_keypress__(struct libterminput_marshaller *how, const struct libterminput_keypress *what)
+{
+ if (how->store(how, &what->key, sizeof(what->key)) ||
+ how->store(how, &what->times, sizeof(what->times)) ||
+ how->store(how, &what->mods, sizeof(what->mods)))
+ return -1;
+ if (what->key == LIBTERMINPUT_SYMBOL)
+ return how->store(how, what->symbol, sizeof(what->symbol));
+ else
+ return 0;
+}
diff --git a/libterminput_marshal_mouseevent__.c b/libterminput_marshal_mouseevent__.c
new file mode 100644
index 0000000..8fe64c7
--- /dev/null
+++ b/libterminput_marshal_mouseevent__.c
@@ -0,0 +1,20 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_marshal_mouseevent__(struct libterminput_marshaller *how, const struct libterminput_mouseevent *what)
+{
+ if (how->store(how, &what->event, sizeof(what->event)) ||
+ how->store(how, &what->x, sizeof(size_t) * 2U))
+ return -1;
+ if (what->event == LIBTERMINPUT_HIGHLIGHT_OUTSIDE) {
+ if (how->store(how, &what->start_x, sizeof(size_t) * 4U))
+ return -1;
+ } else if (what->event != LIBTERMINPUT_HIGHLIGHT_INSIDE) {
+ if (how->store(how, &what->mods, sizeof(what->mods)) ||
+ how->store(how, &what->button, sizeof(what->button)))
+ return -1;
+ }
+ return 0;
+}
diff --git a/libterminput_marshal_position__.c b/libterminput_marshal_position__.c
new file mode 100644
index 0000000..59fc20e
--- /dev/null
+++ b/libterminput_marshal_position__.c
@@ -0,0 +1,9 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_marshal_position__(struct libterminput_marshaller *how, const struct libterminput_position *what)
+{
+ return how->store(how, &what->x, sizeof(size_t) * 2U);
+}
diff --git a/libterminput_marshal_state.c b/libterminput_marshal_state.c
new file mode 100644
index 0000000..8c0c79c
--- /dev/null
+++ b/libterminput_marshal_state.c
@@ -0,0 +1,9 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_marshal_state(struct libterminput_marshaller *how, const struct libterminput_state *what) /* TODO test */
+{
+ return how->store(how, what, sizeof(*what));
+}
diff --git a/libterminput_marshal_text__.c b/libterminput_marshal_text__.c
new file mode 100644
index 0000000..fa9b542
--- /dev/null
+++ b/libterminput_marshal_text__.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_marshal_text__(struct libterminput_marshaller *how, const struct libterminput_text *what)
+{
+ if (how->store(how, &what->nbytes, sizeof(what->nbytes)) ||
+ how->store(how, what->bytes, sizeof(what->nbytes)))
+ return -1;
+ return 0;
+}
diff --git a/libterminput_parse_csi_m_mouse_tracking__.c b/libterminput_parse_csi_m_mouse_tracking__.c
index f943c04..988a665 100644
--- a/libterminput_parse_csi_m_mouse_tracking__.c
+++ b/libterminput_parse_csi_m_mouse_tracking__.c
@@ -45,7 +45,7 @@ libterminput_parse_csi_m_mouse_tracking__(union libterminput_input *input, struc
ctx->stored_head = ctx->stored_tail = 0;
} else {
- input->type = LIBTERMINPUT_NONE;
+ NOTHING(input);
return;
}
diff --git a/libterminput_parse_sequence__.c b/libterminput_parse_sequence__.c
index aaf0fb4..78f0161 100644
--- a/libterminput_parse_sequence__.c
+++ b/libterminput_parse_sequence__.c
@@ -112,7 +112,7 @@ libterminput_parse_sequence__(union libterminput_input *input, struct libterminp
break;
case 'u':
if (nums[0] > 0x10FFFFULL || (nums[0] & 0xFFF800ULL) == 0xD800ULL) {
- input->type = LIBTERMINPUT_NONE;
+ NOTHING(input);
break;
}
libterminput_encode_utf8__(nums[0], input->keypress.symbol);
@@ -268,7 +268,7 @@ libterminput_parse_sequence__(union libterminput_input *input, struct libterminp
default:
/* This shouldn't happen (without goto) */
suppress:
- input->type = LIBTERMINPUT_NONE;
+ NOTHING(input);
break;
}
}
diff --git a/libterminput_read.c b/libterminput_read.c
index 42bb710..9324573 100644
--- a/libterminput_read.c
+++ b/libterminput_read.c
@@ -74,6 +74,8 @@ again:
if (ctx->meta > 1)
input->keypress.mods |= LIBTERMINPUT_META;
ctx->queued = 1;
+ input->type = LIBTERMINPUT_NONE;
+ return 1;
}
goto none;
}
@@ -117,7 +119,8 @@ again:
if (ctx->meta > 1)
input->keypress.mods |= LIBTERMINPUT_META;
ctx->queued = 1;
- goto none;
+ input->type = LIBTERMINPUT_NONE;
+ return 1;
} else if (ctx->key[0] == '[' && ctx->key[1] == 'M' && (ctx->flags & LIBTERMINPUT_DECSET_1005)) {
ctx->mouse_tracking = 1;
n = ctx->stored_tail;
@@ -188,6 +191,6 @@ again:
return 1;
none:
- input->type = LIBTERMINPUT_NONE;
+ NOTHING(input);
return 1;
}
diff --git a/libterminput_read_bracketed_paste__.c b/libterminput_read_bracketed_paste__.c
index 02fecc5..b580b70 100644
--- a/libterminput_read_bracketed_paste__.c
+++ b/libterminput_read_bracketed_paste__.c
@@ -87,11 +87,11 @@ libterminput_read_bracketed_paste__(int fd, union libterminput_input *input, str
* end marker, output that we do not have any complete input,
* and pause as the available buffered input is incomplete */
if (input->text.nbytes < 6U) {
- input->text.type = LIBTERMINPUT_NONE;
memcpy(ctx->stored, input->text.bytes, input->text.nbytes);
ctx->stored_tail = 0;
ctx->stored_head = input->text.nbytes;
ctx->paused = 1;
+ NOTHING(input);
return 1;
}
diff --git a/libterminput_unmarshal_input.c b/libterminput_unmarshal_input.c
new file mode 100644
index 0000000..ef8606c
--- /dev/null
+++ b/libterminput_unmarshal_input.c
@@ -0,0 +1,30 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_unmarshal_input(struct libterminput_unmarshaller *how, union libterminput_input *what) /* TODO test */
+{
+ enum libterminput_type type;
+ int r;
+ if (how->load(how, &what->type, sizeof(what->type)))
+ return -1;
+ type = what->type;
+ if (what->type == LIBTERMINPUT_NONE) {
+ what->keypress.key = LIBTERMINPUT_SYMBOL;
+ if (how->load(how, &what->type, sizeof(what->type)))
+ return -1;
+ }
+ if (what->type == LIBTERMINPUT_KEYPRESS)
+ r = libterminput_unmarshal_keypress__(how, &what->keypress);
+ else if (what->type == LIBTERMINPUT_TEXT)
+ r = libterminput_unmarshal_text__(how, &what->text);
+ else if (what->type == LIBTERMINPUT_MOUSEEVENT)
+ r = libterminput_unmarshal_mouseevent__(how, &what->mouseevent);
+ else if (what->type == LIBTERMINPUT_CURSOR_POSITION)
+ r = libterminput_unmarshal_position__(how, &what->position);
+ else
+ r = 0;
+ what->type = type;
+ return r;
+}
diff --git a/libterminput_unmarshal_keypress__.c b/libterminput_unmarshal_keypress__.c
new file mode 100644
index 0000000..68a622d
--- /dev/null
+++ b/libterminput_unmarshal_keypress__.c
@@ -0,0 +1,19 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_unmarshal_keypress__(struct libterminput_unmarshaller *how, struct libterminput_keypress *what)
+{
+ what->type = LIBTERMINPUT_KEYPRESS;
+ if (how->load(how, &what->key, sizeof(what->key)) ||
+ how->load(how, &what->times, sizeof(what->times)) ||
+ how->load(how, &what->mods, sizeof(what->mods)))
+ return -1;
+ if (what->key == LIBTERMINPUT_SYMBOL) {
+ return how->load(how, what->symbol, sizeof(what->symbol));
+ } else {
+ memset(what->symbol, 0, sizeof(what->symbol));
+ return 0;
+ }
+}
diff --git a/libterminput_unmarshal_mouseevent__.c b/libterminput_unmarshal_mouseevent__.c
new file mode 100644
index 0000000..55f72ea
--- /dev/null
+++ b/libterminput_unmarshal_mouseevent__.c
@@ -0,0 +1,23 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_unmarshal_mouseevent__(struct libterminput_unmarshaller *how, struct libterminput_mouseevent *what)
+{
+ what->type = LIBTERMINPUT_MOUSEEVENT;
+ if (how->load(how, &what->event, sizeof(what->event)) ||
+ how->load(how, &what->x, sizeof(size_t) * 2U))
+ return -1;
+ what->mods = 0;
+ what->button = LIBTERMINPUT_BUTTON1;
+ if (what->event == LIBTERMINPUT_HIGHLIGHT_OUTSIDE) {
+ if (how->load(how, &what->start_x, sizeof(size_t) * 4U))
+ return -1;
+ } else if (what->event != LIBTERMINPUT_HIGHLIGHT_INSIDE) {
+ if (how->load(how, &what->mods, sizeof(what->mods)) ||
+ how->load(how, &what->button, sizeof(what->button)))
+ return -1;
+ }
+ return 0;
+}
diff --git a/libterminput_unmarshal_position__.c b/libterminput_unmarshal_position__.c
new file mode 100644
index 0000000..9040c50
--- /dev/null
+++ b/libterminput_unmarshal_position__.c
@@ -0,0 +1,10 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_unmarshal_position__(struct libterminput_unmarshaller *how, struct libterminput_position *what)
+{
+ what->type = LIBTERMINPUT_CURSOR_POSITION;
+ return how->load(how, &what->x, sizeof(size_t) * 2U);
+}
diff --git a/libterminput_unmarshal_state.c b/libterminput_unmarshal_state.c
new file mode 100644
index 0000000..fd1d6db
--- /dev/null
+++ b/libterminput_unmarshal_state.c
@@ -0,0 +1,9 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_unmarshal_state(struct libterminput_unmarshaller *how, struct libterminput_state *what) /* TODO test */
+{
+ return how->load(how, what, sizeof(*what));
+}
diff --git a/libterminput_unmarshal_text__.c b/libterminput_unmarshal_text__.c
new file mode 100644
index 0000000..4843db4
--- /dev/null
+++ b/libterminput_unmarshal_text__.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libterminput_unmarshal_text__(struct libterminput_unmarshaller *how, struct libterminput_text *what)
+{
+ what->type = LIBTERMINPUT_TEXT;
+ if (how->load(how, &what->nbytes, sizeof(what->nbytes)) ||
+ how->load(how, what->bytes, sizeof(what->nbytes)))
+ return -1;
+ return 0;
+}