Skip to content

Commit b0a635a

Browse files
authored
Merge pull request #7381 from jepler/issue7380
Correctly handle settings.toml that ends without a newline
2 parents 0d3b777 + 337b1da commit b0a635a

File tree

6 files changed

+100
-35
lines changed

6 files changed

+100
-35
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ clean:
9090
rm -rf autoapi
9191
rm -rf $(STUBDIR) $(DISTDIR) *.egg-info
9292

93-
html: stubs
93+
html:
9494
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
9595
@echo
9696
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

locale/circuitpython.pot

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ msgstr ""
6565
msgid "%02X"
6666
msgstr ""
6767

68+
#: shared-module/os/getenv.c
69+
#, c-format
70+
msgid "%S"
71+
msgstr ""
72+
6873
#: shared-bindings/rgbmatrix/RGBMatrix.c
6974
#, c-format
7075
msgid ""
@@ -488,6 +493,11 @@ msgstr ""
488493
msgid "Already scanning for wifi networks"
489494
msgstr ""
490495

496+
#: shared-module/os/getenv.c
497+
#, c-format
498+
msgid "An error occurred while retrieving '%s':\n"
499+
msgstr ""
500+
491501
#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c
492502
msgid "Another PWMAudioOut is already active"
493503
msgstr ""
@@ -1754,10 +1764,6 @@ msgid ""
17541764
"constructor"
17551765
msgstr ""
17561766

1757-
#: ports/espressif/common-hal/espulp/ULP.c
1758-
msgid "Pins 21+ not supported from ULP"
1759-
msgstr ""
1760-
17611767
#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c
17621768
msgid "Pins must be sequential"
17631769
msgstr ""

shared-module/os/__init__.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ typedef enum {
3838
// Allocation free version that returns the full length of the value.
3939
// If it fits, the return value is 0-terminated. The passed in buffer
4040
// may be modified even if an error is returned. Allocation free.
41+
// An error that is not 'open' or 'not found' is printed on the repl.
4142
os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len);
4243

4344
// Returns GETENV_OK and sets value to the read value. Returns
4445
// GETENV_ERR_... if the value was not numeric. allocation-free.
4546
// If any error code is returned, value is guaranteed not modified
47+
// An error that is not 'open' or 'not found' is printed on the repl.
4648
os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value);

shared-module/os/getenv.c

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
// tested in the unix "coverage" build, without bringing in "our" os module
2929

3030
#include <stdlib.h>
31+
#include <stdarg.h>
3132
#include <string.h>
3233

