// method socket.recvfrom(bufsize) STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { mod_network_socket_obj_t *self = self_in; if (self->nic == MP_OBJ_NULL) { // not connected mp_raise_OSError(MP_ENOTCONN); } vstr_t vstr; vstr_init_len(&vstr, mp_obj_get_int(len_in)); byte ip[4]; mp_uint_t port; int _errno; mp_int_t ret = self->nic_type->recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno); if (ret == -1) { mp_raise_OSError(_errno); } mp_obj_t tuple[2]; if (ret == 0) { tuple[0] = mp_const_empty_bytes; } else { vstr.len = ret; tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); return mp_obj_new_tuple(2, tuple); }
// method socket.recvfrom(bufsize) STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { mod_network_socket_obj_t *self = self_in; vstr_t vstr; vstr_init_len(&vstr, mp_obj_get_int(len_in)); byte ip[4]; mp_uint_t port; int _errno; mp_int_t ret = wlan_socket_recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno); if (ret < 0) { if (_errno == EAGAIN && self->sock_base.has_timeout) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TimeoutError, "timed out")); } nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); } mp_obj_t tuple[2]; if (ret == 0) { tuple[0] = mp_const_empty_bytes; } else { vstr.len = ret; vstr.buf[vstr.len] = '\0'; tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_LITTLE); return mp_obj_new_tuple(2, tuple); }
// method socket.recvfrom(bufsize) STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { mod_network_socket_obj_t *self = self_in; if (self->nic == MP_OBJ_NULL) { // not connected nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN))); } vstr_t vstr; vstr_init_len(&vstr, mp_obj_get_int(len_in)); byte ip[4]; mp_uint_t port; int _errno; mp_int_t ret = self->nic_type->recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno); if (ret == -1) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); } mp_obj_t tuple[2]; if (ret == 0) { tuple[0] = mp_const_empty_bytes; } else { vstr.len = ret; vstr.buf[vstr.len] = '\0'; tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } tuple[1] = mod_network_format_inet_addr(ip, port); return mp_obj_new_tuple(2, tuple); }
/** * def system(command) */ static mp_obj_t os_system(mp_obj_t command_in) { int res; char command[128]; struct vstr_chan_t chout; strncpy(command, mp_obj_str_get_str(command_in), membersof(command)); command[membersof(command) - 1] = '\0'; vstr_chan_init(&chout); res = fs_call(command, sys_get_stdin(), &chout, NULL); if (res == -ENOENT) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Command not found: '%s'", mp_obj_str_get_str(command_in))); } else if (res != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Command failed with %d", res)); } return (mp_obj_new_str_from_vstr(&mp_type_str, vstr_chan_get_vstr(&chout))); }
STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) { vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 8, &print); mp_obj_print_helper(&print, obj, PRINT_JSON); return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); }
STATIC mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) { lwip_socket_obj_t *socket = self_in; int _errno; lwip_socket_check_connected(socket); mp_int_t len = mp_obj_get_int(len_in); vstr_t vstr; vstr_init_len(&vstr, len); mp_uint_t ret = 0; switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: { ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno); break; } case MOD_NETWORK_SOCK_DGRAM: { ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, NULL, NULL, &_errno); break; } } if (ret == -1) { mp_raise_OSError(_errno); } if (ret == 0) { return mp_const_empty_bytes; } vstr.len = ret; return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); }
STATIC mp_obj_t os_urandom(mp_obj_t num) { mp_int_t n = mp_obj_get_int(num); vstr_t vstr; vstr_init_len(&vstr, n); for (int i = 0; i < n; i++) { vstr.buf[i] = *WDEV_HWRNG; } return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); }
// Unbuffered, inefficient implementation of readline() for raw I/O files. STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) { const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); mp_int_t max_size = -1; if (n_args > 1) { max_size = MP_OBJ_SMALL_INT_VALUE(args[1]); } vstr_t vstr; if (max_size != -1) { vstr_init(&vstr, max_size); } else { vstr_init(&vstr, 16); } while (max_size == -1 || max_size-- != 0) { char *p = vstr_add_len(&vstr, 1); if (p == NULL) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory")); } int error; mp_uint_t out_sz = stream_p->read(args[0], p, 1, &error); if (out_sz == MP_STREAM_ERROR) { if (mp_is_nonblocking_error(error)) { if (vstr.len == 1) { // We just incremented it, but otherwise we read nothing // and immediately got EAGAIN. This case is not well // specified in // https://docs.python.org/3/library/io.html#io.IOBase.readline // unlike similar case for read(). But we follow the latter's // behavior - return None. vstr_clear(&vstr); return mp_const_none; } else { goto done; } } mp_raise_OSError(error); } if (out_sz == 0) { done: // Back out previously added byte // Consider, what's better - read a char and get OutOfMemory (so read // char is lost), or allocate first as we do. vstr_cut_tail_bytes(&vstr, 1); break; } if (*p == '\n') { break; } } return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); }
STATIC mp_obj_t mp_builtin_input(uint n_args, const mp_obj_t *args) { if (n_args == 1) { mp_obj_print(args[0], PRINT_STR); } vstr_t line; vstr_init(&line, 16); int ret = readline(&line, ""); if (line.len == 0 && ret == CHAR_CTRL_D) { nlr_raise(mp_obj_new_exception(&mp_type_EOFError)); } return mp_obj_new_str_from_vstr(&mp_type_str, &line); }
STATIC mp_obj_t mod_socket_inet_ntop(mp_obj_t family_in, mp_obj_t binaddr_in) { int family = mp_obj_get_int(family_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(binaddr_in, &bufinfo, MP_BUFFER_READ); vstr_t vstr; vstr_init_len(&vstr, family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN); if (inet_ntop(family, bufinfo.buf, vstr.buf, vstr.len) == NULL) { mp_raise_OSError(errno); } vstr.len = strlen(vstr.buf); return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); }
// method socket.recv(bufsize) STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { mod_network_socket_obj_t *self = self_in; mp_int_t len = mp_obj_get_int(len_in); vstr_t vstr; vstr_init_len(&vstr, len); int _errno; mp_uint_t ret = wlan_socket_recv(self, (byte*)vstr.buf, len, &_errno); if (ret == -1) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); } if (ret == 0) { return mp_const_empty_bytes; } vstr.len = ret; vstr.buf[vstr.len] = '\0'; return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); }
mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in, struct sockaddr *from, socklen_t *from_len) { socket_obj_t *sock = MP_OBJ_TO_PTR(self_in); size_t len = mp_obj_get_int(len_in); vstr_t vstr; vstr_init_len(&vstr, len); // XXX Would be nicer to use RTC to handle timeouts for (int i=0; i<=sock->retries; i++) { MP_THREAD_GIL_EXIT(); int r = lwip_recvfrom_r(sock->fd, vstr.buf, len, 0, from, from_len); MP_THREAD_GIL_ENTER(); if (r >= 0) { vstr.len = r; return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } if (errno != EWOULDBLOCK) exception_from_errno(errno); check_for_exceptions(); } mp_raise_OSError(MP_ETIMEDOUT); }
STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { lwip_socket_obj_t *socket = self_in; int _errno; if (socket->pcb == NULL) { // not connected _errno = error_lookup_table[-(socket->connected)]; socket->connected = -16; nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); } mp_int_t len = mp_obj_get_int(len_in); vstr_t vstr; vstr_init_len(&vstr, len); byte ip[4]; mp_uint_t port; mp_uint_t ret = 0; switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: { memcpy(ip, &socket->peer, 4); port = (mp_uint_t) socket->peer_port; ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno); break; } case MOD_NETWORK_SOCK_DGRAM: { ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, ip, &port, &_errno); break; } } if (ret == -1) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); } mp_obj_t tuple[2]; if (ret == 0) { tuple[0] = mp_const_empty_bytes; } else { vstr.len = ret; tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); return mp_obj_new_tuple(2, tuple); }
STATIC mp_obj_t load_obj(mp_reader_t *reader) { byte obj_type = read_byte(reader); if (obj_type == 'e') { return MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj); } else { size_t len = read_uint(reader); vstr_t vstr; vstr_init_len(&vstr, len); read_bytes(reader, (byte*)vstr.buf, len); if (obj_type == 's' || obj_type == 'b') { return mp_obj_new_str_from_vstr(obj_type == 's' ? &mp_type_str : &mp_type_bytes, &vstr); } else if (obj_type == 'i') { return mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL); } else { assert(obj_type == 'f' || obj_type == 'c'); return mp_parse_num_decimal(vstr.buf, vstr.len, obj_type == 'c', false, NULL); } } }
/** * def read(self, mask) */ static mp_obj_t class_queue_read(mp_obj_t self_in, mp_obj_t size_in) { struct class_queue_t *self_p; vstr_t vstr; size_t size; self_p = MP_OBJ_TO_PTR(self_in); size = mp_obj_get_int(size_in); vstr_init_len(&vstr, size); size = queue_read(&self_p->queue, vstr.buf, size); if (size <= 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "failed to read from queue")); } return (mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr)); }
/** * def read_block(self, block) */ static mp_obj_t class_sd_read_block(mp_obj_t self_in, mp_obj_t block_in) { struct class_sd_t *self_p; vstr_t vstr; uint32_t block; self_p = MP_OBJ_TO_PTR(self_in); block = mp_obj_get_int(block_in); vstr_init_len(&vstr, SD_BLOCK_SIZE); if (sd_read_block(&self_p->drv, vstr.buf, block) != SD_BLOCK_SIZE) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "sd_read_block(%d) failed", block)); } return (mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr)); }
// method socket.recv(bufsize) STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { mod_network_socket_obj_t *self = self_in; if (self->nic == MP_OBJ_NULL) { // not connected nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN))); } mp_int_t len = mp_obj_get_int(len_in); vstr_t vstr; vstr_init_len(&vstr, len); int _errno; mp_uint_t ret = self->nic_type->recv(self, (byte*)vstr.buf, len, &_errno); if (ret == -1) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); } if (ret == 0) { return mp_const_empty_bytes; } vstr.len = ret; return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); }
// method socket.recv(bufsize) STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { mod_network_socket_obj_t *self = self_in; mp_int_t len = mp_obj_get_int(len_in); vstr_t vstr; vstr_init_len(&vstr, len); int _errno; mp_int_t ret = wlan_socket_recv(self, (byte*)vstr.buf, len, &_errno); if (ret < 0) { if (_errno == EAGAIN && self->sock_base.has_timeout) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TimeoutError, "timed out")); } nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); } if (ret == 0) { return mp_const_empty_bytes; } vstr.len = ret; vstr.buf[vstr.len] = '\0'; return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); }
STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { mp_int_t max_len = mp_obj_get_int(len_in); vstr_t vstr; // +1 to accommodate for trailing \0 vstr_init_len(&vstr, max_len + 1); int err; mp_uint_t len = sock_read(self_in, vstr.buf, max_len, &err); if (len == MP_STREAM_ERROR) { vstr_clear(&vstr); mp_raise_OSError(err); } if (len == 0) { vstr_clear(&vstr); return mp_const_empty_bytes; } vstr.len = len; return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); }
STATIC mp_obj_t stream_readall(mp_obj_t self_in) { const mp_stream_p_t *stream_p = mp_get_stream(self_in); mp_uint_t total_size = 0; vstr_t vstr; vstr_init(&vstr, DEFAULT_BUFFER_SIZE); char *p = vstr.buf; mp_uint_t current_read = DEFAULT_BUFFER_SIZE; while (true) { int error; mp_uint_t out_sz = stream_p->read(self_in, p, current_read, &error); if (out_sz == MP_STREAM_ERROR) { if (mp_is_nonblocking_error(error)) { // With non-blocking streams, we read as much as we can. // If we read nothing, return None, just like read(). // Otherwise, return data read so far. if (total_size == 0) { return mp_const_none; } break; } mp_raise_OSError(error); } if (out_sz == 0) { break; } total_size += out_sz; if (out_sz < current_read) { current_read -= out_sz; p += out_sz; } else { p = vstr_extend(&vstr, DEFAULT_BUFFER_SIZE); current_read = DEFAULT_BUFFER_SIZE; } } vstr.len = total_size; return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); }
STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { lwip_socket_obj_t *socket = self_in; int _errno; lwip_socket_check_connected(socket); mp_int_t len = mp_obj_get_int(len_in); vstr_t vstr; vstr_init_len(&vstr, len); byte ip[4]; mp_uint_t port; mp_uint_t ret = 0; switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: { memcpy(ip, &socket->peer, sizeof(socket->peer)); port = (mp_uint_t) socket->peer_port; ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno); break; } case MOD_NETWORK_SOCK_DGRAM: { ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, ip, &port, &_errno); break; } } if (ret == -1) { mp_raise_OSError(_errno); } mp_obj_t tuple[2]; if (ret == 0) { tuple[0] = mp_const_empty_bytes; } else { vstr.len = ret; tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); return mp_obj_new_tuple(2, tuple); }
STATIC mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) { lwip_socket_obj_t *socket = self_in; int _errno; if (socket->pcb == NULL) { // not connected _errno = error_lookup_table[-(socket->connected)]; socket->connected = -16; nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); } mp_int_t len = mp_obj_get_int(len_in); vstr_t vstr; vstr_init_len(&vstr, len); mp_uint_t ret = 0; switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: { ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno); break; } case MOD_NETWORK_SOCK_DGRAM: { ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, NULL, NULL, &_errno); break; } } if (ret == -1) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); } if (ret == 0) { return mp_const_empty_bytes; } vstr.len = ret; return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); }
STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) { vstr_t vstr; vstr_init(&vstr, 8); mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, &vstr, obj, PRINT_JSON); return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); }
STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) { // What to do if sz < -1? Python docs don't specify this case. // CPython does a readall, but here we silently let negatives through, // and they will cause a MemoryError. mp_int_t sz; if (n_args == 1 || ((sz = mp_obj_get_int(args[1])) == -1)) { return stream_readall(args[0]); } const mp_stream_p_t *stream_p = mp_get_stream(args[0]); #if MICROPY_PY_BUILTINS_STR_UNICODE if (stream_p->is_text) { // We need to read sz number of unicode characters. Because we don't have any // buffering, and because the stream API can only read bytes, we must read here // in units of bytes and must never over read. If we want sz chars, then reading // sz bytes will never over-read, so we follow this approach, in a loop to keep // reading until we have exactly enough chars. This will be 1 read for text // with ASCII-only chars, and about 2 reads for text with a couple of non-ASCII // chars. For text with lots of non-ASCII chars, it'll be pretty inefficient // in time and memory. vstr_t vstr; vstr_init(&vstr, sz); mp_uint_t more_bytes = sz; mp_uint_t last_buf_offset = 0; while (more_bytes > 0) { char *p = vstr_add_len(&vstr, more_bytes); int error; mp_uint_t out_sz = mp_stream_read_exactly(args[0], p, more_bytes, &error); if (error != 0) { vstr_cut_tail_bytes(&vstr, more_bytes); if (mp_is_nonblocking_error(error)) { // With non-blocking streams, we read as much as we can. // If we read nothing, return None, just like read(). // Otherwise, return data read so far. // TODO what if we have read only half a non-ASCII char? if (vstr.len == 0) { vstr_clear(&vstr); return mp_const_none; } break; } mp_raise_OSError(error); } if (out_sz < more_bytes) { // Finish reading. // TODO what if we have read only half a non-ASCII char? vstr_cut_tail_bytes(&vstr, more_bytes - out_sz); if (out_sz == 0) { break; } } // count chars from bytes just read for (mp_uint_t off = last_buf_offset;;) { byte b = vstr.buf[off]; int n; if (!UTF8_IS_NONASCII(b)) { // 1-byte ASCII char n = 1; } else if ((b & 0xe0) == 0xc0) { // 2-byte char n = 2; } else if ((b & 0xf0) == 0xe0) { // 3-byte char n = 3; } else if ((b & 0xf8) == 0xf0) { // 4-byte char n = 4; } else { // TODO n = 5; } if (off + n <= vstr.len) { // got a whole char in n bytes off += n; sz -= 1; last_buf_offset = off; if (off >= vstr.len) { more_bytes = sz; break; } } else { // didn't get a whole char, so work out how many extra bytes are needed for // this partial char, plus bytes for additional chars that we want more_bytes = (off + n - vstr.len) + (sz - 1); break; } } } return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } #endif vstr_t vstr; vstr_init_len(&vstr, sz); int error; mp_uint_t out_sz = mp_stream_rw(args[0], vstr.buf, sz, &error, flags); if (error != 0) { vstr_clear(&vstr); if (mp_is_nonblocking_error(error)) { // https://docs.python.org/3.4/library/io.html#io.RawIOBase.read // "If the object is in non-blocking mode and no bytes are available, // None is returned." // This is actually very weird, as naive truth check will treat // this as EOF. return mp_const_none; } mp_raise_OSError(error); } else { vstr.len = out_sz; return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); } }
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) { // check that the given type is an exception type assert(exc_type->make_new == mp_obj_exception_make_new); // make exception object mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. // Unfortunately, we won't be able to format the string... o = &MP_STATE_VM(mp_emergency_exception_obj); o->base.type = exc_type; o->traceback_data = NULL; o->args = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF // If the user has provided a buffer, then we try to create a tuple // of length 1, which has a string object and the string data. if (mp_emergency_exception_buf_size > (sizeof(mp_obj_tuple_t) + sizeof(mp_obj_str_t) + sizeof(mp_obj_t))) { mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)MP_STATE_VM(mp_emergency_exception_buf); mp_obj_str_t *str = (mp_obj_str_t *)&tuple->items[1]; tuple->base.type = &mp_type_tuple; tuple->len = 1; tuple->items[0] = MP_OBJ_FROM_PTR(str); byte *str_data = (byte *)&str[1]; uint max_len = MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - str_data; vstr_t vstr; vstr_init_fixed_buf(&vstr, max_len, (char *)str_data); va_list ap; va_start(ap, fmt); vstr_vprintf(&vstr, fmt, ap); va_end(ap); str->base.type = &mp_type_str; str->hash = qstr_compute_hash(str_data, str->len); str->len = vstr.len; str->data = str_data; o->args = tuple; uint offset = &str_data[str->len] - MP_STATE_VM(mp_emergency_exception_buf); offset += sizeof(void *) - 1; offset &= ~(sizeof(void *) - 1); if ((mp_emergency_exception_buf_size - offset) > (sizeof(o->traceback_data[0]) * 3)) { // We have room to store some traceback. o->traceback_data = (size_t*)((byte *)MP_STATE_VM(mp_emergency_exception_buf) + offset); o->traceback_alloc = (MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - (byte *)o->traceback_data) / sizeof(o->traceback_data[0]); o->traceback_len = 0; } } #endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF } else { o->base.type = exc_type; o->traceback_data = NULL; o->args = MP_OBJ_TO_PTR(mp_obj_new_tuple(1, NULL)); assert(fmt != NULL); { if (strchr(fmt, '%') == NULL) { // no formatting substitutions, avoid allocating vstr. o->args->items[0] = mp_obj_new_str(fmt, strlen(fmt), false); } else { // render exception message and store as .args[0] va_list ap; vstr_t vstr; vstr_init(&vstr, 16); va_start(ap, fmt); vstr_vprintf(&vstr, fmt, ap); va_end(ap); o->args->items[0] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } } } return MP_OBJ_FROM_PTR(o); }