Merge pull request #7381 from jepler/issue7380

Correctly handle settings.toml that ends without a newline
This commit is contained in:
Jeff Epler 2022-12-27 11:42:24 -06:00 committed by GitHub
commit b0a635af4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 107 additions and 42 deletions

View File

@ -90,7 +90,7 @@ clean:
rm -rf autoapi rm -rf autoapi
rm -rf $(STUBDIR) $(DISTDIR) *.egg-info rm -rf $(STUBDIR) $(DISTDIR) *.egg-info
html: stubs html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo @echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html." @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

View File

@ -65,6 +65,11 @@ msgstr ""
msgid "%02X" msgid "%02X"
msgstr "" msgstr ""
#: shared-module/os/getenv.c
#, c-format
msgid "%S"
msgstr ""
#: shared-bindings/rgbmatrix/RGBMatrix.c #: shared-bindings/rgbmatrix/RGBMatrix.c
#, c-format #, c-format
msgid "" msgid ""
@ -488,6 +493,11 @@ msgstr ""
msgid "Already scanning for wifi networks" msgid "Already scanning for wifi networks"
msgstr "" msgstr ""
#: shared-module/os/getenv.c
#, c-format
msgid "An error occurred while retrieving '%s':\n"
msgstr ""
#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c #: ports/stm/common-hal/audiopwmio/PWMAudioOut.c
msgid "Another PWMAudioOut is already active" msgid "Another PWMAudioOut is already active"
msgstr "" msgstr ""
@ -1754,10 +1764,6 @@ msgid ""
"constructor" "constructor"
msgstr "" msgstr ""
#: ports/espressif/common-hal/espulp/ULP.c
msgid "Pins 21+ not supported from ULP"
msgstr ""
#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c #: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c
msgid "Pins must be sequential" msgid "Pins must be sequential"
msgstr "" msgstr ""

View File

@ -38,9 +38,11 @@ typedef enum {
// Allocation free version that returns the full length of the value. // Allocation free version that returns the full length of the value.
// If it fits, the return value is 0-terminated. The passed in buffer // If it fits, the return value is 0-terminated. The passed in buffer
// may be modified even if an error is returned. Allocation free. // may be modified even if an error is returned. Allocation free.
// An error that is not 'open' or 'not found' is printed on the repl.
os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len); os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len);
// Returns GETENV_OK and sets value to the read value. Returns // Returns GETENV_OK and sets value to the read value. Returns
// GETENV_ERR_... if the value was not numeric. allocation-free. // GETENV_ERR_... if the value was not numeric. allocation-free.
// If any error code is returned, value is guaranteed not modified // If any error code is returned, value is guaranteed not modified
// An error that is not 'open' or 'not found' is printed on the repl.
os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value); os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value);

View File

