freedos-micro-python 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. freedos_micro_python/__init__.py +8 -0
  2. freedos_micro_python/cli.py +106 -0
  3. freedos_micro_python/gen_qstrdefs.py +275 -0
  4. freedos_micro_python/port/arch/bpstruct.h +2 -0
  5. freedos_micro_python/port/arch/cc.h +4 -0
  6. freedos_micro_python/port/arch/epstruct.h +1 -0
  7. freedos_micro_python/port/base64_uc386dos.c +164 -0
  8. freedos_micro_python/port/file_uc386dos.c +228 -0
  9. freedos_micro_python/port/lib/axtls/crypto/crypto.h +45 -0
  10. freedos_micro_python/port/lwip-arch-cc.h +46 -0
  11. freedos_micro_python/port/lwip_uc386dos.c +248 -0
  12. freedos_micro_python/port/lwipopts.h +117 -0
  13. freedos_micro_python/port/math_gamma.c +63 -0
  14. freedos_micro_python/port/modtime_uc386dos.c +60 -0
  15. freedos_micro_python/port/modtls_axtls_uc386dos.c +461 -0
  16. freedos_micro_python/port/mpconfigport.h +358 -0
  17. freedos_micro_python/port/mphal_uc386dos.c +103 -0
  18. freedos_micro_python/port/mphalport.h +11 -0
  19. freedos_micro_python/port/os_uc386dos.c +264 -0
  20. freedos_micro_python/port/path_uc386dos.c +307 -0
  21. freedos_micro_python/port/pktdrv_uc386dos.c +650 -0
  22. freedos_micro_python/port/qstrdefsport.h +2 -0
  23. freedos_micro_python/port/shutil_uc386dos.c +111 -0
  24. freedos_micro_python/port/tempfile_uc386dos.c +129 -0
  25. freedos_micro_python/port/time_real_uc386dos.c +77 -0
  26. freedos_micro_python/port/uc386_net_uc386dos.c +126 -0
  27. freedos_micro_python/port/urllib_parse_uc386dos.c +360 -0
  28. freedos_micro_python/port/urllib_uc386dos.c +29 -0
  29. freedos_micro_python/scripts/build.sh +641 -0
  30. freedos_micro_python/scripts/build_port.sh +241 -0
  31. freedos_micro_python/scripts/fetch.sh +238 -0
  32. freedos_micro_python-0.1.0.dist-info/METADATA +131 -0
  33. freedos_micro_python-0.1.0.dist-info/RECORD +37 -0
  34. freedos_micro_python-0.1.0.dist-info/WHEEL +5 -0
  35. freedos_micro_python-0.1.0.dist-info/entry_points.txt +2 -0
  36. freedos_micro_python-0.1.0.dist-info/licenses/LICENSE +25 -0
  37. freedos_micro_python-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,360 @@
