35
35
#include "py/objstr.h"
36
36
#include "supervisor/filesystem.h"
37
37
38
- STATIC uint8_t consume_spaces (FIL * active_file ) {
39
- uint8_t character = ' ' ;
40
- UINT quantity_read = 1 ;
41
- while (unichar_isspace (character ) && quantity_read > 0 ) {
42
- f_read (active_file , & character , 1 , & quantity_read );
43
- }
38
+ // Return 0 if there is no next character (EOF).
39
+ STATIC uint8_t get_next_character (FIL * active_file ) {
40
+ uint8_t character = 0 ;
41
+ UINT quantity_read ;
42
+ // If there's an error or quantity_read is 0, character will remain 0.
43
+ f_read (active_file , & character , 1 , & quantity_read );
44
+ return character ;
45
+ }
46
+
47
+ // Discard whitespace, except for newlines, returning the next character after the whitespace.
48
+ // Return 0 if there is no next character (EOF).
49
+ STATIC uint8_t consume_whitespace (FIL * active_file ) {
50
+ uint8_t character ;
51
+ do {
52
+ character = get_next_character (active_file );
53
+ } while (character != '\n' && character != 0 && unichar_isspace (character ));
44
54
return character ;
45
55
}
46
56
47
57
// Starting at the start of a new line, determines if the key matches the given
48
- // key. File pointer is left after the = after the key.
58
+ // key. File pointer is set to be just before the = after the key.
49
59
STATIC bool key_matches (FIL * active_file , const char * key ) {
50
- uint8_t character = ' ' ;
51
- UINT quantity_read = 1 ;
52
- character = consume_spaces (active_file );
60
+ uint8_t character ;
61
+ character = consume_whitespace (active_file );
62
+ if (character == 0 ) {
63
+ return false;
64
+ }
53
65
bool quoted = false;
54
66
if (character == '\'' ) {
67
+ // Beginning of single-quoted string.
55
68
quoted = true;
56
- f_read ( active_file , & character , 1 , & quantity_read );
69
+ character = get_next_character ( active_file );
57
70
}
58
71
size_t key_pos = 0 ;
59
72
bool escaped = false;
60
73
bool matches = true;
61
74
size_t key_len = strlen (key );
62
- while (quantity_read > 0 ) {
75
+ while (character != 0 ) {
63
76
if (character == '\\' && !escaped && quoted ) {
64
77
escaped = true;
65
78
} else if (!escaped && quoted && character == '\'' ) {
66
79
quoted = false;
67
- // Move past the quoted before breaking so we can check the validity of data past it .
68
- f_read ( active_file , & character , 1 , & quantity_read );
80
+ // End of quoted key. Skip over the ending quote .
81
+ character = get_next_character ( active_file );
69
82
break ;
70
- } else if (!quoted && (unichar_isspace (character ) || character == '=' || character == '\n' || character == '#' )) {
83
+ } else if (!quoted && (unichar_isspace (character ) || character == '=' || character == '\n' || character == '#' || character == 0 )) {
84
+ // End of unquoted key.
71
85
break ;
72
86
} else {
73
- matches = matches && key [key_pos ] == character ;
74
- escaped = false;
75
- key_pos ++ ;
87
+ // Still on tentative key; see if it matches the next supplied key character,
88
+ // but don't run off the end of the supplied key.
89
+ if (key_pos < key_len ) {
90
+ matches = matches && key [key_pos ] == character ;
91
+ escaped = false;
92
+ key_pos ++ ;
93
+ } else {
94
+ // Key on line is too long.
95
+ matches = false;
96
+ }
76
97
}
77
-
78
- f_read (active_file , & character , 1 , & quantity_read );
98
+ character = get_next_character (active_file );
79
99
}
80
- if (unichar_isspace (character )) {
81
- character = consume_spaces (active_file );
82
- }
83
- if (character == '=' || character == '\n' || character == '#' ) {
84
- // Rewind one so the value can find it.
100
+ if (character == '=' || character == '\n' || character == '#' || character == 0 ) {
101
+ // Rewind one so the value, if any, can be found.
85
102
f_lseek (active_file , f_tell (active_file ) - 1 );
86
103
} else {
87
104
// We're followed by something else that is invalid syntax.
88
105
matches = false;
89
106
}
107
+
90
108
return matches && key_pos == key_len ;
91
109
}
92
110
93
111
STATIC bool next_line (FIL * active_file ) {
94
- uint8_t character = ' ' ;
95
- UINT quantity_read = 1 ;
112
+ uint8_t character ;
96
113
bool quoted = false;
97
114
bool escaped = false;
98
115
// Track comments because they last until the end of the line.
99
116
bool comment = false;
100
- FRESULT result = FR_OK ;
101
117
// Consume all characters while quoted or others up to \n.
102
- while (result == FR_OK && quantity_read > 0 && (quoted || character != '\n' )) {
103
- if (character == '#' || comment ) {
118
+ do {
119
+ character = get_next_character (active_file );
120
+
121
+ if ((!quoted || character == '#' ) || comment ) {
104
122
// Comments consume any escaping.
105
123
comment = true;
106
124
} else if (!escaped ) {
@@ -112,33 +130,32 @@ STATIC bool next_line(FIL *active_file) {
112
130
} else {
113
131
escaped = false;
114
132
}
115
- result = f_read ( active_file , & character , 1 , & quantity_read );
116
- }
117
- return result == FR_OK && quantity_read > 0 ;
133
+ } while ( character != 0 && ( quoted || character != '\n' ) );
134
+
135
+ return character != 0 ;
118
136
}
119
137
120
138
STATIC mp_int_t read_value (FIL * active_file , char * value , size_t value_len ) {
121
- uint8_t character = ' ' ;
122
- UINT quantity_read = 1 ;
123
- // Consume spaces before =
124
- character = consume_spaces (active_file );
139
+ uint8_t character ;
140
+ // Consume spaces before "=", and get first character of interest.
141
+ character = consume_whitespace (active_file );
125
142
if (character != '=' ) {
126
143
if (character == '#' || character == '\n' ) {
127
144
// Keys without an = after them are valid with the value None.
128
- return 0 ;
145
+ return -1 ;
129
146
}
130
147
// All other characters are invalid.
131
148
return -1 ;
132
149
}
133
- character = ' ' ;
134
150
// Consume space after =
135
- while (unichar_isspace (character ) && quantity_read > 0 ) {
136
- f_read (active_file , & character , 1 , & quantity_read );
151
+ if (character != '#' ) {
152
+ // a # immediately after = is part of the value!
153
+ character = consume_whitespace (active_file );
137
154
}
138
155
bool quoted = false;
139
156
if (character == '\'' ) {
140
157
quoted = true;
141
- f_read ( active_file , & character , 1 , & quantity_read );
158
+ character = get_next_character ( active_file );
142
159
}
143
160
if (character == '"' ) {
144
161
// We don't support double quoted values.
@@ -150,20 +167,21 @@ STATIC mp_int_t read_value(FIL *active_file, char *value, size_t value_len) {
150
167
// Count trailing spaces so we can ignore them at the end of unquoted
151
168
// values.
152
169
size_t trailing_spaces = 0 ;
153
- while (quantity_read > 0 ) {
170
+ bool first_char = true;
171
+ while (character != 0 ) {
154
172
// Consume the first \ if the value is quoted.
155
173
if (quoted && character == '\\' && !escaped ) {
156
174
escaped = true;
157
- // Drop this slash by short circuiting the rest of the loop.
158
- f_read ( active_file , & character , 1 , & quantity_read );
175
+ // Drop this backslash by short circuiting the rest of the loop.
176
+ character = get_next_character ( active_file );
159
177
continue ;
160
178
}
161
179
if (quoted && !escaped && character == '\'' ) {
162
180
// trailing ' means the value is done.
163
181
break ;
164
182
}
165
183
// Unquoted values are ended by a newline or comment.
166
- if (!quoted && (character == '\n' || character == '#' )) {
184
+ if (!quoted && (character == '\n' || ( character == '#' && ! first_char ) )) {
167
185
if (character == '\n' ) {
168
186
// Rewind one so the next_line can find the \n.
169
187
f_lseek (active_file , f_tell (active_file ) - 1 );
@@ -182,7 +200,8 @@ STATIC mp_int_t read_value(FIL *active_file, char *value, size_t value_len) {
182
200
value [value_pos ] = character ;
183
201
}
184
202
value_pos ++ ;
185
- f_read (active_file , & character , 1 , & quantity_read );
203
+ character = get_next_character (active_file );
204
+ first_char = false;
186
205
}
187
206
188
207
return value_pos - trailing_spaces ;
@@ -214,7 +233,7 @@ mp_obj_t common_hal_dotenv_get_key(const char *path, const char *key) {
214
233
// the length.
215
234
char value [64 ];
216
235
mp_int_t actual_len = dotenv_get_key (path , key , value , sizeof (value ));
217
- if (actual_len <= 0 ) {
236
+ if (actual_len < 0 ) {
218
237
return mp_const_none ;
219
238
}
220
239
if ((size_t )actual_len >= sizeof (value )) {
0 commit comments