@ -28,6 +28,7 @@
// tested in the unix "coverage" build, without bringing in "our" os module // tested in the unix "coverage" build, without bringing in "our" os module
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h>
#include <string.h> #include <string.h>
#include "shared-bindings/os/__init__.h" #include "shared-bindings/os/__init__.h"
@ -36,6 +37,7 @@
#include "py/gc.h" #include "py/gc.h"
#include "py/misc.h" #include "py/misc.h"
#include "py/mpstate.h" #include "py/mpstate.h"
#include "py/mpprint.h"
#include "py/objstr.h" #include "py/objstr.h"
#include "py/parsenum.h" #include "py/parsenum.h"
#include "py/runtime.h" #include "py/runtime.h"
@ -199,6 +201,7 @@ STATIC os_getenv_err_t read_string_value(file_arg *active_file, vstr_t *buf) {
case '#': case '#':
next_line(active_file); next_line(active_file);
MP_FALLTHROUGH; MP_FALLTHROUGH;
case 0:
case '\n': case '\n':
return GETENV_OK; return GETENV_OK;
default: default:
@ -255,7 +258,6 @@ STATIC os_getenv_err_t read_bare_value(file_arg *active_file, vstr_t *buf, int f
while (true) { while (true) {
switch (character) { switch (character) {
case 0: case 0:
return GETENV_ERR_UNEXPECTED | character;
case '\n': case '\n':
return GETENV_OK; return GETENV_OK;
case '#': case '#':
@ -311,7 +313,58 @@ STATIC os_getenv_err_t os_getenv_buf_terminated(const char *key, char *value, si
return result; return result;
} }
os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len) { STATIC void print_dont_raise(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, ...) {
va_list argptr;
va_start(argptr,fmt);
mp_vcprintf(&mp_plat_print, fmt, argptr);
mp_printf(&mp_plat_print, "\n");
va_end(argptr);
}
STATIC void handle_getenv_error(os_getenv_err_t error, void (*handle)(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, ...)) {
if (error == GETENV_OK) {
return;
}
if (error & GETENV_ERR_UNEXPECTED) {
byte character = (error & 0xff);
char buf[8];
vstr_t vstr;
vstr_init_fixed_buf(&vstr, sizeof(buf), buf);
mp_print_t print = { .data = &vstr, .print_strn = (mp_print_strn_t)vstr_add_strn };
if (character) {
mp_str_print_quoted(&print, &character, 1, true);
} else {
mp_str_print_quoted(&print, (byte *)"EOF", 3, true);
}
handle(&mp_type_ValueError, translate("Invalid byte %.*s"), vstr.len, vstr.buf);
} else {
switch (error) {
case GETENV_ERR_OPEN:
handle(&mp_type_ValueError, translate("%S"), translate("File not found"));
break;
case GETENV_ERR_UNICODE:
handle(&mp_type_ValueError, translate("%S"), translate("Invalid unicode escape"));
break;
case GETENV_ERR_NOT_FOUND:
handle(&mp_type_ValueError, translate("%S"), translate("Key not found"));
break;
default:
handle(&mp_type_RuntimeError, translate("%S"), translate("Internal error"));
break;
}
}
}
STATIC void common_hal_os_getenv_showerr(const char *key, os_getenv_err_t result) {
if (result != GETENV_OK && result != GETENV_ERR_OPEN && result != GETENV_ERR_NOT_FOUND) {
mp_cprintf(&mp_plat_print, translate("An error occurred while retrieving '%s':\n"), key);
handle_getenv_error(result, print_dont_raise);
}
}
STATIC
os_getenv_err_t common_hal_os_getenv_str_inner(const char *key, char *value, size_t value_len) {
bool quoted; bool quoted;
os_getenv_err_t result = os_getenv_buf_terminated(key, value, value_len, &quoted); os_getenv_err_t result = os_getenv_buf_terminated(key, value, value_len, &quoted);
if (result == GETENV_OK && !quoted) { if (result == GETENV_OK && !quoted) {
@ -320,33 +373,10 @@ os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t va
return result; return result;
} }
STATIC void throw_getenv_error(os_getenv_err_t error) { os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len) {
if (error == GETENV_OK) { os_getenv_err_t result = common_hal_os_getenv_str_inner(key, value, value_len);
return; common_hal_os_getenv_showerr(key, result);
} return result;
if (error & GETENV_ERR_UNEXPECTED) {
byte character = (error & 0xff);
mp_print_t print;
vstr_t vstr;
vstr_init_print(&vstr, 8 + 4 + 1, &print);
if (character) {
mp_str_print_quoted(&print, &character, 1, true);
} else {
mp_str_print_quoted(&print, (byte *)"EOF", 3, true);
}
mp_raise_ValueError_varg(translate("Invalid byte %.*s"),
vstr.len, vstr.buf);
}
switch (error) {
case GETENV_ERR_OPEN:
mp_raise_ValueError(translate("File not found"));
case GETENV_ERR_UNICODE:
mp_raise_ValueError(translate("Invalid unicode escape"));
case GETENV_ERR_NOT_FOUND:
mp_raise_ValueError(translate("Key not found"));
default:
mp_raise_RuntimeError(translate("Internal error"));
}
} }
mp_obj_t common_hal_os_getenv_path(const char *path, const char *key, mp_obj_t default_) { mp_obj_t common_hal_os_getenv_path(const char *path, const char *key, mp_obj_t default_) {
@ -358,7 +388,7 @@ mp_obj_t common_hal_os_getenv_path(const char *path, const char *key, mp_obj_t d
if (result == GETENV_ERR_NOT_FOUND || result == GETENV_ERR_OPEN) { if (result == GETENV_ERR_NOT_FOUND || result == GETENV_ERR_OPEN) {
return default_; return default_;
} }
throw_getenv_error(result); handle_getenv_error(result, mp_raise_msg_varg);
if (quoted) { if (quoted) {
return mp_obj_new_str_from_vstr(&mp_type_str, &buf); return mp_obj_new_str_from_vstr(&mp_type_str, &buf);
@ -371,7 +401,7 @@ mp_obj_t common_hal_os_getenv(const char *key, mp_obj_t default_) {
return common_hal_os_getenv_path(GETENV_PATH, key, default_); return common_hal_os_getenv_path(GETENV_PATH, key, default_);
} }
os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value) { STATIC os_getenv_err_t common_hal_os_getenv_int_inner(const char *key, mp_int_t *value) {
char buf[16]; char buf[16];
bool quoted; bool quoted;
os_getenv_err_t result = os_getenv_buf_terminated(key, buf, sizeof(buf), &quoted); os_getenv_err_t result = os_getenv_buf_terminated(key, buf, sizeof(buf), &quoted);
@ -389,3 +419,9 @@ os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value) {
*value = (mp_int_t)num; *value = (mp_int_t)num;
return GETENV_OK; return GETENV_OK;
} }
os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value) {
os_getenv_err_t result = common_hal_os_getenv_int_inner(key, value);
common_hal_os_getenv_showerr(key, result);
return result;
}

View File

@ -35,7 +35,7 @@ bdev = RAMBlockDevice(64)
uos.VfsFat.mkfs(bdev) uos.VfsFat.mkfs(bdev)
uos.mount(uos.VfsFat(bdev), "/") uos.mount(uos.VfsFat(bdev), "/")
content_good = """ content_good = b"""
# comment # comment
key0 = "hello world" key0 = "hello world"
key1 = 7 key1 = 7
@ -54,15 +54,15 @@ subvalue = "hi"
""" """
content_bad = [ content_bad = [
'key = "\n', b'key = "\n',
'key = """\n', b'key = """\n',
"key =\n", b"key =\n",
'key="', b'key="',
] ]
def run_test(key, content): def run_test(key, content):
with open("/settings.toml", "w") as f: with open("/settings.toml", "wb") as f:
f.write(content) f.write(content)
try: try:
@ -75,5 +75,12 @@ def run_test(key, content):
for i in range(13): for i in range(13):
run_test(f"key{i}", content_good) run_test(f"key{i}", content_good)
content_good = content_good.replace(b"\n", b"\r\n")
for i in range(13):
run_test(f"key{i}", content_good)
# Test value without trailing newline
run_test(f"noeol", b"noeol=3")
for content in content_bad: for content in content_bad:
run_test("key", content) run_test("key", content)

View File

@ -11,6 +11,20 @@ key9 'hello comment'
key10 127 key10 127
key11 0 key11 0
key12 None key12 None
key0 'hello world'
key1 7
key2 Invalid byte '\n'
key3 'Áx'
key4 'Áx'
key5 Invalid byte '\\'
key6 '\t\r\x08'
key7 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
key8 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
key9 'hello comment'
key10 127
key11 0
key12 None
noeol 3
key Invalid byte '\n' key Invalid byte '\n'
key Invalid byte '"' key Invalid byte '"'
key invalid syntax for integer with base 10: '' key invalid syntax for integer with base 10: ''