1
+ // uc386-dos `urllib.parse` module — port-supplied stdlib shim.
2
+ //
3
+ // Surface (CPython-compat subset, minus the rarely-used bits):
4
+ // quote(s, safe='/') → percent-encoded str
5
+ // unquote(s) → percent-decoded str
6
+ // quote_plus(s, safe='') → quote + ' ' → '+'
7
+ // unquote_plus(s) → unquote + '+' → ' '
8
+ // urlsplit(url) → SplitResult (attrtuple of 5)
9
+ // urlencode(seq) → form-encoded query string
10
+ // parse_qsl(qs, keep_blank=False) → list of (key, value) tuples
11
+ //
12
+ // Skipped: urlparse / urlunparse / urlunsplit / urljoin / parse_qs
13
+ // (dict-of-lists). Add when somebody asks — current shape covers
14
+ // the parse-and-build patterns most htget-style scripts need.
15
+ //
16
+ // `urllib.parse` is the CPython idiom; we register it as a single
17
+ // flat `urllib_parse` module too (no submodule machinery required)
18
+ // so `import urllib_parse` and `from urllib import parse` both work
19
+ // once the moduledefs entry is in place.
20
+
21
+ #include <string.h>
22
+
23
+ #include "py/runtime.h"
24
+ #include "py/objstr.h"
25
+ #include "py/objtuple.h"
26
+
27
+ // RFC 3986 §2.3 unreserved characters: A-Z a-z 0-9 - _ . ~
28
+ static int is_unreserved(int c) {
29
+ return (c >= 'A' && c <= 'Z') ||
30
+ (c >= 'a' && c <= 'z') ||
31
+ (c >= '0' && c <= '9') ||
32
+ c == '-' || c == '_' || c == '.' || c == '~';
33
+ }
34
+
35
+ static int hex_value(int c) {
36
+ if (c >= '0' && c <= '9') return c - '0';
37
+ if (c >= 'A' && c <= 'F') return c - 'A' + 10;
38
+ if (c >= 'a' && c <= 'f') return c - 'a' + 10;
39
+ return -1;
40
+ }
41
+
42
+ static void vstr_add_pct(vstr_t *vstr, int byte) {
43
+ static const char hex[] = "0123456789ABCDEF";
44
+ vstr_add_byte(vstr, '%');
45
+ vstr_add_byte(vstr, hex[(byte >> 4) & 0x0F]);
46
+ vstr_add_byte(vstr, hex[byte & 0x0F]);
47
+ }
48
+
49
+ // Internal: encode `string` with optional `safe` char set, optional
50
+ // plus-encoding for quote_plus(). `safe_in` may be `mp_const_none`
51
+ // (use defaults). Doesn't touch mp_arg_parse_all so it's safe to
52
+ // call from internal helpers that don't have a kw_args map.
53
+ static mp_obj_t quote_inner(mp_obj_t string_in, mp_obj_t safe_in,
54
+ int plus) {
55
+ mp_buffer_info_t src_buf;
56
+ mp_get_buffer_raise(string_in, &src_buf, MP_BUFFER_READ);
57
+ const unsigned char *src = (const unsigned char *)src_buf.buf;
58
+ size_t n = src_buf.len;
59
+
60
+ // For plain quote(), `safe` defaults to '/' (CPython behavior).
61
+ // For quote_plus(), `safe` defaults to '' and ' ' becomes '+'.
62
+ const char *safe = NULL;
63
+ size_t safe_len = 0;
64
+ if (safe_in != mp_const_none && mp_obj_is_str_or_bytes(safe_in)) {
65
+ size_t sl;
66
+ const char *s = mp_obj_str_get_data(safe_in, &sl);
67
+ safe = s;
68
+ safe_len = sl;
69
+ }
70
+ int default_safe_slash = !plus && (safe_len == 0);
71
+
72
+ vstr_t vstr;
73
+ vstr_init(&vstr, n);
74
+ for (size_t i = 0; i < n; i++) {
75
+ int c = src[i];
76
+ int passthrough = is_unreserved(c);
77
+ if (!passthrough) {
78
+ if (default_safe_slash && c == '/') {
79
+ passthrough = 1;
80
+ }
81
+ for (size_t j = 0; j < safe_len; j++) {
82
+ if (c == (unsigned char)safe[j]) {
83
+ passthrough = 1;
84
+ break;
85
+ }
86
+ }
87
+ }
88
+ if (plus && c == ' ') {
89
+ vstr_add_byte(&vstr, '+');
90
+ } else if (passthrough) {
91
+ vstr_add_byte(&vstr, c);
92
+ } else {
93
+ vstr_add_pct(&vstr, c);
94
+ }
95
+ }
96
+ return mp_obj_new_str_from_vstr(&vstr);
97
+ }
98
+
99
+ // Public quote() / quote_plus() — accept (string [, safe]). Use
100
+ // 1-or-2 positional dispatch instead of mp_arg_parse_all so we
101
+ // don't need a non-NULL kw_args map; quote_inner does the actual
102
+ // work and is reusable from urlencode_pair below.
103
+ static mp_obj_t urllib_quote(size_t n_args, const mp_obj_t *args) {
104
+ mp_obj_t safe = (n_args >= 2) ? args[1] : mp_const_none;
105
+ return quote_inner(args[0], safe, 0);
106
+ }
107
+ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(urllib_quote_obj, 1, 2, urllib_quote);
108
+
109
+ static mp_obj_t urllib_quote_plus(size_t n_args, const mp_obj_t *args) {
110
+ mp_obj_t safe = (n_args >= 2) ? args[1] : mp_const_none;
111
+ return quote_inner(args[0], safe, 1);
112
+ }
113
+ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(urllib_quote_plus_obj, 1, 2,
114
+ urllib_quote_plus);
115
+
116
+ static mp_obj_t do_unquote(mp_obj_t s_in, int plus) {
117
+ mp_buffer_info_t buf;
118
+ mp_get_buffer_raise(s_in, &buf, MP_BUFFER_READ);
119
+ const unsigned char *src = (const unsigned char *)buf.buf;
120
+ size_t n = buf.len;
121
+
122
+ vstr_t vstr;
123
+ vstr_init(&vstr, n);
124
+ for (size_t i = 0; i < n; i++) {
125
+ int c = src[i];
126
+ if (plus && c == '+') {
127
+ vstr_add_byte(&vstr, ' ');
128
+ } else if (c == '%' && i + 2 < n) {
129
+ int hi = hex_value(src[i + 1]);
130
+ int lo = hex_value(src[i + 2]);
131
+ if (hi >= 0 && lo >= 0) {
132
+ vstr_add_byte(&vstr, (hi << 4) | lo);
133
+ i += 2;
134
+ } else {
135
+ vstr_add_byte(&vstr, c); // malformed escape — pass through
136
+ }
137
+ } else {
138
+ vstr_add_byte(&vstr, c);
139
+ }
140
+ }
141
+ return mp_obj_new_str_from_vstr(&vstr);
142
+ }
143
+
144
+ static mp_obj_t urllib_unquote(mp_obj_t s_in) {
145
+ return do_unquote(s_in, 0);
146
+ }
147
+ static MP_DEFINE_CONST_FUN_OBJ_1(urllib_unquote_obj, urllib_unquote);
148
+
149
+ static mp_obj_t urllib_unquote_plus(mp_obj_t s_in) {
150
+ return do_unquote(s_in, 1);
151
+ }
152
+ static MP_DEFINE_CONST_FUN_OBJ_1(urllib_unquote_plus_obj, urllib_unquote_plus);
153
+
154
+ // `urlsplit(url)` → SplitResult(scheme, netloc, path, query, fragment).
155
+ // Field positions match CPython's so unpacking (s, n, p, q, f) = ...
156
+ // works the same. Doesn't separate path-params (leading `;` segment);
157
+ // users who want urlparse-style 6-tuples can split path themselves.
158
+ static mp_obj_t urllib_urlsplit(mp_obj_t url_in) {
159
+ size_t n;
160
+ const char *url = mp_obj_str_get_data(url_in, &n);
161
+
162
+ size_t scheme_end = 0;
163
+ int has_scheme = 0;
164
+ if (n > 0 && ((url[0] >= 'A' && url[0] <= 'Z') ||
165
+ (url[0] >= 'a' && url[0] <= 'z'))) {
166
+ for (size_t i = 1; i < n; i++) {
167
+ char c = url[i];
168
+ if (c == ':') {
169
+ scheme_end = i;
170
+ has_scheme = 1;
171
+ break;
172
+ }
173
+ int valid = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
174
+ (c >= '0' && c <= '9') ||
175
+ c == '+' || c == '-' || c == '.';
176
+ if (!valid) {
177
+ break;
178
+ }
179
+ }
180
+ }
181
+
182
+ size_t pos = has_scheme ? scheme_end + 1 : 0;
183
+ size_t netloc_start = pos;
184
+ size_t netloc_end = pos;
185
+ if (pos + 1 < n && url[pos] == '/' && url[pos + 1] == '/') {
186
+ pos += 2;
187
+ netloc_start = pos;
188
+ while (pos < n && url[pos] != '/' && url[pos] != '?' &&
189
+ url[pos] != '#') {
190
+ pos++;
191
+ }
192
+ netloc_end = pos;
193
+ }
194
+
195
+ size_t path_start = pos;
196
+ while (pos < n && url[pos] != '?' && url[pos] != '#') {
197
+ pos++;
198
+ }
199
+ size_t path_end = pos;
200
+
201
+ size_t query_start = path_end;
202
+ size_t query_end = path_end;
203
+ if (pos < n && url[pos] == '?') {
204
+ pos++;
205
+ query_start = pos;
206
+ while (pos < n && url[pos] != '#') {
207
+ pos++;
208
+ }
209
+ query_end = pos;
210
+ }
211
+
212
+ size_t frag_start = query_end;
213
+ if (pos < n && url[pos] == '#') {
214
+ pos++;
215
+ frag_start = pos;
216
+ }
217
+ size_t frag_end = n;
218
+
219
+ mp_obj_t items[5] = {
220
+ mp_obj_new_str(url, has_scheme ? scheme_end : 0),
221
+ mp_obj_new_str(url + netloc_start, netloc_end - netloc_start),
222
+ mp_obj_new_str(url + path_start, path_end - path_start),
223
+ mp_obj_new_str(url + query_start, query_end - query_start),
224
+ mp_obj_new_str(url + frag_start, frag_end - frag_start),
225
+ };
226
+ static const qstr fields[5] = {
227
+ MP_QSTR_scheme, MP_QSTR_netloc, MP_QSTR_path,
228
+ MP_QSTR_query, MP_QSTR_fragment,
229
+ };
230
+ return mp_obj_new_attrtuple(fields, 5, items);
231
+ }
232
+ static MP_DEFINE_CONST_FUN_OBJ_1(urllib_urlsplit_obj, urllib_urlsplit);
233
+
234
+ // `urlencode(query)` — accepts a dict OR an iterable of (k, v)
235
+ // pairs. Each value is run through quote_plus.
236
+ static void urlencode_pair(vstr_t *vstr, mp_obj_t key, mp_obj_t val,
237
+ int *first) {
238
+ if (!*first) {
239
+ vstr_add_byte(vstr, '&');
240
+ }
241
+ *first = 0;
242
+ // Quote key (always a str/bytes per dict-key contract).
243
+ mp_obj_t k_quoted = quote_inner(key, mp_const_none, 1);
244
+ size_t klen;
245
+ const char *ks = mp_obj_str_get_data(k_quoted, &klen);
246
+ vstr_add_strn(vstr, ks, klen);
247
+ vstr_add_byte(vstr, '=');
248
+ // Quote value. Coerce ints/floats/etc. via str(val).
249
+ if (!mp_obj_is_str_or_bytes(val)) {
250
+ val = mp_call_function_1(MP_OBJ_FROM_PTR(&mp_type_str), val);
251
+ }
252
+ mp_obj_t v_quoted = quote_inner(val, mp_const_none, 1);
253
+ size_t vlen;
254
+ const char *vs = mp_obj_str_get_data(v_quoted, &vlen);
255
+ vstr_add_strn(vstr, vs, vlen);
256
+ }
257
+
258
+ static mp_obj_t urllib_urlencode(mp_obj_t query_in) {
259
+ vstr_t vstr;
260
+ vstr_init(&vstr, 64);
261
+ int first = 1;
262
+ if (mp_obj_is_type(query_in, &mp_type_dict)) {
263
+ // Walk the dict's internal map directly. Public APIs would
264
+ // require either a key-only iterator + per-key lookup, or
265
+ // mp_map_lookup with MP_MAP_LOOKUP_KIND_REMOVE_IF_FOUND
266
+ // games. The struct fields (`map`, `map.alloc`, `map.table`,
267
+ // `MP_MAP_SLOT_IS_FILLED`) are stable public surface — used
268
+ // throughout extmod/.
269
+ mp_obj_dict_t *d = MP_OBJ_TO_PTR(query_in);
270
+ for (size_t i = 0; i < d->map.alloc; i++) {
271
+ if (MP_MAP_SLOT_IS_FILLED(&d->map, i)) {
272
+ urlencode_pair(&vstr, d->map.table[i].key,
273
+ d->map.table[i].value, &first);
274
+ }
275
+ }
276
+ } else {
277
+ mp_obj_iter_buf_t iter_buf;
278
+ mp_obj_t iter = mp_getiter(query_in, &iter_buf);
279
+ mp_obj_t pair;
280
+ while ((pair = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
281
+ mp_obj_t *items;
282
+ size_t pn;
283
+ mp_obj_get_array(pair, &pn, &items);
284
+ if (pn != 2) {
285
+ mp_raise_ValueError(MP_ERROR_TEXT(
286
+ "urlencode pair not a 2-tuple"));
287
+ }
288
+ urlencode_pair(&vstr, items[0], items[1], &first);
289
+ }
290
+ }
291
+ return mp_obj_new_str_from_vstr(&vstr);
292
+ }
293
+ static MP_DEFINE_CONST_FUN_OBJ_1(urllib_urlencode_obj, urllib_urlencode);
294
+
295
+ // `parse_qsl(qs, keep_blank_values=False)` — split on `&`, then `=`,
296
+ // applying unquote_plus to each side. Returns a list of (k, v).
297
+ static mp_obj_t urllib_parse_qsl(size_t n_args, const mp_obj_t *pos_args,
298
+ mp_map_t *kw_args) {
299
+ static const mp_arg_t allowed[] = {
300
+ { MP_QSTR_qs, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} },
301
+ { MP_QSTR_keep_blank_values, MP_ARG_BOOL, {.u_bool = false} },
302
+ };
303
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed)];
304
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed),
305
+ allowed, args);
306
+
307
+ size_t n;
308
+ const char *qs = mp_obj_str_get_data(args[0].u_obj, &n);
309
+ int keep_blank = args[1].u_bool;
310
+
311
+ mp_obj_t result = mp_obj_new_list(0, NULL);
312
+ size_t i = 0;
313
+ while (i < n) {
314
+ // Find next `&` or end.
315
+ size_t pair_end = i;
316
+ while (pair_end < n && qs[pair_end] != '&' && qs[pair_end] != ';') {
317
+ pair_end++;
318
+ }
319
+ // Within [i, pair_end), find `=`.
320
+ size_t eq = i;
321
+ while (eq < pair_end && qs[eq] != '=') {
322
+ eq++;
323
+ }
324
+ size_t key_len = eq - i;
325
+ size_t val_off = (eq < pair_end) ? eq + 1 : pair_end;
326
+ size_t val_len = pair_end - val_off;
327
+ // CPython parse_qsl drops empty-value pairs unless
328
+ // keep_blank_values. Empty *key* always drops.
329
+ if (key_len > 0 && (val_len > 0 || keep_blank)) {
330
+ mp_obj_t key_raw = mp_obj_new_str(qs + i, key_len);
331
+ mp_obj_t val_raw = mp_obj_new_str(qs + val_off, val_len);
332
+ mp_obj_t key = do_unquote(key_raw, 1);
333
+ mp_obj_t val = do_unquote(val_raw, 1);
334
+ mp_obj_t pair_items[2] = { key, val };
335
+ mp_obj_list_append(result,
336
+ mp_obj_new_tuple(2, pair_items));
337
+ }
338
+ i = pair_end + 1;
339
+ }
340
+ return result;
341
+ }
342
+ static MP_DEFINE_CONST_FUN_OBJ_KW(urllib_parse_qsl_obj, 1, urllib_parse_qsl);
343
+
344
+ static const mp_rom_map_elem_t mp_module_urllib_parse_globals_table[] = {
345
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urllib_parse) },
346
+ { MP_ROM_QSTR(MP_QSTR_quote), MP_ROM_PTR(&urllib_quote_obj) },
347
+ { MP_ROM_QSTR(MP_QSTR_unquote), MP_ROM_PTR(&urllib_unquote_obj) },
348
+ { MP_ROM_QSTR(MP_QSTR_quote_plus), MP_ROM_PTR(&urllib_quote_plus_obj) },
349
+ { MP_ROM_QSTR(MP_QSTR_unquote_plus), MP_ROM_PTR(&urllib_unquote_plus_obj) },
350
+ { MP_ROM_QSTR(MP_QSTR_urlsplit), MP_ROM_PTR(&urllib_urlsplit_obj) },
351
+ { MP_ROM_QSTR(MP_QSTR_urlencode), MP_ROM_PTR(&urllib_urlencode_obj) },
352
+ { MP_ROM_QSTR(MP_QSTR_parse_qsl), MP_ROM_PTR(&urllib_parse_qsl_obj) },
353
+ };
354
+ static MP_DEFINE_CONST_DICT(mp_module_urllib_parse_globals,
355
+ mp_module_urllib_parse_globals_table);
356
+
357
+ const mp_obj_module_t mp_module_urllib_parse = {
358
+ .base = { &mp_type_module },
359
+ .globals = (mp_obj_dict_t *)&mp_module_urllib_parse_globals,
360
+ };
@@ -0,0 +1,29 @@
1
+ // uc386-dos `urllib` module — package shim that exposes the `parse`
2
+ // submodule attribute. CPython's stdlib has urllib as a package with
3
+ // `parse`, `request`, `error`, `robotparser` submodules; we ship
4
+ // only `parse` (the rest involve sockets we don't have).
5
+ //
6
+ // Two import patterns this enables:
7
+ // from urllib import parse # works
8
+ // import urllib; urllib.parse.quote(...)
9
+ //
10
+ // `import urllib.parse` and `from urllib.parse import quote` would
11
+ // need MP's import system to look up "urllib.parse" as a dotted path
12
+ // which it does — but only if `urllib_parse` is also a registered
13
+ // top-level module (build.sh's moduledefs.h registers both).
14
+
15
+ #include "py/runtime.h"
16
+
17
+ extern const mp_obj_module_t mp_module_urllib_parse;
18
+
19
+ static const mp_rom_map_elem_t mp_module_urllib_globals_table[] = {
20
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urllib) },
21
+ { MP_ROM_QSTR(MP_QSTR_parse), MP_ROM_PTR(&mp_module_urllib_parse) },
22
+ };
23
+ static MP_DEFINE_CONST_DICT(mp_module_urllib_globals,
24
+ mp_module_urllib_globals_table);
25
+
26
+ const mp_obj_module_t mp_module_urllib = {
27
+ .base = { &mp_type_module },
28
+ .globals = (mp_obj_dict_t *)&mp_module_urllib_globals,
29
+ };