Add vstr_ins and vstr_cut_out; improve stmhal readline.
diff --git a/py/builtinimport.c b/py/builtinimport.c
index e64ca82..7cbb460 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -211,13 +211,13 @@
                     vstr_add_char(&path, PATH_SEP_CHAR);
                     vstr_add_str(&path, "__init__.py");
                     if (mp_import_stat(vstr_str(&path)) != MP_IMPORT_STAT_FILE) {
-                        vstr_cut_tail(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
+                        vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
                         nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ImportError,
                             "Per PEP-420 a dir without __init__.py (%s) is a namespace package; "
                             "namespace packages are not supported", vstr_str(&path)));
                     }
                     do_load(module_obj, &path);
-                    vstr_cut_tail(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
+                    vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
                 } else { // MP_IMPORT_STAT_FILE
                     do_load(module_obj, &path);
                     // TODO: We cannot just break here, at the very least, we must execute
diff --git a/py/lexer.c b/py/lexer.c
index be0b188..26fec12 100644
--- a/py/lexer.c
+++ b/py/lexer.c
@@ -516,7 +516,7 @@
         }
 
         // cut off the end quotes from the token text
-        vstr_cut_tail(&lex->vstr, n_closing);
+        vstr_cut_tail_bytes(&lex->vstr, n_closing);
 
     } else if (is_head_of_identifier(lex)) {
         tok->kind = MP_TOKEN_NAME;
diff --git a/py/misc.h b/py/misc.h
index 3671f42..19a21d5 100644
--- a/py/misc.h
+++ b/py/misc.h
@@ -63,8 +63,8 @@
 /** variable string *********************************************/
 
 typedef struct _vstr_t {
-    int alloc;
-    int len;
+    uint alloc;
+    uint len;
     char *buf;
     bool had_error : 1;
     bool fixed_buf : 1;
@@ -94,7 +94,11 @@
 void vstr_add_strn(vstr_t *vstr, const char *str, int len);
 //void vstr_add_le16(vstr_t *vstr, unsigned short v);
 //void vstr_add_le32(vstr_t *vstr, unsigned int v);
-void vstr_cut_tail(vstr_t *vstr, int len);
+void vstr_ins_byte(vstr_t *vstr, uint byte_pos, byte b);
+void vstr_ins_char(vstr_t *vstr, uint char_pos, unichar chr);
+void vstr_cut_head_bytes(vstr_t *vstr, uint bytes_to_cut);
+void vstr_cut_tail_bytes(vstr_t *vstr, uint bytes_to_cut);
+void vstr_cut_out_bytes(vstr_t *vstr, uint byte_pos, uint bytes_to_cut);
 void vstr_printf(vstr_t *vstr, const char *fmt, ...);
 
 /** non-dynamic size-bounded variable buffer/string *************/
diff --git a/py/vstr.c b/py/vstr.c
index 6630ac4..90c3c06 100644
--- a/py/vstr.c
+++ b/py/vstr.c
@@ -159,12 +159,12 @@
     return buf;
 }
 
-void vstr_add_byte(vstr_t *vstr, byte v) {
+void vstr_add_byte(vstr_t *vstr, byte b) {
     byte *buf = (byte*)vstr_add_len(vstr, 1);
     if (buf == NULL) {
         return;
     }
-    buf[0] = v;
+    buf[0] = b;
 }
 
 void vstr_add_char(vstr_t *vstr, unichar c) {
@@ -214,7 +214,48 @@
 }
 */
 
-void vstr_cut_tail(vstr_t *vstr, int len) {
+char *vstr_ins_blank_bytes(vstr_t *vstr, uint byte_pos, uint byte_len) {
+    if (vstr->had_error) {
+        return NULL;
+    }
+    uint l = vstr->len;
+    if (byte_pos > l) {
+        byte_pos = l;
+    }
+    if (byte_len > 0) {
+        // ensure room for the new bytes
+        if (!vstr_ensure_extra(vstr, byte_len)) {
+            return NULL;
+        }
+        // copy up the string to make room for the new bytes
+        memmove(vstr->buf + l - 1 + byte_len, vstr->buf + l - 1, l - byte_pos);
+        // increase the length
+        vstr->len += byte_len;
+        vstr->buf[vstr->len] = 0;
+    }
+    return vstr->buf + byte_pos;
+}
+
+void vstr_ins_byte(vstr_t *vstr, uint byte_pos, byte b) {
+    char *s = vstr_ins_blank_bytes(vstr, byte_pos, 1);
+    if (s != NULL) {
+        *s = b;
+    }
+}
+
+void vstr_ins_char(vstr_t *vstr, uint pos, unichar chr) {
+    // TODO UNICODE
+    char *s = vstr_ins_blank_bytes(vstr, pos, 1);
+    if (s != NULL) {
+        *s = chr;
+    }
+}
+
+void vstr_cut_head_bytes(vstr_t *vstr, uint bytes_to_cut) {
+    vstr_cut_out_bytes(vstr, 0, bytes_to_cut);
+}
+
+void vstr_cut_tail_bytes(vstr_t *vstr, uint len) {
     if (vstr->had_error) {
         return;
     }
@@ -226,6 +267,19 @@
     vstr->buf[vstr->len] = 0;
 }
 
+void vstr_cut_out_bytes(vstr_t *vstr, uint byte_pos, uint bytes_to_cut) {
+    if (vstr->had_error || byte_pos >= vstr->len) {
+        return;
+    } else if (byte_pos + bytes_to_cut >= vstr->len) {
+        vstr->len = byte_pos;
+        vstr->buf[vstr->len] = 0;
+    } else {
+        // move includes +1 for null byte at the end
+        memmove(vstr->buf + byte_pos, vstr->buf + byte_pos + bytes_to_cut, vstr->len - byte_pos - bytes_to_cut + 1);
+        vstr->len -= bytes_to_cut;
+    }
+}
+
 void vstr_printf(vstr_t *vstr, const char *fmt, ...) {
     va_list ap;
     va_start(ap, fmt);