3334
#include "shared-bindings/os/__init__.h"
@@ -36,6 +37,7 @@
3637
#include "py/gc.h"
3738
#include "py/misc.h"
3839
#include "py/mpstate.h"
40+
#include "py/mpprint.h"
3941
#include "py/objstr.h"
4042
#include "py/parsenum.h"
4143
#include "py/runtime.h"
@@ -199,6 +201,7 @@ STATIC os_getenv_err_t read_string_value(file_arg *active_file, vstr_t *buf) {
199201
case '#':
200202
next_line(active_file);
201203
MP_FALLTHROUGH;
204+
case 0:
202205
case '\n':
203206
return GETENV_OK;
204207
default:
@@ -255,7 +258,6 @@ STATIC os_getenv_err_t read_bare_value(file_arg *active_file, vstr_t *buf, int f
255258
while (true) {
256259
switch (character) {
257260
case 0:
258-
return GETENV_ERR_UNEXPECTED | character;
259261
case '\n':
260262
return GETENV_OK;
261263
case '#':
@@ -311,42 +313,70 @@ STATIC os_getenv_err_t os_getenv_buf_terminated(const char *key, char *value, si
311313
return result;
312314
}
313315

314-
os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len) {
315-
bool quoted;
316-
os_getenv_err_t result = os_getenv_buf_terminated(key, value, value_len, &quoted);
317-
if (result == GETENV_OK && !quoted) {
318-
result = GETENV_ERR_UNEXPECTED | value[0];
319-
}
320-
return result;
316+
STATIC void print_dont_raise(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, ...) {
317+
va_list argptr;
318+
va_start(argptr,fmt);
319+
mp_vcprintf(&mp_plat_print, fmt, argptr);
320+
mp_printf(&mp_plat_print, "\n");
321+
va_end(argptr);
321322
}
322323

323-
STATIC void throw_getenv_error(os_getenv_err_t error) {
324+
STATIC void handle_getenv_error(os_getenv_err_t error, void (*handle)(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, ...)) {
324325
if (error == GETENV_OK) {
325326
return;
326327
}
327328
if (error & GETENV_ERR_UNEXPECTED) {
328329
byte character = (error & 0xff);
329-
mp_print_t print;
330+
char buf[8];
330331
vstr_t vstr;
331-
vstr_init_print(&vstr, 8 + 4 + 1, &print);
332+
vstr_init_fixed_buf(&vstr, sizeof(buf), buf);
333+
mp_print_t print = { .data = &vstr, .print_strn = (mp_print_strn_t)vstr_add_strn };
334+
332335
if (character) {
333336
mp_str_print_quoted(&print, &character, 1, true);
334337
} else {
335338
mp_str_print_quoted(&print, (byte *)"EOF", 3, true);
336339
}
337-
mp_raise_ValueError_varg(translate("Invalid byte %.*s"),
338-
vstr.len, vstr.buf);
340+
handle(&mp_type_ValueError, translate("Invalid byte %.*s"), vstr.len, vstr.buf);
341+
} else {
342+
switch (error) {
343+
case GETENV_ERR_OPEN:
344+
handle(&mp_type_ValueError, translate("%S"), translate("File not found"));
345+
break;
346+
case GETENV_ERR_UNICODE:
347+
handle(&mp_type_ValueError, translate("%S"), translate("Invalid unicode escape"));
348+
break;
349+
case GETENV_ERR_NOT_FOUND:
350+
handle(&mp_type_ValueError, translate("%S"), translate("Key not found"));
351+
break;
352+
default:
353+
handle(&mp_type_RuntimeError, translate("%S"), translate("Internal error"));
354+
break;
355+
}
356+
}
357+
}
358+
359+
STATIC void common_hal_os_getenv_showerr(const char *key, os_getenv_err_t result) {
360+
if (result != GETENV_OK && result != GETENV_ERR_OPEN && result != GETENV_ERR_NOT_FOUND) {
361+
mp_cprintf(&mp_plat_print, translate("An error occurred while retrieving '%s':\n"), key);
362+
handle_getenv_error(result, print_dont_raise);
339363
}
340-
switch (error) {
341-
case GETENV_ERR_OPEN:
342-
mp_raise_ValueError(translate("File not found"));
343-
case GETENV_ERR_UNICODE:
344-
mp_raise_ValueError(translate("Invalid unicode escape"));
345-
case GETENV_ERR_NOT_FOUND:
346-
mp_raise_ValueError(translate("Key not found"));
347-
default:
348-
mp_raise_RuntimeError(translate("Internal error"));
364+
}
365+
366+
STATIC
367+
os_getenv_err_t common_hal_os_getenv_str_inner(const char *key, char *value, size_t value_len) {
368+
bool quoted;
369+
os_getenv_err_t result = os_getenv_buf_terminated(key, value, value_len, &quoted);
370+
if (result == GETENV_OK && !quoted) {
371+
result = GETENV_ERR_UNEXPECTED | value[0];
349372
}
373+
return result;
374+
}
375+
376+
os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len) {
377+
os_getenv_err_t result = common_hal_os_getenv_str_inner(key, value, value_len);
378+
common_hal_os_getenv_showerr(key, result);
379+
return result;
350380
}
351381

352382
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
358388
if (result == GETENV_ERR_NOT_FOUND || result == GETENV_ERR_OPEN) {
359389
return default_;
360390
}
361-
throw_getenv_error(result);
391+
handle_getenv_error(result, mp_raise_msg_varg);
362392

363393
if (quoted) {
364394
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_) {
371401
return common_hal_os_getenv_path(GETENV_PATH, key, default_);
372402
}
373403

374-
os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value) {
404+
STATIC os_getenv_err_t common_hal_os_getenv_int_inner(const char *key, mp_int_t *value) {
375405
char buf[16];
376406
bool quoted;
377407
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) {
389419
*value = (mp_int_t)num;
390420
return GETENV_OK;
391421
}
422+
423+
os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value) {
424+
os_getenv_err_t result = common_hal_os_getenv_int_inner(key, value);
425+
common_hal_os_getenv_showerr(key, result);
426+
return result;
427+
}

tests/circuitpython/getenv.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def ioctl(self, op, arg):
3535
uos.VfsFat.mkfs(bdev)
3636
uos.mount(uos.VfsFat(bdev), "/")
3737

38-
content_good = """
38+
content_good = b"""
3939
# comment
4040
key0 = "hello world"
4141
key1 = 7
@@ -54,15 +54,15 @@ def ioctl(self, op, arg):
5454
"""
5555

5656
content_bad = [
57-
'key = "\n',
58-
'key = """\n',
59-
"key =\n",
60-
'key="',
57+
b'key = "\n',
58+
b'key = """\n',
59+
b"key =\n",
60+
b'key="',
6161
]
6262

6363

6464
def run_test(key, content):
65-
with open("/settings.toml", "w") as f:
65+
with open("/settings.toml", "wb") as f:
6666
f.write(content)
6767

6868
try:
@@ -75,5 +75,12 @@ def run_test(key, content):
7575
for i in range(13):
7676
run_test(f"key{i}", content_good)
7777

78+
content_good = content_good.replace(b"\n", b"\r\n")
79+
for i in range(13):
80+
run_test(f"key{i}", content_good)
81+
82+
# Test value without trailing newline
83+
run_test(f"noeol", b"noeol=3")
84+
7885
for content in content_bad:
7986
run_test("key", content)

tests/circuitpython/getenv.py.exp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ key9 'hello comment'
1111
key10 127
1212
key11 0
1313
key12 None
14+
key0 'hello world'
15+
key1 7
16+
key2 Invalid byte '\n'
17+
key3 'Áx'
18+
key4 'Áx'
19+
key5 Invalid byte '\\'
20+
key6 '\t\r\x08'
21+
key7 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
22+
key8 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
23+
key9 'hello comment'
24+
key10 127
25+
key11 0
26+
key12 None
27+
noeol 3
1428
key Invalid byte '\n'
1529
key Invalid byte '"'
1630
key invalid syntax for integer with base 10: ''

0 commit comments

Comments
 (0)