From 76033d5115889d779debfddc14c6990df31de799 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 22 Apr 2021 17:55:39 -0700 Subject: [PATCH] Merge MicroPython v1.11 into CircuitPython --- .gitmodules | 2 +- LICENSE | 2 +- devices/ble_hci/common-hal/_bleio/Adapter.c | 4 +- devices/ble_hci/common-hal/_bleio/Attribute.c | 6 +- .../common-hal/_bleio/Characteristic.c | 4 +- .../ble_hci/common-hal/_bleio/Connection.c | 2 +- devices/ble_hci/common-hal/_bleio/att.c | 24 +- docs/library/re.rst | 2 +- extmod/misc.h | 1 + extmod/modubinascii.c | 2 +- extmod/moductypes.c | 38 +- extmod/moduhashlib.c | 10 +- extmod/moduheapq.c | 2 +- extmod/modujson.c | 2 +- extmod/modurandom.c | 11 + extmod/moduselect.c | 13 +- extmod/modussl_axtls.c | 244 -- extmod/modussl_mbedtls.c | 330 -- extmod/modutimeq.c | 2 +- extmod/moduwebsocket.h | 10 + extmod/modwebrepl.c | 19 +- extmod/modwebsocket.c | 294 -- extmod/modwebsocket.h | 14 - extmod/ulab | 2 +- extmod/uos_dupterm.c | 25 + extmod/vfs.c | 4 +- extmod/vfs_fat.c | 17 +- extmod/vfs_fat_diskio.c | 14 +- extmod/vfs_posix.c | 2 +- extmod/vfs_posix_file.c | 2 +- lib/netutils/netutils.h | 6 + lib/netutils/trace.c | 170 + lib/oofatfs/diskio.h | 12 +- lib/oofatfs/ff.c | 3814 +++++++++-------- lib/oofatfs/ff.h | 220 +- lib/oofatfs/ffconf.h | 242 +- lib/oofatfs/{option/ccsbcs.c => ffunicode.c} | 578 ++- lib/oofatfs/option/unicode.c | 17 - lib/utils/gchelper.h | 34 + lib/utils/gchelper_m0.s | 61 + lib/utils/gchelper_m3.s | 67 + lib/utils/interrupt_char.c | 2 +- lib/utils/pyexec.c | 56 +- lib/utils/pyexec.h | 3 +- locale/circuitpython.pot | 32 +- mpy-cross/Makefile | 2 + mpy-cross/gccollect.c | 3 - mpy-cross/main.c | 63 +- mpy-cross/mpconfigport.h | 20 +- ports/atmel-samd/Makefile | 13 +- .../feather_m0_supersized/mpconfigboard.mk | 18 +- .../hallowing_m0_express/mpconfigboard.mk | 1 + .../itsybitsy_m0_express/mpconfigboard.mk | 1 + .../boards/metro_m0_express/mpconfigboard.mk | 1 + .../boards/pewpew_m4/mpconfigboard.mk | 1 + .../boards/qtpy_m0_haxpress/mpconfigboard.mk | 1 + .../boards/serpente/mpconfigboard.mk | 3 +- .../sparkfun_lumidrive/mpconfigboard.mk | 3 +- .../stackrduino_m0_pro/mpconfigboard.mk | 1 + .../trinket_m0_haxpress/mpconfigboard.mk | 16 +- ports/cxd56/Makefile | 13 +- ports/esp32s2/Makefile | 15 +- ports/esp32s2/common-hal/alarm/pin/PinAlarm.c | 4 +- .../esp32s2/common-hal/alarm/time/TimeAlarm.c | 4 +- .../common-hal/alarm/touch/TouchAlarm.c | 4 +- ports/esp32s2/common-hal/wifi/__init__.c | 2 +- ports/litex/Makefile | 15 +- ports/mimxrt10xx/Makefile | 14 +- ports/nrf/Makefile | 15 +- ports/nrf/boards/simmel/mpconfigboard.mk | 1 + ports/nrf/common-hal/_bleio/Connection.c | 2 +- ports/raspberrypi/Makefile | 13 +- .../bindings/rp2pio/StateMachine.c | 2 +- ports/stm/Makefile | 17 +- ports/unix/Makefile | 11 +- ports/unix/coverage.c | 3 +- ports/unix/file.c | 2 +- ports/unix/gccollect.c | 9 +- ports/unix/main.c | 5 + ports/unix/modffi.c | 11 +- ports/unix/modjni.c | 4 +- ports/unix/modmachine.c | 6 +- ports/unix/modos.c | 4 +- ports/unix/modtermios.c | 4 +- ports/unix/modtime.c | 3 +- ports/unix/moduselect.c | 4 +- ports/unix/modusocket.c | 48 +- ports/unix/mpconfigport.h | 4 +- ports/unix/mpconfigport_coverage.h | 4 + ports/unix/mpthreadport.c | 64 +- ports/unix/mpthreadport.h | 1 + py/asmarm.c | 16 +- py/asmarm.h | 7 +- py/asmthumb.c | 27 +- py/asmthumb.h | 6 +- py/asmx64.c | 4 +- py/asmx64.h | 3 + py/asmx86.c | 4 +- py/asmx86.h | 4 +- py/asmxtensa.c | 24 +- py/asmxtensa.h | 8 +- py/bc.c | 10 +- py/bc.h | 3 +- py/bc0.h | 3 +- py/binary.c | 7 +- py/binary.h | 3 +- py/builtin.h | 6 +- py/builtinevex.c | 6 +- py/builtinhelp.c | 4 +- py/builtinimport.c | 10 +- py/circuitpy_defns.mk | 13 + py/circuitpy_mpconfig.h | 4 +- py/compile.c | 175 +- py/emit.h | 18 +- py/emitbc.c | 19 +- py/emitglue.c | 52 +- py/emitglue.h | 46 +- py/emitinlinethumb.c | 5 + py/emitinlinextensa.c | 5 + py/emitnative.c | 165 +- py/enum.c | 2 +- py/frozenmod.h | 3 +- py/gc.c | 1 + py/gc_long_lived.c | 16 +- py/makemoduledefs.py | 4 +- py/makeqstrdata.py | 187 +- py/makeqstrdefs.py | 3 +- py/makeversionhdr.py | 1 + py/map.c | 14 +- py/misc.h | 4 +- py/mkenv.mk | 2 + py/mkrules.mk | 4 +- py/modarray.c | 2 + py/modbuiltins.c | 23 +- py/modio.c | 2 + py/modmath.c | 2 +- py/modthread.c | 2 +- py/moduerrno.c | 2 +- py/mpconfig.h | 61 +- py/mpprint.c | 22 +- py/mpstate.h | 4 +- py/nativeglue.c | 36 +- py/obj.c | 54 +- py/obj.h | 69 +- py/objarray.c | 60 +- py/objcomplex.c | 10 +- py/objdict.c | 35 +- py/objenumerate.c | 2 +- py/objexcept.c | 5 +- py/objfilter.c | 2 +- py/objfloat.c | 2 +- py/objfun.c | 32 +- py/objgenerator.c | 26 +- py/objint.c | 14 +- py/objint_longlong.c | 18 +- py/objint_mpz.c | 34 +- py/objlist.c | 34 +- py/objmap.c | 2 +- py/objmodule.c | 17 +- py/objnamedtuple.c | 2 +- py/objobject.c | 2 +- py/objproperty.c | 2 +- py/objrange.c | 4 +- py/objreversed.c | 2 +- py/objset.c | 28 +- py/objslice.c | 4 +- py/objstr.c | 56 +- py/objstr.h | 7 +- py/objstringio.c | 4 +- py/objstrunicode.c | 6 +- py/objtuple.c | 11 +- py/objtype.c | 50 +- py/objzip.c | 2 +- py/parse.c | 10 +- py/persistentcode.c | 592 ++- py/persistentcode.h | 16 + py/py.mk | 34 +- py/runtime.c | 67 +- py/runtime.h | 11 +- py/scheduler.c | 27 +- py/showbc.c | 11 +- py/stream.c | 6 +- py/stream.h | 1 + py/vm.c | 75 +- py/vmentrytable.h | 3 +- py/vstr.c | 1 + py/warning.c | 12 +- shared-bindings/_bleio/Adapter.c | 8 +- shared-bindings/_bleio/Address.c | 2 +- shared-bindings/_bleio/Characteristic.c | 4 +- shared-bindings/_bleio/CharacteristicBuffer.c | 2 +- shared-bindings/_bleio/Descriptor.c | 4 +- shared-bindings/_bleio/PacketBuffer.c | 2 +- shared-bindings/_bleio/ScanResults.c | 2 +- shared-bindings/_bleio/Service.c | 2 +- shared-bindings/_bleio/UUID.c | 6 +- shared-bindings/_bleio/__init__.c | 2 +- shared-bindings/_pew/PewPew.c | 6 +- shared-bindings/_pixelbuf/PixelBuf.c | 4 +- shared-bindings/_pixelbuf/__init__.c | 2 +- shared-bindings/_stage/__init__.c | 2 +- shared-bindings/aesio/aes.c | 8 +- shared-bindings/alarm/SleepMemory.c | 10 +- shared-bindings/alarm/__init__.c | 6 +- shared-bindings/audiobusio/PDMIn.c | 4 +- shared-bindings/audiocore/WaveFile.c | 2 +- shared-bindings/audiomp3/MP3Decoder.c | 4 +- shared-bindings/bitmaptools/__init__.c | 8 +- shared-bindings/busio/SPI.c | 2 +- shared-bindings/digitalio/DigitalInOut.c | 2 +- shared-bindings/displayio/Bitmap.c | 4 +- shared-bindings/displayio/Group.c | 2 +- shared-bindings/displayio/I2CDisplay.c | 2 +- shared-bindings/displayio/OnDiskBitmap.c | 2 +- shared-bindings/displayio/Palette.c | 6 +- shared-bindings/displayio/ParallelBus.c | 2 +- shared-bindings/displayio/TileGrid.c | 14 +- shared-bindings/gamepad/GamePad.c | 2 +- shared-bindings/gamepadshift/GamePadShift.c | 2 +- shared-bindings/gnss/GNSS.c | 6 +- shared-bindings/i2cperipheral/I2CPeripheral.c | 22 +- shared-bindings/ipaddress/IPv4Address.c | 4 +- shared-bindings/ipaddress/__init__.c | 2 +- .../memorymonitor/AllocationSize.c | 2 +- shared-bindings/microcontroller/Pin.c | 2 +- shared-bindings/msgpack/__init__.c | 6 +- shared-bindings/neopixel_write/__init__.c | 2 +- shared-bindings/nvm/ByteArray.c | 10 +- shared-bindings/ps2io/Ps2.c | 2 +- shared-bindings/pulseio/PulseIn.c | 2 +- shared-bindings/pulseio/PulseOut.c | 2 +- shared-bindings/storage/__init__.c | 2 +- shared-bindings/synthio/__init__.c | 2 +- shared-bindings/terminalio/Terminal.c | 4 +- shared-bindings/time/__init__.c | 4 +- shared-bindings/vectorio/Polygon.c | 2 +- shared-bindings/vectorio/VectorShape.c | 18 +- shared-bindings/wifi/ScannedNetworks.c | 2 +- shared-module/_pixelbuf/PixelBuf.c | 8 +- shared-module/displayio/TileGrid.c | 28 +- shared-module/displayio/display_core.c | 6 +- shared-module/gamepad/__init__.c | 2 +- shared-module/gamepadshift/__init__.c | 2 +- shared-module/msgpack/__init__.c | 14 +- shared-module/uheap/__init__.c | 32 +- shared-module/vectorio/VectorShape.c | 12 +- supervisor/shared/filesystem.c | 2 +- supervisor/shared/usb/usb_msc_flash.c | 4 +- supervisor/supervisor.mk | 1 + tests/basics/async_with.py | 10 + tests/basics/async_with.py.exp | 3 + tests/basics/builtin_next_arg2.py | 34 + tests/basics/bytearray_decode.py | 6 + tests/basics/gen_yield_from_throw.py | 22 +- tests/basics/generator_throw.py | 14 +- tests/basics/memoryview1.py | 54 + tests/basics/memoryview_itemsize.py | 15 + tests/basics/sys1.py | 5 + tests/basics/try_else.py | 76 + tests/basics/try_else_finally.py | 94 + tests/basics/try_finally_break.py | 99 + tests/basics/try_return.py | 9 + tests/cmdline/cmd_showbc.py | 1 + tests/cmdline/cmd_showbc.py.exp | 36 +- tests/cmdline/repl_autocomplete.py | 3 - tests/cmdline/repl_autocomplete.py.exp | 6 - tests/extmod/ucryptolib_aes128_ctr.py | 28 + tests/extmod/ucryptolib_aes128_ctr.py.exp | 3 + tests/extmod/ujson_loads_float.py | 1 + tests/extmod/ussl_basic.py | 13 +- tests/extmod/ussl_basic.py.exp | 1 - tests/extmod/vfs_fat_ramdisklarge.py | 70 + tests/extmod/vfs_fat_ramdisklarge.py.exp | 3 + tests/extmod/websocket_basic.py | 62 - tests/import/mpy_invalid.py | 1 + tests/import/mpy_invalid.py.exp | 5 +- tests/import/mpy_native.py | 96 + tests/import/mpy_native.py.exp | 2 + tests/micropython/heapalloc_fail_bytearray.py | 93 + .../heapalloc_fail_bytearray.py.exp | 11 + tests/micropython/heapalloc_fail_dict.py | 21 + tests/micropython/heapalloc_fail_dict.py.exp | 2 + tests/micropython/heapalloc_fail_list.py | 39 + tests/micropython/heapalloc_fail_list.py.exp | 4 + .../micropython/heapalloc_fail_memoryview.py | 28 + .../heapalloc_fail_memoryview.py.exp | 2 + tests/micropython/heapalloc_fail_set.py | 23 + tests/micropython/heapalloc_fail_set.py.exp | 2 + tests/micropython/heapalloc_fail_tuple.py | 12 + tests/micropython/heapalloc_fail_tuple.py.exp | 1 + tests/micropython/viper_types.py | 32 + tests/micropython/viper_types.py.exp | 8 + tests/run-tests | 15 +- tests/unix/extra_coverage.py.exp | 7 +- tools/mpy-tool.py | 584 ++- tools/pyboard.py | 8 +- tools/upip.py | 22 +- 297 files changed, 6821 insertions(+), 4591 deletions(-) delete mode 100644 extmod/modussl_axtls.c delete mode 100644 extmod/modussl_mbedtls.c create mode 100644 extmod/moduwebsocket.h delete mode 100644 extmod/modwebsocket.c delete mode 100644 extmod/modwebsocket.h create mode 100644 lib/netutils/trace.c rename lib/oofatfs/{option/ccsbcs.c => ffunicode.c} (58%) delete mode 100644 lib/oofatfs/option/unicode.c create mode 100644 lib/utils/gchelper.h create mode 100644 lib/utils/gchelper_m0.s create mode 100644 lib/utils/gchelper_m3.s create mode 100644 tests/basics/builtin_next_arg2.py create mode 100644 tests/basics/bytearray_decode.py create mode 100644 tests/basics/memoryview_itemsize.py create mode 100644 tests/basics/try_else.py create mode 100644 tests/basics/try_else_finally.py create mode 100644 tests/basics/try_finally_break.py create mode 100644 tests/extmod/ucryptolib_aes128_ctr.py create mode 100644 tests/extmod/ucryptolib_aes128_ctr.py.exp create mode 100644 tests/extmod/vfs_fat_ramdisklarge.py create mode 100644 tests/extmod/vfs_fat_ramdisklarge.py.exp delete mode 100644 tests/extmod/websocket_basic.py create mode 100644 tests/import/mpy_native.py create mode 100644 tests/import/mpy_native.py.exp create mode 100644 tests/micropython/heapalloc_fail_bytearray.py create mode 100644 tests/micropython/heapalloc_fail_bytearray.py.exp create mode 100644 tests/micropython/heapalloc_fail_dict.py create mode 100644 tests/micropython/heapalloc_fail_dict.py.exp create mode 100644 tests/micropython/heapalloc_fail_list.py create mode 100644 tests/micropython/heapalloc_fail_list.py.exp create mode 100644 tests/micropython/heapalloc_fail_memoryview.py create mode 100644 tests/micropython/heapalloc_fail_memoryview.py.exp create mode 100644 tests/micropython/heapalloc_fail_set.py create mode 100644 tests/micropython/heapalloc_fail_set.py.exp create mode 100644 tests/micropython/heapalloc_fail_tuple.py create mode 100644 tests/micropython/heapalloc_fail_tuple.py.exp create mode 100644 tests/micropython/viper_types.py create mode 100644 tests/micropython/viper_types.py.exp diff --git a/.gitmodules b/.gitmodules index da5b5835a6..24ba2e2f6f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -113,7 +113,7 @@ url = https://github.com/adafruit/Adafruit_CircuitPython_Register.git [submodule "extmod/ulab"] path = extmod/ulab - url = https://github.com/v923z/micropython-ulab + url = https://github.com/adafruit/circuitpython-ulab [submodule "frozen/Adafruit_CircuitPython_ESP32SPI"] path = frozen/Adafruit_CircuitPython_ESP32SPI url = https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI diff --git a/LICENSE b/LICENSE index e3474e33dd..e6a54cf269 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013, 2014 Damien P. George +Copyright (c) 2013-2019 Damien P. George Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 7f0b088c4e..14938e8a1d 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -886,10 +886,10 @@ uint16_t bleio_adapter_add_attribute(bleio_adapter_obj_t *adapter, mp_obj_t *att uint16_t handle = (uint16_t)adapter->attributes->len; mp_obj_list_append(adapter->attributes, attribute); - if (MP_OBJ_IS_TYPE(attribute, &bleio_service_type)) { + if (mp_obj_is_type(attribute, &bleio_service_type)) { adapter->last_added_service_handle = handle; } - if (MP_OBJ_IS_TYPE(attribute, &bleio_characteristic_type)) { + if (mp_obj_is_type(attribute, &bleio_characteristic_type)) { adapter->last_added_characteristic_handle = handle; } diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.c b/devices/ble_hci/common-hal/_bleio/Attribute.c index 26fabed098..b1b31d604f 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.c +++ b/devices/ble_hci/common-hal/_bleio/Attribute.c @@ -33,15 +33,15 @@ bleio_uuid_obj_t *bleio_attribute_get_uuid(mp_obj_t *attribute) { - if (MP_OBJ_IS_TYPE(attribute, &bleio_characteristic_type)) { + if (mp_obj_is_type(attribute, &bleio_characteristic_type)) { bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute); return characteristic->uuid; } - if (MP_OBJ_IS_TYPE(attribute, &bleio_descriptor_type)) { + if (mp_obj_is_type(attribute, &bleio_descriptor_type)) { bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute); return descriptor->uuid; } - if (MP_OBJ_IS_TYPE(attribute, &bleio_service_type)) { + if (mp_obj_is_type(attribute, &bleio_service_type)) { bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute); return service->uuid; } diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.c b/devices/ble_hci/common-hal/_bleio/Characteristic.c index db1317f4c8..940fdfc755 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -213,9 +213,9 @@ bool bleio_characteristic_set_local_value(bleio_characteristic_obj_t *self, mp_b self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len); - if (MP_OBJ_IS_TYPE(self->observer, &bleio_characteristic_buffer_type)) { + if (mp_obj_is_type(self->observer, &bleio_characteristic_buffer_type)) { bleio_characteristic_buffer_update(MP_OBJ_FROM_PTR(self->observer), bufinfo); - } else if (MP_OBJ_IS_TYPE(self->observer, &bleio_packet_buffer_type)) { + } else if (mp_obj_is_type(self->observer, &bleio_packet_buffer_type)) { bleio_packet_buffer_update(MP_OBJ_FROM_PTR(self->observer), bufinfo); } else { return false; diff --git a/devices/ble_hci/common-hal/_bleio/Connection.c b/devices/ble_hci/common-hal/_bleio/Connection.c index a27c243f44..fd041ca002 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.c +++ b/devices/ble_hci/common-hal/_bleio/Connection.c @@ -644,7 +644,7 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); // mp_obj_t uuid_obj; // while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { -// if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { +// if (!mp_obj_is_type(uuid_obj, &bleio_uuid_type)) { // mp_raise_TypeError(translate("non-UUID found in service_uuids_whitelist")); // } // bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index 5a3eb94737..5767045481 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -539,7 +539,7 @@ void att_remove_connection(uint16_t conn_handle, uint8_t reason) { .len = sizeof(zero), }; - if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_descriptor_type)) { + if (mp_obj_is_type(attribute_obj, &bleio_descriptor_type)) { bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute_obj); if (bleio_uuid_get_uuid16_or_unknown(descriptor->uuid) == BLE_UUID_CCCD) { common_hal_bleio_descriptor_set_value(descriptor, &zero_cccd_value); @@ -800,7 +800,7 @@ STATIC void process_find_info_req(uint16_t conn_handle, uint16_t mtu, uint8_t dl // Fetch the uuid for the given attribute, which might be a characteristic or a descriptor. bleio_uuid_obj_t *uuid; - if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + if (mp_obj_is_type(attribute_obj, &bleio_characteristic_type)) { bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); if (characteristic->handle != handle) { // If the handles don't match, this is the characteristic definition attribute. @@ -971,7 +971,7 @@ void process_read_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, ui } mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); - if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_service_type)) { + if (mp_obj_is_type(attribute_obj, &bleio_service_type)) { bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute_obj); // Is this a 16-bit or a 128-bit uuid? It must match in size with any previous attribute @@ -1083,7 +1083,7 @@ STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, ui size_t rsp_length = sizeof(rsp_t); mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); - if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_service_type)) { + if (mp_obj_is_type(attribute_obj, &bleio_service_type)) { if (offset) { send_error(conn_handle, BT_ATT_ERR_ATTRIBUTE_NOT_LONG, handle, BT_ATT_ERR_INVALID_PDU); return; @@ -1095,7 +1095,7 @@ STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, ui common_hal_bleio_uuid_pack_into(service->uuid, rsp->r.value); rsp_length += sizeof_service_uuid; - } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + } else if (mp_obj_is_type(attribute_obj, &bleio_characteristic_type)) { bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); if (characteristic->decl_handle == handle) { // Read characteristic declaration. Return properties, value handle, and uuid. @@ -1135,7 +1135,7 @@ STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, ui memcpy(rsp->r.value, bufinfo.buf + offset, value_length); rsp_length += value_length; } - } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_descriptor_type)) { + } else if (mp_obj_is_type(attribute_obj, &bleio_descriptor_type)) { bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute_obj); mp_buffer_info_t bufinfo; @@ -1203,7 +1203,7 @@ STATIC void process_read_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dl mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); if (type_uuid == BLE_UUID_CHARACTERISTIC && - MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + mp_obj_is_type(attribute_obj, &bleio_characteristic_type)) { // Request is for characteristic declarations. bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); @@ -1250,7 +1250,7 @@ STATIC void process_read_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dl rsp_length += data_length; no_data = false; - } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_descriptor_type)) { + } else if (mp_obj_is_type(attribute_obj, &bleio_descriptor_type)) { // See if request is for a descriptor value with a 16-bit UUID, such as the CCCD. bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute_obj); if (bleio_uuid_get_uuid16_or_unknown(descriptor->uuid) == type_uuid) { @@ -1271,7 +1271,7 @@ STATIC void process_read_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dl break; } - } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + } else if (mp_obj_is_type(attribute_obj, &bleio_characteristic_type)) { // See if request is for a characteristic value with a 16-bit UUID. bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); if (bleio_uuid_get_uuid16_or_unknown(characteristic->uuid) == type_uuid) { @@ -1359,7 +1359,7 @@ STATIC void process_write_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t mp_obj_t attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, req->handle); - if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + if (mp_obj_is_type(attribute_obj, &bleio_characteristic_type)) { bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); // Don't write the characteristic declaration. @@ -1377,7 +1377,7 @@ STATIC void process_write_req_or_cmd(uint16_t conn_handle, uint16_t mtu, uint8_t // Just change the local value. Don't fire off notifications, etc. bleio_characteristic_set_local_value(characteristic, &bufinfo); - } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_descriptor_type)) { + } else if (mp_obj_is_type(attribute_obj, &bleio_descriptor_type)) { bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute_obj); // Only CCCD's are writable. if (bleio_uuid_get_uuid16_or_unknown(descriptor->uuid) != BLE_UUID_CCCD) { @@ -1427,7 +1427,7 @@ STATIC void process_prepare_write_req(uint16_t conn_handle, uint16_t mtu, uint8_ mp_obj_t *attribute = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); - if (!MP_OBJ_IS_TYPE(attribute, &bleio_characteristic_type)) { + if (!mp_obj_is_type(attribute, &bleio_characteristic_type)) { send_error(conn_handle, BT_ATT_OP_PREPARE_WRITE_REQ, handle, BT_ATT_ERR_ATTRIBUTE_NOT_LONG); return; } diff --git a/docs/library/re.rst b/docs/library/re.rst index 9c266a6d8f..8cbd43e83b 100644 --- a/docs/library/re.rst +++ b/docs/library/re.rst @@ -174,7 +174,7 @@ Match objects Match objects as returned by `match()` and `search()` methods, and passed to the replacement function in `sub()`. -.. method:: match.group([index]) +.. method:: match.group(index) Return matching (sub)string. *index* is 0 for entire match, 1 and above for each capturing group. Only numeric groups are supported. diff --git a/extmod/misc.h b/extmod/misc.h index 3e12e56719..6ff9bd8c87 100644 --- a/extmod/misc.h +++ b/extmod/misc.h @@ -15,6 +15,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj); #if MICROPY_PY_OS_DUPTERM +bool mp_uos_dupterm_is_builtin_stream(mp_const_obj_t stream); int mp_uos_dupterm_rx_chr(void); void mp_uos_dupterm_tx_strn(const char *str, size_t len); void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc); diff --git a/extmod/modubinascii.c b/extmod/modubinascii.c index 91df02317e..3fae9e9e4d 100644 --- a/extmod/modubinascii.c +++ b/extmod/modubinascii.c @@ -13,7 +13,7 @@ static void check_not_unicode(const mp_obj_t arg) { #if MICROPY_CPYTHON_COMPAT - if (MP_OBJ_IS_STR(arg)) { + if (mp_obj_is_str(arg)) { mp_raise_TypeError(translate("a bytes-like object is required")); } #endif diff --git a/extmod/moductypes.c b/extmod/moductypes.c index d093d39787..ec698bf65c 100644 --- a/extmod/moductypes.c +++ b/extmod/moductypes.c @@ -118,13 +118,13 @@ STATIC void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_p (void)kind; mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); const char *typen = "unk"; - if (MP_OBJ_IS_TYPE(self->desc, &mp_type_dict) + if (mp_obj_is_type(self->desc, &mp_type_dict) #if MICROPY_PY_COLLECTIONS_ORDEREDDICT - || MP_OBJ_IS_TYPE(self->desc, &mp_type_ordereddict) + || mp_obj_is_type(self->desc, &mp_type_ordereddict) #endif ) { typen = "STRUCT"; - } else if (MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) { + } else if (mp_obj_is_type(self->desc, &mp_type_tuple)) { mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS); @@ -195,14 +195,14 @@ STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_ } STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size) { - if (!MP_OBJ_IS_TYPE(desc_in, &mp_type_dict) + if (!mp_obj_is_type(desc_in, &mp_type_dict) #if MICROPY_PY_COLLECTIONS_ORDEREDDICT - && !MP_OBJ_IS_TYPE(desc_in, &mp_type_ordereddict) + && !mp_obj_is_type(desc_in, &mp_type_ordereddict) #endif ) { - if (MP_OBJ_IS_TYPE(desc_in, &mp_type_tuple)) { + if (mp_obj_is_type(desc_in, &mp_type_tuple)) { return uctypes_struct_agg_size((mp_obj_tuple_t *)MP_OBJ_TO_PTR(desc_in), layout_type, max_field_size); - } else if (MP_OBJ_IS_SMALL_INT(desc_in)) { + } else if (mp_obj_is_small_int(desc_in)) { // We allow sizeof on both type definitions and structures/structure fields, // but scalar structure field is lowered into native Python int, so all // type info is lost. So, we cannot say if it's scalar type description, @@ -216,9 +216,9 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_ mp_uint_t total_size = 0; for (mp_uint_t i = 0; i < d->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&d->map, i)) { + if (mp_map_slot_is_filled(&d->map, i)) { mp_obj_t v = d->map.table[i].value; - if (MP_OBJ_IS_SMALL_INT(v)) { + if (mp_obj_is_small_int(v)) { mp_uint_t offset = MP_OBJ_SMALL_INT_VALUE(v); mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS); offset &= VALUE_MASK(VAL_TYPE_BITS); @@ -233,7 +233,7 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_ total_size = offset + s; } } else { - if (!MP_OBJ_IS_TYPE(v, &mp_type_tuple)) { + if (!mp_obj_is_type(v, &mp_type_tuple)) { syntax_error(); } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(v); @@ -257,13 +257,13 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_ STATIC mp_obj_t uctypes_struct_sizeof(size_t n_args, const mp_obj_t *args) { mp_obj_t obj_in = args[0]; mp_uint_t max_field_size = 0; - if (MP_OBJ_IS_TYPE(obj_in, &mp_type_bytearray)) { + if (mp_obj_is_type(obj_in, &mp_type_bytearray)) { return mp_obj_len(obj_in); } int layout_type = LAYOUT_NATIVE; // We can apply sizeof either to structure definition (a dict) // or to instantiated structure - if (MP_OBJ_IS_TYPE(obj_in, &uctypes_struct_type)) { + if (mp_obj_is_type(obj_in, &uctypes_struct_type)) { if (n_args != 1) { mp_raise_TypeError(NULL); } @@ -400,16 +400,16 @@ STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) { STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) { mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); - if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_dict) + if (!mp_obj_is_type(self->desc, &mp_type_dict) #if MICROPY_PY_COLLECTIONS_ORDEREDDICT - && !MP_OBJ_IS_TYPE(self->desc, &mp_type_ordereddict) + && !mp_obj_is_type(self->desc, &mp_type_ordereddict) #endif ) { mp_raise_TypeError(translate("struct: no fields")); } mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr)); - if (MP_OBJ_IS_SMALL_INT(deref)) { + if (mp_obj_is_small_int(deref)) { mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref); mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS); offset &= VALUE_MASK(VAL_TYPE_BITS); @@ -470,7 +470,7 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set return MP_OBJ_NULL; } - if (!MP_OBJ_IS_TYPE(deref, &mp_type_tuple)) { + if (!mp_obj_is_type(deref, &mp_type_tuple)) { syntax_error(); } @@ -537,7 +537,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_ob return MP_OBJ_NULL; // op not supported } else { // load / store - if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) { + if (!mp_obj_is_type(self->desc, &mp_type_tuple)) { mp_raise_TypeError(translate("struct: cannot index")); } @@ -588,7 +588,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_ob } else if (agg_type == PTR) { byte *p = *(void **)self->addr; - if (MP_OBJ_IS_SMALL_INT(t->items[1])) { + if (mp_obj_is_small_int(t->items[1])) { uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS); return get_aligned(val_type, p, index); } else { @@ -612,7 +612,7 @@ STATIC mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in) { mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); switch (op) { case MP_UNARY_OP_INT: - if (MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) { + if (mp_obj_is_type(self->desc, &mp_type_tuple)) { mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS); diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index 7069cc4792..379ba8c285 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -88,12 +88,16 @@ STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { static void check_not_unicode(const mp_obj_t arg) { #if MICROPY_CPYTHON_COMPAT - if (MP_OBJ_IS_STR(arg)) { + if (mp_obj_is_str(arg)) { mp_raise_TypeError(translate("a bytes-like object is required")); } #endif } +#if MICROPY_PY_UHASHLIB_SHA256 +#include "crypto-algorithms/sha256.c" +#endif + STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { mp_arg_check_num(n_args, kw_args, 0, 1, false); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX)); @@ -336,8 +340,4 @@ const mp_obj_module_t mp_module_uhashlib = { .globals = (mp_obj_dict_t *)&mp_module_uhashlib_globals, }; -#if MICROPY_PY_UHASHLIB_SHA256 -#include "crypto-algorithms/sha256.c" -#endif - #endif // MICROPY_PY_UHASHLIB diff --git a/extmod/moduheapq.c b/extmod/moduheapq.c index 9e02d367a2..880b0ad273 100644 --- a/extmod/moduheapq.c +++ b/extmod/moduheapq.c @@ -13,7 +13,7 @@ // the algorithm here is modelled on CPython's heapq.py STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) { - if (!MP_OBJ_IS_TYPE(heap_in, &mp_type_list)) { + if (!mp_obj_is_type(heap_in, &mp_type_list)) { mp_raise_TypeError(translate("heap must be a list")); } return MP_OBJ_TO_PTR(heap_in); diff --git a/extmod/modujson.c b/extmod/modujson.c index 63e8a011bf..07d18e5e88 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -243,7 +243,7 @@ STATIC mp_obj_t _mod_ujson_load(mp_obj_t stream_obj, bool return_first_json) { cur = S_CUR(s); if (cur == '.' || cur == 'E' || cur == 'e') { flt = true; - } else if (cur == '-' || unichar_isdigit(cur)) { + } else if (cur == '+' || cur == '-' || unichar_isdigit(cur)) { // pass } else { break; diff --git a/extmod/modurandom.c b/extmod/modurandom.c index 26e89f77f2..f0662a1432 100644 --- a/extmod/modurandom.c +++ b/extmod/modurandom.c @@ -180,8 +180,19 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_uniform_obj, mod_urandom_uniform); #endif // MICROPY_PY_URANDOM_EXTRA_FUNCS +#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC +STATIC mp_obj_t mod_urandom___init__() { + mod_urandom_seed(MP_OBJ_NEW_SMALL_INT(MICROPY_PY_URANDOM_SEED_INIT_FUNC)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__); +#endif + STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) }, + #ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&mod_urandom___init___obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_urandom_getrandbits_obj) }, { MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_urandom_seed_obj) }, #if MICROPY_PY_URANDOM_EXTRA_FUNCS diff --git a/extmod/moduselect.c b/extmod/moduselect.c index e88494b279..50587184c0 100644 --- a/extmod/moduselect.c +++ b/extmod/moduselect.c @@ -1,5 +1,6 @@ // SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) // SPDX-FileCopyrightText: Copyright (c) 2014 Damien P. George +// SPDX-FileCopyrightText: Copyright (c) 2015-2017 Paul Sokolovsky // // SPDX-License-Identifier: MIT @@ -57,7 +58,7 @@ STATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) { mp_uint_t n_ready = 0; for (mp_uint_t i = 0; i < poll_map->alloc; ++i) { - if (!MP_MAP_SLOT_IS_FILLED(poll_map, i)) { + if (!mp_map_slot_is_filled(poll_map, i)) { continue; } @@ -91,7 +92,7 @@ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) { } /// \function select(rlist, wlist, xlist[, timeout]) -STATIC mp_obj_t select_select(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) { // get array data from tuple/list arguments size_t rwx_len[3]; mp_obj_t *r_array, *w_array, *x_array; @@ -135,7 +136,7 @@ STATIC mp_obj_t select_select(uint n_args, const mp_obj_t *args) { list_array[2] = mp_obj_new_list(rwx_len[2], NULL); rwx_len[0] = rwx_len[1] = rwx_len[2] = 0; for (mp_uint_t i = 0; i < poll_map.alloc; ++i) { - if (!MP_MAP_SLOT_IS_FILLED(&poll_map, i)) { + if (!mp_map_slot_is_filled(&poll_map, i)) { continue; } poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map.table[i].value); @@ -170,7 +171,7 @@ typedef struct _mp_obj_poll_t { } mp_obj_poll_t; /// \method register(obj[, eventmask]) -STATIC mp_obj_t poll_register(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) { mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); mp_uint_t flags; if (n_args == 3) { @@ -246,7 +247,7 @@ STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) { mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL)); n_ready = 0; for (mp_uint_t i = 0; i < self->poll_map.alloc; ++i) { - if (!MP_MAP_SLOT_IS_FILLED(&self->poll_map, i)) { + if (!mp_map_slot_is_filled(&self->poll_map, i)) { continue; } poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value); @@ -289,7 +290,7 @@ STATIC mp_obj_t poll_iternext(mp_obj_t self_in) { for (mp_uint_t i = self->iter_idx; i < self->poll_map.alloc; ++i) { self->iter_idx++; - if (!MP_MAP_SLOT_IS_FILLED(&self->poll_map, i)) { + if (!mp_map_slot_is_filled(&self->poll_map, i)) { continue; } poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value); diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c deleted file mode 100644 index 673f480b2c..0000000000 --- a/extmod/modussl_axtls.c +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) 2015-2017 Paul Sokolovsky -// SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) -// -// SPDX-License-Identifier: MIT - -#include -#include - -#include "py/runtime.h" -#include "py/stream.h" - -#include "supervisor/shared/translate.h" - -#if MICROPY_PY_USSL && MICROPY_SSL_AXTLS - -#include "ssl.h" - -typedef struct _mp_obj_ssl_socket_t { - mp_obj_base_t base; - mp_obj_t sock; - SSL_CTX *ssl_ctx; - SSL *ssl_sock; - byte *buf; - uint32_t bytes_left; -} mp_obj_ssl_socket_t; - -struct ssl_args { - mp_arg_val_t key; - mp_arg_val_t cert; - mp_arg_val_t server_side; - mp_arg_val_t server_hostname; -}; - -STATIC const mp_obj_type_t ussl_socket_type; - -STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { - #if MICROPY_PY_USSL_FINALISER - mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); - #else - mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); - #endif - o->base.type = &ussl_socket_type; - o->buf = NULL; - o->bytes_left = 0; - o->sock = sock; - - uint32_t options = SSL_SERVER_VERIFY_LATER; - if (args->key.u_obj != mp_const_none) { - options |= SSL_NO_DEFAULT_KEY; - } - if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) { - mp_raise_OSError(MP_EINVAL); - } - - if (args->key.u_obj != mp_const_none) { - size_t len; - const byte *data = (const byte *)mp_obj_str_get_data(args->key.u_obj, &len); - int res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_RSA_KEY, data, len, NULL); - if (res != SSL_OK) { - mp_raise_ValueError(translate("invalid key")); - } - - data = (const byte *)mp_obj_str_get_data(args->cert.u_obj, &len); - res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_X509_CERT, data, len, NULL); - if (res != SSL_OK) { - mp_raise_ValueError(translate("invalid cert")); - } - } - - if (args->server_side.u_bool) { - o->ssl_sock = ssl_server_new(o->ssl_ctx, (long)sock); - } else { - SSL_EXTENSIONS *ext = ssl_ext_new(); - - if (args->server_hostname.u_obj != mp_const_none) { - ext->host_name = (char *)mp_obj_str_get_str(args->server_hostname.u_obj); - } - - o->ssl_sock = ssl_client_new(o->ssl_ctx, (long)sock, NULL, 0, ext); - - int res = ssl_handshake_status(o->ssl_sock); - // Pointer to SSL_EXTENSIONS as being passed to ssl_client_new() - // is saved in ssl_sock->extensions. - // As of axTLS 2.1.3, extensions aren't used beyond the initial - // handshake, and that's pretty much how it's expected to be. So - // we allocate them on stack and reset the pointer after handshake. - - if (res != SSL_OK) { - printf("ssl_handshake_status: %d\n", res); - ssl_display_error(res); - mp_raise_OSError(MP_EIO); - } - - } - - return o; -} - -STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - (void)kind; - mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "<_SSLSocket %p>", self->ssl_sock); -} - -STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { - mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); - - if (o->ssl_sock == NULL) { - *errcode = EBADF; - return MP_STREAM_ERROR; - } - - while (o->bytes_left == 0) { - mp_int_t r = ssl_read(o->ssl_sock, &o->buf); - if (r == SSL_OK) { - // SSL_OK from ssl_read() means "everything is ok, but there's - // no user data yet". So, we just keep reading. - continue; - } - if (r < 0) { - if (r == SSL_CLOSE_NOTIFY || r == SSL_ERROR_CONN_LOST) { - // EOF - return 0; - } - if (r == SSL_EAGAIN) { - r = MP_EAGAIN; - } - *errcode = r; - return MP_STREAM_ERROR; - } - o->bytes_left = r; - } - - if (size > o->bytes_left) { - size = o->bytes_left; - } - memcpy(buf, o->buf, size); - o->buf += size; - o->bytes_left -= size; - return size; -} - -STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { - mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); - - if (o->ssl_sock == NULL) { - *errcode = EBADF; - return MP_STREAM_ERROR; - } - - mp_int_t r = ssl_write(o->ssl_sock, buf, size); - if (r < 0) { - *errcode = r; - return MP_STREAM_ERROR; - } - return r; -} - -STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { - mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); - if (request == MP_STREAM_CLOSE && self->ssl_sock != NULL) { - ssl_free(self->ssl_sock); - ssl_ctx_free(self->ssl_ctx); - self->ssl_sock = NULL; - } - // Pass all requests down to the underlying socket - return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode); -} - -STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { - // Currently supports only blocking mode - (void)self_in; - if (!mp_obj_is_true(flag_in)) { - mp_raise_NotImplementedError(NULL); - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); - -STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, - #if MICROPY_PY_USSL_FINALISER - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, - #endif -}; - -STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table); - -STATIC const mp_stream_p_t ussl_socket_stream_p = { - MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream) - .read = socket_read, - .write = socket_write, - .ioctl = socket_ioctl, -}; - -STATIC const mp_obj_type_t ussl_socket_type = { - { &mp_type_type }, - // Save on qstr's, reuse same as for module - .name = MP_QSTR_ussl, - .print = socket_print, - .getiter = NULL, - .iternext = NULL, - .protocol = &ussl_socket_stream_p, - .locals_dict = (void *)&ussl_socket_locals_dict, -}; - -STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // TODO: Implement more args - static const mp_arg_t allowed_args[] = { - { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, - }; - - // TODO: Check that sock implements stream protocol - mp_obj_t sock = pos_args[0]; - - struct ssl_args args; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, - MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args); - - return MP_OBJ_FROM_PTR(socket_new(sock, &args)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket); - -STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) }, - { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table); - -const mp_obj_module_t mp_module_ussl = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&mp_module_ssl_globals, -}; - -#endif // MICROPY_PY_USSL diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c deleted file mode 100644 index 05d6047f9b..0000000000 --- a/extmod/modussl_mbedtls.c +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright (c) 2016 Linaro Ltd. -// SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) -// -// SPDX-License-Identifier: MIT - -#include "py/mpconfig.h" -#if MICROPY_PY_USSL && MICROPY_SSL_MBEDTLS - -#include -#include -#include // needed because mp_is_nonblocking_error uses system error codes - -#include "py/runtime.h" -#include "py/stream.h" - -// mbedtls_time_t -#include "mbedtls/platform.h" -#include "mbedtls/net.h" -#include "mbedtls/ssl.h" -#include "mbedtls/x509_crt.h" -#include "mbedtls/pk.h" -#include "mbedtls/entropy.h" -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/debug.h" - -typedef struct _mp_obj_ssl_socket_t { - mp_obj_base_t base; - mp_obj_t sock; - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_ssl_context ssl; - mbedtls_ssl_config conf; - mbedtls_x509_crt cacert; - mbedtls_x509_crt cert; - mbedtls_pk_context pkey; -} mp_obj_ssl_socket_t; - -struct ssl_args { - mp_arg_val_t key; - mp_arg_val_t cert; - mp_arg_val_t server_side; - mp_arg_val_t server_hostname; -}; - -STATIC const mp_obj_type_t ussl_socket_type; - -#ifdef MBEDTLS_DEBUG_C -STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) { - (void)ctx; - (void)level; - printf("DBG:%s:%04d: %s\n", file, line, str); -} -#endif - -STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) { - mp_obj_t sock = *(mp_obj_t *)ctx; - - const mp_stream_p_t *sock_stream = mp_get_stream(sock); - int err; - - mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err); - if (out_sz == MP_STREAM_ERROR) { - if (mp_is_nonblocking_error(err)) { - return MBEDTLS_ERR_SSL_WANT_WRITE; - } - return -err; - } else { - return out_sz; - } -} - -STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { - mp_obj_t sock = *(mp_obj_t *)ctx; - - const mp_stream_p_t *sock_stream = mp_get_stream(sock); - int err; - - mp_uint_t out_sz = sock_stream->read(sock, buf, len, &err); - if (out_sz == MP_STREAM_ERROR) { - if (mp_is_nonblocking_error(err)) { - return MBEDTLS_ERR_SSL_WANT_READ; - } - return -err; - } else { - return out_sz; - } -} - - -STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { - // Verify the socket object has the full stream protocol - mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); - - #if MICROPY_PY_USSL_FINALISER - mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); - #else - mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); - #endif - o->base.type = &ussl_socket_type; - o->sock = sock; - - int ret; - mbedtls_ssl_init(&o->ssl); - mbedtls_ssl_config_init(&o->conf); - mbedtls_x509_crt_init(&o->cacert); - mbedtls_x509_crt_init(&o->cert); - mbedtls_pk_init(&o->pkey); - mbedtls_ctr_drbg_init(&o->ctr_drbg); - #ifdef MBEDTLS_DEBUG_C - // Debug level (0-4) - mbedtls_debug_set_threshold(0); - #endif - - mbedtls_entropy_init(&o->entropy); - const byte seed[] = "upy"; - ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed)); - if (ret != 0) { - goto cleanup; - } - - ret = mbedtls_ssl_config_defaults(&o->conf, - args->server_side.u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT); - if (ret != 0) { - goto cleanup; - } - - mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); - mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg); - #ifdef MBEDTLS_DEBUG_C - mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL); - #endif - - ret = mbedtls_ssl_setup(&o->ssl, &o->conf); - if (ret != 0) { - goto cleanup; - } - - if (args->server_hostname.u_obj != mp_const_none) { - const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj); - ret = mbedtls_ssl_set_hostname(&o->ssl, sni); - if (ret != 0) { - goto cleanup; - } - } - - mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); - - if (args->key.u_obj != MP_OBJ_NULL) { - size_t key_len; - const byte *key = (const byte *)mp_obj_str_get_data(args->key.u_obj, &key_len); - // len should include terminating null - ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0); - assert(ret == 0); - - size_t cert_len; - const byte *cert = (const byte *)mp_obj_str_get_data(args->cert.u_obj, &cert_len); - // len should include terminating null - ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1); - assert(ret == 0); - - ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey); - assert(ret == 0); - } - - while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) { - if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - printf("mbedtls_ssl_handshake error: -%x\n", -ret); - goto cleanup; - } - } - - return o; - -cleanup: - mbedtls_pk_free(&o->pkey); - mbedtls_x509_crt_free(&o->cert); - mbedtls_x509_crt_free(&o->cacert); - mbedtls_ssl_free(&o->ssl); - mbedtls_ssl_config_free(&o->conf); - mbedtls_ctr_drbg_free(&o->ctr_drbg); - mbedtls_entropy_free(&o->entropy); - - if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { - mp_raise_OSError(MP_ENOMEM); - } else { - mp_raise_OSError(MP_EIO); - } -} - -STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) { - mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); - if (!mp_obj_is_true(binary_form)) { - mp_raise_NotImplementedError(NULL); - } - const mbedtls_x509_crt *peer_cert = mbedtls_ssl_get_peer_cert(&o->ssl); - return mp_obj_new_bytes(peer_cert->raw.p, peer_cert->raw.len); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert); - -STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - (void)kind; - mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "<_SSLSocket %p>", self); -} - -STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { - mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); - - int ret = mbedtls_ssl_read(&o->ssl, buf, size); - if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { - // end of stream - return 0; - } - if (ret >= 0) { - return ret; - } - if (ret == MBEDTLS_ERR_SSL_WANT_READ) { - ret = MP_EWOULDBLOCK; - } - *errcode = ret; - return MP_STREAM_ERROR; -} - -STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { - mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); - - int ret = mbedtls_ssl_write(&o->ssl, buf, size); - if (ret >= 0) { - return ret; - } - if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { - ret = MP_EWOULDBLOCK; - } - *errcode = ret; - return MP_STREAM_ERROR; -} - -STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { - mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in); - mp_obj_t sock = o->sock; - mp_obj_t dest[3]; - mp_load_method(sock, MP_QSTR_setblocking, dest); - dest[2] = flag_in; - return mp_call_method_n_kw(1, 0, dest); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); - -STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { - mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); - if (request == MP_STREAM_CLOSE) { - mbedtls_pk_free(&self->pkey); - mbedtls_x509_crt_free(&self->cert); - mbedtls_x509_crt_free(&self->cacert); - mbedtls_ssl_free(&self->ssl); - mbedtls_ssl_config_free(&self->conf); - mbedtls_ctr_drbg_free(&self->ctr_drbg); - mbedtls_entropy_free(&self->entropy); - } - // Pass all requests down to the underlying socket - return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode); -} - -STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, - #if MICROPY_PY_USSL_FINALISER - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, - #endif - { MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table); - -STATIC const mp_stream_p_t ussl_socket_stream_p = { - MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream) - .read = socket_read, - .write = socket_write, - .ioctl = socket_ioctl, -}; - -STATIC const mp_obj_type_t ussl_socket_type = { - { &mp_type_type }, - // Save on qstr's, reuse same as for module - .name = MP_QSTR_ussl, - .print = socket_print, - .getiter = NULL, - .iternext = NULL, - .protocol = &ussl_socket_stream_p, - .locals_dict = (void *)&ussl_socket_locals_dict, -}; - -STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // TODO: Implement more args - static const mp_arg_t allowed_args[] = { - { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - }; - - // TODO: Check that sock implements stream protocol - mp_obj_t sock = pos_args[0]; - - struct ssl_args args; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, - MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args); - - return MP_OBJ_FROM_PTR(socket_new(sock, &args)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket); - -STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) }, - { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table); - -const mp_obj_module_t mp_module_ussl = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&mp_module_ssl_globals, -}; - -#endif // MICROPY_PY_USSL diff --git a/extmod/modutimeq.c b/extmod/modutimeq.c index beeb4353d9..b24633398c 100644 --- a/extmod/modutimeq.c +++ b/extmod/modutimeq.c @@ -126,7 +126,7 @@ STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) { mp_raise_IndexError(translate("empty heap")); } mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref); - if (!MP_OBJ_IS_TYPE(list_ref, &mp_type_list) || ret->len < 3) { + if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) { mp_raise_TypeError(NULL); } diff --git a/extmod/moduwebsocket.h b/extmod/moduwebsocket.h new file mode 100644 index 0000000000..c1ea291ed7 --- /dev/null +++ b/extmod/moduwebsocket.h @@ -0,0 +1,10 @@ +#ifndef MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H +#define MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H + +#define FRAME_OPCODE_MASK 0x0f +enum { + FRAME_CONT, FRAME_TXT, FRAME_BIN, + FRAME_CLOSE = 0x8, FRAME_PING, FRAME_PONG +}; + +#endif // MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index f470e26dba..9edea9b087 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -13,7 +13,7 @@ #ifdef MICROPY_PY_WEBREPL_DELAY #include "py/mphal.h" #endif -#include "extmod/modwebsocket.h" +#include "extmod/moduwebsocket.h" #if MICROPY_PY_WEBREPL @@ -87,6 +87,15 @@ STATIC mp_obj_t webrepl_make_new(const mp_obj_type_t *type, size_t n_args, size_ return o; } +STATIC void check_file_op_finished(mp_obj_webrepl_t *self) { + if (self->data_to_recv == 0) { + mp_stream_close(self->cur_file); + self->hdr_to_recv = sizeof(struct webrepl_file); + DEBUG_printf("webrepl: Finished file operation %d\n", self->hdr.type); + write_webrepl_resp(self->sock, 0); + } +} + STATIC int write_file_chunk(mp_obj_webrepl_t *self) { const mp_stream_p_t *file_stream = mp_get_stream(self->cur_file); byte readbuf[2 + 256]; @@ -139,6 +148,7 @@ STATIC void handle_op(mp_obj_webrepl_t *self) { if (self->hdr.type == PUT_FILE) { self->data_to_recv = self->hdr.size; + check_file_op_finished(self); } else if (self->hdr.type == GET_FILE) { self->data_to_recv = 1; } @@ -245,12 +255,7 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int } } - if (self->data_to_recv == 0) { - mp_stream_close(self->cur_file); - self->hdr_to_recv = sizeof(struct webrepl_file); - DEBUG_printf("webrepl: Finished file operation %d\n", self->hdr.type); - write_webrepl_resp(self->sock, 0); - } + check_file_op_finished(self); #ifdef MICROPY_PY_WEBREPL_DELAY // Some platforms may have broken drivers and easily gets diff --git a/extmod/modwebsocket.c b/extmod/modwebsocket.c deleted file mode 100644 index 6547ebee44..0000000000 --- a/extmod/modwebsocket.c +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright (c) 2016 Paul Sokolovsky -// SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) -// -// SPDX-License-Identifier: MIT - -#include -#include -#include - -#include "py/runtime.h" -#include "py/stream.h" -#include "extmod/modwebsocket.h" - -#if MICROPY_PY_WEBSOCKET - -enum { FRAME_HEADER, FRAME_OPT, PAYLOAD, CONTROL }; - -enum { BLOCKING_WRITE = 0x80 }; - -typedef struct _mp_obj_websocket_t { - mp_obj_base_t base; - mp_obj_t sock; - uint32_t msg_sz; - byte mask[4]; - byte state; - byte to_recv; - byte mask_pos; - byte buf_pos; - byte buf[6]; - byte opts; - // Copy of last data frame flags - byte ws_flags; - // Copy of current frame flags - byte last_flags; -} mp_obj_websocket_t; - -STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode); - -STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - mp_arg_check_num(n_args, kw_args, 1, 2, false); - mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); - mp_obj_websocket_t *o = m_new_obj(mp_obj_websocket_t); - o->base.type = type; - o->sock = args[0]; - o->state = FRAME_HEADER; - o->to_recv = 2; - o->mask_pos = 0; - o->buf_pos = 0; - o->opts = FRAME_TXT; - if (n_args > 1 && args[1] == mp_const_true) { - o->opts |= BLOCKING_WRITE; - } - return MP_OBJ_FROM_PTR(o); -} - -STATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { - mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); - const mp_stream_p_t *stream_p = mp_get_stream(self->sock); - while (1) { - if (self->to_recv != 0) { - mp_uint_t out_sz = stream_p->read(self->sock, self->buf + self->buf_pos, self->to_recv, errcode); - if (out_sz == 0 || out_sz == MP_STREAM_ERROR) { - return out_sz; - } - self->buf_pos += out_sz; - self->to_recv -= out_sz; - if (self->to_recv != 0) { - *errcode = MP_EAGAIN; - return MP_STREAM_ERROR; - } - } - - switch (self->state) { - case FRAME_HEADER: { - // TODO: Split frame handling below is untested so far, so conservatively disable it - assert(self->buf[0] & 0x80); - - // "Control frames MAY be injected in the middle of a fragmented message." - // So, they must be processed before data frames (and not alter - // self->ws_flags) - byte frame_type = self->buf[0]; - self->last_flags = frame_type; - frame_type &= FRAME_OPCODE_MASK; - - if ((self->buf[0] & FRAME_OPCODE_MASK) == FRAME_CONT) { - // Preserve previous frame type - self->ws_flags = (self->ws_flags & FRAME_OPCODE_MASK) | (self->buf[0] & ~FRAME_OPCODE_MASK); - } else { - self->ws_flags = self->buf[0]; - } - - // Reset mask in case someone will use "simplified" protocol - // without masks. - memset(self->mask, 0, sizeof(self->mask)); - - int to_recv = 0; - size_t sz = self->buf[1] & 0x7f; - if (sz == 126) { - // Msg size is next 2 bytes - to_recv += 2; - } else if (sz == 127) { - // Msg size is next 8 bytes - assert(0); - } - if (self->buf[1] & 0x80) { - // Next 4 bytes is mask - to_recv += 4; - } - - self->buf_pos = 0; - self->to_recv = to_recv; - self->msg_sz = sz; // May be overridden by FRAME_OPT - if (to_recv != 0) { - self->state = FRAME_OPT; - } else { - if (frame_type >= FRAME_CLOSE) { - self->state = CONTROL; - } else { - self->state = PAYLOAD; - } - } - continue; - } - - case FRAME_OPT: { - if ((self->buf_pos & 3) == 2) { - // First two bytes are message length - self->msg_sz = (self->buf[0] << 8) | self->buf[1]; - } - if (self->buf_pos >= 4) { - // Last 4 bytes is mask - memcpy(self->mask, self->buf + self->buf_pos - 4, 4); - } - self->buf_pos = 0; - if ((self->last_flags & FRAME_OPCODE_MASK) >= FRAME_CLOSE) { - self->state = CONTROL; - } else { - self->state = PAYLOAD; - } - continue; - } - - case PAYLOAD: - case CONTROL: { - mp_uint_t out_sz = 0; - if (self->msg_sz == 0) { - // In case message had zero payload - goto no_payload; - } - - size_t sz = MIN(size, self->msg_sz); - out_sz = stream_p->read(self->sock, buf, sz, errcode); - if (out_sz == 0 || out_sz == MP_STREAM_ERROR) { - return out_sz; - } - - sz = out_sz; - for (byte *p = buf; sz--; p++) { - *p ^= self->mask[self->mask_pos++ & 3]; - } - - self->msg_sz -= out_sz; - if (self->msg_sz == 0) { - byte last_state; - no_payload: - last_state = self->state; - self->state = FRAME_HEADER; - self->to_recv = 2; - self->mask_pos = 0; - self->buf_pos = 0; - - // Handle control frame - if (last_state == CONTROL) { - byte frame_type = self->last_flags & FRAME_OPCODE_MASK; - if (frame_type == FRAME_CLOSE) { - static char close_resp[2] = {0x88, 0}; - int err; - websocket_write(self_in, close_resp, sizeof(close_resp), &err); - return 0; - } - - // DEBUG_printf("Finished receiving ctrl message %x, ignoring\n", self->last_flags); - continue; - } - } - - if (out_sz != 0) { - return out_sz; - } - // Empty (data) frame received is not EOF - continue; - } - - } - } -} - -STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { - mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); - assert(size < 0x10000); - byte header[4] = {0x80 | (self->opts & FRAME_OPCODE_MASK)}; - int hdr_sz; - if (size < 126) { - header[1] = size; - hdr_sz = 2; - } else { - header[1] = 126; - header[2] = size >> 8; - header[3] = size & 0xff; - hdr_sz = 4; - } - - mp_obj_t dest[3]; - if (self->opts & BLOCKING_WRITE) { - mp_load_method(self->sock, MP_QSTR_setblocking, dest); - dest[2] = mp_const_true; - mp_call_method_n_kw(1, 0, dest); - } - - mp_uint_t out_sz = mp_stream_write_exactly(self->sock, header, hdr_sz, errcode); - if (*errcode == 0) { - out_sz = mp_stream_write_exactly(self->sock, buf, size, errcode); - } - - if (self->opts & BLOCKING_WRITE) { - dest[2] = mp_const_false; - mp_call_method_n_kw(1, 0, dest); - } - - if (*errcode != 0) { - return MP_STREAM_ERROR; - } - return out_sz; -} - -STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { - mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); - switch (request) { - case MP_STREAM_CLOSE: - // TODO: Send close signaling to the other side, otherwise it's - // abrupt close (connection abort). - mp_stream_close(self->sock); - return 0; - case MP_STREAM_GET_DATA_OPTS: - return self->ws_flags & FRAME_OPCODE_MASK; - case MP_STREAM_SET_DATA_OPTS: { - int cur = self->opts & FRAME_OPCODE_MASK; - self->opts = (self->opts & ~FRAME_OPCODE_MASK) | (arg & FRAME_OPCODE_MASK); - return cur; - } - default: - *errcode = MP_EINVAL; - return MP_STREAM_ERROR; - } -} - -STATIC const mp_rom_map_elem_t websocket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table); - -STATIC const mp_stream_p_t websocket_stream_p = { - MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream) - .read = websocket_read, - .write = websocket_write, - .ioctl = websocket_ioctl, -}; - -STATIC const mp_obj_type_t websocket_type = { - { &mp_type_type }, - .name = MP_QSTR_websocket, - .make_new = websocket_make_new, - .protocol = &websocket_stream_p, - .locals_dict = (void *)&websocket_locals_dict, -}; - -STATIC const mp_rom_map_elem_t websocket_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_websocket) }, - { MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&websocket_type) }, -}; - -STATIC MP_DEFINE_CONST_DICT(websocket_module_globals, websocket_module_globals_table); - -const mp_obj_module_t mp_module_websocket = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&websocket_module_globals, -}; - -#endif // MICROPY_PY_WEBSOCKET diff --git a/extmod/modwebsocket.h b/extmod/modwebsocket.h deleted file mode 100644 index 46aa0408b6..0000000000 --- a/extmod/modwebsocket.h +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) -// -// SPDX-License-Identifier: MIT - -#ifndef MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H -#define MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H - -#define FRAME_OPCODE_MASK 0x0f -enum { - FRAME_CONT, FRAME_TXT, FRAME_BIN, - FRAME_CLOSE = 0x8, FRAME_PING, FRAME_PONG -}; - -#endif // MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H diff --git a/extmod/ulab b/extmod/ulab index ef65415b55..e3bf07cabb 160000 --- a/extmod/ulab +++ b/extmod/ulab @@ -1 +1 @@ -Subproject commit ef65415b5503ae71cc0a9064197f2e3fa5365d74 +Subproject commit e3bf07cabb728ecfa2b78ea5e468179f94dbf933 diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c index 4668279bc8..57b7de319f 100644 --- a/extmod/uos_dupterm.c +++ b/extmod/uos_dupterm.c @@ -11,6 +11,7 @@ #include "py/objtuple.h" #include "py/objarray.h" #include "py/stream.h" +#include "extmod/misc.h" #include "lib/utils/interrupt_char.h" #include "supervisor/shared/translate.h" @@ -39,6 +40,20 @@ int mp_uos_dupterm_rx_chr(void) { continue; } + #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM + if (mp_uos_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) { + byte buf[1]; + int errcode = 0; + const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx])); + mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode); + if (errcode == 0 && out_sz != 0) { + return buf[0]; + } else { + continue; + } + } + #endif + nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { byte buf[1]; @@ -79,6 +94,16 @@ void mp_uos_dupterm_tx_strn(const char *str, size_t len) { if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) { continue; } + + #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM + if (mp_uos_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) { + int errcode = 0; + const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx])); + stream_p->write(MP_STATE_VM(dupterm_objs[idx]), str, len, &errcode); + continue; + } + #endif + nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE); diff --git a/extmod/vfs.c b/extmod/vfs.c index cac51289fd..eff41da5a8 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -207,7 +207,7 @@ mp_obj_t mp_vfs_umount(mp_obj_t mnt_in) { mp_vfs_mount_t *vfs = NULL; size_t mnt_len; const char *mnt_str = NULL; - if (MP_OBJ_IS_STR(mnt_in)) { + if (mp_obj_is_str(mnt_in)) { mnt_str = mp_obj_str_get_data(mnt_in, &mnt_len); } for (mp_vfs_mount_t **vfsp = &MP_STATE_VM(vfs_mount_table); *vfsp != NULL; vfsp = &(*vfsp)->next) { @@ -250,7 +250,7 @@ mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) #if defined(MICROPY_VFS_POSIX) && MICROPY_VFS_POSIX // If the file is an integer then delegate straight to the POSIX handler - if (MP_OBJ_IS_SMALL_INT(args[ARG_file].u_obj)) { + if (mp_obj_is_small_int(args[ARG_file].u_obj)) { return mp_vfs_posix_file_open(&mp_type_textio, args[ARG_file].u_obj, args[ARG_mode].u_obj); } #endif diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 5da4ecd872..f6645e50a1 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -21,8 +21,8 @@ #include "supervisor/filesystem.h" #include "supervisor/shared/translate.h" -#if _MAX_SS == _MIN_SS -#define SECSIZE(fs) (_MIN_SS) +#if FF_MAX_SS == FF_MIN_SS +#define SECSIZE(fs) (FF_MIN_SS) #else #define SECSIZE(fs) ((fs)->ssize) #endif @@ -84,7 +84,7 @@ STATIC void verify_fs_writable(fs_user_mount_t *vfs) { } } -#if _FS_REENTRANT +#if FF_FS_REENTRANT STATIC mp_obj_t fat_vfs_del(mp_obj_t self_in) { mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(self_in); // f_umount only needs to be called to release the sync object @@ -99,8 +99,11 @@ STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, &bdev_in, NULL)); // make the filesystem - uint8_t working_buf[_MAX_SS]; + uint8_t working_buf[FF_MAX_SS]; FRESULT res = f_mkfs(&vfs->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); + if (res == FR_MKFS_ABORTED) { // Probably doesn't support FAT16 + res = f_mkfs(&vfs->fatfs, FM_FAT32, 0, working_buf, sizeof(working_buf)); + } if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } @@ -377,7 +380,7 @@ STATIC mp_obj_t fat_vfs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) { t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags - t->items[9] = MP_OBJ_NEW_SMALL_INT(_MAX_LFN); // f_namemax + t->items[9] = MP_OBJ_NEW_SMALL_INT(FF_MAX_LFN); // f_namemax return MP_OBJ_FROM_PTR(t); } @@ -397,7 +400,7 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs // check if we need to make the filesystem FRESULT res = (self->flags & FSUSER_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK; if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) { - uint8_t working_buf[_MAX_SS]; + uint8_t working_buf[FF_MAX_SS]; res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); } if (res != FR_OK) { @@ -451,7 +454,7 @@ STATIC const mp_obj_property_t fat_vfs_label_obj = { #endif STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { - #if _FS_REENTRANT + #if FF_FS_REENTRANT { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&fat_vfs_del_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) }, diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index b3054ef2c6..c656984a67 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -18,8 +18,8 @@ #include "lib/oofatfs/diskio.h" #include "extmod/vfs_fat.h" -#if _MAX_SS == _MIN_SS -#define SECSIZE(fs) (_MIN_SS) +#if FF_MAX_SS == FF_MIN_SS +#define SECSIZE(fs) (FF_MIN_SS) #else #define SECSIZE(fs) ((fs)->ssize) #endif @@ -34,7 +34,7 @@ STATIC fs_user_mount_t *disk_get_device(void *bdev) { /*-----------------------------------------------------------------------*/ DRESULT disk_read( - bdev_t pdrv, /* Physical drive */ + bdev_t pdrv, /* Physical drive nmuber (0..) */ BYTE *buff, /* Data buffer to store read data */ DWORD sector, /* Sector address (LBA) */ UINT count /* Number of sectors to read (1..128) */ @@ -74,7 +74,7 @@ DRESULT disk_read( /*-----------------------------------------------------------------------*/ DRESULT disk_write( - bdev_t pdrv, /* Physical drive */ + bdev_t pdrv, /* Physical drive nmuber (0..) */ const BYTE *buff, /* Data to be written */ DWORD sector, /* Sector address (LBA) */ UINT count /* Number of sectors to write (1..128) */ @@ -120,8 +120,8 @@ DRESULT disk_write( /*-----------------------------------------------------------------------*/ DRESULT disk_ioctl( - bdev_t pdrv, /* Physical drive */ - BYTE cmd, /* Control code */ + bdev_t pdrv, /* Physical drive nmuber (0..) */ + BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ ) { fs_user_mount_t *vfs = disk_get_device(pdrv); @@ -198,7 +198,7 @@ DRESULT disk_ioctl( } else { *((WORD *)buff) = out_value; } - #if _MAX_SS != _MIN_SS + #if FF_MAX_SS != FF_MIN_SS // need to store ssize because we use it in disk_read/disk_write vfs->fatfs.ssize = *((WORD *)buff); #endif diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c index ff2ed04715..73f4a1d874 100644 --- a/extmod/vfs_posix.c +++ b/extmod/vfs_posix.c @@ -110,7 +110,7 @@ STATIC mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode && (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) { mp_raise_OSError(MP_EROFS); } - if (!MP_OBJ_IS_SMALL_INT(path_in)) { + if (!mp_obj_is_small_int(path_in)) { path_in = vfs_posix_get_path_obj(self, path_in); } return mp_vfs_posix_file_open(&mp_type_textio, path_in, mode_in); diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index bc45a2cf2e..cf638cd239 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -74,7 +74,7 @@ mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_ mp_obj_t fid = file_in; - if (MP_OBJ_IS_SMALL_INT(fid)) { + if (mp_obj_is_small_int(fid)) { o->fd = MP_OBJ_SMALL_INT_VALUE(fid); return MP_OBJ_FROM_PTR(o); } diff --git a/lib/netutils/netutils.h b/lib/netutils/netutils.h index 98e1d24932..b23a78e5b8 100644 --- a/lib/netutils/netutils.h +++ b/lib/netutils/netutils.h @@ -29,6 +29,10 @@ #define NETUTILS_IPV4ADDR_BUFSIZE 4 +#define NETUTILS_TRACE_IS_TX (0x0001) +#define NETUTILS_TRACE_PAYLOAD (0x0002) +#define NETUTILS_TRACE_NEWLINE (0x0004) + typedef enum _netutils_endian_t { NETUTILS_LITTLE, NETUTILS_BIG, @@ -47,4 +51,6 @@ void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian // puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes). mp_uint_t netutils_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian); +void netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags); + #endif // MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H diff --git a/lib/netutils/trace.c b/lib/netutils/trace.c new file mode 100644 index 0000000000..1610966c2d --- /dev/null +++ b/lib/netutils/trace.c @@ -0,0 +1,170 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" +#include "lib/netutils/netutils.h" + +static uint32_t get_be16(const uint8_t *buf) { + return buf[0] << 8 | buf[1]; +} + +static uint32_t get_be32(const uint8_t *buf) { + return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; +} + +static void dump_hex_bytes(const mp_print_t *print, size_t len, const uint8_t *buf) { + for (size_t i = 0; i < len; ++i) { + mp_printf(print, " %02x", buf[i]); + } +} + +static const char *ethertype_str(uint16_t type) { + // A value between 0x0000 - 0x05dc (inclusive) indicates a length, not type + switch (type) { + case 0x0800: + return "IPv4"; + case 0x0806: + return "ARP"; + case 0x86dd: + return "IPv6"; + default: + return NULL; + } +} + +void netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags) { + mp_printf(print, "[% 8d] ETH%cX len=%u", mp_hal_ticks_ms(), flags & NETUTILS_TRACE_IS_TX ? 'T' : 'R', len); + mp_printf(print, " dst=%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + mp_printf(print, " src=%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]); + + const char *ethertype = ethertype_str(buf[12] << 8 | buf[13]); + if (ethertype) { + mp_printf(print, " type=%s", ethertype); + } else { + mp_printf(print, " type=0x%04x", buf[12] << 8 | buf[13]); + } + if (len > 14) { + len -= 14; + buf += 14; + if (buf[-2] == 0x08 && buf[-1] == 0x00 && buf[0] == 0x45) { + // IPv4 packet + len = get_be16(buf + 2); + mp_printf(print, " srcip=%u.%u.%u.%u dstip=%u.%u.%u.%u", + buf[12], buf[13], buf[14], buf[15], + buf[16], buf[17], buf[18], buf[19]); + uint8_t prot = buf[9]; + buf += 20; + len -= 20; + if (prot == 6) { + // TCP packet + uint16_t srcport = get_be16(buf); + uint16_t dstport = get_be16(buf + 2); + uint32_t seqnum = get_be32(buf + 4); + uint32_t acknum = get_be32(buf + 8); + uint16_t dataoff_flags = get_be16(buf + 12); + uint16_t winsz = get_be16(buf + 14); + mp_printf(print, " TCP srcport=%u dstport=%u seqnum=%u acknum=%u dataoff=%u flags=%x winsz=%u", + srcport, dstport, (unsigned)seqnum, (unsigned)acknum, dataoff_flags >> 12, dataoff_flags & 0x1ff, winsz); + buf += 20; + len -= 20; + if (dataoff_flags >> 12 > 5) { + mp_printf(print, " opts="); + size_t opts_len = ((dataoff_flags >> 12) - 5) * 4; + dump_hex_bytes(print, opts_len, buf); + buf += opts_len; + len -= opts_len; + } + } else if (prot == 17) { + // UDP packet + uint16_t srcport = get_be16(buf); + uint16_t dstport = get_be16(buf + 2); + mp_printf(print, " UDP srcport=%u dstport=%u", srcport, dstport); + len = get_be16(buf + 4); + buf += 8; + if ((srcport == 67 && dstport == 68) || (srcport == 68 && dstport == 67)) { + // DHCP + if (srcport == 67) { + mp_printf(print, " DHCPS"); + } else { + mp_printf(print, " DHCPC"); + } + dump_hex_bytes(print, 12 + 16 + 16 + 64, buf); + size_t n = 12 + 16 + 16 + 64 + 128; + len -= n; + buf += n; + mp_printf(print, " opts:"); + switch (buf[6]) { + case 1: + mp_printf(print, " DISCOVER"); + break; + case 2: + mp_printf(print, " OFFER"); + break; + case 3: + mp_printf(print, " REQUEST"); + break; + case 4: + mp_printf(print, " DECLINE"); + break; + case 5: + mp_printf(print, " ACK"); + break; + case 6: + mp_printf(print, " NACK"); + break; + case 7: + mp_printf(print, " RELEASE"); + break; + case 8: + mp_printf(print, " INFORM"); + break; + } + } + } else { + // Non-UDP packet + mp_printf(print, " prot=%u", prot); + } + } else if (buf[-2] == 0x86 && buf[-1] == 0xdd && (buf[0] >> 4) == 6) { + // IPv6 packet + uint32_t h = get_be32(buf); + uint16_t l = get_be16(buf + 4); + mp_printf(print, " tclass=%u flow=%u len=%u nexthdr=%u hoplimit=%u", (unsigned)((h >> 20) & 0xff), (unsigned)(h & 0xfffff), l, buf[6], buf[7]); + mp_printf(print, " srcip="); + dump_hex_bytes(print, 16, buf + 8); + mp_printf(print, " dstip="); + dump_hex_bytes(print, 16, buf + 24); + buf += 40; + len -= 40; + } + if (flags & NETUTILS_TRACE_PAYLOAD) { + mp_printf(print, " data="); + dump_hex_bytes(print, len, buf); + } + } + if (flags & NETUTILS_TRACE_NEWLINE) { + mp_printf(print, "\n"); + } +} diff --git a/lib/oofatfs/diskio.h b/lib/oofatfs/diskio.h index 8deb68ecea..d886bdd9cc 100644 --- a/lib/oofatfs/diskio.h +++ b/lib/oofatfs/diskio.h @@ -13,8 +13,6 @@ extern "C" { #endif - - /* Status of Disk Functions */ typedef BYTE DSTATUS; @@ -47,11 +45,11 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff); /* Command code for disk_ioctrl fucntion */ /* Generic command (Used by FatFs) */ -#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ -#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ -#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ -#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ -#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ +#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ +#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ +#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ #define IOCTL_INIT 5 #define IOCTL_STATUS 6 diff --git a/lib/oofatfs/ff.c b/lib/oofatfs/ff.c index e961c789d8..06743947e0 100644 --- a/lib/oofatfs/ff.c +++ b/lib/oofatfs/ff.c @@ -3,15 +3,15 @@ */ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT file system module R0.12b / +/ FatFs - Generic FAT Filesystem Module R0.13c / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2016, ChaN, all right reserved. +/ Copyright (C) 2018, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: - +/ / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / @@ -19,6 +19,7 @@ / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. +/ /----------------------------------------------------------------------------*/ @@ -36,343 +37,43 @@ ---------------------------------------------------------------------------*/ -#if _FATFS != 68020 /* Revision ID */ +#if FF_DEFINED != 86604 /* Revision ID */ #error Wrong include file (ff.h). #endif -#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } - - -/* Reentrancy related */ -#if _FS_REENTRANT -#if _USE_LFN == 1 -#error Static LFN work area cannot be used at thread-safe configuration -#endif -#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } -#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } -#else -#define ENTER_FF(fs) -#define LEAVE_FF(fs, res) return res -#endif - - - -/* Definitions of sector size */ -#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) -#error Wrong sector size configuration -#endif -#if _MAX_SS == _MIN_SS -#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ -#else -#define SS(fs) ((fs)->ssize) /* Variable sector size */ -#endif - - -/* Timestamp */ -#if _FS_NORTC == 1 -#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 -#error Invalid _FS_NORTC settings -#endif -#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16) -#else -#define GET_FATTIME() get_fattime() -#endif - - -/* File lock controls */ -#if _FS_LOCK != 0 -#if _FS_READONLY -#error _FS_LOCK must be 0 at read-only configuration -#endif -typedef struct { - FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ - DWORD clu; /* Object ID 2, directory (0:root) */ - DWORD ofs; /* Object ID 3, directory offset */ - WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ -} FILESEM; -#endif - - - -/* DBCS code ranges and SBCS upper conversion tables */ - -#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ -#define _DF1S 0x81 /* DBC 1st byte range 1 start */ -#define _DF1E 0x9F /* DBC 1st byte range 1 end */ -#define _DF2S 0xE0 /* DBC 1st byte range 2 start */ -#define _DF2E 0xFC /* DBC 1st byte range 2 end */ -#define _DS1S 0x40 /* DBC 2nd byte range 1 start */ -#define _DS1E 0x7E /* DBC 2nd byte range 1 end */ -#define _DS2S 0x80 /* DBC 2nd byte range 2 start */ -#define _DS2E 0xFC /* DBC 2nd byte range 2 end */ - -#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ -#define _DF1S 0x81 -#define _DF1E 0xFE -#define _DS1S 0x40 -#define _DS1E 0x7E -#define _DS2S 0x80 -#define _DS2E 0xFE - -#elif _CODE_PAGE == 949 /* Korean */ -#define _DF1S 0x81 -#define _DF1E 0xFE -#define _DS1S 0x41 -#define _DS1E 0x5A -#define _DS2S 0x61 -#define _DS2E 0x7A -#define _DS3S 0x81 -#define _DS3E 0xFE - -#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ -#define _DF1S 0x81 -#define _DF1E 0xFE -#define _DS1S 0x40 -#define _DS1E 0x7E -#define _DS2S 0xA1 -#define _DS2E 0xFE - -#elif _CODE_PAGE == 437 /* U.S. */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ - 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 720 /* Arabic */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 737 /* Greek */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ - 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 771 /* KBL */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} - -#elif _CODE_PAGE == 775 /* Baltic */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ - 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 850 /* Latin 1 */ -#define _DF1S 0 -#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ - 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ - 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 852 /* Latin 2 */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ - 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} - -#elif _CODE_PAGE == 855 /* Cyrillic */ -#define _DF1S 0 -#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ - 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ - 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ - 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ - 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 857 /* Turkish */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ - 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ - 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 860 /* Portuguese */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ - 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 861 /* Icelandic */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ - 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ - 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 862 /* Hebrew */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 863 /* Canadian-French */ -#define _DF1S 0 -#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ - 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ - 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 864 /* Arabic */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ - 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 865 /* Nordic */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ - 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ - 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 866 /* Russian */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 869 /* Greek 2 */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ - 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ - 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ - 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ - 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ - 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ - 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} - -#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ -#if _USE_LFN != 0 -#error Cannot enable LFN without valid code page. -#endif -#define _DF1S 0 - -#else -#error Unknown code page - -#endif +/* Limits and boundaries */ +#define MAX_DIR 0x200000 /* Max size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ +#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ +#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ /* Character code support macros */ -#define IsUpper(c) (((c)>='A')&&((c)<='Z')) -#define IsLower(c) (((c)>='a')&&((c)<='z')) -#define IsDigit(c) (((c)>='0')&&((c)<='9')) - -#if _DF1S != 0 /* Code page is DBCS */ - -#ifdef _DF2S /* Two 1st byte areas */ -#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) -#else /* One 1st byte area */ -#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) -#endif - -#ifdef _DS3S /* Three 2nd byte areas */ -#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) -#else /* Two 2nd byte areas */ -#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) -#endif - -#else /* Code page is SBCS */ - -#define IsDBCS1(c) 0 -#define IsDBCS2(c) 0 - -#endif /* _DF1S */ +#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') +#define IsLower(c) ((c) >= 'a' && (c) <= 'z') +#define IsDigit(c) ((c) >= '0' && (c) <= '9') +#define IsSurrogate(c) ((c) >= 0xD800 && (c) <= 0xDFFF) +#define IsSurrogateH(c) ((c) >= 0xD800 && (c) <= 0xDBFF) +#define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) -/* File attribute bits (internal use) */ -#define AM_VOL 0x08 /* Volume label */ -#define AM_LFN 0x0F /* LFN entry */ -#define AM_MASK 0x3F /* Mask of defined bits */ - - -/* File access control and file status flags (internal use) */ +/* Additional file access control and file status flags for internal use */ #define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ #define FA_MODIFIED 0x40 /* File has been modified */ #define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ -/* Name status flags */ -#define NSFLAG 11 /* Index of name status byte in fn[] */ +/* Additional file attribute bits for internal use */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_MASK 0x3F /* Mask of defined bits */ + + +/* Name status flags in fn[11] */ +#define NSFLAG 11 /* Index of the name status byte */ #define NS_LOSS 0x01 /* Out of 8.3 format */ #define NS_LFN 0x02 /* Force to create LFN entry */ #define NS_LAST 0x04 /* Last segment */ @@ -383,18 +84,17 @@ typedef struct { #define NS_NONAME 0x80 /* Not followed */ -/* Limits and boundaries (differ from specs but correct for real DOS/Windows) */ -#define MAX_FAT12 0xFF5 /* Maximum number of FAT12 clusters */ -#define MAX_FAT16 0xFFF5 /* Maximum number of FAT16 clusters */ -#define MAX_FAT32 0xFFFFFF5 /* Maximum number of FAT32 clusters */ -#define MAX_EXFAT 0x7FFFFFFD /* Maximum number of exFAT clusters (limited by implementation) */ -#define MAX_DIR 0x200000 /* Maximum size of FAT directory */ -#define MAX_DIR_EX 0x10000000 /* Maximum size of exFAT directory */ +/* exFAT directory entry types */ +#define ET_BITMAP 0x81 /* Allocation bitmap */ +#define ET_UPCASE 0x82 /* Up-case table */ +#define ET_VLABEL 0x83 /* Volume label */ +#define ET_FILEDIR 0x85 /* File and directory */ +#define ET_STREAM 0xC0 /* Stream extension */ +#define ET_FILENAME 0xC1 /* Name extension */ -/* FatFs refers the members in the FAT structures as byte array instead of -/ structure members because the structure is not binary compatible between -/ different platforms */ +/* FatFs refers the FAT structure as simple byte array instead of structure member +/ because the C structure is not binary compatible between different platforms */ #define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ #define BS_OEMName 3 /* OEM name (8-byte) */ @@ -402,26 +102,26 @@ typedef struct { #define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ #define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ #define BPB_NumFATs 16 /* Number of FATs (BYTE) */ -#define BPB_RootEntCnt 17 /* Size of root directory area for FAT12/16 [entry] (WORD) */ +#define BPB_RootEntCnt 17 /* Size of root directory area for FAT [entry] (WORD) */ #define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ #define BPB_Media 21 /* Media descriptor byte (BYTE) */ #define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ -#define BPB_SecPerTrk 24 /* Track size for int13h [sector] (WORD) */ +#define BPB_SecPerTrk 24 /* Number of sectors per track for int13h [sector] (WORD) */ #define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ #define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ #define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ #define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ -#define BS_NTres 37 /* Error flag (BYTE) */ +#define BS_NTres 37 /* WindowsNT error flag (BYTE) */ #define BS_BootSig 38 /* Extended boot signature (BYTE) */ #define BS_VolID 39 /* Volume serial number (DWORD) */ #define BS_VolLab 43 /* Volume label string (8-byte) */ -#define BS_FilSysType 54 /* File system type string (8-byte) */ +#define BS_FilSysType 54 /* Filesystem type string (8-byte) */ #define BS_BootCode 62 /* Boot code (448-byte) */ #define BS_55AA 510 /* Signature word (WORD) */ #define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ #define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ -#define BPB_FSVer32 42 /* FAT32: File system version (WORD) */ +#define BPB_FSVer32 42 /* FAT32: Filesystem version (WORD) */ #define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ #define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ #define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ @@ -430,7 +130,7 @@ typedef struct { #define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ #define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ #define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ -#define BS_FilSysType32 82 /* FAT32: File system type string (8-byte) */ +#define BS_FilSysType32 82 /* FAT32: Filesystem type string (8-byte) */ #define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ #define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ @@ -440,19 +140,60 @@ typedef struct { #define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ #define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ #define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ -#define BPB_RootClusEx 96 /* exFAT: Root directory cluster (DWORD) */ +#define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ #define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ -#define BPB_FSVerEx 104 /* exFAT: File system version (WORD) */ -#define BPB_VolFlagEx 106 /* exFAT: Volume flags (BYTE) */ -#define BPB_ActFatEx 107 /* exFAT: Active FAT flags (BYTE) */ -#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in byte (BYTE) */ -#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in sector (BYTE) */ +#define BPB_FSVerEx 104 /* exFAT: Filesystem version (WORD) */ +#define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD) */ +#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ +#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ #define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ #define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ #define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ #define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ #define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ +#define DIR_Name 0 /* Short file name (11-byte) */ +#define DIR_Attr 11 /* Attribute (BYTE) */ +#define DIR_NTres 12 /* Lower case flag (BYTE) */ +#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ +#define DIR_CrtTime 14 /* Created time (DWORD) */ +#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ +#define DIR_ModTime 22 /* Modified time (DWORD) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ +#define DIR_FileSize 28 /* File size (DWORD) */ +#define LDIR_Ord 0 /* LFN: LFN order and LLE flag (BYTE) */ +#define LDIR_Attr 11 /* LFN: LFN attribute (BYTE) */ +#define LDIR_Type 12 /* LFN: Entry type (BYTE) */ +#define LDIR_Chksum 13 /* LFN: Checksum of the SFN (BYTE) */ +#define LDIR_FstClusLO 26 /* LFN: MBZ field (WORD) */ +#define XDIR_Type 0 /* exFAT: Type of exFAT directory entry (BYTE) */ +#define XDIR_NumLabel 1 /* exFAT: Number of volume label characters (BYTE) */ +#define XDIR_Label 2 /* exFAT: Volume label (11-WORD) */ +#define XDIR_CaseSum 4 /* exFAT: Sum of case conversion table (DWORD) */ +#define XDIR_NumSec 1 /* exFAT: Number of secondary entries (BYTE) */ +#define XDIR_SetSum 2 /* exFAT: Sum of the set of directory entries (WORD) */ +#define XDIR_Attr 4 /* exFAT: File attribute (WORD) */ +#define XDIR_CrtTime 8 /* exFAT: Created time (DWORD) */ +#define XDIR_ModTime 12 /* exFAT: Modified time (DWORD) */ +#define XDIR_AccTime 16 /* exFAT: Last accessed time (DWORD) */ +#define XDIR_CrtTime10 20 /* exFAT: Created time subsecond (BYTE) */ +#define XDIR_ModTime10 21 /* exFAT: Modified time subsecond (BYTE) */ +#define XDIR_CrtTZ 22 /* exFAT: Created timezone (BYTE) */ +#define XDIR_ModTZ 23 /* exFAT: Modified timezone (BYTE) */ +#define XDIR_AccTZ 24 /* exFAT: Last accessed timezone (BYTE) */ +#define XDIR_GenFlags 33 /* exFAT: General secondary flags (BYTE) */ +#define XDIR_NumName 35 /* exFAT: Number of file name characters (BYTE) */ +#define XDIR_NameHash 36 /* exFAT: Hash of file name (WORD) */ +#define XDIR_ValidFileSize 40 /* exFAT: Valid file size (QWORD) */ +#define XDIR_FstClus 52 /* exFAT: First cluster of the file data (DWORD) */ +#define XDIR_FileSize 56 /* exFAT: File/Directory size (QWORD) */ + +#define SZDIRE 32 /* Size of a directory entry */ +#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ +#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ +#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ + #define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ #define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ #define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ @@ -471,49 +212,216 @@ typedef struct { #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ -#define DIR_Name 0 /* Short file name (11-byte) */ -#define DIR_Attr 11 /* Attribute (BYTE) */ -#define DIR_NTres 12 /* Lower case flag (BYTE) */ -#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ -#define DIR_CrtTime 14 /* Created time (DWORD) */ -#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ -#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ -#define DIR_ModTime 22 /* Modified time (DWORD) */ -#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ -#define DIR_FileSize 28 /* File size (DWORD) */ -#define LDIR_Ord 0 /* LFN entry order and LLE flag (BYTE) */ -#define LDIR_Attr 11 /* LFN attribute (BYTE) */ -#define LDIR_Type 12 /* LFN type (BYTE) */ -#define LDIR_Chksum 13 /* Checksum of the SFN entry (BYTE) */ -#define LDIR_FstClusLO 26 /* Must be zero (WORD) */ -#define XDIR_Type 0 /* Type of exFAT directory entry (BYTE) */ -#define XDIR_NumLabel 1 /* Number of volume label characters (BYTE) */ -#define XDIR_Label 2 /* Volume label (11-WORD) */ -#define XDIR_CaseSum 4 /* Sum of case conversion table (DWORD) */ -#define XDIR_NumSec 1 /* Number of secondary entries (BYTE) */ -#define XDIR_SetSum 2 /* Sum of the set of directory entries (WORD) */ -#define XDIR_Attr 4 /* File attribute (WORD) */ -#define XDIR_CrtTime 8 /* Created time (DWORD) */ -#define XDIR_ModTime 12 /* Modified time (DWORD) */ -#define XDIR_AccTime 16 /* Last accessed time (DWORD) */ -#define XDIR_CrtTime10 20 /* Created time subsecond (BYTE) */ -#define XDIR_ModTime10 21 /* Modified time subsecond (BYTE) */ -#define XDIR_CrtTZ 22 /* Created timezone (BYTE) */ -#define XDIR_ModTZ 23 /* Modified timezone (BYTE) */ -#define XDIR_AccTZ 24 /* Last accessed timezone (BYTE) */ -#define XDIR_GenFlags 33 /* Gneral secondary flags (WORD) */ -#define XDIR_NumName 35 /* Number of file name characters (BYTE) */ -#define XDIR_NameHash 36 /* Hash of file name (WORD) */ -#define XDIR_ValidFileSize 40 /* Valid file size (QWORD) */ -#define XDIR_FstClus 52 /* First cluster of the file data (DWORD) */ -#define XDIR_FileSize 56 /* File/Directory size (QWORD) */ -#define SZDIRE 32 /* Size of a directory entry */ -#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ -#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ -#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ +/* Post process on fatal error in the file operations */ +#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } +/* Re-entrancy related */ +#if FF_FS_REENTRANT +#if FF_USE_LFN == 1 +#error Static LFN work area cannot be used at thread-safe configuration +#endif +#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#else +#define LEAVE_FF(fs, res) return res +#endif + + +/* Definitions of volume - physical location conversion */ +#if FF_MULTI_PARTITION +#define LD2PT(fs) (fs->part) /* Get partition index */ +#else +#define LD2PT(fs) 0 /* Find first valid partition or in SFD */ +#endif + + +/* Definitions of sector size */ +#if (FF_MAX_SS < FF_MIN_SS) || (FF_MAX_SS != 512 && FF_MAX_SS != 1024 && FF_MAX_SS != 2048 && FF_MAX_SS != 4096) || (FF_MIN_SS != 512 && FF_MIN_SS != 1024 && FF_MIN_SS != 2048 && FF_MIN_SS != 4096) +#error Wrong sector size configuration +#endif +#if FF_MAX_SS == FF_MIN_SS +#define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */ +#else +#define SS(fs) ((fs)->ssize) /* Variable sector size */ +#endif + + +/* Timestamp */ +#if FF_FS_NORTC == 1 +#if FF_NORTC_YEAR < 1980 || FF_NORTC_YEAR > 2107 || FF_NORTC_MON < 1 || FF_NORTC_MON > 12 || FF_NORTC_MDAY < 1 || FF_NORTC_MDAY > 31 +#error Invalid FF_FS_NORTC settings +#endif +#define GET_FATTIME() ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16) +#else +#define GET_FATTIME() get_fattime() +#endif + + +/* File lock controls */ +#if FF_FS_LOCK != 0 +#if FF_FS_READONLY +#error FF_FS_LOCK must be 0 at read-only configuration +#endif +typedef struct { + FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, containing directory (0:root) */ + DWORD ofs; /* Object ID 3, offset in the directory */ + WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +} FILESEM; +#endif + + +/* SBCS up-case tables (\x80-\xFF) */ +#define TBL_CT437 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT720 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT737 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ + 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT771 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} +#define TBL_CT775 {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT850 {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ + 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ + 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT852 {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ + 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} +#define TBL_CT855 {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ + 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ + 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ + 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ + 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT857 {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT860 {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ + 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT861 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT862 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT863 {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ + 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ + 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT864 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT865 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT866 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define TBL_CT869 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ + 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ + 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ + 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} + + +/* DBCS code range |----- 1st byte -----| |----------- 2nd byte -----------| */ +#define TBL_DC932 {0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00} +#define TBL_DC936 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00} +#define TBL_DC949 {0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE} +#define TBL_DC950 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0xA1, 0xFE, 0x00, 0x00} + + +/* Macros for table definitions */ +#define MERGE_2STR(a, b) a ## b +#define MKCVTBL(hd, cp) MERGE_2STR(hd, cp) + @@ -522,71 +430,140 @@ typedef struct { Module Private Work Area ---------------------------------------------------------------------------*/ - -/* Remark: Variables here without initial value shall be guaranteed zero/null -/ at start-up. If not, either the linker or start-up routine being used is +/* Remark: Variables defined here without initial value shall be guaranteed +/ zero/null at start-up. If not, the linker option or start-up routine is / not compliance with C standard. */ -#if _VOLUMES < 1 || _VOLUMES > 9 -#error Wrong _VOLUMES setting -#endif -static WORD Fsid; /* File system mount ID */ +/*--------------------------------*/ +/* File/Volume controls */ +/*--------------------------------*/ -#if _FS_LOCK != 0 -static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ +#if FF_VOLUMES < 1 || FF_VOLUMES > 10 +#error Wrong FF_VOLUMES setting +#endif +static WORD Fsid; /* Filesystem mount ID */ + +#if FF_FS_LOCK != 0 +static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ #endif -#if _USE_LFN == 0 /* Non-LFN configuration */ +#if FF_STR_VOLUME_ID +#ifdef FF_VOLUME_STRS +static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ +#endif +#endif + + +/*--------------------------------*/ +/* LFN/Directory working buffer */ +/*--------------------------------*/ + +#if FF_USE_LFN == 0 /* Non-LFN configuration */ +#if FF_FS_EXFAT +#error LFN must be enabled when enable exFAT +#endif #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() -#else -#if _MAX_LFN < 12 || _MAX_LFN > 255 -#error Wrong _MAX_LFN setting -#endif +#define LEAVE_MKFS(res) return res -#if _USE_LFN == 1 /* LFN enabled with static working buffer */ -#if _FS_EXFAT -static BYTE DirBuf[SZDIRE*19]; /* Directory entry block scratchpad buffer (19 entries in size) */ +#else /* LFN configurations */ +#if FF_MAX_LFN < 12 || FF_MAX_LFN > 255 +#error Wrong setting of FF_MAX_LFN #endif -static WCHAR LfnBuf[_MAX_LFN+1]; /* LFN enabled with static working buffer */ +#if FF_LFN_BUF < FF_SFN_BUF || FF_SFN_BUF < 12 +#error Wrong setting of FF_LFN_BUF or FF_SFN_BUF +#endif +#if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3 +#error Wrong setting of FF_LFN_UNICODE +#endif +static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* FAT: Offset of LFN characters in the directory entry */ +#define MAXDIRB(nc) ((nc + 44U) / 15 * SZDIRE) /* exFAT: Size of directory entry block scratchpad buffer needed for the name length */ + +#if FF_USE_LFN == 1 /* LFN enabled with static working buffer */ +#if FF_FS_EXFAT +static BYTE DirBuf[MAXDIRB(FF_MAX_LFN)]; /* Directory entry block scratchpad buffer */ +#endif +static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() +#define LEAVE_MKFS(res) return res -#elif _USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ -#if _FS_EXFAT -#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[SZDIRE*19]; +#elif FF_USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ +#if FF_FS_EXFAT +#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } #define FREE_NAMBUF() #else -#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; +#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } #define FREE_NAMBUF() #endif +#define LEAVE_MKFS(res) return res -#elif _USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ -#if _FS_EXFAT -#define DEF_NAMBUF WCHAR *lfn; -#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2 + SZDIRE*19); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); } +#elif FF_USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ +#if FF_FS_EXFAT +#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } #define FREE_NAMBUF() ff_memfree(lfn) #else -#define DEF_NAMBUF WCHAR *lfn; -#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } +#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer */ +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } #define FREE_NAMBUF() ff_memfree(lfn) #endif +#define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } +#define MAX_MALLOC 0x8000 /* Must be >=FF_MAX_SS */ #else -#error Wrong _USE_LFN setting -#endif -#endif +#error Wrong setting of FF_USE_LFN -#ifdef _EXCVT -static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */ -#endif +#endif /* FF_USE_LFN == 1 */ +#endif /* FF_USE_LFN == 0 */ +/*--------------------------------*/ +/* Code conversion tables */ +/*--------------------------------*/ + +#if FF_CODE_PAGE == 0 /* Run-time code page configuration */ +#define CODEPAGE CodePage +static WORD CodePage; /* Current code page */ +static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ + +static const BYTE Ct437[] = TBL_CT437; +static const BYTE Ct720[] = TBL_CT720; +static const BYTE Ct737[] = TBL_CT737; +static const BYTE Ct771[] = TBL_CT771; +static const BYTE Ct775[] = TBL_CT775; +static const BYTE Ct850[] = TBL_CT850; +static const BYTE Ct852[] = TBL_CT852; +static const BYTE Ct855[] = TBL_CT855; +static const BYTE Ct857[] = TBL_CT857; +static const BYTE Ct860[] = TBL_CT860; +static const BYTE Ct861[] = TBL_CT861; +static const BYTE Ct862[] = TBL_CT862; +static const BYTE Ct863[] = TBL_CT863; +static const BYTE Ct864[] = TBL_CT864; +static const BYTE Ct865[] = TBL_CT865; +static const BYTE Ct866[] = TBL_CT866; +static const BYTE Ct869[] = TBL_CT869; +static const BYTE Dc932[] = TBL_DC932; +static const BYTE Dc936[] = TBL_DC936; +static const BYTE Dc949[] = TBL_DC949; +static const BYTE Dc950[] = TBL_DC950; + +#elif FF_CODE_PAGE < 900 /* Static code page configuration (SBCS) */ +#define CODEPAGE FF_CODE_PAGE +static const BYTE ExCvt[] = MKCVTBL(TBL_CT, FF_CODE_PAGE); + +#else /* Static code page configuration (DBCS) */ +#define CODEPAGE FF_CODE_PAGE +static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); + +#endif + @@ -601,8 +578,7 @@ static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended /* Load/Store multi-byte word in the FAT structure */ /*-----------------------------------------------------------------------*/ -static -WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ +static WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ { WORD rv; @@ -611,8 +587,7 @@ WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ return rv; } -static -DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ +static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ { DWORD rv; @@ -623,9 +598,8 @@ DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ return rv; } -#if _FS_EXFAT -static -QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ +#if FF_FS_EXFAT +static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ { QWORD rv; @@ -641,16 +615,14 @@ QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ } #endif -#if !_FS_READONLY -static -void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ +#if !FF_FS_READONLY +static void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } -static -void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ +static void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; @@ -658,9 +630,8 @@ void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian *ptr++ = (BYTE)val; } -#if _FS_EXFAT -static -void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ +#if FF_FS_EXFAT +static void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; @@ -672,7 +643,7 @@ void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian *ptr++ = (BYTE)val; } #endif -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ @@ -687,32 +658,232 @@ void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian #define mem_set memset #define mem_cmp memcmp + /* Check if chr is contained in the string */ -static -int chk_chr (const char* str, int chr) { /* NZ:contained, ZR:not contained */ +static int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained */ +{ while (*str && *str != chr) str++; return *str; } +/* Test if the character is DBC 1st byte */ +static int dbc_1st (BYTE c) +{ +#if FF_CODE_PAGE == 0 /* Variable code page */ + if (DbcTbl && c >= DbcTbl[0]) { + if (c <= DbcTbl[1]) return 1; /* 1st byte range 1 */ + if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; /* 1st byte range 2 */ + } +#elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ + if (c >= DbcTbl[0]) { + if (c <= DbcTbl[1]) return 1; + if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; + } +#else /* SBCS fixed code page */ + if (c != 0) return 0; /* Always false */ +#endif + return 0; +} -#if _FS_REENTRANT +/* Test if the character is DBC 2nd byte */ +static int dbc_2nd (BYTE c) +{ +#if FF_CODE_PAGE == 0 /* Variable code page */ + if (DbcTbl && c >= DbcTbl[4]) { + if (c <= DbcTbl[5]) return 1; /* 2nd byte range 1 */ + if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; /* 2nd byte range 2 */ + if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; /* 2nd byte range 3 */ + } +#elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ + if (c >= DbcTbl[4]) { + if (c <= DbcTbl[5]) return 1; + if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; + if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; + } +#else /* SBCS fixed code page */ + if (c != 0) return 0; /* Always false */ +#endif + return 0; +} + + +#if FF_USE_LFN + +/* Get a character from TCHAR string in defined API encodeing */ +static DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double encoding unit, 0xFFFFFFFF on decode error) */ + const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ +) +{ + DWORD uc; + const TCHAR *p = *str; + +#if FF_LFN_UNICODE == 1 /* UTF-16 input */ + WCHAR wc; + + uc = *p++; /* Get a unit */ + if (IsSurrogate(uc)) { /* Surrogate? */ + wc = *p++; /* Get low surrogate */ + if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF; /* Wrong surrogate? */ + uc = uc << 16 | wc; + } + +#elif FF_LFN_UNICODE == 2 /* UTF-8 input */ + BYTE b; + int nf; + + uc = (BYTE)*p++; /* Get a unit */ + if (uc & 0x80) { /* Multiple byte code? */ + if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ + uc &= 0x1F; nf = 1; + } else { + if ((uc & 0xF0) == 0xE0) { /* 3-byte sequence? */ + uc &= 0x0F; nf = 2; + } else { + if ((uc & 0xF8) == 0xF0) { /* 4-byte sequence? */ + uc &= 0x07; nf = 3; + } else { /* Wrong sequence */ + return 0xFFFFFFFF; + } + } + } + do { /* Get trailing bytes */ + b = (BYTE)*p++; + if ((b & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ + uc = uc << 6 | (b & 0x3F); + } while (--nf != 0); + if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ + if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ + } + +#elif FF_LFN_UNICODE == 3 /* UTF-32 input */ + uc = (TCHAR)*p++; /* Get a unit */ + if (uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ + if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ + +#else /* ANSI/OEM input */ + BYTE b; + WCHAR wc; + + wc = (BYTE)*p++; /* Get a byte */ + if (dbc_1st((BYTE)wc)) { /* Is it a DBC 1st byte? */ + b = (BYTE)*p++; /* Get 2nd byte */ + if (!dbc_2nd(b)) return 0xFFFFFFFF; /* Invalid code? */ + wc = (wc << 8) + b; /* Make a DBC */ + } + if (wc != 0) { + wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM ==> Unicode */ + if (wc == 0) return 0xFFFFFFFF; /* Invalid code? */ + } + uc = wc; + +#endif + *str = p; /* Next read pointer */ + return uc; +} + + +/* Output a TCHAR string in defined API encoding */ +static BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ + DWORD chr, /* UTF-16 encoded character (Double encoding unit char if >=0x10000) */ + TCHAR* buf, /* Output buffer */ + UINT szb /* Size of the buffer */ +) +{ +#if FF_LFN_UNICODE == 1 /* UTF-16 output */ + WCHAR hs, wc; + + hs = (WCHAR)(chr >> 16); + wc = (WCHAR)chr; + if (hs == 0) { /* Single encoding unit? */ + if (szb < 1 || IsSurrogate(wc)) return 0; /* Buffer overflow or wrong code? */ + *buf = wc; + return 1; + } + if (szb < 2 || !IsSurrogateH(hs) || !IsSurrogateL(wc)) return 0; /* Buffer overflow or wrong surrogate? */ + *buf++ = hs; + *buf++ = wc; + return 2; + +#elif FF_LFN_UNICODE == 2 /* UTF-8 output */ + DWORD hc; + + if (chr < 0x80) { /* Single byte code? */ + if (szb < 1) return 0; /* Buffer overflow? */ + *buf = (TCHAR)chr; + return 1; + } + if (chr < 0x800) { /* 2-byte sequence? */ + if (szb < 2) return 0; /* Buffer overflow? */ + *buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 2; + } + if (chr < 0x10000) { /* 3-byte sequence? */ + if (szb < 3 || IsSurrogate(chr)) return 0; /* Buffer overflow or wrong code? */ + *buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F)); + *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 3; + } + /* 4-byte sequence */ + if (szb < 4) return 0; /* Buffer overflow? */ + hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ + chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ + if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ + chr = (hc | chr) + 0x10000; + *buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07)); + *buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); + *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + return 4; + +#elif FF_LFN_UNICODE == 3 /* UTF-32 output */ + DWORD hc; + + if (szb < 1) return 0; /* Buffer overflow? */ + if (chr >= 0x10000) { /* Out of BMP? */ + hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ + chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ + if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ + chr = (hc | chr) + 0x10000; + } + *buf++ = (TCHAR)chr; + return 1; + +#else /* ANSI/OEM output */ + WCHAR wc; + + wc = ff_uni2oem(chr, CODEPAGE); + if (wc >= 0x100) { /* Is this a DBC? */ + if (szb < 2) return 0; + *buf++ = (char)(wc >> 8); /* Store DBC 1st byte */ + *buf++ = (TCHAR)wc; /* Store DBC 2nd byte */ + return 2; + } + if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */ + *buf++ = (TCHAR)wc; /* Store the character */ + return 1; +#endif +} +#endif /* FF_USE_LFN */ + + +#if FF_FS_REENTRANT /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ -static -int lock_fs ( - FATFS* fs /* File system object */ +static int lock_fs ( /* 1:Ok, 0:timeout */ + FATFS* fs /* Filesystem object */ ) { return ff_req_grant(fs->sobj); } -static -void unlock_fs ( - FATFS* fs, /* File system object */ +static void unlock_fs ( + FATFS* fs, /* Filesystem object */ FRESULT res /* Result code to be returned */ ) { @@ -725,50 +896,48 @@ void unlock_fs ( -#if _FS_LOCK != 0 +#if FF_FS_LOCK != 0 /*-----------------------------------------------------------------------*/ /* File lock control functions */ /*-----------------------------------------------------------------------*/ -static -FRESULT chk_lock ( /* Check if the file can be accessed */ +static FRESULT chk_lock ( /* Check if the file can be accessed */ DIR* dp, /* Directory object pointing the file to be checked */ - int acc /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */ + int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ ) { UINT i, be; - /* Search file semaphore table */ - for (i = be = 0; i < _FS_LOCK; i++) { + /* Search open object table for the object */ + be = 0; + for (i = 0; i < FF_FS_LOCK; i++) { if (Files[i].fs) { /* Existing entry */ - if (Files[i].fs == dp->obj.fs && /* Check if the object matched with an open object */ + if (Files[i].fs == dp->obj.fs && /* Check if the object matches with an open object */ Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break; } else { /* Blank entry */ be = 1; } } - if (i == _FS_LOCK) { /* The object is not opened */ - return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */ + if (i == FF_FS_LOCK) { /* The object has not been opened */ + return (!be && acc != 2) ? FR_TOO_MANY_OPEN_FILES : FR_OK; /* Is there a blank entry for new object? */ } - /* The object has been opened. Reject any open against writing file and all write mode open */ - return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; + /* The object was opened. Reject any open against writing file and all write mode open */ + return (acc != 0 || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; } -static -int enq_lock (void) /* Check if an entry is available for a new object */ +static int enq_lock (void) /* Check if an entry is available for a new object */ { UINT i; - for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; - return (i == _FS_LOCK) ? 0 : 1; + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + return (i == FF_FS_LOCK) ? 0 : 1; } -static -UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ +static UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ DIR* dp, /* Directory object pointing the file to register or increment */ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ ) @@ -776,31 +945,30 @@ UINT inc_lock ( /* Increment object open counter and returns its index (0:Intern UINT i; - for (i = 0; i < _FS_LOCK; i++) { /* Find the object */ + for (i = 0; i < FF_FS_LOCK; i++) { /* Find the object */ if (Files[i].fs == dp->obj.fs && Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break; } - if (i == _FS_LOCK) { /* Not opened. Register it as new. */ - for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; - if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */ + if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ Files[i].fs = dp->obj.fs; Files[i].clu = dp->obj.sclust; Files[i].ofs = dp->dptr; Files[i].ctr = 0; } - if (acc && Files[i].ctr) return 0; /* Access violation (int err) */ + if (acc >= 1 && Files[i].ctr) return 0; /* Access violation (int err) */ Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ - return i + 1; + return i + 1; /* Index number origin from 1 */ } -static -FRESULT dec_lock ( /* Decrement object open counter */ +static FRESULT dec_lock ( /* Decrement object open counter */ UINT i /* Semaphore index (1..) */ ) { @@ -808,7 +976,7 @@ FRESULT dec_lock ( /* Decrement object open counter */ FRESULT res; - if (--i < _FS_LOCK) { /* Shift index number origin from 0 */ + if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ n = Files[i].ctr; if (n == 0x100) n = 0; /* If write mode open, delete the entry */ if (n > 0) n--; /* Decrement read mode open count */ @@ -822,48 +990,40 @@ FRESULT dec_lock ( /* Decrement object open counter */ } -static -void clear_lock ( /* Clear lock entries of the volume */ +static void clear_lock ( /* Clear lock entries of the volume */ FATFS *fs ) { UINT i; - for (i = 0; i < _FS_LOCK; i++) { + for (i = 0; i < FF_FS_LOCK; i++) { if (Files[i].fs == fs) Files[i].fs = 0; } } -#endif /* _FS_LOCK != 0 */ +#endif /* FF_FS_LOCK != 0 */ /*-----------------------------------------------------------------------*/ -/* Move/Flush disk access window in the file system object */ +/* Move/Flush disk access window in the filesystem object */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY -static -FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERROR */ - FATFS* fs /* File system object */ +#if !FF_FS_READONLY +static FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs /* Filesystem object */ ) { - DWORD wsect; - UINT nf; FRESULT res = FR_OK; - if (fs->wflag) { /* Write back the sector if it is dirty */ - wsect = fs->winsect; /* Current sector number */ - if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) { - res = FR_DISK_ERR; - } else { - fs->wflag = 0; - if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */ - for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */ - wsect += fs->fsize; - disk_write(fs->drv, fs->win, wsect, 1); - } + if (fs->wflag) { /* Is the disk access window dirty */ + if (disk_write(fs->drv, fs->win, fs->winsect, 1) == RES_OK) { /* Write back the window */ + fs->wflag = 0; /* Clear window dirty flag */ + if (fs->winsect - fs->fatbase < fs->fsize) { /* Is it in the 1st FAT? */ + if (fs->n_fats == 2) disk_write(fs->drv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */ } + } else { + res = FR_DISK_ERR; } } return res; @@ -871,9 +1031,8 @@ FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERROR */ #endif -static -FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */ - FATFS* fs, /* File system object */ +static FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs, /* Filesystem object */ DWORD sector /* Sector number to make appearance in the fs->win[] */ ) { @@ -881,12 +1040,12 @@ FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */ if (sector != fs->winsect) { /* Window offset changed? */ -#if !_FS_READONLY +#if !FF_FS_READONLY res = sync_window(fs); /* Write-back changes */ #endif if (res == FR_OK) { /* Fill sector window with new data */ if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) { - sector = 0xFFFFFFFF; /* Invalidate window if data is not reliable */ + sector = 0xFFFFFFFF; /* Invalidate window if read data is not valid */ res = FR_DISK_ERR; } fs->winsect = sector; @@ -898,14 +1057,13 @@ FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */ -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Synchronize file system and strage device */ +/* Synchronize filesystem and data on the storage */ /*-----------------------------------------------------------------------*/ -static -FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ - FATFS* fs /* File system object */ +static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS* fs /* Filesystem object */ ) { FRESULT res; @@ -913,10 +1071,9 @@ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ res = sync_window(fs); if (res == FR_OK) { - /* Update FSInfo sector if needed */ - if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { + if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ /* Create FSInfo structure */ - mem_set(fs->win, 0, SS(fs)); + mem_set(fs->win, 0, sizeof fs->win); st_word(fs->win + BS_55AA, 0xAA55); st_dword(fs->win + FSI_LeadSig, 0x41615252); st_dword(fs->win + FSI_StrucSig, 0x61417272); @@ -927,7 +1084,7 @@ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ disk_write(fs->drv, fs->win, fs->winsect, 1); fs->fsi_flag = 0; } - /* Make sure that no pending write process in the physical drive */ + /* Make sure that no pending write process in the lower layer */ if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; } @@ -939,18 +1096,17 @@ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ /*-----------------------------------------------------------------------*/ -/* Get sector# from cluster# */ +/* Get physical sector number from cluster number */ /*-----------------------------------------------------------------------*/ -static -DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ - FATFS* fs, /* File system object */ +static DWORD clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ + FATFS* fs, /* Filesystem object */ DWORD clst /* Cluster# to be converted */ ) { - clst -= 2; - if (clst >= fs->n_fatent - 2) return 0; /* Invalid cluster# */ - return clst * fs->csize + fs->database; + clst -= 2; /* Cluster number is origin from 2 */ + if (clst >= fs->n_fatent - 2) return 0; /* Is it invalid cluster number? */ + return fs->database + fs->csize * clst; /* Start sector number of the cluster */ } @@ -960,10 +1116,9 @@ DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ /* FAT access - Read value of a FAT entry */ /*-----------------------------------------------------------------------*/ -static -DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ - _FDID* obj, /* Corresponding object */ - DWORD clst /* Cluster number to get the value */ +static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ + FFOBJID* obj, /* Corresponding object */ + DWORD clst /* Cluster number to get the value */ ) { UINT wc, bc; @@ -981,44 +1136,46 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste case FS_FAT12 : bc = (UINT)clst; bc += bc / 2; if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; - wc = fs->win[bc++ % SS(fs)]; + wc = fs->win[bc++ % SS(fs)]; /* Get 1st byte of the entry */ if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; - wc |= fs->win[bc % SS(fs)] << 8; - val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); + wc |= fs->win[bc % SS(fs)] << 8; /* Merge 2nd byte of the entry */ + val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); /* Adjust bit position */ break; case FS_FAT16 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; - val = ld_word(fs->win + clst * 2 % SS(fs)); + val = ld_word(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ break; case FS_FAT32 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ break; -#if _FS_EXFAT +#if FF_FS_EXFAT case FS_EXFAT : - if (obj->objsize) { + if ((obj->objsize != 0 && obj->sclust != 0) || obj->stat == 0) { /* Object except root dir must have valid data length */ DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */ - if (obj->stat == 2) { /* Is there no valid chain on the FAT? */ - if (cofs <= clen) { - val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* Generate the value */ - break; - } + if (obj->stat == 2 && cofs <= clen) { /* Is it a contiguous chain? */ + val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* No data on the FAT, generate the value */ + break; } - if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the contiguous part? */ + if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */ val = clst + 1; /* Generate the value */ break; } if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ - if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + if (obj->n_frag != 0) { /* Is it on the growing edge? */ + val = 0x7FFFFFFF; /* Generate EOC */ + } else { + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + } break; } } - /* go next */ + /* go to default */ #endif default: val = 1; /* Internal error */ @@ -1031,14 +1188,13 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT access - Change value of a FAT entry */ /*-----------------------------------------------------------------------*/ -static -FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ - FATFS* fs, /* Corresponding file system object */ +static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ + FATFS* fs, /* Corresponding filesystem object */ DWORD clst, /* FAT index number (cluster number) to be changed */ DWORD val /* New value to be set to the entry */ ) @@ -1050,34 +1206,34 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ switch (fs->fs_type) { - case FS_FAT12 : /* Bitfield items */ - bc = (UINT)clst; bc += bc / 2; + case FS_FAT12 : + bc = (UINT)clst; bc += bc / 2; /* bc: byte offset of the entry */ res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc++ % SS(fs); - *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; + *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; /* Put 1st byte */ fs->wflag = 1; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc % SS(fs); - *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); + *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); /* Put 2nd byte */ fs->wflag = 1; break; - case FS_FAT16 : /* WORD aligned items */ + case FS_FAT16 : res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); if (res != FR_OK) break; - st_word(fs->win + clst * 2 % SS(fs), (WORD)val); + st_word(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ fs->wflag = 1; break; - case FS_FAT32 : /* DWORD aligned items */ -#if _FS_EXFAT + case FS_FAT32 : +#if FF_FS_EXFAT case FS_EXFAT : #endif res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); if (res != FR_OK) break; - if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); } st_dword(fs->win + clst * 4 % SS(fs), val); @@ -1088,23 +1244,22 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ return res; } -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ -#if _FS_EXFAT && !_FS_READONLY +#if FF_FS_EXFAT && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* exFAT: Accessing FAT and Allocation Bitmap */ /*-----------------------------------------------------------------------*/ -/*---------------------------------------------*/ -/* exFAT: Find a contiguous free cluster block */ -/*---------------------------------------------*/ +/*--------------------------------------*/ +/* Find a contiguous free cluster block */ +/*--------------------------------------*/ -static -DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Disk error */ - FATFS* fs, /* File system object */ +static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ + FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to scan from */ DWORD ncl /* Number of contiguous clusters to find (1..) */ ) @@ -1118,34 +1273,33 @@ DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Dis if (clst >= fs->n_fatent - 2) clst = 0; scl = val = clst; ctr = 0; for (;;) { - if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ + if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; i = val / 8 % SS(fs); bm = 1 << (val % 8); do { do { bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ - val = 0; bm = 0; i = 4096; + val = 0; bm = 0; i = SS(fs); } - if (!bv) { /* Is it a free cluster? */ - if (++ctr == ncl) return scl + 2; /* Check run length */ + if (bv == 0) { /* Is it a free cluster? */ + if (++ctr == ncl) return scl + 2; /* Check if run length is sufficient for required */ } else { - scl = val; ctr = 0; /* Encountered a live cluster, restart to scan */ + scl = val; ctr = 0; /* Encountered a cluster in-use, restart to scan */ } if (val == clst) return 0; /* All cluster scanned? */ - } while (bm); + } while (bm != 0); bm = 1; } while (++i < SS(fs)); } } -/*------------------------------------*/ -/* exFAT: Set/Clear a block of bitmap */ -/*------------------------------------*/ +/*----------------------------------------*/ +/* Set/Clear a block of allocation bitmap */ +/*----------------------------------------*/ -static -FRESULT change_bitmap ( - FATFS* fs, /* File system object */ +static FRESULT change_bitmap ( + FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to change from */ DWORD ncl, /* Number of clusters to be changed */ int bv /* bit value to be set (0 or 1) */ @@ -1157,9 +1311,9 @@ FRESULT change_bitmap ( clst -= 2; /* The first bit corresponds to cluster #2 */ - sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ - i = clst / 8 % SS(fs); /* Byte offset in the sector */ - bm = 1 << (clst % 8); /* Bit mask in the byte */ + sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */ + i = clst / 8 % SS(fs); /* Byte offset in the sector */ + bm = 1 << (clst % 8); /* Bit mask in the byte */ for (;;) { if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; do { @@ -1177,18 +1331,18 @@ FRESULT change_bitmap ( /*---------------------------------------------*/ -/* Complement contiguous part of the FAT chain */ +/* Fill the first fragment of the FAT chain */ /*---------------------------------------------*/ -static -FRESULT fill_fat_chain ( - _FDID* obj /* Pointer to the corresponding object */ +static FRESULT fill_first_frag ( + FFOBJID* obj /* Pointer to the corresponding object */ ) { FRESULT res; DWORD cl, n; - if (obj->stat == 3) { /* Has the object been changed 'fragmented'? */ + + if (obj->stat == 3) { /* Has the object been changed 'fragmented' in this session? */ for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ res = put_fat(obj->fs, cl, cl + 1); if (res != FR_OK) return res; @@ -1198,35 +1352,57 @@ FRESULT fill_fat_chain ( return FR_OK; } -#endif /* _FS_EXFAT && !_FS_READONLY */ + +/*---------------------------------------------*/ +/* Fill the last fragment of the FAT chain */ +/*---------------------------------------------*/ + +static FRESULT fill_last_frag ( + FFOBJID* obj, /* Pointer to the corresponding object */ + DWORD lcl, /* Last cluster of the fragment */ + DWORD term /* Value to set the last FAT entry */ +) +{ + FRESULT res; + + + while (obj->n_frag > 0) { /* Create the chain of last fragment */ + res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term); + if (res != FR_OK) return res; + obj->n_frag--; + } + return FR_OK; +} + +#endif /* FF_FS_EXFAT && !FF_FS_READONLY */ -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT handling - Remove a cluster chain */ /*-----------------------------------------------------------------------*/ -static -FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ - _FDID* obj, /* Corresponding object */ + +static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ + FFOBJID* obj, /* Corresponding object */ DWORD clst, /* Cluster to remove a chain from */ - DWORD pclst /* Previous cluster of clst (0:an entire chain) */ + DWORD pclst /* Previous cluster of clst (0 if entire chain) */ ) { FRESULT res = FR_OK; DWORD nxt; FATFS *fs = obj->fs; -#if _FS_EXFAT || _USE_TRIM +#if FF_FS_EXFAT || FF_USE_TRIM DWORD scl = clst, ecl = clst; #endif -#if _USE_TRIM +#if FF_USE_TRIM DWORD rt[2]; #endif if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ /* Mark the previous cluster 'EOC' on the FAT if it exists */ - if (pclst && (!_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { + if (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { res = put_fat(fs, pclst, 0xFFFFFFFF); if (res != FR_OK) return res; } @@ -1237,7 +1413,7 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ if (nxt == 0) break; /* Empty cluster? */ if (nxt == 1) return FR_INT_ERR; /* Internal error? */ if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ - if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ if (res != FR_OK) return res; } @@ -1245,20 +1421,20 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ fs->free_clst++; fs->fsi_flag |= 1; } -#if _FS_EXFAT || _USE_TRIM +#if FF_FS_EXFAT || FF_USE_TRIM if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ ecl = nxt; } else { /* End of contiguous cluster block */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ if (res != FR_OK) return res; } #endif -#if _USE_TRIM - rt[0] = clust2sect(fs, scl); /* Start sector */ - rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ - disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Inform device the block can be erased */ +#if FF_USE_TRIM + rt[0] = clst2sect(fs, scl); /* Start of data area freed */ + rt[1] = clst2sect(fs, ecl) + fs->csize - 1; /* End of data area freed */ + disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Inform device the data in the block is no longer needed */ #endif scl = ecl = nxt; } @@ -1266,13 +1442,28 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ clst = nxt; /* Next cluster */ } while (clst < fs->n_fatent); /* Repeat while not the last link */ -#if _FS_EXFAT +#if FF_FS_EXFAT + /* Some post processes for chain status */ if (fs->fs_type == FS_EXFAT) { - if (pclst == 0) { /* Does object have no chain? */ - obj->stat = 0; /* Change the object status 'initial' */ + if (pclst == 0) { /* Has the entire chain been removed? */ + obj->stat = 0; /* Change the chain status 'initial' */ } else { - if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Did the chain got contiguous? */ - obj->stat = 2; /* Change the object status 'contiguous' */ + if (obj->stat == 0) { /* Is it a fragmented chain from the beginning of this session? */ + clst = obj->sclust; /* Follow the chain to check if it gets contiguous */ + while (clst != pclst) { + nxt = get_fat(obj, clst); + if (nxt < 2) return FR_INT_ERR; + if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; + if (nxt != clst + 1) break; /* Not contiguous? */ + clst++; + } + if (clst == pclst) { /* Has the chain got contiguous again? */ + obj->stat = 2; /* Change the chain status 'contiguous' */ + } + } else { + if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Was the chain fragmented in this session and got contiguous again? */ + obj->stat = 2; /* Change the chain status 'contiguous' */ + } } } } @@ -1286,9 +1477,9 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ /*-----------------------------------------------------------------------*/ /* FAT handling - Stretch a chain or Create a new chain */ /*-----------------------------------------------------------------------*/ -static -DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ - _FDID* obj, /* Corresponding object */ + +static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ + FFOBJID* obj, /* Corresponding object */ DWORD clst /* Cluster# to stretch, 0:Create a new chain */ ) { @@ -1298,18 +1489,19 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk if (clst == 0) { /* Create a new chain */ - scl = fs->last_clst; /* Get suggested cluster to start from */ + scl = fs->last_clst; /* Suggested cluster to start to find */ if (scl == 0 || scl >= fs->n_fatent) scl = 1; } - else { /* Stretch current chain */ + else { /* Stretch a chain */ cs = get_fat(obj, clst); /* Check the cluster status */ - if (cs < 2) return 1; /* Invalid value */ - if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ + if (cs < 2) return 1; /* Test for insanity */ + if (cs == 0xFFFFFFFF) return cs; /* Test for disk error */ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ - scl = clst; + scl = clst; /* Cluster to start to find */ } + if (fs->free_clst == 0) return 0; /* No free cluster */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ @@ -1317,62 +1509,79 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk if (res == FR_INT_ERR) return 1; if (res == FR_DISK_ERR) return 0xFFFFFFFF; if (clst == 0) { /* Is it a new chain? */ - obj->stat = 2; /* Set status 'contiguous chain' */ - } else { /* This is a stretched chain */ + obj->stat = 2; /* Set status 'contiguous' */ + } else { /* It is a stretched chain */ if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ obj->stat = 3; /* Change status 'just fragmented' */ } } + if (obj->stat != 2) { /* Is the file non-contiguous? */ + if (ncl == clst + 1) { /* Is the cluster next to previous one? */ + obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */ + } else { /* New fragment */ + if (obj->n_frag == 0) obj->n_frag = 1; + res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */ + if (res == FR_OK) obj->n_frag = 1; + } + } } else #endif - { /* On the FAT12/16/32 volume */ - ncl = scl; /* Start cluster */ - for (;;) { - ncl++; /* Next cluster */ - if (ncl >= fs->n_fatent) { /* Check wrap-around */ - ncl = 2; - if (ncl > scl) return 0; /* No free cluster */ + { /* On the FAT/FAT32 volume */ + ncl = 0; + if (scl == clst) { /* Stretching an existing chain? */ + ncl = scl + 1; /* Test if next cluster is free */ + if (ncl >= fs->n_fatent) ncl = 2; + cs = get_fat(obj, ncl); /* Get next cluster status */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ + if (cs != 0) { /* Not free? */ + cs = fs->last_clst; /* Start at suggested cluster if it is valid */ + if (cs >= 2 && cs < fs->n_fatent) scl = cs; + ncl = 0; } - cs = get_fat(obj, ncl); /* Get the cluster status */ - if (cs == 0) break; /* Found a free cluster */ - if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* An error occurred */ - if (ncl == scl) return 0; /* No free cluster */ } - } - - if (_FS_EXFAT && fs->fs_type == FS_EXFAT && obj->stat == 2) { /* Is it a contiguous chain? */ - res = FR_OK; /* FAT does not need to be written */ - } else { - res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ - if (res == FR_OK && clst) { - res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ + if (ncl == 0) { /* The new cluster cannot be contiguous and find another fragment */ + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= fs->n_fatent) { /* Check wrap-around */ + ncl = 2; + if (ncl > scl) return 0; /* No free cluster found? */ + } + cs = get_fat(obj, ncl); /* Get the cluster status */ + if (cs == 0) break; /* Found a free cluster? */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ + if (ncl == scl) return 0; /* No free cluster found? */ + } + } + res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ + if (res == FR_OK && clst != 0) { + res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ } } if (res == FR_OK) { /* Update FSINFO if function succeeded. */ fs->last_clst = ncl; - if (fs->free_clst < fs->n_fatent - 2) fs->free_clst--; + if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; fs->fsi_flag |= 1; } else { - ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Create error status */ + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ } return ncl; /* Return new cluster number or error status */ } -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* FAT handling - Convert offset into cluster with link map table */ /*-----------------------------------------------------------------------*/ -static -DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ +static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FIL* fp, /* Pointer to the file object */ FSIZE_t ofs /* File offset to be converted to cluster# */ ) @@ -1392,7 +1601,47 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ return cl + *tbl; /* Return the cluster number */ } -#endif /* _USE_FASTSEEK */ +#endif /* FF_USE_FASTSEEK */ + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Fill a cluster with zeros */ +/*-----------------------------------------------------------------------*/ + +#if !FF_FS_READONLY +static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ + FATFS *fs, /* Filesystem object */ + DWORD clst /* Directory table to clear */ +) +{ + DWORD sect; + UINT n, szb; + BYTE *ibuf; + + + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ + sect = clst2sect(fs, clst); /* Top of the cluster */ + fs->winsect = sect; /* Set window to top of the cluster */ + mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */ +#if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ + /* Allocate a temporary buffer */ + for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ; + if (szb > SS(fs)) { /* Buffer allocated? */ + mem_set(ibuf, 0, szb); + szb /= SS(fs); /* Bytes -> Sectors */ + for (n = 0; n < fs->csize && disk_write(fs->drv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ + ff_memfree(ibuf); + } else +#endif + { + ibuf = fs->win; szb = 1; /* Use window buffer (many single-sector writes may take a time) */ + for (n = 0; n < fs->csize && disk_write(fs->drv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ + } + return (n == fs->csize) ? FR_OK : FR_DISK_ERR; +} +#endif /* !FF_FS_READONLY */ @@ -1401,8 +1650,7 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ /* Directory handling - Set directory index */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ +static FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to directory object */ DWORD ofs /* Offset of directory table */ ) @@ -1411,21 +1659,21 @@ FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ FATFS *fs = dp->obj.fs; - if (ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ + if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ return FR_INT_ERR; } dp->dptr = ofs; /* Set current offset */ clst = dp->obj.sclust; /* Table start cluster (0:root) */ if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ clst = fs->dirbase; - if (_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ + if (FF_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ } - if (clst == 0) { /* Static table (root-directory in FAT12/16) */ - if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ + if (clst == 0) { /* Static table (root-directory on the FAT volume) */ + if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ dp->sect = fs->dirbase; - } else { /* Dynamic table (sub-directory or root-directory in FAT32+) */ + } else { /* Dynamic table (sub-directory or root-directory on the FAT32/exFAT volume) */ csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ while (ofs >= csz) { /* Follow cluster chain */ clst = get_fat(&dp->obj, clst); /* Get next cluster */ @@ -1433,10 +1681,10 @@ FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ ofs -= csz; } - dp->sect = clust2sect(fs, clst); + dp->sect = clst2sect(fs, clst); } dp->clust = clst; /* Current cluster# */ - if (!dp->sect) return FR_INT_ERR; + if (dp->sect == 0) return FR_INT_ERR; dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ @@ -1450,36 +1698,34 @@ FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ /* Directory handling - Move directory table index next */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ - DIR* dp, /* Pointer to the directory object */ - int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ +static FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ + DIR* dp, /* Pointer to the directory object */ + int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ ) { DWORD ofs, clst; FATFS *fs = dp->obj.fs; -#if !_FS_READONLY - UINT n; -#endif + ofs = dp->dptr + SZDIRE; /* Next entry */ - if (!dp->sect || ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */ + if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */ + if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */ if (ofs % SS(fs) == 0) { /* Sector changed? */ dp->sect++; /* Next sector */ - if (!dp->clust) { /* Static table */ + if (dp->clust == 0) { /* Static table */ if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ dp->sect = 0; return FR_NO_FILE; } } else { /* Dynamic table */ - if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ - clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ - if (clst <= 1) return FR_INT_ERR; /* Internal error */ - if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ - if (clst >= fs->n_fatent) { /* Reached end of dynamic table */ -#if !_FS_READONLY + if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ + clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ + if (clst <= 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst >= fs->n_fatent) { /* It reached end of dynamic table */ +#if !FF_FS_READONLY if (!stretch) { /* If no stretch, report EOT */ dp->sect = 0; return FR_NO_FILE; } @@ -1487,22 +1733,15 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Co if (clst == 0) return FR_DENIED; /* No free cluster */ if (clst == 1) return FR_INT_ERR; /* Internal error */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ - /* Clean-up the stretched table */ - if (_FS_EXFAT) dp->obj.stat |= 4; /* The directory needs to be updated */ - if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ - mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ - for (n = 0, fs->winsect = clust2sect(fs, clst); n < fs->csize; n++, fs->winsect++) { /* Fill the new cluster with 0 */ - fs->wflag = 1; - if (sync_window(fs) != FR_OK) return FR_DISK_ERR; - } - fs->winsect -= n; /* Restore window offset */ + if (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR; /* Clean up the stretched table */ + if (FF_FS_EXFAT) dp->obj.stat |= 4; /* exFAT: The directory has been stretched */ #else - if (!stretch) dp->sect = 0; /* If no stretch, report EOT (this is to suppress warning) */ + if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ dp->sect = 0; return FR_NO_FILE; /* Report EOT */ #endif } dp->clust = clst; /* Initialize data for new cluster */ - dp->sect = clust2sect(fs, clst); + dp->sect = clst2sect(fs, clst); } } } @@ -1515,15 +1754,14 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Co -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Directory handling - Reserve a block of directory entries */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ - DIR* dp, /* Pointer to the directory object */ - UINT nent /* Number of contiguous entries to allocate */ +static FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp, /* Pointer to the directory object */ + UINT nent /* Number of contiguous entries to allocate */ ) { FRESULT res; @@ -1537,7 +1775,7 @@ FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ do { res = move_window(fs, dp->sect); if (res != FR_OK) break; -#if _FS_EXFAT +#if FF_FS_EXFAT if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { #else if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { @@ -1554,7 +1792,7 @@ FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ return res; } -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ @@ -1563,10 +1801,9 @@ FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ /* FAT: Directory handling - Load/Store start cluster number */ /*-----------------------------------------------------------------------*/ -static -DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ - FATFS* fs, /* Pointer to the fs object */ - const BYTE* dir /* Pointer to the key entry */ +static DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ + FATFS* fs, /* Pointer to the fs object */ + const BYTE* dir /* Pointer to the key entry */ ) { DWORD cl; @@ -1580,9 +1817,8 @@ DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ } -#if !_FS_READONLY -static -void st_clust ( +#if !FF_FS_READONLY +static void st_clust ( FATFS* fs, /* Pointer to the fs object */ BYTE* dir, /* Pointer to the key entry */ DWORD cl /* Value to be set */ @@ -1597,19 +1833,12 @@ void st_clust ( -#if _USE_LFN != 0 -/*------------------------------------------------------------------------*/ -/* FAT-LFN: LFN handling */ -/*------------------------------------------------------------------------*/ -static -const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */ - - +#if FF_USE_LFN /*--------------------------------------------------------*/ /* FAT-LFN: Compare a part of file name with an LFN entry */ /*--------------------------------------------------------*/ -static -int cmp_lfn ( /* 1:matched, 0:not matched */ + +static int cmp_lfn ( /* 1:matched, 0:not matched */ const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ BYTE* dir /* Pointer to the directory entry containing the part of LFN */ ) @@ -1624,8 +1853,8 @@ int cmp_lfn ( /* 1:matched, 0:not matched */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ - if (wc) { - if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + if (wc != 0) { + if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ return 0; /* Not matched */ } wc = uc; @@ -1640,12 +1869,12 @@ int cmp_lfn ( /* 1:matched, 0:not matched */ } -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT /*-----------------------------------------------------*/ /* FAT-LFN: Pick a part of file name from an LFN entry */ /*-----------------------------------------------------*/ -static -int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ + +static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ BYTE* dir /* Pointer to the LFN entry */ ) @@ -1654,22 +1883,22 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry * WCHAR wc, uc; - if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ - i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ - if (wc) { - if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + if (wc != 0) { + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i++] = wc = uc; /* Store it */ } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } - if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ - if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i] = 0; } @@ -1678,12 +1907,12 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry * #endif -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------*/ /* FAT-LFN: Create an entry of LFN entries */ /*-----------------------------------------*/ -static -void put_lfn ( + +static void put_lfn ( const WCHAR* lfn, /* Pointer to the LFN */ BYTE* dir, /* Pointer to the LFN entry to be created */ BYTE ord, /* LFN order (1-20) */ @@ -1710,18 +1939,17 @@ void put_lfn ( dir[LDIR_Ord] = ord; /* Set the LFN order */ } -#endif /* !_FS_READONLY */ -#endif /* _USE_LFN != 0 */ +#endif /* !FF_FS_READONLY */ +#endif /* FF_USE_LFN */ -#if _USE_LFN != 0 && !_FS_READONLY +#if FF_USE_LFN && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT-LFN: Create a Numbered SFN */ /*-----------------------------------------------------------------------*/ -static -void gen_numname ( +static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ const BYTE* src, /* Pointer to SFN */ const WCHAR* lfn, /* Pointer to LFN */ @@ -1738,7 +1966,7 @@ void gen_numname ( if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ sr = seq; - while (*lfn) { /* Create a CRC */ + while (*lfn) { /* Create a CRC as hash value */ wc = *lfn++; for (i = 0; i < 16; i++) { sr = (sr << 1) + (wc & 1); @@ -1759,9 +1987,9 @@ void gen_numname ( } while (seq); ns[i] = '~'; - /* Append the number */ + /* Append the number to the SFN body */ for (j = 0; j < i && dst[j] != ' '; j++) { - if (IsDBCS1(dst[j])) { + if (dbc_1st(dst[j])) { if (j == i - 1) break; j++; } @@ -1770,38 +1998,38 @@ void gen_numname ( dst[j++] = (i < 8) ? ns[i++] : ' '; } while (j < 8); } -#endif /* _USE_LFN != 0 && !_FS_READONLY */ +#endif /* FF_USE_LFN && !FF_FS_READONLY */ -#if _USE_LFN != 0 +#if FF_USE_LFN /*-----------------------------------------------------------------------*/ /* FAT-LFN: Calculate checksum of an SFN entry */ /*-----------------------------------------------------------------------*/ -static -BYTE sum_sfn ( +static BYTE sum_sfn ( const BYTE* dir /* Pointer to the SFN entry */ ) { BYTE sum = 0; UINT n = 11; - do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); + do { + sum = (sum >> 1) + (sum << 7) + *dir++; + } while (--n); return sum; } -#endif /* _USE_LFN != 0 */ +#endif /* FF_USE_LFN */ -#if _FS_EXFAT +#if FF_FS_EXFAT /*-----------------------------------------------------------------------*/ /* exFAT: Checksum */ /*-----------------------------------------------------------------------*/ -static -WORD xdir_sum ( /* Get checksum of the directoly block */ +static WORD xdir_sum ( /* Get checksum of the directoly entry block */ const BYTE* dir /* Directory entry block to be calculated */ ) { @@ -1809,9 +2037,9 @@ WORD xdir_sum ( /* Get checksum of the directoly block */ WORD sum; - szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; + szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; /* Number of bytes of the entry block */ for (i = sum = 0; i < szblk; i++) { - if (i == XDIR_SetSum) { /* Skip sum field */ + if (i == XDIR_SetSum) { /* Skip 2-byte sum field */ i++; } else { sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; @@ -1822,8 +2050,7 @@ WORD xdir_sum ( /* Get checksum of the directoly block */ -static -WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ +static WORD xname_sum ( /* Get check sum (to be used as hash) of the file name */ const WCHAR* name /* File name to be calculated */ ) { @@ -1832,7 +2059,7 @@ WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ while ((chr = *name++) != 0) { - chr = ff_wtoupper(chr); /* File name needs to be ignored case */ + chr = (WCHAR)ff_wtoupper(chr); /* File name needs to be up-case converted */ sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); } @@ -1840,11 +2067,10 @@ WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ } -#if !_FS_READONLY && _USE_MKFS -static -DWORD xsum32 ( - BYTE dat, /* Data to be sumed */ - DWORD sum /* Previous value */ +#if !FF_FS_READONLY && FF_USE_MKFS +static DWORD xsum32 ( /* Returns 32-bit checksum */ + BYTE dat, /* Byte to be calculated (byte-by-byte processing) */ + DWORD sum /* Previous sum value */ ) { sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; @@ -1853,130 +2079,137 @@ DWORD xsum32 ( #endif -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 /*------------------------------------------------------*/ /* exFAT: Get object information from a directory block */ /*------------------------------------------------------*/ -static -void get_xdir_info ( +static void get_xfileinfo ( BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ FILINFO* fno /* Buffer to store the extracted file information */ ) { - UINT di, si; - WCHAR w; -#if !_LFN_UNICODE - UINT nc; -#endif + WCHAR wc, hs; + UINT di, si, nc; - /* Get file name */ -#if _LFN_UNICODE - if (dirb[XDIR_NumName] <= _MAX_LFN) { - for (si = SZDIRE * 2, di = 0; di < dirb[XDIR_NumName]; si += 2, di++) { - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ - w = ld_word(dirb + si); /* Get a character */ - fno->fname[di] = w; /* Store it */ + /* Get file name from the entry block */ + si = SZDIRE * 2; /* 1st C1 entry */ + nc = 0; hs = 0; di = 0; + while (nc < dirb[XDIR_NumName]) { + if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + wc = ld_word(dirb + si); si += 2; nc++; /* Get a character */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ } - } else { - di = 0; /* Buffer overflow and inaccessible object */ + wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ + if (wc == 0) { di = 0; break; } /* Buffer overflow or wrong encoding? */ + di += wc; + hs = 0; } -#else - for (si = SZDIRE * 2, di = nc = 0; nc < dirb[XDIR_NumName]; si += 2, nc++) { - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ - w = ld_word(dirb + si); /* Get a character */ - w = ff_convert(w, 0); /* Unicode -> OEM */ - if (w == 0) { di = 0; break; } /* Could not be converted and inaccessible object */ - if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ - fno->fname[di++] = (char)(w >> 8); - } - if (di >= _MAX_LFN) { di = 0; break; } /* Buffer overflow and inaccessible object */ - fno->fname[di++] = (char)w; - } -#endif - if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object? */ - fno->fname[di] = 0; /* Terminate file name */ + if (hs != 0) di = 0; /* Broken surrogate pair? */ + if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ + fno->fname[di] = 0; /* Terminate the name */ + fno->altname[0] = 0; /* exFAT does not support SFN */ - fno->altname[0] = 0; /* No SFN */ - fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ + fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ } -#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ +#endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ /*-----------------------------------*/ /* exFAT: Get a directry entry block */ /*-----------------------------------*/ -static -FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ - DIR* dp /* Pointer to the reading direcotry object pointing the 85 entry */ +static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ + DIR* dp /* Reading direcotry object pointing top of the entry block to load */ ) { FRESULT res; - UINT i, nent; + UINT i, sz_ent; BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ - /* Load 85 entry */ + /* Load file-directory entry */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; - mem_cpy(dirb, dp->dir, SZDIRE); - nent = dirb[XDIR_NumSec] + 1; + if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */ + mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); + sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; + if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; - /* Load C0 entry */ + /* Load stream-extension entry */ res = dir_next(dp, 0); + if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; - mem_cpy(dirb + SZDIRE, dp->dir, SZDIRE); + if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */ + mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); + if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; - /* Load C1 entries */ - if (nent < 3 || nent > 19) return FR_NO_FILE; - i = SZDIRE * 2; nent *= SZDIRE; + /* Load file-name entries */ + i = 2 * SZDIRE; /* Name offset to load */ do { res = dir_next(dp, 0); + if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; - mem_cpy(dirb + i, dp->dir, SZDIRE); - i += SZDIRE; - } while (i < nent); - - /* Sanity check */ - if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */ + if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); + } while ((i += SZDIRE) < sz_ent); + /* Sanity check (do it for only accessible object) */ + if (i <= MAXDIRB(FF_MAX_LFN)) { + if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + } return FR_OK; } -#if !_FS_READONLY || _FS_RPATH != 0 +/*------------------------------------------------------------------*/ +/* exFAT: Initialize object allocation info with loaded entry block */ +/*------------------------------------------------------------------*/ + +static void init_alloc_info ( + FATFS* fs, /* Filesystem object */ + FFOBJID* obj /* Object allocation information to be initialized */ +) +{ + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Start cluster */ + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ + obj->n_frag = 0; /* No last fragment info */ +} + + + +#if !FF_FS_READONLY || FF_FS_RPATH != 0 /*------------------------------------------------*/ /* exFAT: Load the object's directory entry block */ /*------------------------------------------------*/ -static -FRESULT load_obj_dir ( + +static FRESULT load_obj_xdir ( DIR* dp, /* Blank directory object to be used to access containing direcotry */ - const _FDID* obj /* Object with containing directory information */ + const FFOBJID* obj /* Object with its containing directory information */ ) { FRESULT res; - /* Open object containing directory */ dp->obj.fs = obj->fs; dp->obj.sclust = obj->c_scl; dp->obj.stat = (BYTE)obj->c_size; dp->obj.objsize = obj->c_size & 0xFFFFFF00; + dp->obj.n_frag = 0; dp->blk_ofs = obj->c_ofs; - res = dir_sdi(dp, dp->blk_ofs); /* Goto the block location */ + res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ if (res == FR_OK) { res = load_xdir(dp); /* Load the object's entry block */ } @@ -1985,12 +2218,12 @@ FRESULT load_obj_dir ( #endif -#if !_FS_READONLY -/*-----------------------------------------------*/ -/* exFAT: Store the directory block to the media */ -/*-----------------------------------------------*/ -static -FRESULT store_xdir ( +#if !FF_FS_READONLY +/*----------------------------------------*/ +/* exFAT: Store the directory entry block */ +/*----------------------------------------*/ + +static FRESULT store_xdir ( DIR* dp /* Pointer to the direcotry object */ ) { @@ -2002,7 +2235,7 @@ FRESULT store_xdir ( st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); nent = dirb[XDIR_NumSec] + 1; - /* Store the set of directory to the volume */ + /* Store the direcotry entry block to the directory */ res = dir_sdi(dp, dp->blk_ofs); while (res == FR_OK) { res = move_window(dp->obj.fs, dp->sect); @@ -2022,71 +2255,77 @@ FRESULT store_xdir ( /* exFAT: Create a new directory enrty block */ /*-------------------------------------------*/ -static -void create_xdir ( +static void create_xdir ( BYTE* dirb, /* Pointer to the direcotry entry block buffer */ - const WCHAR* lfn /* Pointer to the nul terminated file name */ + const WCHAR* lfn /* Pointer to the object name */ ) { UINT i; - BYTE nb, nc; - WCHAR chr; + BYTE nc1, nlen; + WCHAR wc; - mem_set(dirb, 0, 2 * SZDIRE); /* Initialize 85+C0 entry */ - dirb[XDIR_Type] = 0x85; - dirb[XDIR_Type + SZDIRE] = 0xC0; - st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ + /* Create file-directory and stream-extension entry */ + mem_set(dirb, 0, 2 * SZDIRE); + dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; + dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; - i = SZDIRE * 2; /* C1 offset */ - nc = 0; nb = 1; chr = 1; + /* Create file-name entries */ + i = SZDIRE * 2; /* Top of file_name entries */ + nlen = nc1 = 0; wc = 1; do { - dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ + dirb[i++] = ET_FILENAME; dirb[i++] = 0; do { /* Fill name field */ - if (chr && (chr = lfn[nc]) != 0) nc++; /* Get a character if exist */ - st_word(dirb + i, chr); i += 2; /* Store it */ - } while (i % SZDIRE); - nb++; - } while (lfn[nc]); /* Fill next entry if any char follows */ + if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ + st_word(dirb + i, wc); /* Store it */ + i += 2; + } while (i % SZDIRE != 0); + nc1++; + } while (lfn[nlen]); /* Fill next entry if any char follows */ - dirb[XDIR_NumName] = nc; /* Set name length */ - dirb[XDIR_NumSec] = nb; /* Set number of C0+C1s */ + dirb[XDIR_NumName] = nlen; /* Set name length */ + dirb[XDIR_NumSec] = 1 + nc1; /* Set secondary count (C0 + C1s) */ + st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ } -#endif /* !_FS_READONLY */ -#endif /* _FS_EXFAT */ +#endif /* !FF_FS_READONLY */ +#endif /* FF_FS_EXFAT */ -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT /*-----------------------------------------------------------------------*/ /* Read an object from the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_read ( +#define DIR_READ_FILE(dp) dir_read(dp, 0) +#define DIR_READ_LABEL(dp) dir_read(dp, 1) + +static FRESULT dir_read ( DIR* dp, /* Pointer to the directory object */ int vol /* Filtered by 0:file/directory or 1:volume label */ ) { FRESULT res = FR_NO_FILE; FATFS *fs = dp->obj.fs; - BYTE a, c; -#if _USE_LFN != 0 + BYTE attr, b; +#if FF_USE_LFN BYTE ord = 0xFF, sum = 0xFF; #endif while (dp->sect) { res = move_window(fs, dp->sect); if (res != FR_OK) break; - c = dp->dir[DIR_Name]; /* Test for the entry type */ - if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of the directory */ -#if _FS_EXFAT + b = dp->dir[DIR_Name]; /* Test for the entry type */ + if (b == 0) { + res = FR_NO_FILE; break; /* Reached to end of the directory */ + } +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - if (_USE_LABEL && vol) { - if (c == 0x83) break; /* Volume label entry? */ + if (FF_USE_LABEL && vol) { + if (b == ET_VLABEL) break; /* Volume label entry? */ } else { - if (c == 0x85) { /* Start of the file entry block? */ + if (b == ET_FILEDIR) { /* Start of the file entry block? */ dp->blk_ofs = dp->dptr; /* Get location of the block */ res = load_xdir(dp); /* Load the entry block */ if (res == FR_OK) { @@ -2097,29 +2336,29 @@ FRESULT dir_read ( } } else #endif - { /* On the FAT12/16/32 volume */ - dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ -#if _USE_LFN != 0 /* LFN configuration */ - if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + { /* On the FAT/FAT32 volume */ + dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ +#if FF_USE_LFN /* LFN configuration */ + if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ ord = 0xFF; } else { - if (a == AM_LFN) { /* An LFN entry is found */ - if (c & LLEF) { /* Is it start of an LFN sequence? */ + if (attr == AM_LFN) { /* An LFN entry is found */ + if (b & LLEF) { /* Is it start of an LFN sequence? */ sum = dp->dir[LDIR_Chksum]; - c &= (BYTE)~LLEF; ord = c; + b &= (BYTE)~LLEF; ord = b; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ - ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } else { /* An SFN entry is found */ - if (ord || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ + if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ } break; } } #else /* Non LFN configuration */ - if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ + if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ break; } #endif @@ -2132,7 +2371,7 @@ FRESULT dir_read ( return res; } -#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ +#endif /* FF_FS_MINIMIZE <= 1 || FF_USE_LABEL || FF_FS_RPATH >= 2 */ @@ -2140,28 +2379,30 @@ FRESULT dir_read ( /* Directory handling - Find an object in the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ - DIR* dp /* Pointer to the directory object with the file name */ +static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp /* Pointer to the directory object with the file name */ ) { FRESULT res; FATFS *fs = dp->obj.fs; BYTE c; -#if _USE_LFN != 0 +#if FF_USE_LFN BYTE a, ord, sum; #endif res = dir_sdi(dp, 0); /* Rewind directory object */ if (res != FR_OK) return res; -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ BYTE nc; UINT di, ni; WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ - while ((res = dir_read(dp, 0)) == FR_OK) { /* Read an item */ - if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip the comparison if hash value mismatched */ + while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */ +#if FF_MAX_LFN < 255 + if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ +#endif + if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ if ((di % SZDIRE) == 0) di += 2; if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; @@ -2171,8 +2412,8 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ return res; } #endif - /* On the FAT12/16/32 volume */ -#if _USE_LFN != 0 + /* On the FAT/FAT32 volume */ +#if FF_USE_LFN ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ #endif do { @@ -2180,7 +2421,7 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ if (res != FR_OK) break; c = dp->dir[DIR_Name]; if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ -#if _USE_LFN != 0 /* LFN configuration */ +#if FF_USE_LFN /* LFN configuration */ dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ @@ -2196,7 +2437,7 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } } else { /* An SFN entry is found */ - if (!ord && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ + if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } @@ -2214,19 +2455,18 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Register an object to the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ - DIR* dp /* Target directory with object name to be created */ +static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ + DIR* dp /* Target directory with object name to be created */ ) { FRESULT res; FATFS *fs = dp->obj.fs; -#if _USE_LFN != 0 /* LFN configuration */ +#if FF_USE_LFN /* LFN configuration */ UINT n, nlen, nent; BYTE sn[12], sum; @@ -2234,34 +2474,38 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - DIR dj; - nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ - res = dir_alloc(dp, nent); /* Allocate entries */ + res = dir_alloc(dp, nent); /* Allocate directory entries */ if (res != FR_OK) return res; - dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set block position */ + dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ - if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */ - dp->obj.stat &= 3; - dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase object size by cluster size */ - res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */ + if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */ + dp->obj.stat &= ~4; + res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ if (res != FR_OK) return res; - res = load_obj_dir(&dj, &dp->obj); - if (res != FR_OK) return res; /* Load the object status */ - st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ - st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); - fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; - res = store_xdir(&dj); /* Store the object status */ + res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ if (res != FR_OK) return res; + if (dp->obj.sclust != 0) { /* Is it a sub-directory? */ + DIR dj; + + res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ + if (res != FR_OK) return res; + dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ + st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ + st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); + fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; + res = store_xdir(&dj); /* Store the object status */ + if (res != FR_OK) return res; + } } create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ return FR_OK; } #endif - /* On the FAT12/16/32 volume */ + /* On the FAT/FAT32 volume */ mem_cpy(sn, dp->fn, 12); if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ @@ -2303,7 +2547,7 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many if (res == FR_OK) { mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ -#if _USE_LFN != 0 +#if FF_USE_LFN dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ #endif fs->wflag = 1; @@ -2313,23 +2557,22 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many return res; } -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ -#if !_FS_READONLY && _FS_MINIMIZE == 0 +#if !FF_FS_READONLY && FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Remove an object from the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ - DIR* dp /* Directory object pointing the entry to be removed */ +static FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ + DIR* dp /* Directory object pointing the entry to be removed */ ) { FRESULT res; FATFS *fs = dp->obj.fs; -#if _USE_LFN != 0 /* LFN configuration */ +#if FF_USE_LFN /* LFN configuration */ DWORD last = dp->dptr; res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ @@ -2337,11 +2580,10 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ do { res = move_window(fs, dp->sect); if (res != FR_OK) break; - /* Mark an entry 'deleted' */ - if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - dp->dir[XDIR_Type] &= 0x7F; - } else { /* On the FAT12/16/32 volume */ - dp->dir[DIR_Name] = DDEM; + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + dp->dir[XDIR_Type] &= 0x7F; /* Clear the entry InUse flag. */ + } else { /* On the FAT/FAT32 volume */ + dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'. */ } fs->wflag = 1; if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ @@ -2353,7 +2595,7 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ res = move_window(fs, dp->sect); if (res == FR_OK) { - dp->dir[DIR_Name] = DDEM; + dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'.*/ fs->wflag = 1; } #endif @@ -2361,143 +2603,153 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ return res; } -#endif /* !_FS_READONLY && _FS_MINIMIZE == 0 */ +#endif /* !FF_FS_READONLY && FF_FS_MINIMIZE == 0 */ -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 /*-----------------------------------------------------------------------*/ /* Get file information from directory entry */ /*-----------------------------------------------------------------------*/ -static -void get_fileinfo ( /* No return code */ +static void get_fileinfo ( DIR* dp, /* Pointer to the directory object */ FILINFO* fno /* Pointer to the file information to be filled */ ) { - UINT i, j; - TCHAR c; - DWORD tm; -#if _USE_LFN != 0 - WCHAR w, lfv; + UINT si, di; +#if FF_USE_LFN + BYTE lcf; + WCHAR wc, hs; FATFS *fs = dp->obj.fs; +#else + TCHAR c; #endif - fno->fname[0] = 0; /* Invaidate file info */ - if (!dp->sect) return; /* Exit if read pointer has reached end of directory */ + fno->fname[0] = 0; /* Invaidate file info */ + if (dp->sect == 0) return; /* Exit if read pointer has reached end of directory */ -#if _USE_LFN != 0 /* LFN configuration */ -#if _FS_EXFAT +#if FF_USE_LFN /* LFN configuration */ +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - get_xdir_info(fs->dirbuf, fno); + get_xfileinfo(fs->dirbuf, fno); return; } else #endif - { /* On the FAT12/16/32 volume */ + { /* On the FAT/FAT32 volume */ if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ - i = j = 0; - while ((w = fs->lfnbuf[j++]) != 0) { /* Get an LFN character */ -#if !_LFN_UNICODE - w = ff_convert(w, 0); /* Unicode -> OEM */ - if (w == 0) { i = 0; break; } /* No LFN if it could not be converted */ - if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ - fno->fname[i++] = (char)(w >> 8); + si = di = hs = 0; + while (fs->lfnbuf[si] != 0) { + wc = fs->lfnbuf[si++]; /* Get an LFN character (UTF-16) */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ } -#endif - if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */ - fno->fname[i++] = (TCHAR)w; + wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ + if (wc == 0) { di = 0; break; } /* Invalid char or buffer overflow? */ + di += wc; + hs = 0; } - fno->fname[i] = 0; /* Terminate the LFN */ + if (hs != 0) di = 0; /* Broken surrogate pair? */ + fno->fname[di] = 0; /* Terminate the LFN (null string means LFN is invalid) */ } } - i = j = 0; - lfv = fno->fname[i]; /* LFN is exist if non-zero */ - while (i < 11) { /* Copy name body and extension */ - c = (TCHAR)dp->dir[i++]; - if (c == ' ') continue; /* Skip padding spaces */ - if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ - if (i == 9) { /* Insert a . if extension is exist */ - if (!lfv) fno->fname[j] = '.'; - fno->altname[j++] = '.'; + si = di = 0; + while (si < 11) { /* Get SFN from SFN entry */ + wc = dp->dir[si++]; /* Get a char */ + if (wc == ' ') continue; /* Skip padding spaces */ + if (wc == RDDEM) wc = DDEM; /* Restore replaced DDEM character */ + if (si == 9 && di < FF_SFN_BUF) fno->altname[di++] = '.'; /* Insert a . if extension is exist */ +#if FF_LFN_UNICODE >= 1 /* Unicode output */ + if (dbc_1st((BYTE)wc) && si != 8 && si != 11 && dbc_2nd(dp->dir[si])) { /* Make a DBC if needed */ + wc = wc << 8 | dp->dir[si++]; } -#if _LFN_UNICODE - if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dp->dir[i])) { - c = c << 8 | dp->dir[i++]; - } - c = ff_convert(c, 1); /* OEM -> Unicode */ - if (!c) c = '?'; + wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ + if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ + wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in Unicode */ + if (wc == 0) { di = 0; break; } /* Buffer overflow? */ + di += wc; +#else /* ANSI/OEM output */ + fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ #endif - fno->altname[j] = c; - if (!lfv) { - if (IsUpper(c) && (dp->dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) { - c += 0x20; /* To lower */ + } + fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ + + if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ + if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ + fno->fname[di++] = '?'; + } else { + for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ + wc = (WCHAR)fno->altname[si]; + if (wc == '.') lcf = NS_EXT; + if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; + fno->fname[di] = (TCHAR)wc; } - fno->fname[j] = c; } - j++; + fno->fname[di] = 0; /* Terminate the LFN */ + if (!dp->dir[DIR_NTres]) fno->altname[0] = 0; /* Altname is not needed if neither LFN nor case info is exist. */ } - if (!lfv) { - fno->fname[j] = 0; - if (!dp->dir[DIR_NTres]) j = 0; /* Altname is no longer needed if neither LFN nor case info is exist. */ - } - fno->altname[j] = 0; /* Terminate the SFN */ #else /* Non-LFN configuration */ - i = j = 0; - while (i < 11) { /* Copy name body and extension */ - c = (TCHAR)dp->dir[i++]; - if (c == ' ') continue; /* Skip padding spaces */ - if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ - if (i == 9) fno->fname[j++] = '.'; /* Insert a . if extension is exist */ - fno->fname[j++] = c; + si = di = 0; + while (si < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[si++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = DDEM; /* Restore replaced DDEM character */ + if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */ + fno->fname[di++] = c; } - fno->fname[j] = 0; + fno->fname[di] = 0; #endif - fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ - fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ - tm = ld_dword(dp->dir + DIR_ModTime); /* Timestamp */ - fno->ftime = (WORD)tm; fno->fdate = (WORD)(tm >> 16); + fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ + fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ + fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ + fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ } -#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ +#endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ -#if _USE_FIND && _FS_MINIMIZE <= 1 +#if FF_USE_FIND && FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Pattern matching */ /*-----------------------------------------------------------------------*/ -static -WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */ - const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */ +static DWORD get_achar ( /* Get a character and advances ptr */ + const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ ) { -#if !_LFN_UNICODE - WCHAR chr; + DWORD chr; - chr = (BYTE)*(*ptr)++; /* Get a byte */ - if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ -#ifdef _EXCVT + +#if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode input */ + chr = tchar2uni(ptr); + if (chr == 0xFFFFFFFF) chr = 0; /* Wrong UTF encoding is recognized as end of the string */ + chr = ff_wtoupper(chr); + +#else /* ANSI/OEM input */ + chr = (BYTE)*(*ptr)++; /* Get a byte */ + if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ +#if FF_CODE_PAGE == 0 + if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ +#elif FF_CODE_PAGE < 900 if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ -#else - if (IsDBCS1(chr) && IsDBCS2(**ptr)) { /* Get DBC 2nd byte if needed */ - chr = chr << 8 | (BYTE)*(*ptr)++; +#endif +#if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900 + if (dbc_1st((BYTE)chr)) { /* Get DBC 2nd byte if needed */ + chr = dbc_2nd((BYTE)**ptr) ? chr << 8 | (BYTE)*(*ptr)++ : 0; } #endif - return chr; -#else - return ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ + #endif + return chr; } -static -int pattern_matching ( /* 0:not matched, 1:matched */ +static int pattern_matching ( /* 0:not matched, 1:matched */ const TCHAR* pat, /* Matching pattern */ const TCHAR* nam, /* String to be tested */ int skip, /* Number of pre-skip chars (number of ?s) */ @@ -2505,21 +2757,21 @@ int pattern_matching ( /* 0:not matched, 1:matched */ ) { const TCHAR *pp, *np; - WCHAR pc, nc; + DWORD pc, nc; int nm, nx; while (skip--) { /* Pre-skip name chars */ if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ } - if (!*pat && inf) return 1; /* (short circuit) */ + if (*pat == 0 && inf) return 1; /* (short circuit) */ do { pp = pat; np = nam; /* Top of pattern and name to match */ for (;;) { if (*pp == '?' || *pp == '*') { /* Wildcard? */ nm = nx = 0; - do { /* Analyze the wildcard chars */ + do { /* Analyze the wildcard block */ if (*pp++ == '?') nm++; else nx = 1; } while (*pp == '?' || *pp == '*'); if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ @@ -2536,7 +2788,7 @@ int pattern_matching ( /* 0:not matched, 1:matched */ return 0; } -#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */ +#endif /* FF_USE_FIND && FF_FS_MINIMIZE <= 1 */ @@ -2544,131 +2796,133 @@ int pattern_matching ( /* 0:not matched, 1:matched */ /* Pick a top segment and create the object name in directory form */ /*-----------------------------------------------------------------------*/ -static -FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ - DIR* dp, /* Pointer to the directory object */ - const TCHAR** path /* Pointer to pointer to the segment in the path string */ +static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ + DIR* dp, /* Pointer to the directory object */ + const TCHAR** path /* Pointer to pointer to the segment in the path string */ ) { -#if _USE_LFN != 0 /* LFN configuration */ +#if FF_USE_LFN /* LFN configuration */ BYTE b, cf; - WCHAR w, *lfn; + WCHAR wc, *lfn; + DWORD uc; UINT i, ni, si, di; const TCHAR *p; - /* Create LFN in Unicode */ - p = *path; lfn = dp->obj.fs->lfnbuf; si = di = 0; + + /* Create LFN into LFN working buffer */ + p = *path; lfn = dp->obj.fs->lfnbuf; di = 0; for (;;) { - w = p[si++]; /* Get a character */ - if (w < ' ') break; /* Break if end of the path name */ - if (w == '/' || w == '\\') { /* Break if a separator is found */ - while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ - break; - } - if (di >= _MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ -#if !_LFN_UNICODE - w &= 0xFF; - if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ - b = (BYTE)p[si++]; /* Get 2nd byte */ - w = (w << 8) + b; /* Create a DBC */ - if (!IsDBCS2(b)) return FR_INVALID_NAME; /* Reject invalid sequence */ - } - w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ - if (!w) return FR_INVALID_NAME; /* Reject invalid code */ -#endif - if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ - lfn[di++] = w; /* Store the Unicode character */ + uc = tchar2uni(&p); /* Get a character */ + if (uc == 0xFFFFFFFF) return FR_INVALID_NAME; /* Invalid code or UTF decode error */ + if (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16); /* Store high surrogate if needed */ + wc = (WCHAR)uc; + if (wc < ' ' || wc == '/' || wc == '\\') break; /* Break if end of the path or a separator is found */ + if (wc < 0x80 && chk_chr("\"*:<>\?|\x7F", wc)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ + if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ + lfn[di++] = wc; /* Store the Unicode character */ } - *path = &p[si]; /* Return pointer to the next segment */ - cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ -#if _FS_RPATH != 0 + while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ + *path = p; /* Return pointer to the next segment */ + cf = (wc < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ + +#if FF_FS_RPATH != 0 if ((di == 1 && lfn[di - 1] == '.') || (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ lfn[di] = 0; - for (i = 0; i < 11; i++) /* Create dot name for SFN entry */ + for (i = 0; i < 11; i++) { /* Create dot name for SFN entry */ dp->fn[i] = (i < di) ? '.' : ' '; + } dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ return FR_OK; } #endif while (di) { /* Snip off trailing spaces and dots if exist */ - w = lfn[di - 1]; - if (w != ' ' && w != '.') break; + wc = lfn[di - 1]; + if (wc != ' ' && wc != '.') break; di--; } - lfn[di] = 0; /* LFN is created */ - if (di == 0) return FR_INVALID_NAME; /* Reject nul name */ + lfn[di] = 0; /* LFN is created into the working buffer */ + if (di == 0) return FR_INVALID_NAME; /* Reject null name */ /* Create SFN in directory form */ - mem_set(dp->fn, ' ', 11); - for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */ - if (si) cf |= NS_LOSS | NS_LFN; - while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */ + for (si = 0; lfn[si] == ' '; si++) ; /* Remove leading spaces */ + if (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN; /* Is there any leading space or dot? */ + while (di > 0 && lfn[di - 1] != '.') di--; /* Find last dot (di<=si: no extension) */ + mem_set(dp->fn, ' ', 11); i = b = 0; ni = 8; for (;;) { - w = lfn[si++]; /* Get an LFN character */ - if (!w) break; /* Break on end of the LFN */ - if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */ - cf |= NS_LOSS | NS_LFN; continue; + wc = lfn[si++]; /* Get an LFN character */ + if (wc == 0) break; /* Break on end of the LFN */ + if (wc == ' ' || (wc == '.' && si != di)) { /* Remove embedded spaces and dots */ + cf |= NS_LOSS | NS_LFN; + continue; } - if (i >= ni || si == di) { /* Extension or end of SFN */ - if (ni == 11) { /* Long extension */ - cf |= NS_LOSS | NS_LFN; break; + if (i >= ni || si == di) { /* End of field? */ + if (ni == 11) { /* Name extension overflow? */ + cf |= NS_LOSS | NS_LFN; + break; } - if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */ - if (si > di) break; /* No extension */ - si = di; i = 8; ni = 11; /* Enter extension section */ - b <<= 2; continue; + if (si != di) cf |= NS_LOSS | NS_LFN; /* Name body overflow? */ + if (si > di) break; /* No name extension? */ + si = di; i = 8; ni = 11; b <<= 2; /* Enter name extension */ + continue; } - if (w >= 0x80) { /* Non ASCII character */ -#ifdef _EXCVT - w = ff_convert(w, 0); /* Unicode -> OEM code */ - if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */ -#else - w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */ + if (wc >= 0x80) { /* Is this a non-ASCII character? */ + cf |= NS_LFN; /* LFN entry needs to be created */ +#if FF_CODE_PAGE == 0 + if (ExCvt) { /* At SBCS */ + wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ + if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ + } else { /* At DBCS */ + wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ + } +#elif FF_CODE_PAGE < 900 /* SBCS cfg */ + wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ + if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ +#else /* DBCS cfg */ + wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ #endif - cf |= NS_LFN; /* Force create LFN entry */ } - if (_DF1S && w >= 0x100) { /* Is this DBC? (always false at SBCS cfg) */ - if (i >= ni - 1) { - cf |= NS_LOSS | NS_LFN; i = ni; continue; + if (wc >= 0x100) { /* Is this a DBC? */ + if (i >= ni - 1) { /* Field overflow? */ + cf |= NS_LOSS | NS_LFN; + i = ni; continue; /* Next field */ } - dp->fn[i++] = (BYTE)(w >> 8); + dp->fn[i++] = (BYTE)(wc >> 8); /* Put 1st byte */ } else { /* SBC */ - if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */ - w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ + if (wc == 0 || chk_chr("+,;=[]", wc)) { /* Replace illegal characters for SFN if needed */ + wc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ } else { - if (IsUpper(w)) { /* ASCII large capital */ + if (IsUpper(wc)) { /* ASCII upper case? */ b |= 2; - } else { - if (IsLower(w)) { /* ASCII small capital */ - b |= 1; w -= 0x20; - } + } + if (IsLower(wc)) { /* ASCII lower case? */ + b |= 1; wc -= 0x20; } } } - dp->fn[i++] = (BYTE)w; + dp->fn[i++] = (BYTE)wc; } if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ - if (ni == 8) b <<= 2; - if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* Create LFN entry when there are composite capitals */ - if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ - if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */ - if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */ + if (ni == 8) b <<= 2; /* Shift capital flags if no extension */ + if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* LFN entry needs to be created if composite capitals */ + if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ + if (b & 0x01) cf |= NS_EXT; /* NT flag (Extension has small capital letters only) */ + if (b & 0x04) cf |= NS_BODY; /* NT flag (Body has small capital letters only) */ } - dp->fn[NSFLAG] = cf; /* SFN is created */ + dp->fn[NSFLAG] = cf; /* SFN is created into dp->fn[] */ return FR_OK; -#else /* _USE_LFN != 0 : Non-LFN configuration */ +#else /* FF_USE_LFN : Non-LFN configuration */ BYTE c, d, *sfn; UINT ni, si, i; const char *p; @@ -2677,7 +2931,7 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create p = *path; sfn = dp->fn; mem_set(sfn, ' ', 11); si = i = 0; ni = 8; -#if _FS_RPATH != 0 +#if FF_FS_RPATH != 0 if (p[si] == '.') { /* Is this a dot entry? */ for (;;) { c = (BYTE)p[si++]; @@ -2691,29 +2945,29 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create } #endif for (;;) { - c = (BYTE)p[si++]; + c = (BYTE)p[si++]; /* Get a byte */ if (c <= ' ') break; /* Break if end of the path name */ if (c == '/' || c == '\\') { /* Break if a separator is found */ while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ break; } - if (c == '.' || i >= ni) { /* End of body or over size? */ - if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Over size or invalid dot */ - i = 8; ni = 11; /* Goto extension */ + if (c == '.' || i >= ni) { /* End of body or field overflow? */ + if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Field overflow or invalid dot? */ + i = 8; ni = 11; /* Enter file extension field */ continue; } - if (c >= 0x80) { /* Extended character? */ -#ifdef _EXCVT - c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */ -#else -#if !_DF1S - return FR_INVALID_NAME; /* Reject extended characters (ASCII only cfg) */ -#endif -#endif +#if FF_CODE_PAGE == 0 + if (ExCvt && c >= 0x80) { /* Is SBC extended character? */ + c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ } - if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */ +#elif FF_CODE_PAGE < 900 + if (c >= 0x80) { /* Is SBC extended character? */ + c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ + } +#endif + if (dbc_1st(c)) { /* Check if it is a DBC 1st byte */ d = (BYTE)p[si++]; /* Get 2nd byte */ - if (!IsDBCS2(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ + if (!dbc_2nd(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ sfn[i++] = c; sfn[i++] = d; } else { /* SBC */ @@ -2729,7 +2983,7 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ return FR_OK; -#endif /* _USE_LFN != 0 */ +#endif /* FF_USE_LFN */ } @@ -2739,39 +2993,40 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create /* Follow a file path */ /*-----------------------------------------------------------------------*/ -static -FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ - DIR* dp, /* Directory object to return last directory and found object */ - const TCHAR* path /* Full-path string to find a file or directory */ +static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ + DIR* dp, /* Directory object to return last directory and found object */ + const TCHAR* path /* Full-path string to find a file or directory */ ) { FRESULT res; BYTE ns; - _FDID *obj = &dp->obj; - FATFS *fs = obj->fs; + FATFS *fs = dp->obj.fs; -#if _FS_RPATH != 0 +#if FF_FS_RPATH != 0 if (*path != '/' && *path != '\\') { /* Without heading separator */ - obj->sclust = fs->cdir; /* Start from the current directory */ + dp->obj.sclust = fs->cdir; /* Start from current directory */ } else #endif { /* With heading separator */ while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ - obj->sclust = 0; /* Start from the root directory */ + dp->obj.sclust = 0; /* Start from root directory */ } -#if _FS_EXFAT && _FS_RPATH != 0 - if (fs->fs_type == FS_EXFAT && obj->sclust) { /* Retrieve the sub-directory status if needed */ +#if FF_FS_EXFAT + dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ +#if FF_FS_RPATH != 0 + if (fs->fs_type == FS_EXFAT && dp->obj.sclust) { /* exFAT: Retrieve the sub-directory's status */ DIR dj; - obj->c_scl = fs->cdc_scl; - obj->c_size = fs->cdc_size; - obj->c_ofs = fs->cdc_ofs; - res = load_obj_dir(&dj, obj); + dp->obj.c_scl = fs->cdc_scl; + dp->obj.c_size = fs->cdc_size; + dp->obj.c_ofs = fs->cdc_ofs; + res = load_obj_xdir(&dj, &dp->obj); if (res != FR_OK) return res; - obj->objsize = ld_dword(fs->dirbuf + XDIR_FileSize); - obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize); + dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; } +#endif #endif if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ @@ -2786,7 +3041,7 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ ns = dp->fn[NSFLAG]; if (res != FR_OK) { /* Failed to find the object */ if (res == FR_NO_FILE) { /* Object is not found */ - if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ + if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ dp->fn[NSFLAG] = NS_NONAME; res = FR_OK; @@ -2798,21 +3053,19 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ } if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ /* Get into the sub-directory */ - if (!(obj->attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ + if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ res = FR_NO_PATH; break; } -#if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { - obj->c_scl = obj->sclust; /* Save containing directory information for next dir */ - obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; - obj->c_ofs = dp->blk_ofs; - obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Open next directory */ - obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; - obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ + dp->obj.c_scl = dp->obj.sclust; + dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; + dp->obj.c_ofs = dp->blk_ofs; + init_alloc_info(fs, &dp->obj); /* Open next directory */ } else #endif { - obj->sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ + dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ } } } @@ -2824,41 +3077,39 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ /*-----------------------------------------------------------------------*/ -/* Load a sector and check if it is an FAT boot sector */ +/* Load a sector and check if it is an FAT VBR */ /*-----------------------------------------------------------------------*/ -static -BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ - FATFS* fs, /* File system object */ - DWORD sect /* Sector# (lba) to check if it is an FAT-VBR or not */ +static BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ + FATFS* fs, /* Filesystem object */ + DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ ) { fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ - if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ + if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always here regardless of the sector size) */ - if (fs->win[BS_JmpBoot] == 0xE9 || (fs->win[BS_JmpBoot] == 0xEB && fs->win[BS_JmpBoot + 2] == 0x90)) { - if ((ld_dword(fs->win + BS_FilSysType) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */ - if (ld_dword(fs->win + BS_FilSysType32) == 0x33544146) return 0; /* Check "FAT3" string */ - } -#if _FS_EXFAT - if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; +#if FF_FS_EXFAT + if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* Check if exFAT VBR */ #endif - return 2; + if (fs->win[BS_JmpBoot] == 0xE9 || fs->win[BS_JmpBoot] == 0xEB || fs->win[BS_JmpBoot] == 0xE8) { /* Valid JumpBoot code? */ + if (!mem_cmp(fs->win + BS_FilSysType, "FAT", 3)) return 0; /* Is it an FAT VBR? */ + if (!mem_cmp(fs->win + BS_FilSysType32, "FAT32", 5)) return 0; /* Is it an FAT32 VBR? */ + } + return 2; /* Valid BS but not FAT */ } /*-----------------------------------------------------------------------*/ -/* Find logical drive and check if the volume is mounted */ +/* Determine logical drive number and mount the volume if needed */ /*-----------------------------------------------------------------------*/ -static -FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ - FATFS* fs, /* Pointer to the file system object */ - BYTE mode /* !=0: Check write protection for write access */ +static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ + FATFS *fs, /* Pointer to the file system object */ + BYTE mode /* !=0: Check write protection for write access */ ) { BYTE fmt, *pt; @@ -2868,65 +3119,70 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ UINT i; - ENTER_FF(fs); /* Lock the volume */ +#if FF_FS_REENTRANT + if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ +#endif mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ - if (fs->fs_type) { /* If the volume has been mounted */ + if (fs->fs_type != 0) { /* If the volume has been mounted */ disk_ioctl(fs->drv, IOCTL_STATUS, &stat); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ - if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ + if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ return FR_WRITE_PROTECTED; } - return FR_OK; /* The file system object is valid */ + return FR_OK; /* The filesystem object is valid */ } } - /* The file system object is not valid. */ - /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */ + /* The filesystem object is not valid. */ + /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */ - fs->fs_type = 0; /* Clear the file system object */ + fs->fs_type = 0; /* Clear the filesystem object */ disk_ioctl(fs->drv, IOCTL_INIT, &stat); /* Initialize the physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ } - if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ + if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ return FR_WRITE_PROTECTED; } -#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ +#if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; - if (SS(fs) > _MAX_SS || SS(fs) < _MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; + if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif - /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ + + /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */ bsect = 0; fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ if (fmt == 2 || (fmt < 2 && LD2PT(fs) != 0)) { /* Not an FAT-VBR or forced partition number */ - for (i = 0; i < 4; i++) { /* Get partition offset */ + for (i = 0; i < 4; i++) { /* Get partition offset */ pt = fs->win + (MBR_Table + i * SZ_PTE); br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; } - i = LD2PT(fs); /* Partition number: 0:auto, 1-4:forced */ - if (i) i--; - do { /* Find an FAT volume */ + i = LD2PT(fs); /* Partition number: 0:auto, 1-4:forced */ + if (i != 0) i--; + do { /* Find an FAT volume */ bsect = br[i]; fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ - } while (!LD2PT(fs) && fmt >= 2 && ++i < 4); + } while (LD2PT(fs) == 0 && fmt >= 2 && ++i < 4); } if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ - /* An FAT volume is found. Following code initializes the file system object */ + /* An FAT volume is found (bsect). Following code initializes the filesystem object */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fmt == 1) { QWORD maxlba; + DWORD so, cv, bcl; for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; - if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT revision (Must be 1.0) */ + if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ - if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ + if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ return FR_NO_FILESYSTEM; + } maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ @@ -2950,106 +3206,123 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); - /* Check if bitmap location is in assumption (at the first cluster) */ - if (move_window(fs, clust2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR; - for (i = 0; i < SS(fs); i += SZDIRE) { - if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ + /* Get bitmap location and check if it is contiguous (implementation assumption) */ + so = i = 0; + for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */ + if (i == 0) { + if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */ + if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) return FR_DISK_ERR; + so++; + } + if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ + i = (i + SZDIRE) % SS(fs); /* Next entry */ } - if (i == SS(fs)) return FR_NO_FILESYSTEM; -#if !_FS_READONLY + bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ + if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM; + fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */ + for (;;) { /* Check if bitmap is contiguous */ + if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; + cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); + if (cv == 0xFFFFFFFF) break; /* Last link? */ + if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented? */ + } + +#if !FF_FS_READONLY fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ #endif fmt = FS_EXFAT; /* FAT sub-type */ } else -#endif /* _FS_EXFAT */ +#endif /* FF_FS_EXFAT */ { if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ - fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); fs->fsize = fasize; - fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ - fasize *= fs->n_fats; /* Number of sectors for FAT area */ + fasize *= fs->n_fats; /* Number of sectors for FAT area */ - fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ + fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ - tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); - nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ - if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ /* Determine the FAT sub type */ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ - if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ - if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - fmt = FS_FAT32; + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = 0; + if (nclst <= MAX_FAT32) fmt = FS_FAT32; if (nclst <= MAX_FAT16) fmt = FS_FAT16; if (nclst <= MAX_FAT12) fmt = FS_FAT12; + if (fmt == 0) return FR_NO_FILESYSTEM; /* Boundaries and Limits */ - fs->n_fatent = nclst + 2; /* Number of FAT entries */ - fs->volbase = bsect; /* Volume start sector */ - fs->fatbase = bsect + nrsv; /* FAT start sector */ - fs->database = bsect + sysect; /* Data start sector */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ if (fmt == FS_FAT32) { if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ - if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ - szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ } else { - if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* (BPB_RootEntCnt must not be 0) */ - fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ - szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); } if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ -#if !_FS_READONLY - /* Get FSINFO if available */ +#if !FF_FS_READONLY + /* Get FSInfo if available */ fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ fs->fsi_flag = 0x80; -#if (_FS_NOFSINFO & 3) != 3 - if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo32 == 1 */ +#if (FF_FS_NOFSINFO & 3) != 3 + if (fmt == FS_FAT32 /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */ && ld_word(fs->win + BPB_FSInfo32) == 1 && move_window(fs, bsect + 1) == FR_OK) { fs->fsi_flag = 0; - if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ + if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSInfo data if available */ && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) { -#if (_FS_NOFSINFO & 1) == 0 +#if (FF_FS_NOFSINFO & 1) == 0 fs->free_clst = ld_dword(fs->win + FSI_Free_Count); #endif -#if (_FS_NOFSINFO & 2) == 0 +#if (FF_FS_NOFSINFO & 2) == 0 fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); #endif } } -#endif /* (_FS_NOFSINFO & 3) != 3 */ -#endif /* !_FS_READONLY */ +#endif /* (FF_FS_NOFSINFO & 3) != 3 */ +#endif /* !FF_FS_READONLY */ } - fs->fs_type = fmt; /* FAT sub-type */ - fs->id = ++Fsid; /* File system mount ID */ -#if _USE_LFN == 1 + fs->fs_type = fmt; /* FAT sub-type */ + fs->id = ++Fsid; /* Volume mount ID */ +#if FF_USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ -#if _FS_EXFAT - fs->dirbuf = DirBuf; /* Static directory block working buuffer */ +#if FF_FS_EXFAT + fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ #endif #endif -#if _FS_RPATH != 0 - fs->cdir = 0; /* Initialize current directory */ +#if FF_FS_RPATH != 0 + fs->cdir = 0; /* Initialize current directory */ #endif -#if _FS_LOCK != 0 /* Clear file lock semaphores */ +#if FF_FS_LOCK != 0 /* Clear file lock semaphores */ clear_lock(fs); #endif return FR_OK; @@ -3062,24 +3335,33 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ /* Check if the file/directory object is valid or not */ /*-----------------------------------------------------------------------*/ -static -FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ - _FDID* obj, /* Pointer to the _OBJ, the 1st member in the FIL/DIR object, to check validity */ - FATFS** fs /* Pointer to pointer to the owner file system object to return */ +static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ + FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */ + FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ ) { - FRESULT res; + FRESULT res = FR_INVALID_OBJECT; DSTATUS stat; - if (!obj || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) != RES_OK || (stat & STA_NOINIT)) { - *fs = 0; /* The object is invalid */ - res = FR_INVALID_OBJECT; - } else { - *fs = obj->fs; /* Owner file sytem object */ - ENTER_FF(obj->fs); /* Lock file system */ - res = FR_OK; + if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ +#if FF_FS_REENTRANT + if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ + if (disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) == RES_OK && !(stat & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + res = FR_OK; + } else { + unlock_fs(obj->fs, FR_OK); + } + } else { + res = FR_TIMEOUT; + } +#else + if (disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) == RES_OK && !(stat & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + res = FR_OK; + } +#endif } + *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ return res; } @@ -3105,7 +3387,7 @@ FRESULT f_mount ( FRESULT res; fs->fs_type = 0; /* Clear new fs object */ -#if _FS_REENTRANT /* Create sync object for the new volume */ +#if FF_FS_REENTRANT /* Create sync object for the new volume */ if (!ff_cre_syncobj(fs, &fs->sobj)) return FR_INT_ERR; #endif @@ -3118,10 +3400,10 @@ FRESULT f_umount ( FATFS* fs /* Pointer to the file system object to unmount */ ) { -#if _FS_LOCK +#if FF_FS_LOCK clear_lock(fs); #endif -#if _FS_REENTRANT /* Discard sync object of the current volume */ +#if FF_FS_REENTRANT /* Discard sync object of the current volume */ if (!ff_del_syncobj(fs->sobj)) return FR_INT_ERR; #endif fs->fs_type = 0; /* Clear old fs object */ @@ -3143,7 +3425,7 @@ FRESULT f_open ( { FRESULT res; DIR dj; -#if !_FS_READONLY +#if !FF_FS_READONLY DWORD dw, cl, bcs, clst, sc; FSIZE_t ofs; #endif @@ -3152,79 +3434,71 @@ FRESULT f_open ( if (!fp) return FR_INVALID_OBJECT; - /* Get logical drive */ - mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND; + /* Get logical drive number */ + mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; res = find_volume(fs, mode); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ -#if !_FS_READONLY /* R/W configuration */ +#if !FF_FS_READONLY /* Read/Write configuration */ if (res == FR_OK) { if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; } -#if _FS_LOCK != 0 +#if FF_FS_LOCK != 0 else { - res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ } #endif } /* Create or Open a file */ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ - if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ -#if _FS_LOCK != 0 + if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ +#if FF_FS_LOCK != 0 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif + } mode |= FA_CREATE_ALWAYS; /* File is created */ } - else { /* Any object is already existing */ + else { /* Any object with the same name is already existing */ if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ res = FR_DENIED; } else { if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ } } - if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ - dw = GET_FATTIME(); -#if _FS_EXFAT + if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate the file if overwrite mode */ +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Get current allocation info */ fp->obj.fs = fs; - fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); - fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); - fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; - /* Initialize directory entry block */ - st_dword(fs->dirbuf + XDIR_CrtTime, dw); /* Set created time */ - fs->dirbuf[XDIR_CrtTime10] = 0; - st_dword(fs->dirbuf + XDIR_ModTime, dw); /* Set modified time */ - fs->dirbuf[XDIR_ModTime10] = 0; - fs->dirbuf[XDIR_Attr] = AM_ARC; /* Reset attribute */ - st_dword(fs->dirbuf + XDIR_FstClus, 0); /* Reset file allocation info */ - st_qword(fs->dirbuf + XDIR_FileSize, 0); - st_qword(fs->dirbuf + XDIR_ValidFileSize, 0); + init_alloc_info(fs, &fp->obj); + /* Set directory entry block initial state */ + mem_set(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ + mem_set(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ + fs->dirbuf[XDIR_Attr] = AM_ARC; + st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); fs->dirbuf[XDIR_GenFlags] = 1; res = store_xdir(&dj); - if (res == FR_OK && fp->obj.sclust) { /* Remove the cluster chain if exist */ + if (res == FR_OK && fp->obj.sclust != 0) { /* Remove the cluster chain if exist */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ } } else #endif { - /* Clean directory info */ - st_dword(dj.dir + DIR_CrtTime, dw); /* Set created time */ - st_dword(dj.dir + DIR_ModTime, dw); /* Set modified time */ + /* Set directory entry initial state */ + cl = ld_clust(fs, dj.dir); /* Get current cluster chain */ + st_dword(dj.dir + DIR_CrtTime, GET_FATTIME()); /* Set created time */ dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ - cl = ld_clust(fs, dj.dir); /* Get cluster chain */ st_clust(fs, dj.dir, 0); /* Reset file allocation info */ st_dword(dj.dir + DIR_FileSize, 0); fs->wflag = 1; - - if (cl) { /* Remove the cluster chain if exist */ + if (cl != 0) { /* Remove the cluster chain if exist */ dw = fs->winsect; res = remove_chain(&dj.obj, cl, 0); if (res == FR_OK) { @@ -3236,32 +3510,31 @@ FRESULT f_open ( } } else { /* Open an existing file */ - if (res == FR_OK) { /* Following succeeded */ - if (dj.obj.attr & AM_DIR) { /* It is a directory */ + if (res == FR_OK) { /* Is the object exsiting? */ + if (dj.obj.attr & AM_DIR) { /* File open against a directory */ res = FR_NO_FILE; } else { - if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* R/O violation */ + if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* Write mode open against R/O file */ res = FR_DENIED; } } } } if (res == FR_OK) { - if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ - mode |= FA_MODIFIED; + if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dj.dir; -#if _FS_LOCK != 0 - fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); - if (!fp->obj.lockid) res = FR_INT_ERR; +#if FF_FS_LOCK != 0 + fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ + if (fp->obj.lockid == 0) res = FR_INT_ERR; #endif } #else /* R/O configuration */ if (res == FR_OK) { - if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it origin directory itself? */ res = FR_INVALID_NAME; } else { - if (dj.obj.attr & AM_DIR) { /* It is a directory */ + if (dj.obj.attr & AM_DIR) { /* Is it a directory? */ res = FR_NO_FILE; } } @@ -3269,21 +3542,19 @@ FRESULT f_open ( #endif if (res == FR_OK) { -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get allocation info */ - fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); - fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; - fp->obj.c_scl = dj.obj.sclust; + fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; fp->obj.c_ofs = dj.blk_ofs; + init_alloc_info(fs, &fp->obj); } else #endif { - fp->obj.sclust = ld_clust(fs, dj.dir); /* Get allocation info */ + fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); } -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK fp->cltbl = 0; /* Disable fast seek mode */ #endif fp->obj.fs = fs; /* Validate the file object */ @@ -3292,9 +3563,9 @@ FRESULT f_open ( fp->err = 0; /* Clear error flag */ fp->sect = 0; /* Invalidate current data sector */ fp->fptr = 0; /* Set file pointer top of the file */ -#if !_FS_READONLY -#if !_FS_TINY - mem_set(fp->buf, 0, _MAX_SS); /* Clear sector buffer */ +#if !FF_FS_READONLY +#if !FF_FS_TINY + mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */ #endif if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ fp->fptr = fp->obj.objsize; /* Offset to seek */ @@ -3307,11 +3578,11 @@ FRESULT f_open ( } fp->clust = clst; if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ - if ((sc = clust2sect(fs, clst)) == 0) { + if ((sc = clst2sect(fs, clst)) == 0) { res = FR_INT_ERR; } else { fp->sect = sc + (DWORD)(ofs / SS(fs)); -#if !_FS_TINY +#if !FF_FS_TINY if (disk_read(fs->drv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; #endif } @@ -3357,15 +3628,15 @@ FRESULT f_read ( remain = fp->obj.objsize - fp->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ - for ( ; btr; /* Repeat until all data read */ - rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { + for ( ; btr; /* Repeat until btr bytes read */ + btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow cluster chain from the origin */ } else { /* Middle or end of the file */ -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ } else @@ -3378,17 +3649,17 @@ FRESULT f_read ( if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ } - sect = clust2sect(fs, fp->clust); /* Get current sector */ - if (!sect) ABORT(fs, FR_INT_ERR); + sect = clst2sect(fs, fp->clust); /* Get current sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btr / SS(fs); /* When remaining bytes >= sector size, */ - if (cc) {/* Read maximum contiguous sectors directly */ + if (cc > 0) { /* Read maximum contiguous sectors directly */ if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); -#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ -#if _FS_TINY +#if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ +#if FF_FS_TINY if (fs->wflag && fs->winsect - sect < cc) { mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); } @@ -3401,22 +3672,22 @@ FRESULT f_read ( rcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } -#if !_FS_TINY +#if !FF_FS_TINY if (fp->sect != sect) { /* Load data sector if not in cache */ -#if !_FS_READONLY +#if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } #endif fp->sect = sect; } rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ -#if _FS_TINY +#if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #else @@ -3430,7 +3701,7 @@ FRESULT f_read ( -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Write File */ /*-----------------------------------------------------------------------*/ @@ -3454,13 +3725,13 @@ FRESULT f_write ( if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - /* Check fptr wrap-around (file size cannot reach 4GiB on FATxx) */ - if ((!_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { + /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ + if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); } for ( ; btw; /* Repeat until all data written */ - wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize, *bw += wcnt, btw -= wcnt) { + btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) { if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ @@ -3470,7 +3741,7 @@ FRESULT f_write ( clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ } } else { /* On the middle or end of the file */ -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ } else @@ -3485,7 +3756,7 @@ FRESULT f_write ( fp->clust = clst; /* Update current cluster */ if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ } -#if _FS_TINY +#if FF_FS_TINY if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ #else if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ @@ -3493,17 +3764,17 @@ FRESULT f_write ( fp->flag &= (BYTE)~FA_DIRTY; } #endif - sect = clust2sect(fs, fp->clust); /* Get current sector */ - if (!sect) ABORT(fs, FR_INT_ERR); + sect = clst2sect(fs, fp->clust); /* Get current sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btw / SS(fs); /* When remaining bytes >= sector size, */ - if (cc) { /* Write maximum contiguous sectors directly */ + if (cc > 0) { /* Write maximum contiguous sectors directly */ if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); -#if _FS_MINIMIZE <= 2 -#if _FS_TINY +#if FF_FS_MINIMIZE <= 2 +#if FF_FS_TINY if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); fs->wflag = 0; @@ -3518,7 +3789,7 @@ FRESULT f_write ( wcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } -#if _FS_TINY +#if FF_FS_TINY if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); fs->winsect = sect; @@ -3534,7 +3805,7 @@ FRESULT f_write ( } wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ -#if _FS_TINY +#if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ fs->wflag = 1; @@ -3564,15 +3835,12 @@ FRESULT f_sync ( FATFS *fs; DWORD tm; BYTE *dir; -#if _FS_EXFAT - DEF_NAMBUF -#endif res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ -#if !_FS_TINY +#if !FF_FS_TINY if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; @@ -3580,17 +3848,21 @@ FRESULT f_sync ( #endif /* Update the directory entry */ tm = GET_FATTIME(); /* Modified time */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - res = fill_fat_chain(&fp->obj); /* Create FAT chain if needed */ + res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ + if (res == FR_OK) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } if (res == FR_OK) { DIR dj; + DEF_NAMBUF INIT_NAMBUF(fs); - res = load_obj_dir(&dj, &fp->obj); /* Load directory entry block */ + res = load_obj_xdir(&dj, &fp->obj); /* Load directory entry block */ if (res == FR_OK) { - fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive bit */ - fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation info */ + fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ + fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation information */ st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); @@ -3611,8 +3883,8 @@ FRESULT f_sync ( res = move_window(fs, fp->dir_sect); if (res == FR_OK) { dir = fp->dir_ptr; - dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ - st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation info */ + dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ + st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ st_dword(dir + DIR_ModTime, tm); /* Update modified time */ st_word(dir + DIR_LstAccDate, 0); @@ -3627,7 +3899,7 @@ FRESULT f_sync ( LEAVE_FF(fs, res); } -#endif /* !_FS_READONLY */ +#endif /* !FF_FS_READONLY */ @@ -3643,21 +3915,20 @@ FRESULT f_close ( FRESULT res; FATFS *fs; -#if !_FS_READONLY +#if !FF_FS_READONLY res = f_sync(fp); /* Flush cached data */ if (res == FR_OK) #endif { res = validate(&fp->obj, &fs); /* Lock volume */ if (res == FR_OK) { -#if _FS_LOCK != 0 - res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ - if (res == FR_OK) +#if FF_FS_LOCK != 0 + res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ + if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ +#else + fp->obj.fs = 0; /* Invalidate file object */ #endif - { - fp->obj.fs = 0; /* Invalidate file object */ - } -#if _FS_REENTRANT +#if FF_FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif } @@ -3668,7 +3939,7 @@ FRESULT f_close ( -#if _FS_RPATH >= 1 +#if FF_FS_RPATH >= 1 /*-----------------------------------------------------------------------*/ /* Change Current Directory or Current Drive, Get Current Directory */ /*-----------------------------------------------------------------------*/ @@ -3678,10 +3949,14 @@ FRESULT f_chdir ( const TCHAR* path /* Pointer to the directory path */ ) { +#if FF_STR_VOLUME_ID == 2 + UINT i; +#endif FRESULT res; DIR dj; DEF_NAMBUF + /* Get logical drive */ res = find_volume(fs, 0); if (res == FR_OK) { @@ -3689,9 +3964,9 @@ FRESULT f_chdir ( INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the path */ if (res == FR_OK) { /* Follow completed */ - if (dj.fn[NSFLAG] & NS_NONAME) { - fs->cdir = dj.obj.sclust; /* It is the start directory itself */ -#if _FS_EXFAT + if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it the start directory itself? */ + fs->cdir = dj.obj.sclust; +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->cdc_scl = dj.obj.c_scl; fs->cdc_size = dj.obj.c_size; @@ -3700,7 +3975,7 @@ FRESULT f_chdir ( #endif } else { if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ @@ -3718,36 +3993,50 @@ FRESULT f_chdir ( } FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; +#if FF_STR_VOLUME_ID == 2 /* Also current drive is changed at Unix style volume ID */ + if (res == FR_OK) { + for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ; /* Set current drive */ + CurrVol = (BYTE)i; + } +#endif } LEAVE_FF(fs, res); } -#if _FS_RPATH >= 2 +#if FF_FS_RPATH >= 2 FRESULT f_getcwd ( FATFS *fs, TCHAR* buff, /* Pointer to the directory path */ - UINT len /* Size of path */ + UINT len /* Size of buff in unit of TCHAR */ ) { FRESULT res; DIR dj; UINT i, n; DWORD ccl; - TCHAR *tp; + TCHAR *tp = buff; +#if FF_VOLUMES >= 2 + UINT vl; +#endif +#if FF_STR_VOLUME_ID + const char *vp; +#endif FILINFO fno; DEF_NAMBUF - *buff = 0; /* Get logical drive */ - res = find_volume(fs, 0); /* Get current volume */ + buff[0] = 0; /* Set null string to get current volume */ + res = find_volume(fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); + + /* Follow parent directories and create the path */ i = len; /* Bottom of buffer (directory stack base) */ - if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ @@ -3758,7 +4047,7 @@ FRESULT f_getcwd ( res = dir_sdi(&dj, 0); if (res != FR_OK) break; do { /* Find the entry links to the child directory */ - res = dir_read(&dj, 0); + res = DIR_READ_FILE(&dj); if (res != FR_OK) break; if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ res = dir_next(&dj, 0); @@ -3766,39 +4055,55 @@ FRESULT f_getcwd ( if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ if (res != FR_OK) break; get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ - for (n = 0; fno.fname[n]; n++) ; - if (i < n + 3) { + for (n = 0; fno.fname[n]; n++) ; /* Name length */ + if (i < n + 1) { /* Insufficient space to store the path name? */ res = FR_NOT_ENOUGH_CORE; break; } - while (n) buff[--i] = fno.fname[--n]; + while (n) buff[--i] = fno.fname[--n]; /* Stack the name */ buff[--i] = '/'; } } - tp = buff; if (res == FR_OK) { - if (i == len) { /* Root-directory */ - *tp++ = '/'; - } else { /* Sub-directroy */ - do /* Add stacked path str */ - *tp++ = buff[i++]; - while (i < len); + if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ +#if FF_VOLUMES >= 2 /* Put drive prefix */ + vl = 0; +#if FF_STR_VOLUME_ID >= 1 /* String volume ID */ + for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ; + if (i >= n + 2) { + if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/'; + for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ; + if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':'; + vl++; + } +#else /* Numeric volume ID */ + if (i >= 3) { + *tp++ = (TCHAR)'0' + CurrVol; + *tp++ = (TCHAR)':'; + vl = 2; + } +#endif + if (vl == 0) res = FR_NOT_ENOUGH_CORE; +#endif + /* Add current directory path */ + if (res == FR_OK) { + do *tp++ = buff[i++]; while (i < len); /* Copy stacked path string */ } } - *tp = 0; FREE_NAMBUF(); } + *tp = 0; LEAVE_FF(fs, res); } -#endif /* _FS_RPATH >= 2 */ -#endif /* _FS_RPATH >= 1 */ +#endif /* FF_FS_RPATH >= 2 */ +#endif /* FF_FS_RPATH >= 1 */ -#if _FS_MINIMIZE <= 2 +#if FF_FS_MINIMIZE <= 2 /*-----------------------------------------------------------------------*/ -/* Seek File R/W Pointer */ +/* Seek File Read/Write Pointer */ /*-----------------------------------------------------------------------*/ FRESULT f_lseek ( @@ -3810,19 +4115,26 @@ FRESULT f_lseek ( FATFS *fs; DWORD clst, bcs, nsect; FSIZE_t ifptr; -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; #endif res = validate(&fp->obj, &fs); /* Check validity of the file object */ - if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ -#if _USE_FASTSEEK + if (res == FR_OK) res = (FRESULT)fp->err; +#if FF_FS_EXFAT && !FF_FS_READONLY + if (res == FR_OK && fs->fs_type == FS_EXFAT) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } +#endif + if (res != FR_OK) LEAVE_FF(fs, res); + +#if FF_USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ if (ofs == CREATE_LINKMAP) { /* Create CLMT */ tbl = fp->cltbl; tlen = *tbl++; ulen = 2; /* Given table size and required table size */ cl = fp->obj.sclust; /* Origin of the chain */ - if (cl) { + if (cl != 0) { do { /* Get a fragment */ tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ @@ -3846,20 +4158,20 @@ FRESULT f_lseek ( } else { /* Fast seek */ if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ fp->fptr = ofs; /* Set file pointer */ - if (ofs) { + if (ofs > 0) { fp->clust = clmt_clust(fp, ofs - 1); - dsc = clust2sect(fs, fp->clust); - if (!dsc) ABORT(fs, FR_INT_ERR); + dsc = clst2sect(fs, fp->clust); + if (dsc == 0) ABORT(fs, FR_INT_ERR); dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ -#if !_FS_TINY -#if !_FS_READONLY +#if !FF_FS_TINY +#if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ + if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ #endif fp->sect = dsc; } @@ -3870,15 +4182,15 @@ FRESULT f_lseek ( /* Normal Seek */ { -#if _FS_EXFAT - if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4GiB-1 if at FATxx */ +#if FF_FS_EXFAT + if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4 GiB - 1 if at FATxx */ #endif - if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ + if (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ ofs = fp->obj.objsize; } ifptr = fp->fptr; fp->fptr = nsect = 0; - if (ofs) { + if (ofs > 0) { bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ if (ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ @@ -3887,7 +4199,7 @@ FRESULT f_lseek ( clst = fp->clust; } else { /* When seek to back cluster, */ clst = fp->obj.sclust; /* start from the first cluster */ -#if !_FS_READONLY +#if !FF_FS_READONLY if (clst == 0) { /* If no cluster chain, create a new chain */ clst = create_chain(&fp->obj, 0); if (clst == 1) ABORT(fs, FR_INT_ERR); @@ -3900,9 +4212,9 @@ FRESULT f_lseek ( if (clst != 0) { while (ofs > bcs) { /* Cluster following loop */ ofs -= bcs; fp->fptr += bcs; -#if !_FS_READONLY +#if !FF_FS_READONLY if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ - if (_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ + if (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ fp->obj.objsize = fp->fptr; fp->flag |= FA_MODIFIED; } @@ -3921,25 +4233,25 @@ FRESULT f_lseek ( } fp->fptr += ofs; if (ofs % SS(fs)) { - nsect = clust2sect(fs, clst); /* Current sector */ - if (!nsect) ABORT(fs, FR_INT_ERR); + nsect = clst2sect(fs, clst); /* Current sector */ + if (nsect == 0) ABORT(fs, FR_INT_ERR); nsect += (DWORD)(ofs / SS(fs)); } } } - if (!_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ + if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ fp->obj.objsize = fp->fptr; fp->flag |= FA_MODIFIED; } if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ -#if !_FS_TINY -#if !_FS_READONLY +#if !FF_FS_TINY +#if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ #endif fp->sect = nsect; } @@ -3950,7 +4262,7 @@ FRESULT f_lseek ( -#if _FS_MINIMIZE <= 1 +#if FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Create a Directory Object */ /*-----------------------------------------------------------------------*/ @@ -3962,49 +4274,45 @@ FRESULT f_opendir ( ) { FRESULT res; - _FDID *obj; DEF_NAMBUF if (!dp) return FR_INVALID_OBJECT; /* Get logical drive */ - obj = &dp->obj; res = find_volume(fs, 0); if (res == FR_OK) { - obj->fs = fs; + dp->obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(dp, path); /* Follow the path to the directory */ if (res == FR_OK) { /* Follow completed */ if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ - if (obj->attr & AM_DIR) { /* This object is a sub-directory */ -#if _FS_EXFAT + if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - obj->c_scl = obj->sclust; /* Save containing directory inforamation */ - obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; - obj->c_ofs = dp->blk_ofs; - obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object location and status */ - obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); - obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ + dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; + dp->obj.c_ofs = dp->blk_ofs; + init_alloc_info(fs, &dp->obj); /* Get object allocation info */ } else #endif { - obj->sclust = ld_clust(fs, dp->dir); /* Get object location */ + dp->obj.sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ } } else { /* This object is a file */ res = FR_NO_PATH; } } if (res == FR_OK) { - obj->id = fs->id; + dp->obj.id = fs->id; res = dir_sdi(dp, 0); /* Rewind directory */ -#if _FS_LOCK != 0 +#if FF_FS_LOCK != 0 if (res == FR_OK) { - if (obj->sclust) { - obj->lockid = inc_lock(dp, 0); /* Lock the sub directory */ - if (!obj->lockid) res = FR_TOO_MANY_OPEN_FILES; + if (dp->obj.sclust != 0) { + dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ + if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; } else { - obj->lockid = 0; /* Root directory need not to be locked */ + dp->obj.lockid = 0; /* Root directory need not to be locked */ } } #endif @@ -4013,7 +4321,7 @@ FRESULT f_opendir ( FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } - if (res != FR_OK) obj->fs = 0; /* Invalidate the directory object if function faild */ + if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ LEAVE_FF(fs, res); } @@ -4033,18 +4341,15 @@ FRESULT f_closedir ( FATFS *fs; - res = validate(&dp->obj, &fs); /* Check validity of the file object */ + res = validate(&dp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { -#if _FS_LOCK != 0 - if (dp->obj.lockid) { /* Decrement sub-directory open counter */ - res = dec_lock(dp->obj.lockid); - } - if (res == FR_OK) +#if FF_FS_LOCK != 0 + if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ + if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ +#else + dp->obj.fs = 0; /* Invalidate directory object */ #endif - { - dp->obj.fs = 0; /* Invalidate directory object */ - } -#if _FS_REENTRANT +#if FF_FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif } @@ -4074,7 +4379,7 @@ FRESULT f_readdir ( res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { INIT_NAMBUF(fs); - res = dir_read(dp, 0); /* Read an item */ + res = DIR_READ_FILE(dp); /* Read an item */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ get_fileinfo(dp, fno); /* Get the object information */ @@ -4089,7 +4394,7 @@ FRESULT f_readdir ( -#if _USE_FIND +#if FF_USE_FIND /*-----------------------------------------------------------------------*/ /* Find Next File */ /*-----------------------------------------------------------------------*/ @@ -4106,7 +4411,7 @@ FRESULT f_findnext ( res = f_readdir(dp, fno); /* Get a directory item */ if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ -#if _USE_LFN != 0 && _USE_FIND == 2 +#if FF_USE_LFN && FF_USE_FIND == 2 if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ #endif } @@ -4137,11 +4442,11 @@ FRESULT f_findfirst ( return res; } -#endif /* _USE_FIND */ +#endif /* FF_USE_FIND */ -#if _FS_MINIMIZE == 0 +#if FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Get File Status */ /*-----------------------------------------------------------------------*/ @@ -4178,7 +4483,7 @@ FRESULT f_stat ( -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Get Number of Free Clusters */ /*-----------------------------------------------------------------------*/ @@ -4191,20 +4496,19 @@ FRESULT f_getfree ( FRESULT res; DWORD nfree, clst, sect, stat; UINT i; - BYTE *p; - _FDID obj; + FFOBJID obj; /* Get logical drive */ res = find_volume(fs, 0); if (res == FR_OK) { - /* If free_clst is valid, return it without full cluster scan */ + /* If free_clst is valid, return it without full FAT scan */ if (fs->free_clst <= fs->n_fatent - 2) { *nclst = fs->free_clst; } else { - /* Get number of free clusters */ + /* Scan FAT to obtain number of free clusters */ nfree = 0; - if (fs->fs_type == FS_FAT12) { /* FAT12: Sector unalighed FAT entries */ + if (fs->fs_type == FS_FAT12) { /* FAT12: Scan bit field FAT entries */ clst = 2; obj.fs = fs; do { stat = get_fat(&obj, clst); @@ -4213,16 +4517,19 @@ FRESULT f_getfree ( if (stat == 0) nfree++; } while (++clst < fs->n_fatent); } else { -#if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan bitmap table */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan allocation bitmap */ BYTE bm; UINT b; - clst = fs->n_fatent - 2; - sect = fs->database; - i = 0; - do { - if (i == 0 && (res = move_window(fs, sect++)) != FR_OK) break; + clst = fs->n_fatent - 2; /* Number of clusters */ + sect = fs->bitbase; /* Bitmap sector */ + i = 0; /* Offset in the sector */ + do { /* Counts numbuer of bits with zero in the bitmap */ + if (i == 0) { + res = move_window(fs, sect++); + if (res != FR_OK) break; + } for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { if (!(bm & 1)) nfree++; bm >>= 1; @@ -4231,29 +4538,29 @@ FRESULT f_getfree ( } while (clst); } else #endif - { /* FAT16/32: Sector alighed FAT entries */ - clst = fs->n_fatent; sect = fs->fatbase; - i = 0; p = 0; - do { + { /* FAT16/32: Scan WORD/DWORD FAT entries */ + clst = fs->n_fatent; /* Number of entries */ + sect = fs->fatbase; /* Top of the FAT */ + i = 0; /* Offset in the sector */ + do { /* Counts numbuer of entries with zero in the FAT */ if (i == 0) { res = move_window(fs, sect++); if (res != FR_OK) break; - p = fs->win; - i = SS(fs); } if (fs->fs_type == FS_FAT16) { - if (ld_word(p) == 0) nfree++; - p += 2; i -= 2; + if (ld_word(fs->win + i) == 0) nfree++; + i += 2; } else { - if ((ld_dword(p) & 0x0FFFFFFF) == 0) nfree++; - p += 4; i -= 4; + if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; + i += 4; } + i %= SS(fs); } while (--clst); } } *nclst = nfree; /* Return the free clusters */ fs->free_clst = nfree; /* Now free_clst is valid */ - fs->fsi_flag |= 1; /* FSInfo is to be updated */ + fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ } } @@ -4280,7 +4587,7 @@ FRESULT f_truncate ( if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - if (fp->obj.objsize > fp->fptr) { + if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fp->obj.sclust = 0; @@ -4293,9 +4600,9 @@ FRESULT f_truncate ( res = remove_chain(&fp->obj, ncl, fp->clust); } } - fp->obj.objsize = fp->fptr; /* Set file size to current R/W point */ + fp->obj.objsize = fp->fptr; /* Set file size to current read/write point */ fp->flag |= FA_MODIFIED; -#if !_FS_TINY +#if !FF_FS_TINY if (res == FR_OK && (fp->flag & FA_DIRTY)) { if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { res = FR_DISK_ERR; @@ -4325,22 +4632,22 @@ FRESULT f_unlink ( FRESULT res; DIR dj, sdj; DWORD dclst = 0; -#if _FS_EXFAT - _FDID obj; +#if FF_FS_EXFAT + FFOBJID obj; #endif DEF_NAMBUF /* Get logical drive */ res = find_volume(fs, FA_WRITE); - dj.obj.fs = fs; if (res == FR_OK) { + dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ - if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { + if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; /* Cannot remove dot entry */ } -#if _FS_LOCK != 0 +#if FF_FS_LOCK != 0 if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ #endif if (res == FR_OK) { /* The object is accessible */ @@ -4352,27 +4659,26 @@ FRESULT f_unlink ( } } if (res == FR_OK) { -#if _FS_EXFAT +#if FF_FS_EXFAT obj.fs = fs; if (fs->fs_type == FS_EXFAT) { - obj.sclust = dclst = ld_dword(fs->dirbuf + XDIR_FstClus); - obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); - obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + init_alloc_info(fs, &obj); + dclst = obj.sclust; } else #endif { dclst = ld_clust(fs, dj.dir); } - if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory ? */ -#if _FS_RPATH != 0 - if (dclst == fs->cdir) { /* Is it the current directory? */ + if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ +#if FF_FS_RPATH != 0 + if (dclst == fs->cdir) { /* Is it the current directory? */ res = FR_DENIED; } else #endif { - sdj.obj.fs = fs; /* Open the sub-directory */ + sdj.obj.fs = fs; /* Open the sub-directory */ sdj.obj.sclust = dclst; -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { sdj.obj.objsize = obj.objsize; sdj.obj.stat = obj.stat; @@ -4380,7 +4686,7 @@ FRESULT f_unlink ( #endif res = dir_sdi(&sdj, 0); if (res == FR_OK) { - res = dir_read(&sdj, 0); /* Read an item */ + res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */ if (res == FR_OK) res = FR_DENIED; /* Not empty? */ if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ } @@ -4389,8 +4695,8 @@ FRESULT f_unlink ( } if (res == FR_OK) { res = dir_remove(&dj); /* Remove the directory entry */ - if (res == FR_OK && dclst) { /* Remove the cluster chain if exist */ -#if _FS_EXFAT + if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ +#if FF_FS_EXFAT res = remove_chain(&obj, dclst, 0); #else res = remove_chain(&dj.obj, dclst, 0); @@ -4419,77 +4725,68 @@ FRESULT f_mkdir ( { FRESULT res; DIR dj; - BYTE *dir; - UINT n; - DWORD dsc, dcl, pcl, tm; + FFOBJID sobj; + DWORD dcl, pcl, tm; DEF_NAMBUF - /* Get logical drive */ - res = find_volume(fs, FA_WRITE); - dj.obj.fs = fs; + res = find_volume(fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { + dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ - if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ - if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { + if (res == FR_OK) res = FR_EXIST; /* Name collision? */ + if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */ res = FR_INVALID_NAME; } - if (res == FR_NO_FILE) { /* Can create a new directory */ - dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ - dj.obj.objsize = (DWORD)fs->csize * SS(fs); + if (res == FR_NO_FILE) { /* It is clear to create a new directory */ + sobj.fs = fs; /* New object id to create a new chain */ + dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ res = FR_OK; - if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ - if (dcl == 1) res = FR_INT_ERR; - if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (res == FR_OK) res = sync_window(fs); /* Flush FAT */ + if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */ + if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */ + if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */ tm = GET_FATTIME(); - if (res == FR_OK) { /* Initialize the new directory table */ - dsc = clust2sect(fs, dcl); - dir = fs->win; - mem_set(dir, 0, SS(fs)); - if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { - mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ - dir[DIR_Name] = '.'; - dir[DIR_Attr] = AM_DIR; - st_dword(dir + DIR_ModTime, tm); - st_clust(fs, dir, dcl); - mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ - dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; - if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase) pcl = 0; - st_clust(fs, dir + SZDIRE, pcl); - } - for (n = fs->csize; n; n--) { /* Write dot entries and clear following sectors */ - fs->winsect = dsc++; - fs->wflag = 1; - res = sync_window(fs); - if (res != FR_OK) break; - mem_set(dir, 0, SS(fs)); + if (res == FR_OK) { + res = dir_clear(fs, dcl); /* Clean up the new table */ + if (res == FR_OK) { + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */ + mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */ + fs->win[DIR_Name] = '.'; + fs->win[DIR_Attr] = AM_DIR; + st_dword(fs->win + DIR_ModTime, tm); + st_clust(fs, fs->win, dcl); + mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */ + fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; + st_clust(fs, fs->win + SZDIRE, pcl); + fs->wflag = 1; + } + res = dir_register(&dj); /* Register the object to the parent directoy */ } } - if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ if (res == FR_OK) { -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ - st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ - st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); - fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag (contiguous) */ + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* File size needs to be valid */ + st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs)); + fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ res = store_xdir(&dj); } else #endif { - dir = dj.dir; - st_dword(dir + DIR_ModTime, tm); /* Created time */ - st_clust(fs, dir, dcl); /* Table start cluster */ - dir[DIR_Attr] = AM_DIR; /* Attribute */ + st_dword(dj.dir + DIR_ModTime, tm); /* Created time */ + st_clust(fs, dj.dir, dcl); /* Table start cluster */ + dj.dir[DIR_Attr] = AM_DIR; /* Attribute */ fs->wflag = 1; } - if (res == FR_OK) res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } else { - remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ + remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */ } } FREE_NAMBUF(); @@ -4513,23 +4810,25 @@ FRESULT f_rename ( { FRESULT res; DIR djo, djn; - BYTE buf[_FS_EXFAT ? SZDIRE * 2 : 24], *dir; + BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; DWORD dw; DEF_NAMBUF - res = find_volume(fs, FA_WRITE); + res = find_volume(fs, FA_WRITE); /* Get logical drive of the old object */ if (res == FR_OK) { djo.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ -#if _FS_LOCK != 0 - if (res == FR_OK) res = chk_lock(&djo, 2); +#if FF_FS_LOCK != 0 + if (res == FR_OK) { + res = chk_lock(&djo, 2); + } #endif if (res == FR_OK) { /* Object to be renamed is found */ -#if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At exFAT */ +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ BYTE nf, nn; WORD nh; @@ -4544,17 +4843,18 @@ FRESULT f_rename ( if (res == FR_OK) { nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; nh = ld_word(fs->dirbuf + XDIR_NameHash); - mem_cpy(fs->dirbuf, buf, SZDIRE * 2); + mem_cpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; st_word(fs->dirbuf + XDIR_NameHash, nh); -/* Start of critical section where any interruption can cause a cross-link */ + if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ +/* Start of critical section where an interruption can cause a cross-link */ res = store_xdir(&djn); } } } else #endif - { /* At FAT12/FAT16/FAT32 */ - mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about the object except name */ + { /* At FAT/FAT32 volume */ + mem_cpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ if (res == FR_OK) { /* Is new name already in use by any other object? */ @@ -4563,16 +4863,17 @@ FRESULT f_rename ( if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { - dir = djn.dir; /* Copy information about object except name */ - mem_cpy(dir + 13, buf + 2, 19); - dir[DIR_Attr] = buf[0] | AM_ARC; + dir = djn.dir; /* Copy directory entry of the object except name */ + mem_cpy(dir + 13, buf + 13, SZDIRE - 13); + dir[DIR_Attr] = buf[DIR_Attr]; + if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ fs->wflag = 1; if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ - dw = clust2sect(fs, ld_clust(fs, dir)); - if (!dw) { + dw = clst2sect(fs, ld_clust(fs, dir)); + if (dw == 0) { res = FR_INT_ERR; } else { -/* Start of critical section where any interruption can cause a cross-link */ +/* Start of critical section where an interruption can cause a cross-link */ res = move_window(fs, dw); dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ if (res == FR_OK && dir[1] == '.') { @@ -4590,7 +4891,7 @@ FRESULT f_rename ( res = sync_fs(fs); } } -/* End of critical section */ +/* End of the critical section */ } FREE_NAMBUF(); } @@ -4598,14 +4899,14 @@ FRESULT f_rename ( LEAVE_FF(fs, res); } -#endif /* !_FS_READONLY */ -#endif /* _FS_MINIMIZE == 0 */ -#endif /* _FS_MINIMIZE <= 1 */ -#endif /* _FS_MINIMIZE <= 2 */ +#endif /* !FF_FS_READONLY */ +#endif /* FF_FS_MINIMIZE == 0 */ +#endif /* FF_FS_MINIMIZE <= 1 */ +#endif /* FF_FS_MINIMIZE <= 2 */ -#if _USE_CHMOD && !_FS_READONLY +#if FF_USE_CHMOD && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Change Attribute */ /*-----------------------------------------------------------------------*/ @@ -4623,14 +4924,14 @@ FRESULT f_chmod ( res = find_volume(fs, FA_WRITE); /* Get logical drive */ - dj.obj.fs = fs; if (res == FR_OK) { + dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ res = store_xdir(&dj); @@ -4640,7 +4941,9 @@ FRESULT f_chmod ( dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ fs->wflag = 1; } - if (res == FR_OK) res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } FREE_NAMBUF(); } @@ -4658,7 +4961,7 @@ FRESULT f_chmod ( FRESULT f_utime ( FATFS *fs, const TCHAR* path, /* Pointer to the file/directory name */ - const FILINFO* fno /* Pointer to the time stamp to be set */ + const FILINFO* fno /* Pointer to the timestamp to be set */ ) { FRESULT res; @@ -4667,13 +4970,13 @@ FRESULT f_utime ( res = find_volume(fs, FA_WRITE); /* Get logical drive */ - dj.obj.fs = fs; if (res == FR_OK) { + dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); res = store_xdir(&dj); @@ -4683,7 +4986,9 @@ FRESULT f_utime ( st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); fs->wflag = 1; } - if (res == FR_OK) res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } FREE_NAMBUF(); } @@ -4691,27 +4996,25 @@ FRESULT f_utime ( LEAVE_FF(fs, res); } -#endif /* _USE_CHMOD && !_FS_READONLY */ +#endif /* FF_USE_CHMOD && !FF_FS_READONLY */ -#if _USE_LABEL +#if FF_USE_LABEL /*-----------------------------------------------------------------------*/ /* Get Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_getlabel ( FATFS *fs, - TCHAR* label, /* Pointer to a buffer to return the volume label */ - DWORD* vsn /* Pointer to a variable to return the volume serial number */ + TCHAR* label, /* Buffer to store the volume label */ + DWORD* vsn /* Variable to store the volume serial number */ ) { FRESULT res; DIR dj; UINT si, di; -#if _LFN_UNICODE || _FS_EXFAT - WCHAR w; -#endif + WCHAR wc; /* Get logical drive */ res = find_volume(fs, 0); @@ -4721,37 +5024,40 @@ FRESULT f_getlabel ( dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read(&dj, 1); /* Find a volume label entry */ + res = DIR_READ_LABEL(&dj); /* Find a volume label entry */ if (res == FR_OK) { -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - for (si = di = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ - w = ld_word(dj.dir + XDIR_Label + si * 2); -#if _LFN_UNICODE - label[di++] = w; -#else - w = ff_convert(w, 0); /* Unicode -> OEM */ - if (w == 0) w = '?'; /* Replace wrong character */ - if (_DF1S && w >= 0x100) label[di++] = (char)(w >> 8); - label[di++] = (char)w; -#endif + WCHAR hs; + + for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ + wc = ld_word(dj.dir + XDIR_Label + si * 2); + if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ + hs = wc; continue; + } + wc = put_utf((DWORD)hs << 16 | wc, &label[di], 4); + if (wc == 0) { di = 0; break; } + di += wc; + hs = 0; } + if (hs != 0) di = 0; /* Broken surrogate pair? */ label[di] = 0; } else #endif { - si = di = 0; /* Extract volume label from AM_VOL entry with code comversion */ - do { -#if _LFN_UNICODE - w = (si < 11) ? dj.dir[si++] : ' '; - if (IsDBCS1(w) && si < 11 && IsDBCS2(dj.dir[si])) { - w = w << 8 | dj.dir[si++]; - } - label[di++] = ff_convert(w, 1); /* OEM -> Unicode */ -#else - label[di++] = dj.dir[si++]; + si = di = 0; /* Extract volume label from AM_VOL entry */ + while (si < 11) { + wc = dj.dir[si++]; +#if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ + if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ + wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ + if (wc != 0) wc = put_utf(wc, &label[di], 4); /* Put it in Unicode */ + if (wc == 0) { di = 0; break; } + di += wc; +#else /* ANSI/OEM output */ + label[di++] = (TCHAR)wc; #endif - } while (di < 11); + } do { /* Truncate trailing spaces */ label[di] = 0; if (di == 0) break; @@ -4770,9 +5076,14 @@ FRESULT f_getlabel ( res = move_window(fs, fs->volbase); if (res == FR_OK) { switch (fs->fs_type) { - case FS_EXFAT: di = BPB_VolIDEx; break; - case FS_FAT32: di = BS_VolID32; break; - default: di = BS_VolID; + case FS_EXFAT: + di = BPB_VolIDEx; break; + + case FS_FAT32: + di = BS_VolID32; break; + + default: + di = BS_VolID; } *vsn = ld_dword(fs->win + di); } @@ -4783,95 +5094,88 @@ FRESULT f_getlabel ( -#if !_FS_READONLY +#if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Set Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_setlabel ( FATFS *fs, - const TCHAR* label /* Pointer to the volume label to set */ + const TCHAR* label /* Volume label to set with heading logical drive number */ ) { FRESULT res; DIR dj; BYTE dirvn[22]; - UINT i, j, slen; - WCHAR w; - static const char badchr[] = "\"*+,.:;<=>\?[]|\x7F"; - + UINT di; + WCHAR wc; + static const char badchr[] = "+.,;=[]/\\\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */ +#if FF_USE_LFN + DWORD dc; +#endif /* Get logical drive */ res = find_volume(fs, FA_WRITE); if (res != FR_OK) LEAVE_FF(fs, res); - dj.obj.fs = fs; - /* Get length of given volume label */ - for (slen = 0; (UINT)label[slen] >= ' '; slen++) { } /* Get name length */ - -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - for (i = j = 0; i < slen; ) { /* Create volume label in directory form */ - w = label[i++]; -#if !_LFN_UNICODE - if (IsDBCS1(w)) { - w = (i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; + mem_set(dirvn, 0, 22); + di = 0; + while ((UINT)*label >= ' ') { /* Create volume label */ + dc = tchar2uni(&label); /* Get a Unicode character */ + if (dc >= 0x10000) { + if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ + dc = 0; + } else { + st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; + } } - w = ff_convert(w, 1); -#endif - if (w == 0 || chk_chr(badchr, w) || j == 22) { /* Check validity check validity of the volume label */ + if (dc == 0 || chk_chr(badchr + 7, (int)dc) || di >= 11) { /* Check validity of the volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } - st_word(dirvn + j, w); j += 2; + st_word(dirvn + di * 2, (WCHAR)dc); di++; } - slen = j; } else #endif - { /* On the FAT12/16/32 volume */ - for ( ; slen && label[slen - 1] == ' '; slen--) ; /* Remove trailing spaces */ - if (slen) { /* Is there a volume label to be set? */ - dirvn[0] = 0; i = j = 0; /* Create volume label in directory form */ - do { -#if _LFN_UNICODE - w = ff_convert(ff_wtoupper(label[i++]), 0); -#else - w = (BYTE)label[i++]; - if (IsDBCS1(w)) { - w = (j < 10 && i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; - } -#if _USE_LFN != 0 - w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); -#else - if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ -#ifdef _EXCVT - if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ -#else - if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ + { /* On the FAT/FAT32 volume */ + mem_set(dirvn, ' ', 11); + di = 0; + while ((UINT)*label >= ' ') { /* Create volume label */ +#if FF_USE_LFN + dc = tchar2uni(&label); + wc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0; +#else /* ANSI/OEM input */ + wc = (BYTE)*label++; + if (dbc_1st((BYTE)wc)) wc = dbc_2nd((BYTE)*label) ? wc << 8 | (BYTE)*label++ : 0; + if (IsLower(wc)) wc -= 0x20; /* To upper ASCII characters */ +#if FF_CODE_PAGE == 0 + if (ExCvt && wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ +#elif FF_CODE_PAGE < 900 + if (wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ #endif #endif -#endif - if (w == 0 || chk_chr(badchr, w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ - LEAVE_FF(fs, FR_INVALID_NAME); - } - if (w >= 0x100) dirvn[j++] = (BYTE)(w >> 8); - dirvn[j++] = (BYTE)w; - } while (i < slen); - while (j < 11) dirvn[j++] = ' '; /* Fill remaining name field */ - if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + if (wc == 0 || chk_chr(badchr + 0, (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + if (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8); + dirvn[di++] = (BYTE)wc; } + if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + while (di && dirvn[di - 1] == ' ') di--; /* Snip trailing spaces */ } /* Set volume label */ - dj.obj.sclust = 0; /* Open root directory */ + dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read(&dj, 1); /* Get volume label entry */ + res = DIR_READ_LABEL(&dj); /* Get volume label entry */ if (res == FR_OK) { - if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { - dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); /* Change the volume label */ - mem_cpy(dj.dir + XDIR_Label, dirvn, slen); + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ + mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { - if (slen) { + if (di != 0) { mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ } else { dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ @@ -4879,17 +5183,17 @@ FRESULT f_setlabel ( } fs->wflag = 1; res = sync_fs(fs); - } else { /* No volume label entry is found or error */ + } else { /* No volume label entry or an error */ if (res == FR_NO_FILE) { res = FR_OK; - if (slen) { /* Create a volume label entry */ + if (di != 0) { /* Create a volume label entry */ res = dir_alloc(&dj, 1); /* Allocate an entry */ if (res == FR_OK) { - mem_set(dj.dir, 0, SZDIRE); /* Clear the entry */ - if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { - dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ - dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); - mem_cpy(dj.dir + XDIR_Label, dirvn, slen); + mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */ + dj.dir[XDIR_NumLabel] = (BYTE)di; + mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ mem_cpy(dj.dir, dirvn, 11); @@ -4905,12 +5209,12 @@ FRESULT f_setlabel ( LEAVE_FF(fs, res); } -#endif /* !_FS_READONLY */ -#endif /* _USE_LABEL */ +#endif /* !FF_FS_READONLY */ +#endif /* FF_USE_LABEL */ -#if _USE_EXPAND && !_FS_READONLY +#if FF_USE_EXPAND && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Allocate a Contiguous Blocks to the File */ /*-----------------------------------------------------------------------*/ @@ -4929,7 +5233,7 @@ FRESULT f_expand ( res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ #endif n = (DWORD)fs->csize * SS(fs); /* Cluster size */ @@ -4937,16 +5241,16 @@ FRESULT f_expand ( stcl = fs->last_clst; lclst = 0; if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; -#if _FS_EXFAT +#if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (res == FR_OK) { - if (opt) { + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ lclst = scl + tcl - 1; - } else { + } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } @@ -4966,14 +5270,14 @@ FRESULT f_expand ( } if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ } - if (res == FR_OK) { - if (opt) { + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); if (res != FR_OK) break; lclst = clst; } - } else { + } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } @@ -4981,12 +5285,12 @@ FRESULT f_expand ( if (res == FR_OK) { fs->last_clst = lclst; /* Set suggested start cluster to start next */ - if (opt) { + if (opt) { /* Is it allocated now? */ fp->obj.sclust = scl; /* Update object allocation information */ fp->obj.objsize = fsz; - if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ + if (FF_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ fp->flag |= FA_MODIFIED; - if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst -= tcl; fs->fsi_flag |= 1; } @@ -4996,13 +5300,13 @@ FRESULT f_expand ( LEAVE_FF(fs, res); } -#endif /* _USE_EXPAND && !_FS_READONLY */ +#endif /* FF_USE_EXPAND && !FF_FS_READONLY */ -#if _USE_FORWARD +#if FF_USE_FORWARD /*-----------------------------------------------------------------------*/ -/* Forward data to the stream directly */ +/* Forward Data to the Stream Directly */ /*-----------------------------------------------------------------------*/ FRESULT f_forward ( @@ -5040,15 +5344,15 @@ FRESULT f_forward ( fp->clust = clst; /* Update current cluster */ } } - sect = clust2sect(fs, fp->clust); /* Get current data sector */ - if (!sect) ABORT(fs, FR_INT_ERR); + sect = clst2sect(fs, fp->clust); /* Get current data sector */ + if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; -#if _FS_TINY +#if FF_FS_TINY if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ dbuf = fs->win; #else if (fp->sect != sect) { /* Fill sector cache with file data */ -#if !_FS_READONLY +#if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; @@ -5062,40 +5366,40 @@ FRESULT f_forward ( rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ - if (!rcnt) ABORT(fs, FR_INT_ERR); + if (rcnt == 0) ABORT(fs, FR_INT_ERR); } LEAVE_FF(fs, FR_OK); } -#endif /* _USE_FORWARD */ +#endif /* FF_USE_FORWARD */ -#if _USE_MKFS && !_FS_READONLY +#if FF_USE_MKFS && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Create FAT file system on the logical drive */ +/* Create an FAT/exFAT volume */ /*-----------------------------------------------------------------------*/ FRESULT f_mkfs ( FATFS *fs, BYTE opt, /* Format option */ - DWORD au, /* Size of allocation unit [byte] */ - void* work, /* Pointer to working buffer */ - UINT len /* Size of working buffer */ + DWORD au, /* Size of allocation unit (cluster) [byte] */ + void* work, /* Pointer to working buffer (null: use heap memory) */ + UINT len /* Size of working buffer [byte] */ ) { - const UINT n_fats = 1; /* Number of FATs for FAT12/16/32 volume (1 or 2) */ - const UINT n_rootdir = 512; /* Number of root directory entries for FAT12/16 volume */ - static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT12/16 volume (4Ks unit) */ + const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ + const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ + static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ BYTE fmt, sys, *buf, *pte, part; void *pdrv; - WORD ss; + WORD ss; /* Sector size */ DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ UINT i; DSTATUS stat; -#if _USE_TRIM || _FS_EXFAT +#if FF_USE_TRIM || FF_FS_EXFAT DWORD tbl[3]; #endif @@ -5110,70 +5414,78 @@ FRESULT f_mkfs ( if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ -#if _MAX_SS != _MIN_SS /* Get sector size of the medium */ +#if FF_MAX_SS != FF_MIN_SS /* Get sector size of the medium if variable sector size cfg. */ if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; - if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; + if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else - ss = _MAX_SS; + ss = FF_MAX_SS; #endif if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ au /= ss; /* Cluster size in unit of sector */ /* Get working buffer */ - buf = (BYTE*)work; /* Working buffer */ - sz_buf = len / ss; /* Size of working buffer (sector) */ - szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ - if (!szb_buf) return FR_MKFS_ABORTED; +#if FF_USE_LFN == 3 + if (!work) { /* Use heap memory for working buffer */ + for (szb_buf = MAX_MALLOC, buf = 0; szb_buf >= ss && (buf = ff_memalloc(szb_buf)) == 0; szb_buf /= 2) ; + sz_buf = szb_buf / ss; /* Size of working buffer (sector) */ + } else +#endif + { + buf = (BYTE*)work; /* Working buffer */ + sz_buf = len / ss; /* Size of working buffer (sector) */ + szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ + } + if (!buf || sz_buf == 0) return FR_NOT_ENOUGH_CORE; /* Determine where the volume to be located (b_vol, sz_vol) */ - if (_MULTI_PARTITION && part != 0) { + if (FF_MULTI_PARTITION && part != 0) { /* Get partition information from partition table in the MBR */ - if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Load MBR */ - if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; /* Check if MBR is valid */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load MBR */ + if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ pte = buf + (MBR_Table + (part - 1) * SZ_PTE); - if (!pte[PTE_System]) return FR_MKFS_ABORTED; /* No partition? */ + if (pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* No partition? */ b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ } else { /* Create a single-partition in this function */ - if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) return FR_DISK_ERR; + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ - if (sz_vol < b_vol) return FR_MKFS_ABORTED; + if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); sz_vol -= b_vol; /* Volume size */ } - if (sz_vol < 50) return FR_MKFS_ABORTED; /* Check if volume size is >=50s */ + if (sz_vol < 22) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=22s (minimum for ss=4096) */ /* Pre-determine the FAT type */ do { - if (_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ + if (FF_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */ fmt = FS_EXFAT; break; } } - if (au > 128) return FR_INVALID_PARAMETER; /* Too large au for FAT/FAT32 */ + if (au > 128) LEAVE_MKFS(FR_INVALID_PARAMETER); /* Too large au for FAT/FAT32 */ if (opt & FM_FAT32) { /* FAT32 possible? */ if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ fmt = FS_FAT32; break; } } - if (!(opt & FM_FAT)) return FR_INVALID_PARAMETER; /* no-FAT? */ + if (!(opt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */ fmt = FS_FAT16; } while (0); -#if _FS_EXFAT +#if FF_FS_EXFAT if (fmt == FS_EXFAT) { /* Create an exFAT volume */ DWORD szb_bit, szb_case, sum, nb, cl; WCHAR ch, si; UINT j, st; BYTE b; - if (sz_vol < 0x1000) return FR_MKFS_ABORTED; /* Too small volume? */ -#if _USE_TRIM - tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ + if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ +#if FF_USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area may be erased */ disk_ioctl(pdrv, CTRL_TRIM, tbl); #endif /* Determine FAT location, data location and number of clusters */ - if (!au) { /* au auto-selection */ + if (au == 0) { /* au auto-selection */ au = 8; if (sz_vol >= 0x80000) au = 64; /* >= 512Ks */ if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */ @@ -5181,10 +5493,10 @@ FRESULT f_mkfs ( b_fat = b_vol + 32; /* FAT start at offset 32 */ sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ - if (b_data >= sz_vol / 2) return FR_MKFS_ABORTED; /* Too small volume? */ + if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ - if (n_clst <16) return FR_MKFS_ABORTED; /* Too few clusters? */ - if (n_clst > MAX_EXFAT) return FR_MKFS_ABORTED; /* Too many clusters? */ + if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ + if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */ @@ -5192,11 +5504,11 @@ FRESULT f_mkfs ( /* Create a compressed up-case table */ sect = b_data + au * tbl[0]; /* Table start sector */ sum = 0; /* Table checksum to be stored in the 82 entry */ - st = si = i = j = szb_case = 0; + st = 0; si = 0; i = 0; j = 0; szb_case = 0; do { switch (st) { case 0: - ch = ff_wtoupper(si); /* Get an up-case char */ + ch = (WCHAR)ff_wtoupper(si); /* Get an up-case char */ if (ch != si) { si++; break; /* Store the up-case char if exist */ } @@ -5205,21 +5517,22 @@ FRESULT f_mkfs ( ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ } st = 1; /* Do not compress short run */ - /* continue */ + /* go to next case */ case 1: ch = si++; /* Fill the short run */ if (--j == 0) st = 0; break; + default: - ch = (WCHAR)j; si += j; /* Number of chars to skip */ + ch = (WCHAR)j; si += (WCHAR)j; /* Number of chars to skip */ st = 0; } sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); i += 2; szb_case += 2; - if (!si || i == szb_buf) { /* Write buffered data when buffer full or end of process */ + if (si == 0 || i == szb_buf) { /* Write buffered data when buffer full or end of process */ n = (i + ss - 1) / ss; - if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; i = 0; } } while (si); @@ -5232,9 +5545,9 @@ FRESULT f_mkfs ( do { mem_set(buf, 0, szb_buf); for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; - for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; + for (b = 1; nb != 0 && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ - if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); @@ -5248,31 +5561,31 @@ FRESULT f_mkfs ( st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; } do { /* Create chains of bitmap, up-case and root dir */ - while (nb && i < szb_buf) { /* Create a chain */ + while (nb != 0 && i < szb_buf) { /* Create a chain */ st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); i += 4; cl++; nb--; } - if (!nb && j < 3) nb = tbl[j++]; /* Next chain */ - } while (nb && i < szb_buf); + if (nb == 0 && j < 3) nb = tbl[j++]; /* Next chain */ + } while (nb != 0 && i < szb_buf); n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ - if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); /* Initialize the root directory */ mem_set(buf, 0, szb_buf); - buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ - buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ - st_dword(buf + SZDIRE * 1 + 20, 2); - st_dword(buf + SZDIRE * 1 + 24, szb_bit); - buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ - st_dword(buf + SZDIRE * 2 + 4, sum); - st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); - st_dword(buf + SZDIRE * 2 + 24, szb_case); + buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */ + buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ + st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ + st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ + buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ + st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ + st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ + st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ do { /* Fill root directory sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; - if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); mem_set(buf, 0, ss); sect += n; nsect -= n; } while (nsect); @@ -5291,7 +5604,7 @@ FRESULT f_mkfs ( st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ - st_word(buf + BPB_FSVerEx, 0x100); /* File system version (1.00) */ + st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem version (1.00) */ for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ buf[BPB_NumFATsEx] = 1; /* Number of FATs */ @@ -5301,33 +5614,33 @@ FRESULT f_mkfs ( for (i = sum = 0; i < ss; i++) { /* VBR checksum */ if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); } - if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Extended bootstrap record (+1..+8) */ mem_set(buf, 0, ss); st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ for (j = 1; j < 9; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ - if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* OEM/Reserved record (+9..+10) */ mem_set(buf, 0, ss); for ( ; j < 11; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ - if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* Sum record (+11) */ for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ - if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } } else -#endif /* _FS_EXFAT */ - { /* Create an FAT12/16/32 volume */ +#endif /* FF_FS_EXFAT */ + { /* Create an FAT/FAT32 volume */ do { pau = au; /* Pre-determine number of clusters and FAT sub-type */ if (fmt == FS_FAT32) { /* FAT32 volume */ - if (!pau) { /* au auto-selection */ + if (pau == 0) { /* au auto-selection */ n = sz_vol / 0x20000; /* Volume size in unit of 128KS */ for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ } @@ -5335,9 +5648,9 @@ FRESULT f_mkfs ( sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 32; /* Number of reserved sectors */ sz_dir = 0; /* No static directory */ - if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) return FR_MKFS_ABORTED; - } else { /* FAT12/16 volume */ - if (!pau) { /* au auto-selection */ + if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED); + } else { /* FAT volume */ + if (pau == 0) { /* au auto-selection */ n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ } @@ -5359,42 +5672,42 @@ FRESULT f_mkfs ( n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ sz_rsv += n; b_fat += n; - } else { /* FAT12/16: Expand FAT size */ + } else { /* FAT: Expand FAT size */ sz_fat += n / n_fats; } /* Determine number of clusters and final check of validity of the FAT sub-type */ - if (sz_vol < b_data + pau * 16 - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ + if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume */ n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau; if (fmt == FS_FAT32) { if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */ - if (!au && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ - return FR_MKFS_ABORTED; + if (au == 0 && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); } } if (fmt == FS_FAT16) { if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ - if (!au && (pau * 2) <= 64) { + if (au == 0 && (pau * 2) <= 64) { au = pau * 2; continue; /* Adjust cluster size and retry */ } if ((opt & FM_FAT32)) { fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */ } - if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ - return FR_MKFS_ABORTED; + if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); } if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ - if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ - return FR_MKFS_ABORTED; + if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + LEAVE_MKFS(FR_MKFS_ABORTED); } } - if (fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED; /* Too many clusters for FAT12 */ + if (fmt == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */ /* Ok, it is the valid cluster configuration */ break; } while (1); -#if _USE_TRIM +#if FF_USE_TRIM tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ disk_ioctl(pdrv, CTRL_TRIM, tbl); #endif @@ -5432,7 +5745,7 @@ FRESULT f_mkfs ( mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ } st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ - if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the VBR sector */ + if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ /* Create FSINFO record if needed */ if (fmt == FS_FAT32) { @@ -5461,7 +5774,7 @@ FRESULT f_mkfs ( nsect = sz_fat; /* Number of FAT sectors */ do { /* Fill FAT sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; - if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); mem_set(buf, 0, ss); sect += n; nsect -= n; } while (nsect); @@ -5471,34 +5784,34 @@ FRESULT f_mkfs ( nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ do { n = (nsect > sz_buf) ? sz_buf : nsect; - if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); } /* Determine system ID in the partition table */ - if (_FS_EXFAT && fmt == FS_EXFAT) { + if (FF_FS_EXFAT && fmt == FS_EXFAT) { sys = 0x07; /* HPFS/NTFS/exFAT */ } else { if (fmt == FS_FAT32) { sys = 0x0C; /* FAT32X */ } else { if (sz_vol >= 0x10000) { - sys = 0x06; /* FAT12/16 (>=64KS) */ + sys = 0x06; /* FAT12/16 (large) */ } else { - sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 (<64KS) : FAT12 (<64KS) */ + sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ } } } - if (_MULTI_PARTITION && part != 0) { + /* Update partition information */ + if (FF_MULTI_PARTITION && part != 0) { /* Created in the existing partition */ /* Update system ID in the partition table */ - if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Read the MBR */ - buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system type */ - if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it back to the MBR */ - } else { - if (!(opt & FM_SFD)) { - /* Create partition table in FDISK format */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ + buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ + } else { /* Created as a new single partition */ + if (!(opt & FM_SFD)) { /* Create partition table if in FDISK format */ mem_set(buf, 0, ss); st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ @@ -5507,38 +5820,39 @@ FRESULT f_mkfs ( pte[PTE_StSec] = 1; /* Start sector */ pte[PTE_StCyl] = 0; /* Start cylinder */ pte[PTE_System] = sys; /* System type */ - n = (b_vol + sz_vol) / (63 * 255); /* (End CHS is incorrect) */ + n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */ pte[PTE_EdHead] = 254; /* End head */ - pte[PTE_EdSec] = (BYTE)(n >> 2 | 63); /* End sector */ + pte[PTE_EdSec] = (BYTE)(((n >> 2) & 0xC0) | 63); /* End sector */ pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */ st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */ - if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the MBR */ } } - if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) return FR_DISK_ERR; + if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); - return FR_OK; + LEAVE_MKFS(FR_OK); } -#if _MULTI_PARTITION +#if FF_MULTI_PARTITION /*-----------------------------------------------------------------------*/ -/* Create partition table on the physical drive */ +/* Create Partition Table on the Physical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_fdisk ( void *pdrv, /* Physical drive number */ const DWORD* szt, /* Pointer to the size table for each partitions */ - void* work /* Pointer to the working buffer */ + void* work /* Pointer to the working buffer (null: use heap memory) */ ) { UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; DSTATUS stat; DWORD sz_disk, sz_part, s_part; + FRESULT res; disk_ioctl(pdrv, IOCTL_INIT, &stat); @@ -5546,19 +5860,25 @@ FRESULT f_fdisk ( if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; - /* Determine the CHS without any care of the drive geometry */ + buf = (BYTE*)work; +#if FF_USE_LFN == 3 + if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ +#endif + if (!buf) return FR_NOT_ENOUGH_CORE; + + /* Determine the CHS without any consideration of the drive geometry */ for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; if (n == 256) n--; - e_hd = n - 1; + e_hd = (BYTE)(n - 1); sz_cyl = 63 * n; tot_cyl = sz_disk / sz_cyl; /* Create partition table */ - mem_set(buf, 0, _MAX_SS); + mem_set(buf, 0, FF_MAX_SS); p = buf + MBR_Table; b_cyl = 0; for (i = 0; i < 4; i++, p += SZ_PTE) { - p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; - if (!p_cyl) continue; + p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */ + if (p_cyl == 0) continue; s_part = (DWORD)sz_cyl * b_cyl; sz_part = (DWORD)sz_cyl * p_cyl; if (i == 0) { /* Exclude first track of cylinder 0 */ @@ -5567,28 +5887,60 @@ FRESULT f_fdisk ( } else { s_hd = 0; } - e_cyl = b_cyl + p_cyl - 1; - if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; + e_cyl = b_cyl + p_cyl - 1; /* End cylinder */ + if (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER); /* Set partition table */ p[1] = s_hd; /* Start head */ - p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ + p[2] = (BYTE)(((b_cyl >> 2) & 0xC0) | 1); /* Start sector */ p[3] = (BYTE)b_cyl; /* Start cylinder */ - p[4] = 0x06; /* System type (temporary setting) */ + p[4] = 0x07; /* System type (temporary setting) */ p[5] = e_hd; /* End head */ - p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ + p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */ p[7] = (BYTE)e_cyl; /* End cylinder */ st_dword(p + 8, s_part); /* Start sector in LBA */ - st_dword(p + 12, sz_part); /* Partition size */ + st_dword(p + 12, sz_part); /* Number of sectors */ /* Next partition */ b_cyl += p_cyl; } - st_word(p, 0xAA55); + st_word(p, 0xAA55); /* MBR signature (always at offset 510) */ /* Write it to the MBR */ - return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK; + res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; + LEAVE_MKFS(res); } -#endif /* _MULTI_PARTITION */ -#endif /* _USE_MKFS && !_FS_READONLY */ +#endif /* FF_MULTI_PARTITION */ +#endif /* FF_USE_MKFS && !FF_FS_READONLY */ + + + +#if FF_CODE_PAGE == 0 +/*-----------------------------------------------------------------------*/ +/* Set Active Codepage for the Path Name */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_setcp ( + WORD cp /* Value to be set as active code page */ +) +{ + static const WORD validcp[] = { 437, 720, 737, 771, 775, 850, 852, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; + static const BYTE* const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; + UINT i; + + + for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ + if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ + + CodePage = cp; + if (cp >= 900) { /* DBCS */ + ExCvt = 0; + DbcTbl = tables[i]; + } else { /* SBCS */ + ExCvt = tables[i]; + DbcTbl = 0; + } + return FR_OK; +} +#endif /* FF_CODE_PAGE == 0 */ diff --git a/lib/oofatfs/ff.h b/lib/oofatfs/ff.h index 068de11660..a8aa00e9af 100644 --- a/lib/oofatfs/ff.h +++ b/lib/oofatfs/ff.h @@ -3,10 +3,10 @@ */ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT file system module R0.12b / +/ FatFs - Generic FAT Filesystem module R0.13c / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2016, ChaN, all right reserved. +/ Copyright (C) 2018, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -19,81 +19,93 @@ / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. +/ /----------------------------------------------------------------------------*/ -#ifndef _FATFS -#define _FATFS 68020 /* Revision ID */ +#ifndef FF_DEFINED +#define FF_DEFINED 86604 /* Revision ID */ #ifdef __cplusplus extern "C" { #endif -#include +#include FFCONF_H /* FatFs configuration options */ -/* This type MUST be 8-bit */ -typedef uint8_t BYTE; - -/* These types MUST be 16-bit */ -typedef int16_t SHORT; -typedef uint16_t WORD; -typedef uint16_t WCHAR; - -/* These types MUST be 16-bit or 32-bit */ -typedef int INT; -typedef unsigned int UINT; - -/* These types MUST be 32-bit */ -typedef int32_t LONG; -typedef uint32_t DWORD; - -/* This type MUST be 64-bit (Remove this for C89 compatibility) */ -typedef uint64_t QWORD; - -#include FFCONF_H /* FatFs configuration options */ - -#if _FATFS != _FFCONF +#if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). #endif +/* Integer types used for FatFs API */ + +#if defined(_WIN32) /* Main development platform */ +#define FF_INTDEF 2 +#include +typedef unsigned __int64 QWORD; +#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */ +#define FF_INTDEF 2 +#include +typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ +typedef unsigned char BYTE; /* char must be 8-bit */ +typedef uint16_t WORD; /* 16-bit unsigned integer */ +typedef uint16_t WCHAR; /* 16-bit unsigned integer */ +typedef uint32_t DWORD; /* 32-bit unsigned integer */ +typedef uint64_t QWORD; /* 64-bit unsigned integer */ +#else /* Earlier than C99 */ +#define FF_INTDEF 1 +typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ +typedef unsigned char BYTE; /* char must be 8-bit */ +typedef unsigned short WORD; /* 16-bit unsigned integer */ +typedef unsigned short WCHAR; /* 16-bit unsigned integer */ +typedef unsigned long DWORD; /* 32-bit unsigned integer */ +#endif + /* Definitions of volume management */ -#if _MULTI_PARTITION /* Multiple partition configuration */ -#define LD2PT(fs) (fs->part) /* Get partition index */ -#else /* Single partition configuration */ -#define LD2PT(fs) 0 /* Find first valid partition or in SFD */ +#if FF_STR_VOLUME_ID +#ifndef FF_VOLUME_STRS +extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ +#endif #endif /* Type of path name strings on FatFs API */ -#if _LFN_UNICODE /* Unicode (UTF-16) string */ -#if _USE_LFN == 0 -#error _LFN_UNICODE must be 0 at non-LFN cfg. -#endif #ifndef _INC_TCHAR +#define _INC_TCHAR + +#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ typedef WCHAR TCHAR; #define _T(x) L ## x #define _TEXT(x) L ## x -#endif -#else /* ANSI/OEM string */ -#ifndef _INC_TCHAR +#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */ +typedef char TCHAR; +#define _T(x) u8 ## x +#define _TEXT(x) u8 ## x +#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */ +typedef DWORD TCHAR; +#define _T(x) U ## x +#define _TEXT(x) U ## x +#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3) +#error Wrong FF_LFN_UNICODE setting +#else /* ANSI/OEM code in SBCS/DBCS */ typedef char TCHAR; #define _T(x) x #define _TEXT(x) x #endif + #endif /* Type of file size variables */ -#if _FS_EXFAT -#if _USE_LFN == 0 -#error LFN must be enabled when enable exFAT +#if FF_FS_EXFAT +#if FF_INTDEF != 2 +#error exFAT feature wants C99 or later #endif typedef QWORD FSIZE_t; #else @@ -102,39 +114,39 @@ typedef DWORD FSIZE_t; -/* File system object structure (FATFS) */ +/* Filesystem object structure (FATFS) */ typedef struct { void *drv; // block device underlying this filesystem -#if _MULTI_PARTITION /* Multiple partition configuration */ +#if FF_MULTI_PARTITION /* Multiple partition configuration */ BYTE part; // Partition: 0:Auto detect, 1-4:Forced partition #endif - BYTE fs_type; /* File system type (0:N/A) */ + BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ - WORD id; /* File system mount ID */ + WORD id; /* Volume mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD csize; /* Cluster size [sectors] */ -#if _MAX_SS != _MIN_SS +#if FF_MAX_SS != FF_MIN_SS WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ #endif -#if _USE_LFN != 0 +#if FF_USE_LFN WCHAR* lfnbuf; /* LFN working buffer */ #endif -#if _FS_EXFAT - BYTE* dirbuf; /* Directory entry block scratchpad buffer */ +#if FF_FS_EXFAT + BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ #endif -#if _FS_REENTRANT - _SYNC_t sobj; /* Identifier of sync object */ +#if FF_FS_REENTRANT + FF_SYNC_t sobj; /* Identifier of sync object */ #endif -#if !_FS_READONLY +#if !FF_FS_READONLY DWORD last_clst; /* Last allocated cluster */ DWORD free_clst; /* Number of free clusters */ #endif -#if _FS_RPATH != 0 +#if FF_FS_RPATH DWORD cdir; /* Current directory start cluster (0:root) */ -#if _FS_EXFAT +#if FF_FS_EXFAT DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ @@ -146,52 +158,56 @@ typedef struct { DWORD fatbase; /* FAT base sector */ DWORD dirbase; /* Root directory base sector/cluster */ DWORD database; /* Data base sector */ +#if FF_FS_EXFAT + DWORD bitbase; /* Allocation bitmap base sector */ +#endif DWORD winsect; /* Current sector appearing in the win[] */ - BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ + BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; -/* Object ID and allocation information (_FDID) */ +/* Object ID and allocation information (FFOBJID) */ typedef struct { - FATFS* fs; /* Pointer to the owner file system object */ - WORD id; /* Owner file system mount ID */ - BYTE attr; /* Object attribute */ - BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */ - DWORD sclust; /* Object start cluster (0:no cluster or root directory) */ - FSIZE_t objsize; /* Object size (valid when sclust != 0) */ -#if _FS_EXFAT - DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */ - DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ - DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ - DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */ + FATFS* fs; /* Pointer to the hosting volume of this object */ + WORD id; /* Hosting volume mount ID */ + BYTE attr; /* Object attribute */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ + DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ + FSIZE_t objsize; /* Object size (valid when sclust != 0) */ +#if FF_FS_EXFAT + DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ + DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ + DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ + DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ + DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ #endif -#if _FS_LOCK != 0 - UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ +#if FF_FS_LOCK + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ #endif -} _FDID; +} FFOBJID; /* File object structure (FIL) */ typedef struct { - _FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ + FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ - DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */ + DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ -#if !_FS_READONLY - DWORD dir_sect; /* Sector number containing the directory entry */ - BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ +#if !FF_FS_READONLY + DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ + BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ #endif -#if _USE_FASTSEEK +#if FF_USE_FASTSEEK DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif -#if !_FS_TINY - BYTE buf[_MAX_SS]; /* File private data read/write window */ +#if !FF_FS_TINY + BYTE buf[FF_MAX_SS]; /* File private data read/write window */ #endif } FIL; @@ -200,16 +216,16 @@ typedef struct { /* Directory object structure (FF_DIR) */ typedef struct { - _FDID obj; /* Object identifier */ + FFOBJID obj; /* Object identifier */ DWORD dptr; /* Current read/write offset */ DWORD clust; /* Current cluster */ - DWORD sect; /* Current sector */ + DWORD sect; /* Current sector (0:Read operation has terminated) */ BYTE* dir; /* Pointer to the directory item in the win[] */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ -#if _USE_LFN != 0 +#if FF_USE_LFN DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ #endif -#if _USE_FIND +#if FF_USE_FIND const TCHAR* pat; /* Pointer to the name matching pattern */ #endif } FF_DIR; @@ -223,11 +239,11 @@ typedef struct { WORD fdate; /* Modified date */ WORD ftime; /* Modified time */ BYTE fattrib; /* File attribute */ -#if _USE_LFN != 0 - TCHAR altname[13]; /* Altenative file name */ - TCHAR fname[_MAX_LFN + 1]; /* Primary file name */ +#if FF_USE_LFN + TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ + TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ #else - TCHAR fname[13]; /* File name */ + TCHAR fname[12 + 1]; /* File name */ #endif } FILINFO; @@ -254,7 +270,7 @@ typedef enum { FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ - FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */ + FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ } FRESULT; @@ -292,6 +308,7 @@ FRESULT f_mount (FATFS* fs); /* Mount/Unm FRESULT f_umount (FATFS* fs); /* Unmount a logical drive */ FRESULT f_mkfs (FATFS *fs, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ +FRESULT f_setcp (WORD cp); /* Set current code page */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) @@ -299,6 +316,8 @@ FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a #define f_size(fp) ((fp)->obj.objsize) #define f_rewind(fp) f_lseek((fp), 0) #define f_rewinddir(dp) f_readdir((dp), 0) +#define f_rmdir(path) f_unlink(path) +#define f_unmount(path) f_mount(0, path, 0) #ifndef EOF #define EOF (-1) @@ -311,26 +330,27 @@ FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a /* Additional user defined functions */ /* RTC function */ -#if !_FS_READONLY && !_FS_NORTC +#if !FF_FS_READONLY && !FF_FS_NORTC DWORD get_fattime (void); #endif -/* Unicode support functions */ -#if _USE_LFN != 0 /* Unicode - OEM code conversion */ -WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ -WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ -#if _USE_LFN == 3 /* Memory functions */ +/* LFN support functions */ +#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ +WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ +WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ +DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ +#endif +#if FF_USE_LFN == 3 /* Dynamic memory allocation */ void* ff_memalloc (UINT msize); /* Allocate memory block */ void ff_memfree (void* mblock); /* Free memory block */ #endif -#endif /* Sync functions */ -#if _FS_REENTRANT -int ff_cre_syncobj (FATFS *fatfs, _SYNC_t* sobj); /* Create a sync object */ -int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ -void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ -int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ +#if FF_FS_REENTRANT +int ff_cre_syncobj (FATFS *fatfs, FF_SYNC_t* sobj); /* Create a sync object */ +int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ +void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ +int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ #endif @@ -377,4 +397,4 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ } #endif -#endif /* _FATFS */ +#endif /* FF_DEFINED */ diff --git a/lib/oofatfs/ffconf.h b/lib/oofatfs/ffconf.h index d8485a293a..7072edf153 100644 --- a/lib/oofatfs/ffconf.h +++ b/lib/oofatfs/ffconf.h @@ -2,11 +2,11 @@ * This file is part of the MicroPython project, http://micropython.org/ * * Original file from: - * FatFs - FAT file system module configuration file R0.12a (C)ChaN, 2016 + * FatFs - FAT file system module configuration file R0.13c (C)ChaN, 2018 * * The MIT License (MIT) * - * SPDX-FileCopyrightText: Copyright (c) 2013-2017 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2013-2019 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,73 +30,72 @@ #include "py/mpconfig.h" /*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module configuration file +/ FatFs Functional Configurations /---------------------------------------------------------------------------*/ -#define _FFCONF 68020 /* Revision ID */ +#define FFCONF_DEF 86604 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations /---------------------------------------------------------------------------*/ -#define _FS_READONLY 0 +#define FF_FS_READONLY 0 /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) / Read-only configuration removes writing API functions, f_write(), f_sync(), / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / and optional writing functions as well. */ -#define _FS_MINIMIZE 0 +#define FF_FS_MINIMIZE 0 /* This option defines minimization level to remove some basic API functions. / -/ 0: All basic functions are enabled. +/ 0: Basic functions are fully enabled. / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() / are removed. / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 3: f_lseek() function is removed in addition to 2. */ -#define _USE_STRFUNC 0 -/* This option switches string functions, f_gets(), f_putc(), f_puts() and -/ f_printf(). +#define FF_USE_STRFUNC 0 +/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). / / 0: Disable string functions. / 1: Enable without LF-CRLF conversion. / 2: Enable with LF-CRLF conversion. */ -#define _USE_FIND 0 +#define FF_USE_FIND 0 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ -#define _USE_MKFS 1 +#define FF_USE_MKFS 1 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ -#define _USE_FASTSEEK 1 +#define FF_USE_FASTSEEK 1 /* This option switches fast seek function. (0:Disable or 1:Enable) */ -#define _USE_EXPAND 0 +#define FF_USE_EXPAND 0 /* This option switches f_expand function. (0:Disable or 1:Enable) */ -#define _USE_CHMOD 1 +#define FF_USE_CHMOD 1 /* This option switches attribute manipulation functions, f_chmod() and f_utime(). -/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */ +/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ #ifdef MICROPY_FATFS_USE_LABEL -#define _USE_LABEL (MICROPY_FATFS_USE_LABEL) +#define FF_USE_LABEL (MICROPY_FATFS_USE_LABEL) #else -#define _USE_LABEL 0 +#define FF_USE_LABEL 0 #endif /* This option switches volume label functions, f_getlabel() and f_setlabel(). / (0:Disable or 1:Enable) */ -#define _USE_FORWARD 0 +#define FF_USE_FORWARD 0 /* This option switches f_forward() function. (0:Disable or 1:Enable) */ @@ -105,14 +104,13 @@ /---------------------------------------------------------------------------*/ #ifdef MICROPY_FATFS_LFN_CODE_PAGE -#define _CODE_PAGE (MICROPY_FATFS_LFN_CODE_PAGE) +#define FF_CODE_PAGE MICROPY_FATFS_LFN_CODE_PAGE #else -#define _CODE_PAGE 1 +#define FF_CODE_PAGE 437 #endif /* This option specifies the OEM code page to be used on the target system. -/ Incorrect setting of the code page can cause a file open failure. +/ Incorrect code page setting can cause a file open failure. / -/ 1 - ASCII (No extended character. Non-LFN cfg. only) / 437 - U.S. / 720 - Arabic / 737 - Greek @@ -134,59 +132,77 @@ / 936 - Simplified Chinese (DBCS) / 949 - Korean (DBCS) / 950 - Traditional Chinese (DBCS) +/ 0 - Include all code pages above and configured by f_setcp() */ #ifdef MICROPY_FATFS_ENABLE_LFN -#define _USE_LFN (MICROPY_FATFS_ENABLE_LFN) +#define FF_USE_LFN (MICROPY_FATFS_ENABLE_LFN) #else -#define _USE_LFN 0 +#define FF_USE_LFN 0 #endif #ifdef MICROPY_FATFS_MAX_LFN -#define _MAX_LFN (MICROPY_FATFS_MAX_LFN) +#define FF_MAX_LFN (MICROPY_FATFS_MAX_LFN) #else -#define _MAX_LFN 255 +#define FF_MAX_LFN 255 #endif -/* The _USE_LFN switches the support of long file name (LFN). +/* The FF_USE_LFN switches the support for LFN (long file name). / -/ 0: Disable support of LFN. _MAX_LFN has no effect. +/ 0: Disable LFN. FF_MAX_LFN has no effect. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / -/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added -/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and -/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255. -/ It should be set 255 to support full featured LFN operations. +/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function +/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and +/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. +/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can +/ be in range of 12 to 255. It is recommended to be set 255 to fully support LFN +/ specification. / When use stack for the working buffer, take care on stack overflow. When use heap / memory for the working buffer, memory management functions, ff_memalloc() and -/ ff_memfree(), must be added to the project. */ +/ ff_memfree() in ffsystem.c, need to be added to the project. */ -#define _LFN_UNICODE 0 -/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) -/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. -/ This option also affects behavior of string I/O functions. */ - - -#define _STRF_ENCODE 3 -/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to -/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). +#define FF_LFN_UNICODE 0 +/* This option switches the character encoding on the API when LFN is enabled. / -/ 0: ANSI/OEM -/ 1: UTF-16LE -/ 2: UTF-16BE -/ 3: UTF-8 +/ 0: ANSI/OEM in current CP (TCHAR = char) +/ 1: Unicode in UTF-16 (TCHAR = WCHAR) +/ 2: Unicode in UTF-8 (TCHAR = char) +/ 3: Unicode in UTF-32 (TCHAR = DWORD) / -/ This option has no effect when _LFN_UNICODE == 0. */ +/ Also behavior of string I/O functions will be affected by this option. +/ When LFN is not enabled, this option has no effect. */ + + +#define FF_LFN_BUF 255 +#define FF_SFN_BUF 12 +/* This set of options defines size of file name members in the FILINFO structure +/ which is used to read out directory items. These values should be suffcient for +/ the file names to read. The maximum possible length of the read file name depends +/ on character encoding. When LFN is not enabled, these options have no effect. */ + + +#define FF_STRF_ENCODE 3 +/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), +/ f_putc(), f_puts and f_printf() convert the character encoding in it. +/ This option selects assumption of character encoding ON THE FILE to be +/ read/written via those functions. +/ +/ 0: ANSI/OEM in current CP +/ 1: Unicode in UTF-16LE +/ 2: Unicode in UTF-16BE +/ 3: Unicode in UTF-8 +*/ #ifdef MICROPY_FATFS_RPATH -#define _FS_RPATH (MICROPY_FATFS_RPATH) +#define FF_FS_RPATH (MICROPY_FATFS_RPATH) #else -#define _FS_RPATH 0 +#define FF_FS_RPATH 0 #endif -/* This option configures support of relative path. +/* This option configures support for relative path. / / 0: Disable relative path and remove related functions. / 1: Enable relative path. f_chdir() and f_chdrive() are available. @@ -198,53 +214,58 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define _VOLUMES 1 -/* Number of volumes (logical drives) to be used. */ +#define FF_VOLUMES 1 +/* Number of volumes (logical drives) to be used. (1-10) */ -#define _STR_VOLUME_ID 0 -#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" -/* _STR_VOLUME_ID switches string support of volume ID. -/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive -/ number in the path name. _VOLUME_STRS defines the drive ID strings for each -/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for -/ the drive ID strings are: A-Z and 0-9. */ +#define FF_STR_VOLUME_ID 0 +#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" +/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. +/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive +/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each +/ logical drives. Number of items must not be less than FF_VOLUMES. Valid +/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are +/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is +/ not defined, a user defined volume string table needs to be defined as: +/ +/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... +*/ #ifdef MICROPY_FATFS_MULTI_PARTITION -#define _MULTI_PARTITION (MICROPY_FATFS_MULTI_PARTITION) +#define FF_MULTI_PARTITION (MICROPY_FATFS_MULTI_PARTITION) #else -#define _MULTI_PARTITION 0 +#define FF_MULTI_PARTITION 0 #endif -/* This option switches support of multi-partition on a physical drive. +/* This option switches support for multiple volumes on the physical drive. / By default (0), each logical drive number is bound to the same physical drive / number and only an FAT volume found on the physical drive will be mounted. -/ When multi-partition is enabled (1), each logical drive number can be bound to +/ When this function is enabled (1), each logical drive number can be bound to / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / funciton will be available. */ -#define _MIN_SS 512 +#define FF_MIN_SS 512 #ifdef MICROPY_FATFS_MAX_SS -#define _MAX_SS (MICROPY_FATFS_MAX_SS) +#define FF_MAX_SS (MICROPY_FATFS_MAX_SS) #else -#define _MAX_SS 512 +#define FF_MAX_SS 512 #endif -/* These options configure the range of sector size to be supported. (512, 1024, -/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and +/* This set of options configures the range of sector size to be supported. (512, +/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and / harddisk. But a larger value may be required for on-board flash memory and some -/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured -/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the -/ disk_ioctl() function. */ +/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured +/ for variable sector size mode and disk_ioctl() function needs to implement +/ GET_SECTOR_SIZE command. */ -#define _USE_TRIM 0 -/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable) +#define FF_USE_TRIM 0 +/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) / To enable Trim function, also CTRL_TRIM command should be implemented to the / disk_ioctl() function. */ -#define _FS_NOFSINFO 0 +#define FF_FS_NOFSINFO 0 /* If you need to know correct free space on the FAT32 volume, set bit 0 of this / option, and f_getfree() function at first time after volume mount will force / a full FAT scan. Bit 1 controls the use of last allocated cluster number. @@ -261,44 +282,44 @@ / System Configurations /---------------------------------------------------------------------------*/ -#define _FS_TINY 1 +#define FF_FS_TINY 1 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) -/ At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes. +/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector -/ buffer in the file system object (FATFS) is used for the file data transfer. */ +/ buffer in the filesystem object (FATFS) is used for the file data transfer. */ #ifdef MICROPY_FATFS_EXFAT -#define _FS_EXFAT (MICROPY_FATFS_EXFAT) +#define FF_FS_EXFAT (MICROPY_FATFS_EXFAT) #else -#define _FS_EXFAT 0 +#define FF_FS_EXFAT 0 #endif -/* This option switches support of exFAT file system. (0:Disable or 1:Enable) -/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1) -/ Note that enabling exFAT discards C89 compatibility. */ +/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) +/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) +/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ #ifdef MICROPY_FATFS_NORTC -#define _FS_NORTC (MICROPY_FATFS_NORTC) +#define FF_FS_NORTC (MICROPY_FATFS_NORTC) #else -#define _FS_NORTC 0 +#define FF_FS_NORTC 0 #endif -#define _NORTC_MON 1 -#define _NORTC_MDAY 1 -#define _NORTC_YEAR 2016 -/* The option _FS_NORTC switches timestamp functiton. If the system does not have -/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable -/ the timestamp function. All objects modified by FatFs will have a fixed timestamp -/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. -/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be -/ added to the project to get current time form real-time clock. _NORTC_MON, -/ _NORTC_MDAY and _NORTC_YEAR have no effect. -/ These options have no effect at read-only configuration (_FS_READONLY = 1). */ +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2018 +/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have +/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable +/ the timestamp function. Every object modified by FatFs will have a fixed timestamp +/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. +/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to read current time form real-time clock. FF_NORTC_MON, +/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. +/ These options have no effect at read-only configuration (FF_FS_READONLY = 1). */ -#define _FS_LOCK 0 -/* The option _FS_LOCK switches file lock function to control duplicated file open -/ and illegal operation to open objects. This option must be 0 when _FS_READONLY +#define FF_FS_LOCK 0 +/* The option FF_FS_LOCK switches file lock function to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY / is 1. / / 0: Disable file lock function. To avoid volume corruption, application program @@ -309,41 +330,40 @@ #ifdef MICROPY_FATFS_REENTRANT -#define _FS_REENTRANT (MICROPY_FATFS_REENTRANT) +#define FF_FS_REENTRANT (MICROPY_FATFS_REENTRANT) #else -#define _FS_REENTRANT 0 +#define FF_FS_REENTRANT 0 #endif // milliseconds #ifdef MICROPY_FATFS_TIMEOUT -#define _FS_TIMEOUT (MICROPY_FATFS_TIMEOUT) +#define FF_FS_TIMEOUT (MICROPY_FATFS_TIMEOUT) #else -#define _FS_TIMEOUT 1000 +#define FF_FS_TIMEOUT 1000 #endif #ifdef MICROPY_FATFS_SYNC_T -#define _SYNC_t MICROPY_FATFS_SYNC_T +#define FF_SYNC_t MICROPY_FATFS_SYNC_T #else -#define _SYNC_t HANDLE +#define FF_SYNC_t HANDLE #endif -/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs +/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access / to the same volume is under control of this function. / -/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. +/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / function, must be added to the project. Samples are available in / option/syscall.c. / -/ The _FS_TIMEOUT defines timeout period in unit of time tick. -/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, -/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be +/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. +/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, +/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / included somewhere in the scope of ff.h. */ -/* #include // O/S definitions */ /*--- End of configuration options ---*/ diff --git a/lib/oofatfs/option/ccsbcs.c b/lib/oofatfs/ffunicode.c similarity index 58% rename from lib/oofatfs/option/ccsbcs.c rename to lib/oofatfs/ffunicode.c index f0c7e90a5c..4153f9131c 100644 --- a/lib/oofatfs/option/ccsbcs.c +++ b/lib/oofatfs/ffunicode.c @@ -1,33 +1,46 @@ /*------------------------------------------------------------------------*/ -/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */ -/* (SBCS code pages) */ +/* Unicode handling functions for FatFs R0.13c */ /*------------------------------------------------------------------------*/ -/* 437 U.S. -/ 720 Arabic -/ 737 Greek -/ 771 KBL -/ 775 Baltic -/ 850 Latin 1 -/ 852 Latin 2 -/ 855 Cyrillic -/ 857 Turkish -/ 860 Portuguese -/ 861 Icelandic -/ 862 Hebrew -/ 863 Canadian French -/ 864 Arabic -/ 865 Nordic -/ 866 Russian -/ 869 Greek 2 +/* This module will occupy a huge memory in the .const section when the / +/ FatFs is configured for LFN with DBCS. If the system has any Unicode / +/ utilitiy for the code conversion, this module should be modified to use / +/ that function to avoid silly memory consumption. / +/-------------------------------------------------------------------------*/ +/* +/ Copyright (C) 2018, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: +/ +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. */ -#include "../ff.h" + +#include "ff.h" + +#if FF_USE_LFN /* This module will be blanked at non-LFN configuration */ + +#if FF_DEFINED != 86604 /* Revision ID */ +#error Wrong include file (ff.h). +#endif + +#define MERGE2(a, b) a ## b +#define CVTBL(tbl, cp) MERGE2(tbl, cp) -#if _CODE_PAGE == 437 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ +/*------------------------------------------------------------------------*/ +/* Code Conversion Tables */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0 +static const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -37,11 +50,9 @@ const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 720 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0 +static const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */ 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, @@ -51,11 +62,9 @@ const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */ 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 737 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0 +static const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, @@ -65,11 +74,9 @@ const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */ 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 771 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0 +static const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, @@ -79,11 +86,9 @@ const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 775 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0 +static const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */ 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, @@ -93,11 +98,9 @@ const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */ 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 850 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0 +static const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -107,11 +110,9 @@ const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 852 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0 +static const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, @@ -121,11 +122,9 @@ const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */ 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 855 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0 +static const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */ 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, @@ -135,11 +134,9 @@ const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */ 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 857 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0 +static const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -149,11 +146,9 @@ const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 860 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0 +static const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -163,11 +158,9 @@ const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 861 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0 +static const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -177,11 +170,9 @@ const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 862 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0 +static const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -191,11 +182,9 @@ const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 863 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0 +static const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, @@ -205,11 +194,9 @@ const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 864 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0 +static const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */ 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, @@ -219,11 +206,9 @@ const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */ 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1, 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000 }; - -#elif _CODE_PAGE == 865 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0 +static const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, @@ -233,11 +218,9 @@ const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 866 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0 +static const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, @@ -247,11 +230,9 @@ const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 }; - -#elif _CODE_PAGE == 869 -#define _TBLDEF 1 -static -const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */ +#endif +#if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0 +static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, @@ -261,36 +242,32 @@ const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */ 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384, 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0 }; - -#endif - - -#if !_TBLDEF || !_USE_LFN -#error This file is not needed at current configuration. Remove from the project. #endif -WCHAR ff_convert ( /* Converted character, Returns zero on error */ - WCHAR chr, /* Character code to be converted */ - UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */ +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode conversions for static code page configuration */ +/* SBCS fixed code page */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ ) { - WCHAR c; + WCHAR c = 0; + const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); - if (chr < 0x80) { /* ASCII */ - c = chr; + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; - } else { - if (dir) { /* OEM code to Unicode */ - c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80]; - - } else { /* Unicode to OEM code */ - for (c = 0; c < 0x80; c++) { - if (chr == Tbl[c]) break; - } + } else { /* Non-ASCII */ + if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ + for (c = 0; c < 0x80 && uni != p[c]; c++) ; c = (c + 0x80) & 0xFF; } } @@ -298,56 +275,314 @@ WCHAR ff_convert ( /* Converted character, Returns zero on error */ return c; } - - -WCHAR ff_wtoupper ( /* Returns upper converted character */ - WCHAR chr /* Unicode character to be upper converted (BMP only) */ +WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ + WCHAR oem, /* OEM code to be converted */ + WORD cp /* Code page for the conversion */ ) { - /* Compressed upper conversion table */ - static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */ + WCHAR c = 0; + const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ + if (oem < 0x100) c = p[oem - 0x80]; + } + } + + return c; +} + +#endif + + + +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode conversions for static code page configuration */ +/* DBCS fixed code page */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE >= 900 +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0, uc; + UINT i = 0, n, li, hi; + + + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; + + } else { /* Non-ASCII */ + if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ + uc = (WCHAR)uni; + p = CVTBL(uni2oem, FF_CODE_PAGE); + hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1; + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (uc == p[i * 2]) break; + if (uc > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + + return c; +} + + +WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ + WCHAR oem, /* OEM code to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0; + UINT i = 0, n, li, hi; + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + if (cp == FF_CODE_PAGE) { /* Is it valid code page? */ + p = CVTBL(oem2uni, FF_CODE_PAGE); + hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1; + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (oem == p[i * 2]) break; + if (oem > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + + return c; +} +#endif + + + +/*------------------------------------------------------------------------*/ +/* OEM <==> Unicode conversions for dynamic code page configuration */ +/*------------------------------------------------------------------------*/ + +#if FF_CODE_PAGE == 0 + +static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0}; +static const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0}; + + +WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ + DWORD uni, /* UTF-16 encoded character to be converted */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0, uc; + UINT i, n, li, hi; + + + if (uni < 0x80) { /* ASCII? */ + c = (WCHAR)uni; + + } else { /* Non-ASCII */ + if (uni < 0x10000) { /* Is it in BMP? */ + uc = (WCHAR)uni; + p = 0; + if (cp < 900) { /* SBCS */ + for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get conversion table */ + p = cp_table[i]; + if (p) { /* Is it valid code page ? */ + for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */ + c = (c + 0x80) & 0xFF; + } + } else { /* DBCS */ + switch (cp) { /* Get conversion table */ + case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break; + case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break; + case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break; + case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break; + } + if (p) { /* Is it valid code page? */ + li = 0; + for (n = 16; n; n--) { /* Find OEM code */ + i = li + (hi - li) / 2; + if (uc == p[i * 2]) break; + if (uc > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + } + } + + return c; +} + + +WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ + WCHAR oem, /* OEM code to be converted (DBC if >=0x100) */ + WORD cp /* Code page for the conversion */ +) +{ + const WCHAR *p; + WCHAR c = 0; + UINT i, n, li, hi; + + + if (oem < 0x80) { /* ASCII? */ + c = oem; + + } else { /* Extended char */ + p = 0; + if (cp < 900) { /* SBCS */ + for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */ + p = cp_table[i]; + if (p) { /* Is it a valid CP ? */ + if (oem < 0x100) c = p[oem - 0x80]; + } + } else { /* DBCS */ + switch (cp) { + case 932 : p = oem2uni932; hi = sizeof oem2uni932 / 4 - 1; break; + case 936 : p = oem2uni936; hi = sizeof oem2uni936 / 4 - 1; break; + case 949 : p = oem2uni949; hi = sizeof oem2uni949 / 4 - 1; break; + case 950 : p = oem2uni950; hi = sizeof oem2uni950 / 4 - 1; break; + } + if (p) { + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (oem == p[i * 2]) break; + if (oem > p[i * 2]) { + li = i; + } else { + hi = i; + } + } + if (n != 0) c = p[i * 2 + 1]; + } + } + } + + return c; +} +#endif + + + +/*------------------------------------------------------------------------*/ +/* Unicode up-case conversion */ +/*------------------------------------------------------------------------*/ + +DWORD ff_wtoupper ( /* Returns up-converted code point */ + DWORD uni /* Unicode code point to be up-converted */ +) +{ + const WORD *p; + WORD uc, bc, nc, cmd; + static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ /* Basic Latin */ 0x0061,0x031A, /* Latin-1 Supplement */ - 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + 0x00E0,0x0317, + 0x00F8,0x0307, + 0x00FF,0x0001,0x0178, /* Latin Extended-A */ - 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + 0x0100,0x0130, + 0x0132,0x0106, + 0x0139,0x0110, + 0x014A,0x012E, + 0x0179,0x0106, /* Latin Extended-B */ 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, - 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, - 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + 0x01CD,0x0110, + 0x01DD,0x0001,0x018E, + 0x01DE,0x0112, + 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, + 0x01F8,0x0128, + 0x0222,0x0112, + 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, + 0x0246,0x010A, /* IPA Extensions */ 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, /* Greek, Coptic */ - 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, - 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, + 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, + 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, + 0x03C4,0x0308, + 0x03CC,0x0003,0x038C,0x038E,0x038F, + 0x03D8,0x0118, 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, /* Cyrillic */ - 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + 0x0430,0x0320, + 0x0450,0x0710, + 0x0460,0x0122, + 0x048A,0x0136, + 0x04C1,0x010E, + 0x04CF,0x0001,0x04C0, + 0x04D0,0x0144, /* Armenian */ 0x0561,0x0426, - 0x0000 + 0x0000 /* EOT */ }; - static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */ + static const WORD cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */ /* Phonetic Extensions */ 0x1D7D,0x0001,0x2C63, /* Latin Extended Additional */ - 0x1E00,0x0196, 0x1EA0,0x015A, + 0x1E00,0x0196, + 0x1EA0,0x015A, /* Greek Extended */ - 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, - 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F00,0x0608, + 0x1F10,0x0606, + 0x1F20,0x0608, + 0x1F30,0x0608, + 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, + 0x1F60,0x0608, 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, - 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, - 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC, + 0x1F80,0x0608, + 0x1F90,0x0608, + 0x1FA0,0x0608, + 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, + 0x1FD0,0x0602, + 0x1FE0,0x0602, + 0x1FE5,0x0001,0x1FEC, + 0x1FF3,0x0001,0x1FFC, /* Letterlike Symbols */ 0x214E,0x0001,0x2132, /* Number forms */ - 0x2170,0x0210, 0x2184,0x0001,0x2183, + 0x2170,0x0210, + 0x2184,0x0001,0x2183, /* Enclosed Alphanumerics */ - 0x24D0,0x051A, 0x2C30,0x042F, + 0x24D0,0x051A, + 0x2C30,0x042F, /* Latin Extended-C */ - 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + 0x2C60,0x0102, + 0x2C67,0x0106, 0x2C75,0x0102, /* Coptic */ 0x2C80,0x0164, /* Georgian Supplement */ @@ -355,33 +590,38 @@ WCHAR ff_wtoupper ( /* Returns upper converted character */ /* Full-width */ 0xFF41,0x031A, - 0x0000 + 0x0000 /* EOT */ }; - const WCHAR *p; - WCHAR bc, nc, cmd; - p = chr < 0x1000 ? cvt1 : cvt2; - for (;;) { - bc = *p++; /* Get block base */ - if (!bc || chr < bc) break; - nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ - if (chr < bc + nc) { /* In the block? */ - switch (cmd) { - case 0: chr = p[chr - bc]; break; /* Table conversion */ - case 1: chr -= (chr - bc) & 1; break; /* Case pairs */ - case 2: chr -= 16; break; /* Shift -16 */ - case 3: chr -= 32; break; /* Shift -32 */ - case 4: chr -= 48; break; /* Shift -48 */ - case 5: chr -= 26; break; /* Shift -26 */ - case 6: chr += 8; break; /* Shift +8 */ - case 7: chr -= 80; break; /* Shift -80 */ - case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */ + if (uni < 0x10000) { /* Is it in BMP? */ + uc = (WORD)uni; + p = uc < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get the block base */ + if (bc == 0 || uc < bc) break; /* Not matched? */ + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (uc < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: uc = p[uc - bc]; break; /* Table conversion */ + case 1: uc -= (uc - bc) & 1; break; /* Case pairs */ + case 2: uc -= 16; break; /* Shift -16 */ + case 3: uc -= 32; break; /* Shift -32 */ + case 4: uc -= 48; break; /* Shift -48 */ + case 5: uc -= 26; break; /* Shift -26 */ + case 6: uc += 8; break; /* Shift +8 */ + case 7: uc -= 80; break; /* Shift -80 */ + case 8: uc -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; } - break; + if (cmd == 0) p += nc; /* Skip table if needed */ } - if (!cmd) p += nc; + uni = uc; } - return chr; + return uni; } + + +#endif /* #if FF_USE_LFN */ diff --git a/lib/oofatfs/option/unicode.c b/lib/oofatfs/option/unicode.c deleted file mode 100644 index e48d09c6b0..0000000000 --- a/lib/oofatfs/option/unicode.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "../ff.h" - -#if _USE_LFN != 0 - -#if _CODE_PAGE == 932 /* Japanese Shift_JIS */ -#include "cc932.c" -#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ -#include "cc936.c" -#elif _CODE_PAGE == 949 /* Korean */ -#include "cc949.c" -#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ -#include "cc950.c" -#else /* Single Byte Character-Set */ -#include "ccsbcs.c" -#endif - -#endif diff --git a/lib/utils/gchelper.h b/lib/utils/gchelper.h new file mode 100644 index 0000000000..7149b6a72e --- /dev/null +++ b/lib/utils/gchelper.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H +#define MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H + +#include + +uintptr_t gc_helper_get_sp(void); +uintptr_t gc_helper_get_regs_and_sp(uintptr_t *regs); + +#endif // MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H diff --git a/lib/utils/gchelper_m0.s b/lib/utils/gchelper_m0.s new file mode 100644 index 0000000000..db0d9738d1 --- /dev/null +++ b/lib/utils/gchelper_m0.s @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m0 + .thumb + + .section .text + .align 2 + + .global gc_helper_get_regs_and_sp + .type gc_helper_get_regs_and_sp, %function + +@ uint gc_helper_get_regs_and_sp(r0=uint regs[10]) +gc_helper_get_regs_and_sp: + @ store registers into given array + str r4, [r0, #0] + str r5, [r0, #4] + str r6, [r0, #8] + str r7, [r0, #12] + mov r1, r8 + str r1, [r0, #16] + mov r1, r9 + str r1, [r0, #20] + mov r1, r10 + str r1, [r0, #24] + mov r1, r11 + str r1, [r0, #28] + mov r1, r12 + str r1, [r0, #32] + mov r1, r13 + str r1, [r0, #36] + + @ return the sp + mov r0, sp + bx lr + + .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp diff --git a/lib/utils/gchelper_m3.s b/lib/utils/gchelper_m3.s new file mode 100644 index 0000000000..3aac0dedfd --- /dev/null +++ b/lib/utils/gchelper_m3.s @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m3 + .thumb + + .section .text + .align 2 + + .global gc_helper_get_sp + .type gc_helper_get_sp, %function + +@ uint gc_helper_get_sp(void) +gc_helper_get_sp: + @ return the sp + mov r0, sp + bx lr + + .size gc_helper_get_sp, .-gc_helper_get_sp + + + .global gc_helper_get_regs_and_sp + .type gc_helper_get_regs_and_sp, %function + +@ uint gc_helper_get_regs_and_sp(r0=uint regs[10]) +gc_helper_get_regs_and_sp: + @ store registers into given array + str r4, [r0], #4 + str r5, [r0], #4 + str r6, [r0], #4 + str r7, [r0], #4 + str r8, [r0], #4 + str r9, [r0], #4 + str r10, [r0], #4 + str r11, [r0], #4 + str r12, [r0], #4 + str r13, [r0], #4 + + @ return the sp + mov r0, sp + bx lr + + .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp diff --git a/lib/utils/interrupt_char.c b/lib/utils/interrupt_char.c index 7410ac1e5d..372479f3a7 100644 --- a/lib/utils/interrupt_char.c +++ b/lib/utils/interrupt_char.c @@ -29,7 +29,7 @@ #if MICROPY_KBD_EXCEPTION -int mp_interrupt_char; +int mp_interrupt_char = -1; void mp_hal_set_interrupt_char(int c) { if (c != -1) { diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 9a105a42ca..e8c182e9bc 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -197,6 +197,7 @@ typedef struct _repl_t { // will be added later. // vstr_t line; bool cont_line; + bool paste_mode; } repl_t; repl_t repl; @@ -207,6 +208,7 @@ STATIC int pyexec_friendly_repl_process_char(int c); void pyexec_event_repl_init(void) { MP_STATE_VM(repl_line) = vstr_new(32); repl.cont_line = false; + repl.paste_mode = false; // no prompt before printing friendly REPL banner or entering raw REPL readline_init(MP_STATE_VM(repl_line), ""); if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { @@ -226,6 +228,7 @@ STATIC int pyexec_raw_repl_process_char(int c) { pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; vstr_reset(MP_STATE_VM(repl_line)); repl.cont_line = false; + repl.paste_mode = false; pyexec_friendly_repl_process_char(CHAR_CTRL_B); return 0; } else if (c == CHAR_CTRL_C) { @@ -263,6 +266,32 @@ reset: } STATIC int pyexec_friendly_repl_process_char(int c) { + if (repl.paste_mode) { + if (c == CHAR_CTRL_C) { + // cancel everything + mp_hal_stdout_tx_str("\r\n"); + goto input_restart; + } else if (c == CHAR_CTRL_D) { + // end of input + mp_hal_stdout_tx_str("\r\n"); + int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_FILE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; + } + goto input_restart; + } else { + // add char to buffer and echo + vstr_add_byte(MP_STATE_VM(repl_line), c); + if (c == '\r') { + mp_hal_stdout_tx_str("\r\n=== "); + } else { + char buf[1] = {c}; + mp_hal_stdout_tx_strn(buf, 1); + } + return 0; + } + } + int ret = readline_process_char(c); if (!repl.cont_line) { @@ -289,6 +318,12 @@ STATIC int pyexec_friendly_repl_process_char(int c) { mp_hal_stdout_tx_str("\r\n"); vstr_clear(MP_STATE_VM(repl_line)); return PYEXEC_FORCED_EXIT; + } else if (ret == CHAR_CTRL_E) { + // paste mode + mp_hal_stdout_tx_str("\r\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\r\n=== "); + vstr_reset(MP_STATE_VM(repl_line)); + repl.paste_mode = true; + return 0; } if (ret < 0) { @@ -335,6 +370,7 @@ STATIC int pyexec_friendly_repl_process_char(int c) { input_restart: vstr_reset(MP_STATE_VM(repl_line)); repl.cont_line = false; + repl.paste_mode = false; readline_init(MP_STATE_VM(repl_line), ">>> "); return 0; } @@ -450,7 +486,7 @@ friendly_repl_reset: // do the user a favor and reenable interrupts. if (query_irq() == IRQ_STATE_DISABLED) { enable_irq(IRQ_STATE_ENABLED); - mp_hal_stdout_tx_str("PYB: enabling IRQs\r\n"); + mp_hal_stdout_tx_str("MPY: enabling IRQs\r\n"); } } #endif @@ -541,20 +577,32 @@ int pyexec_file(const char *filename, pyexec_result_t *result) { return parse_compile_execute(filename, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_FILENAME, result); } +int pyexec_file_if_exists(const char *filename, pyexec_result_t *result) { + #if MICROPY_MODULE_FROZEN + if (mp_frozen_stat(filename) == MP_IMPORT_STAT_FILE) { + return pyexec_frozen_module(filename, result); + } + #endif + if (mp_import_stat(filename) != MP_IMPORT_STAT_FILE) { + return 1; // success (no file is the same as an empty file executing without fail) + } + return pyexec_file(filename, result); +} + #if MICROPY_MODULE_FROZEN -int pyexec_frozen_module(const char *name) { +int pyexec_frozen_module(const char *name, pyexec_result_t *result) { void *frozen_data; int frozen_type = mp_find_frozen_module(name, strlen(name), &frozen_data); switch (frozen_type) { #if MICROPY_MODULE_FROZEN_STR case MP_FROZEN_STR: - return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, 0, NULL); + return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, 0, result); #endif #if MICROPY_MODULE_FROZEN_MPY case MP_FROZEN_MPY: - return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_RAW_CODE, NULL); + return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_RAW_CODE, result); #endif default: diff --git a/lib/utils/pyexec.h b/lib/utils/pyexec.h index bde2960c29..9baef2b9fe 100644 --- a/lib/utils/pyexec.h +++ b/lib/utils/pyexec.h @@ -54,7 +54,8 @@ extern int pyexec_system_exit; int pyexec_raw_repl(void); int pyexec_friendly_repl(void); int pyexec_file(const char *filename, pyexec_result_t *result); -int pyexec_frozen_module(const char *name); +int pyexec_file_if_exists(const char *filename, pyexec_result_t *result); +int pyexec_frozen_module(const char *name, pyexec_result_t *result); void pyexec_event_repl_init(void); int pyexec_event_repl_process_char(int c); extern uint8_t pyexec_repl_active; diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 7b019191e3..d05380fc28 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -733,14 +733,6 @@ msgid "" "connection." msgstr "" -#: py/persistentcode.c -msgid "Corrupt .mpy file" -msgstr "" - -#: py/emitglue.c -msgid "Corrupt raw code" -msgstr "" - #: ports/cxd56/common-hal/camera/Camera.c msgid "Could not initialize Camera" msgstr "" @@ -2560,10 +2552,6 @@ msgstr "" msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: py/persistentcode.c -msgid "can only save bytecode" -msgstr "" - #: py/objtype.c msgid "can't add special method to already-subclassed class" msgstr "" @@ -3071,6 +3059,14 @@ msgstr "" msgid "identifier redefined as nonlocal" msgstr "" +#: py/persistentcode.c +msgid "incompatible .mpy file" +msgstr "" + +#: py/persistentcode.c +msgid "incompatible native .mpy architecture" +msgstr "" + #: py/objstr.c msgid "incomplete format" msgstr "" @@ -3190,6 +3186,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/compile.c +msgid "invalid architecture" +msgstr "" + #: lib/netutils/netutils.c msgid "invalid arguments" msgstr "" @@ -3199,10 +3199,6 @@ msgstr "" msgid "invalid bits_per_pixel %d, must be, 1, 4, 8, 16, 24, or 32" msgstr "" -#: extmod/modussl_axtls.c -msgid "invalid cert" -msgstr "" - #: py/compile.c msgid "invalid decorator" msgstr "" @@ -3233,10 +3229,6 @@ msgstr "" msgid "invalid hostname" msgstr "" -#: extmod/modussl_axtls.c -msgid "invalid key" -msgstr "" - #: py/compile.c msgid "invalid micropython decorator" msgstr "" diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile index 200080bbe5..6e4d7ef316 100644 --- a/mpy-cross/Makefile +++ b/mpy-cross/Makefile @@ -13,6 +13,8 @@ override undefine MICROPY_FORCE_32BIT override undefine CROSS_COMPILE override undefine FROZEN_DIR override undefine FROZEN_MPY_DIR +override undefine USER_C_MODULES +override undefine SRC_MOD override undefine BUILD override undefine PROG endif diff --git a/mpy-cross/gccollect.c b/mpy-cross/gccollect.c index 9a975af8db..117a903869 100644 --- a/mpy-cross/gccollect.c +++ b/mpy-cross/gccollect.c @@ -122,9 +122,6 @@ void gc_collect(void) { // GC stack (and regs because we captured them) void **regs_ptr = (void **)(void *)®s; gc_collect_root(regs_ptr, ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)®s) / sizeof(mp_uint_t)); - #if MICROPY_EMIT_NATIVE - mp_unix_mark_exec(); - #endif gc_collect_end(); } diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 6e99ea2408..786f0635e3 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -13,6 +13,7 @@ #include "py/runtime.h" #include "py/gc.h" #include "py/stackctrl.h" +#include "genhdr/mpversion.h" #ifdef _WIN32 #include "fmode.h" #endif @@ -46,9 +47,7 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha } #if MICROPY_PY___FILE__ - if (input_kind == MP_PARSE_FILE_INPUT) { - mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); - } + mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); @@ -77,20 +76,22 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha STATIC int usage(char **argv) { printf( - "usage: %s [] [-X ] \n" - "Options:\n" - "-o : output file for compiled bytecode (defaults to input with .mpy extension)\n" - "-s : source filename to embed in the compiled bytecode (defaults to input file)\n" - "-v : verbose (trace various operations); can be multiple\n" - "-O[N] : apply bytecode optimizations of level N\n" - "\n" - "Target specific options:\n" - "-msmall-int-bits=number : set the maximum bits used to encode a small-int\n" - "-mno-unicode : don't support unicode in compiled strings\n" - "-mcache-lookup-bc : cache map lookups in the bytecode\n" - "\n" - "Implementation specific options:\n", argv[0] - ); +"usage: %s [] [-X ] \n" +"Options:\n" +"--version : show version information\n" +"-o : output file for compiled bytecode (defaults to input with .mpy extension)\n" +"-s : source filename to embed in the compiled bytecode (defaults to input file)\n" +"-v : verbose (trace various operations); can be multiple\n" +"-O[N] : apply bytecode optimizations of level N\n" +"\n" +"Target specific options:\n" +"-msmall-int-bits=number : set the maximum bits used to encode a small-int\n" +"-mno-unicode : don't support unicode in compiled strings\n" +"-mcache-lookup-bc : cache map lookups in the bytecode\n" +"-march= : set architecture for native emitter; x86, x64, armv6, armv7m, xtensa\n" +"\n" +"Implementation specific options:\n", argv[0] +); int impl_opts_cnt = 0; printf( " emit={bytecode,native,viper} -- set the default code emitter\n" @@ -172,6 +173,15 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_dynamic_compiler.small_int_bits = 31; mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0; mp_dynamic_compiler.py_builtins_str_unicode = 1; + #if defined(__i386__) + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86; + #elif defined(__x86_64__) + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64; + #elif defined(__arm__) && !defined(__thumb2__) + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6; + #else + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_NONE; + #endif const char *input_file = NULL; const char *output_file = NULL; @@ -182,6 +192,10 @@ MP_NOINLINE int main_(int argc, char **argv) { if (argv[a][0] == '-') { if (strcmp(argv[a], "-X") == 0) { a += 1; + } else if (strcmp(argv[a], "--version") == 0) { + printf("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE + "; mpy-cross emitting mpy v" MP_STRINGIFY(MPY_VERSION) "\n"); + return 0; } else if (strcmp(argv[a], "-v") == 0) { mp_verbose_flag++; } else if (strncmp(argv[a], "-O", 2) == 0) { @@ -220,6 +234,21 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_dynamic_compiler.py_builtins_str_unicode = 0; } else if (strcmp(argv[a], "-municode") == 0) { mp_dynamic_compiler.py_builtins_str_unicode = 1; + } else if (strncmp(argv[a], "-march=", sizeof("-march=") - 1) == 0) { + const char *arch = argv[a] + sizeof("-march=") - 1; + if (strcmp(arch, "x86") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86; + } else if (strcmp(arch, "x64") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64; + } else if (strcmp(arch, "armv6") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6; + } else if (strcmp(arch, "armv7m") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7M; + } else if (strcmp(arch, "xtensa") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSA; + } else { + return usage(argv); + } } else { return usage(argv); } diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index 74bb774afc..fc94c27c38 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -9,13 +9,15 @@ #define MICROPY_PERSISTENT_CODE_LOAD (0) #define MICROPY_PERSISTENT_CODE_SAVE (1) -#define MICROPY_EMIT_X64 (0) -#define MICROPY_EMIT_X86 (0) -#define MICROPY_EMIT_THUMB (0) -#define MICROPY_EMIT_INLINE_THUMB (0) -#define MICROPY_EMIT_INLINE_THUMB_ARMV7M (0) -#define MICROPY_EMIT_INLINE_THUMB_FLOAT (0) -#define MICROPY_EMIT_ARM (0) +#define MICROPY_EMIT_X64 (1) +#define MICROPY_EMIT_X86 (1) +#define MICROPY_EMIT_THUMB (1) +#define MICROPY_EMIT_INLINE_THUMB (1) +#define MICROPY_EMIT_INLINE_THUMB_ARMV7M (1) +#define MICROPY_EMIT_INLINE_THUMB_FLOAT (1) +#define MICROPY_EMIT_ARM (1) +#define MICROPY_EMIT_XTENSA (1) +#define MICROPY_EMIT_INLINE_XTENSA (1) #define MICROPY_DYNAMIC_COMPILER (1) #define MICROPY_COMP_CONST_FOLDING (1) @@ -134,10 +136,6 @@ typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) (void)0 -#ifndef MP_NOINLINE -#define MP_NOINLINE __attribute__((noinline)) -#endif - // We need to provide a declaration/definition of alloca() #ifdef __FreeBSD__ #include diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 48724af0c8..574d115260 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -302,18 +302,7 @@ SRC_C += \ eic_handler.c \ fatfs_port.c \ freetouch/adafruit_ptc.c \ - lib/libc/string0.c \ - lib/mp-readline/readline.c \ - lib/oofatfs/ff.c \ - lib/oofatfs/option/ccsbcs.c \ - lib/timeutils/timeutils.c \ lib/tinyusb/src/portable/microchip/samd/dcd_samd.c \ - lib/utils/buffer_helper.c \ - lib/utils/context_manager_helpers.c \ - lib/utils/interrupt_char.c \ - lib/utils/pyexec.c \ - lib/utils/stdout_helpers.c \ - lib/utils/sys_stdio_mphal.c \ mphalport.c \ peripherals/samd/$(PERIPHERALS_CHIP_FAMILY)/adc.c \ peripherals/samd/$(PERIPHERALS_CHIP_FAMILY)/cache.c \ @@ -331,7 +320,6 @@ SRC_C += \ peripherals/samd/sercom.c \ peripherals/samd/timers.c \ reset.c \ - supervisor/shared/memory.c \ timer_handler.c \ ifeq ($(CIRCUITPY_SDIOIO),1) @@ -390,6 +378,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif +OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) diff --git a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk index dd012cb487..5921bd2f1a 100644 --- a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk @@ -12,28 +12,16 @@ LONGINT_IMPL = MPZ CIRCUITPY_BITBANGIO = 0 CIRCUITPY_BITMAPTOOLS = 0 +CIRCUITPY_BUSDEVICE = 0 CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_COUNTIO = 0 CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_MSGPACK = 0 # supersized, not ultra-supersized CIRCUITPY_VECTORIO = 0 -CIRCUITPY_BUSDEVICE = 0 -CFLAGS_INLINE_LIMIT = 60 +CFLAGS_INLINE_LIMIT = 35 SUPEROPT_GC = 0 +SUPEROPT_VM = 0 CFLAGS_BOARD = --param max-inline-insns-auto=15 -ifeq ($(TRANSLATION), ja) -RELEASE_NEEDS_CLEAN_BUILD = 1 -CFLAGS_INLINE_LIMIT = 35 -endif -ifeq ($(TRANSLATION), zh_Latn_pinyin) -RELEASE_NEEDS_CLEAN_BUILD = 1 -CFLAGS_INLINE_LIMIT = 35 -endif -ifeq ($(TRANSLATION), de_DE) -RELEASE_NEEDS_CLEAN_BUILD = 1 -CFLAGS_INLINE_LIMIT = 35 -SUPEROPT_VM = 0 -endif diff --git a/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk index 8c51315429..e97f9884da 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk @@ -17,6 +17,7 @@ CIRCUITPY_COUNTIO = 0 CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_GAMEPAD = 0 CIRCUITPY_I2CPERIPHERAL = 0 +CIRCUITPY_MSGPACK = 0 CIRCUITPY_ROTARYIO = 0 CIRCUITPY_RTC = 0 CIRCUITPY_COUNTIO = 0 diff --git a/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk index 467c6af47a..106eef89cf 100644 --- a/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk @@ -19,6 +19,7 @@ CIRCUITPY_COUNTIO = 0 CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_GAMEPAD = 0 CIRCUITPY_I2CPERIPHERAL = 0 +CIRCUITPY_MSGPACK = 0 CIRCUITPY_RTC = 0 # too itsy bitsy for all of displayio CIRCUITPY_VECTORIO = 0 diff --git a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk index 964d335537..01e6094cdf 100644 --- a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk @@ -17,6 +17,7 @@ CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_MSGPACK = 0 CIRCUITPY_VECTORIO = 0 CIRCUITPY_BUSDEVICE = 0 +MICROPY_PY_ASYNC_AWAIT = 0 SUPEROPT_GC = 0 SUPEROPT_VM = 0 diff --git a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk index 99dddfa892..d500b81112 100644 --- a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk @@ -21,6 +21,7 @@ CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_NEOPIXEL_WRITE = 0 CIRCUITPY_PIXELBUF = 0 CIRCUITPY_PS2IO = 0 +CIRCUITPY_PULSEIO = 0 CIRCUITPY_ROTARYIO = 0 CIRCUITPY_RTC = 0 CIRCUITPY_SAMD = 0 diff --git a/ports/atmel-samd/boards/qtpy_m0_haxpress/mpconfigboard.mk b/ports/atmel-samd/boards/qtpy_m0_haxpress/mpconfigboard.mk index a88bea91de..1ffe1669e7 100644 --- a/ports/atmel-samd/boards/qtpy_m0_haxpress/mpconfigboard.mk +++ b/ports/atmel-samd/boards/qtpy_m0_haxpress/mpconfigboard.mk @@ -18,6 +18,7 @@ CIRCUITPY_COUNTIO = 0 CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_MSGPACK = 0 +CIRCUITPY_VECTORIO = 0 SUPEROPT_GC = 0 SUPEROPT_VM = 0 diff --git a/ports/atmel-samd/boards/serpente/mpconfigboard.mk b/ports/atmel-samd/boards/serpente/mpconfigboard.mk index 32ba32f386..422baf46ad 100644 --- a/ports/atmel-samd/boards/serpente/mpconfigboard.mk +++ b/ports/atmel-samd/boards/serpente/mpconfigboard.mk @@ -12,9 +12,10 @@ LONGINT_IMPL = NONE CIRCUITPY_AUDIOBUSIO = 0 CIRCUITPY_BITMAPTOOLS = 0 +CIRCUITPY_BUSDEVICE = 0 CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_GAMEPAD = 0 -CIRCUITPY_BUSDEVICE = 0 +CIRCUITPY_MSGPACK = 0 SUPEROPT_GC = 0 SUPEROPT_VM = 0 diff --git a/ports/atmel-samd/boards/sparkfun_lumidrive/mpconfigboard.mk b/ports/atmel-samd/boards/sparkfun_lumidrive/mpconfigboard.mk index 197dea6fe2..aca557cec6 100755 --- a/ports/atmel-samd/boards/sparkfun_lumidrive/mpconfigboard.mk +++ b/ports/atmel-samd/boards/sparkfun_lumidrive/mpconfigboard.mk @@ -13,8 +13,9 @@ LONGINT_IMPL = MPZ CIRCUITPY_AUDIOIO = 0 CIRCUITPY_AUDIOBUSIO = 0 CIRCUITPY_BITMAPTOOLS = 0 -CIRCUITPY_VECTORIO = 0 CIRCUITPY_BUSDEVICE = 0 +CIRCUITPY_MSGPACK = 0 +CIRCUITPY_VECTORIO = 0 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DotStar diff --git a/ports/atmel-samd/boards/stackrduino_m0_pro/mpconfigboard.mk b/ports/atmel-samd/boards/stackrduino_m0_pro/mpconfigboard.mk index fb46e99dae..0f9b8a3c18 100644 --- a/ports/atmel-samd/boards/stackrduino_m0_pro/mpconfigboard.mk +++ b/ports/atmel-samd/boards/stackrduino_m0_pro/mpconfigboard.mk @@ -19,6 +19,7 @@ CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_MSGPACK = 0 CIRCUITPY_VECTORIO = 0 CIRCUITPY_BUSDEVICE = 0 +MICROPY_PY_ASYNC_AWAIT = 0 SUPEROPT_GC = 0 SUPEROPT_VM = 0 diff --git a/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk b/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk index 8c9dc71699..e91c94e56d 100644 --- a/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk +++ b/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk @@ -20,18 +20,8 @@ CIRCUITPY_I2CPERIPHERAL = 0 MICROPY_PY_ASYNC_AWAIT = 0 SUPEROPT_GC = 0 +SUPEROPT_VM = 0 + +CFLAGS_INLINE_LIMIT = 35 CFLAGS_BOARD = --param max-inline-insns-auto=15 -ifeq ($(TRANSLATION), zh_Latn_pinyin) -RELEASE_NEEDS_CLEAN_BUILD = 1 -CFLAGS_INLINE_LIMIT = 35 -endif -ifeq ($(TRANSLATION), ja) -RELEASE_NEEDS_CLEAN_BUILD = 1 -CFLAGS_INLINE_LIMIT = 35 -endif -ifeq ($(TRANSLATION), de_DE) -RELEASE_NEEDS_CLEAN_BUILD = 1 -CFLAGS_INLINE_LIMIT = 35 -SUPEROPT_VM = 0 -endif diff --git a/ports/cxd56/Makefile b/ports/cxd56/Makefile index 15eb5e64c7..1fea295194 100644 --- a/ports/cxd56/Makefile +++ b/ports/cxd56/Makefile @@ -168,18 +168,6 @@ SRC_C += \ mphalport.c \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ - lib/utils/stdout_helpers.c \ - lib/utils/pyexec.c \ - lib/libc/string0.c \ - lib/mp-readline/readline.c \ - lib/timeutils/timeutils.c \ - lib/oofatfs/ff.c \ - lib/oofatfs/option/ccsbcs.c \ - lib/utils/interrupt_char.c \ - lib/utils/sys_stdio_mphal.c \ - lib/utils/context_manager_helpers.c \ - lib/utils/buffer_helper.c \ - supervisor/shared/memory.c \ lib/tinyusb/src/portable/sony/cxd56/dcd_cxd56.c \ OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) @@ -189,6 +177,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif +OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) # List of sources for qstr extraction diff --git a/ports/esp32s2/Makefile b/ports/esp32s2/Makefile index b4ff0612b3..22a2bdd3d7 100644 --- a/ports/esp32s2/Makefile +++ b/ports/esp32s2/Makefile @@ -182,24 +182,12 @@ SRC_C += \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ modules/$(CIRCUITPY_MODULE).c \ - lib/libc/string0.c \ - lib/mp-readline/readline.c \ - lib/oofatfs/ff.c \ - lib/oofatfs/option/ccsbcs.c \ - lib/timeutils/timeutils.c \ - lib/utils/buffer_helper.c \ - lib/utils/context_manager_helpers.c \ - lib/utils/interrupt_char.c \ - lib/utils/pyexec.c \ - lib/utils/stdout_helpers.c \ - lib/utils/sys_stdio_mphal.c \ lib/netutils/netutils.c \ peripherals/timer.c \ peripherals/touch.c \ peripherals/pcnt.c \ peripherals/pins.c \ - peripherals/rmt.c \ - supervisor/shared/memory.c + peripherals/rmt.c ifneq ($(USB),FALSE) SRC_C += lib/tinyusb/src/portable/espressif/esp32s2/dcd_esp32s2.c @@ -227,6 +215,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif +OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) diff --git a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c index 9ccb5700cb..872c0f7124 100644 --- a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c +++ b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c @@ -104,7 +104,7 @@ mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *al // First, check to see if we match any given alarms. uint64_t pin_status = ((uint64_t)pin_63_32_status) << 32 | pin_31_0_status; for (size_t i = 0; i < n_alarms; i++) { - if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pinalarm_type)) { + if (!mp_obj_is_type(alarms[i], &alarm_pin_pinalarm_type)) { continue; } alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]); @@ -179,7 +179,7 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob for (size_t i = 0; i < n_alarms; i++) { // TODO: Check for ULP or touch alarms because they can't coexist with GPIO alarms. - if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pinalarm_type)) { + if (!mp_obj_is_type(alarms[i], &alarm_pin_pinalarm_type)) { continue; } alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]); diff --git a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c index 93e4f18091..848ce32a93 100644 --- a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c +++ b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c @@ -45,7 +45,7 @@ mp_float_t common_hal_alarm_time_timealarm_get_monotonic_time(alarm_time_timeala mp_obj_t alarm_time_timealarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms) { // First, check to see if we match for (size_t i = 0; i < n_alarms; i++) { - if (MP_OBJ_IS_TYPE(alarms[i], &alarm_time_timealarm_type)) { + if (mp_obj_is_type(alarms[i], &alarm_time_timealarm_type)) { return alarms[i]; } } @@ -82,7 +82,7 @@ void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ alarm_time_timealarm_obj_t *timealarm = MP_OBJ_NULL; for (size_t i = 0; i < n_alarms; i++) { - if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_time_timealarm_type)) { + if (!mp_obj_is_type(alarms[i], &alarm_time_timealarm_type)) { continue; } if (timealarm_set) { diff --git a/ports/esp32s2/common-hal/alarm/touch/TouchAlarm.c b/ports/esp32s2/common-hal/alarm/touch/TouchAlarm.c index 8c139afaf3..15e3c736a8 100644 --- a/ports/esp32s2/common-hal/alarm/touch/TouchAlarm.c +++ b/ports/esp32s2/common-hal/alarm/touch/TouchAlarm.c @@ -45,7 +45,7 @@ void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *s mp_obj_t alarm_touch_touchalarm_get_wakeup_alarm(const size_t n_alarms, const mp_obj_t *alarms) { // First, check to see if we match any given alarms. for (size_t i = 0; i < n_alarms; i++) { - if (MP_OBJ_IS_TYPE(alarms[i], &alarm_touch_touchalarm_type)) { + if (mp_obj_is_type(alarms[i], &alarm_touch_touchalarm_type)) { return alarms[i]; } } @@ -88,7 +88,7 @@ void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alar alarm_touch_touchalarm_obj_t *touch_alarm = MP_OBJ_NULL; for (size_t i = 0; i < n_alarms; i++) { - if (MP_OBJ_IS_TYPE(alarms[i], &alarm_touch_touchalarm_type)) { + if (mp_obj_is_type(alarms[i], &alarm_touch_touchalarm_type)) { if (deep_sleep && touch_alarm_set) { mp_raise_ValueError(translate("Only one TouchAlarm can be set in deep sleep.")); } diff --git a/ports/esp32s2/common-hal/wifi/__init__.c b/ports/esp32s2/common-hal/wifi/__init__.c index 3ec4ebc24d..720b49c009 100644 --- a/ports/esp32s2/common-hal/wifi/__init__.c +++ b/ports/esp32s2/common-hal/wifi/__init__.c @@ -158,7 +158,7 @@ void wifi_reset(void) { } void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t *esp_ip_address) { - if (!MP_OBJ_IS_TYPE(ip_address, &ipaddress_ipv4address_type)) { + if (!mp_obj_is_type(ip_address, &ipaddress_ipv4address_type)) { mp_raise_ValueError(translate("Only IPv4 addresses supported")); } mp_obj_t packed = common_hal_ipaddress_ipv4address_get_packed(ip_address); diff --git a/ports/litex/Makefile b/ports/litex/Makefile index f384f24577..373a6465b7 100644 --- a/ports/litex/Makefile +++ b/ports/litex/Makefile @@ -122,19 +122,7 @@ SRC_C += \ fatfs_port.c \ mphalport.c \ boards/$(BOARD)/board.c \ - boards/$(BOARD)/pins.c \ - lib/libc/string0.c \ - lib/mp-readline/readline.c \ - lib/oofatfs/ff.c \ - lib/oofatfs/option/ccsbcs.c \ - lib/timeutils/timeutils.c \ - lib/utils/buffer_helper.c \ - lib/utils/context_manager_helpers.c \ - lib/utils/interrupt_char.c \ - lib/utils/pyexec.c \ - lib/utils/stdout_helpers.c \ - lib/utils/sys_stdio_mphal.c \ - supervisor/shared/memory.c + boards/$(BOARD)/pins.c ifneq ($(USB),FALSE) SRC_C += lib/tinyusb/src/portable/valentyusb/eptri/dcd_eptri.c @@ -163,6 +151,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif +OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) diff --git a/ports/mimxrt10xx/Makefile b/ports/mimxrt10xx/Makefile index 33507086ea..fcbb3ecf31 100644 --- a/ports/mimxrt10xx/Makefile +++ b/ports/mimxrt10xx/Makefile @@ -154,24 +154,13 @@ SRC_C += \ boards/$(BOARD)/flash_config.c \ boards/$(BOARD)/pins.c \ fatfs_port.c \ - lib/mp-readline/readline.c \ - lib/oofatfs/ff.c \ - lib/oofatfs/option/ccsbcs.c \ - lib/timeutils/timeutils.c \ - lib/utils/buffer_helper.c \ - lib/utils/context_manager_helpers.c \ - lib/utils/interrupt_char.c \ - lib/utils/pyexec.c \ - lib/utils/stdout_helpers.c \ - lib/utils/sys_stdio_mphal.c \ lib/tinyusb/src/portable/nxp/transdimension/dcd_transdimension.c \ mphalport.c \ peripherals/mimxrt10xx/$(CHIP_FAMILY)/clocks.c \ peripherals/mimxrt10xx/$(CHIP_FAMILY)/periph.c \ peripherals/mimxrt10xx/$(CHIP_FAMILY)/pins.c \ reset.c \ - supervisor/flexspi_nor_flash_ops.c \ - supervisor/shared/memory.c + supervisor/flexspi_nor_flash_ops.c ifeq ($(CIRCUITPY_NETWORK),1) @@ -224,6 +213,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif +OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 278625e92d..13dd955c20 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -156,17 +156,6 @@ SRC_C += \ device/$(MCU_VARIANT)/startup_$(MCU_SUB_VARIANT).c \ bluetooth/ble_drv.c \ common-hal/_bleio/bonding.c \ - lib/libc/string0.c \ - lib/mp-readline/readline.c \ - lib/oofatfs/ff.c \ - lib/oofatfs/option/ccsbcs.c \ - lib/timeutils/timeutils.c \ - lib/utils/buffer_helper.c \ - lib/utils/context_manager_helpers.c \ - lib/utils/interrupt_char.c \ - lib/utils/pyexec.c \ - lib/utils/stdout_helpers.c \ - lib/utils/sys_stdio_mphal.c \ nrfx/mdk/system_$(MCU_SUB_VARIANT).c \ peripherals/nrf/cache.c \ peripherals/nrf/clocks.c \ @@ -174,8 +163,7 @@ SRC_C += \ peripherals/nrf/$(MCU_CHIP)/power.c \ peripherals/nrf/nvm.c \ peripherals/nrf/timers.c \ - sd_mutex.c \ - supervisor/shared/memory.c + sd_mutex.c # USB source files for nrf52840 ifeq ($(MCU_SUB_VARIANT),nrf52840) @@ -235,6 +223,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif +OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) diff --git a/ports/nrf/boards/simmel/mpconfigboard.mk b/ports/nrf/boards/simmel/mpconfigboard.mk index 005ec8af2f..f3fdb19f4e 100644 --- a/ports/nrf/boards/simmel/mpconfigboard.mk +++ b/ports/nrf/boards/simmel/mpconfigboard.mk @@ -27,6 +27,7 @@ CIRCUITPY_RGBMATRIX = 0 CIRCUITPY_ROTARYIO = 0 CIRCUITPY_RTC = 1 CIRCUITPY_SDCARDIO = 0 +CIRCUITPY_SYNTHIO = 0 CIRCUITPY_TOUCHIO = 0 CIRCUITPY_ULAB = 0 CIRCUITPY_USB_CDC = 0 diff --git a/ports/nrf/common-hal/_bleio/Connection.c b/ports/nrf/common-hal/_bleio/Connection.c index 7e0b7a10e9..cdc6fd3d68 100644 --- a/ports/nrf/common-hal/_bleio/Connection.c +++ b/ports/nrf/common-hal/_bleio/Connection.c @@ -645,7 +645,7 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); mp_obj_t uuid_obj; while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { + if (!mp_obj_is_type(uuid_obj, &bleio_uuid_type)) { mp_raise_TypeError(translate("non-UUID found in service_uuids_whitelist")); } bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 2a054516be..9333f5d1f4 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -199,21 +199,9 @@ SRC_C += \ peripherals/pins.c \ extmod/crypto-algorithms/sha256.c \ fatfs_port.c \ - lib/libc/string0.c \ - lib/mp-readline/readline.c \ - lib/oofatfs/ff.c \ - lib/oofatfs/option/ccsbcs.c \ - lib/timeutils/timeutils.c \ lib/tinyusb/src/portable/raspberrypi/rp2040/dcd_rp2040.c \ lib/tinyusb/src/portable/raspberrypi/rp2040/rp2040_usb.c \ - lib/utils/buffer_helper.c \ - lib/utils/context_manager_helpers.c \ - lib/utils/interrupt_char.c \ - lib/utils/pyexec.c \ - lib/utils/stdout_helpers.c \ - lib/utils/sys_stdio_mphal.c \ mphalport.c \ - supervisor/shared/memory.c \ SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ $(addprefix shared-bindings/, $(SRC_BINDINGS_ENUMS)) \ @@ -248,6 +236,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif +OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.c b/ports/raspberrypi/bindings/rp2pio/StateMachine.c index fe36423256..342a223693 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.c +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.c @@ -599,7 +599,7 @@ const mp_obj_type_t rp2pio_statemachine_type = { }; rp2pio_statemachine_obj_t *validate_obj_is_statemachine(mp_obj_t obj) { - if (!MP_OBJ_IS_TYPE(obj, &rp2pio_statemachine_type)) { + if (!mp_obj_is_type(obj, &rp2pio_statemachine_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), rp2pio_statemachine_type.name); } return MP_OBJ_TO_PTR(obj); diff --git a/ports/stm/Makefile b/ports/stm/Makefile index e09fe736cc..1b0e981997 100755 --- a/ports/stm/Makefile +++ b/ports/stm/Makefile @@ -117,7 +117,7 @@ MCU_FLAGS_H7 = -mcpu=cortex-m7 CFLAGS += $(MCU_FLAGS_$(MCU_SERIES)) # Select HAL file for distribution via mpconfigport -CFLAGS += -DSTM32_HAL_H='' +CFLAGS += -DSTM32_HAL_H="" CFLAGS += -DSTM32_SERIES_LOWER='"stm32$(MCU_SERIES_LOWER)"' @@ -224,19 +224,7 @@ SRC_C += \ peripherals/stm32$(MCU_SERIES_LOWER)/$(MCU_VARIANT_LOWER)/pins.c \ peripherals/stm32$(MCU_SERIES_LOWER)/$(MCU_VARIANT_LOWER)/gpio.c \ peripherals/stm32$(MCU_SERIES_LOWER)/$(MCU_VARIANT_LOWER)/periph.c \ - packages/$(MCU_PACKAGE).c \ - lib/libc/string0.c \ - lib/mp-readline/readline.c \ - lib/oofatfs/ff.c \ - lib/oofatfs/option/ccsbcs.c \ - lib/timeutils/timeutils.c \ - lib/utils/buffer_helper.c \ - lib/utils/context_manager_helpers.c \ - lib/utils/interrupt_char.c \ - lib/utils/pyexec.c \ - lib/utils/stdout_helpers.c \ - lib/utils/sys_stdio_mphal.c \ - supervisor/shared/memory.c + packages/$(MCU_PACKAGE).c ifneq ($(USB),FALSE) SRC_C += lib/tinyusb/src/portable/st/synopsys/dcd_synopsys.c @@ -267,6 +255,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif +OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index bb900a29b3..555e76a6aa 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -166,7 +166,7 @@ LIB_SRC_C = $(addprefix lib/,\ # FatFS VFS support LIB_SRC_C += $(addprefix lib/,\ oofatfs/ff.c \ - oofatfs/option/unicode.c \ + oofatfs/ffunicode.c \ ) OBJ = $(PY_O) @@ -259,10 +259,11 @@ coverage: coverage_test: coverage $(eval DIRNAME=ports/$(notdir $(CURDIR))) - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests -j1 - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests -j1 -d thread - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests -j1 --emit native - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests -j1 --via-mpy -d basics float + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests -d thread + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --emit native + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --via-mpy -d basics float micropython + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --via-mpy --emit native -d basics float micropython cat $(TOP)/tests/basics/0prelim.py | ./micropython_coverage | grep -q 'abc' gcov -o build-coverage/py $(TOP)/py/*.c gcov -o build-coverage/extmod $(TOP)/extmod/*.c diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 2d377bc8fe..e498d165cc 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -163,6 +163,7 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned mp_printf(&mp_plat_print, "%X\n", 0x80000000); // should print unsigned mp_printf(&mp_plat_print, "abc\n%"); // string ends in middle of format specifier + mp_printf(&mp_plat_print, "%%\n"); // literal % character } // GC @@ -252,7 +253,7 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "# str\n"); // intern string - mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9)))); + mp_printf(&mp_plat_print, "%d\n", mp_obj_is_qstr(mp_obj_str_intern(mp_obj_new_str("intern me", 9)))); } // bytearray diff --git a/ports/unix/file.c b/ports/unix/file.c index 745593c81c..d0d0b106a7 100644 --- a/ports/unix/file.c +++ b/ports/unix/file.c @@ -193,7 +193,7 @@ STATIC mp_obj_t fdfile_open(const mp_obj_type_t *type, mp_arg_val_t *args) { mp_obj_t fid = args[0].u_obj; - if (MP_OBJ_IS_SMALL_INT(fid)) { + if (mp_obj_is_small_int(fid)) { o->fd = MP_OBJ_SMALL_INT_VALUE(fid); return MP_OBJ_FROM_PTR(o); } diff --git a/ports/unix/gccollect.c b/ports/unix/gccollect.c index 45ad1e0430..efe6205a68 100644 --- a/ports/unix/gccollect.c +++ b/ports/unix/gccollect.c @@ -149,9 +149,14 @@ STATIC void gc_helper_get_regs(regs_t arr) { #endif // MICROPY_GCREGS_SETJMP // this function is used by mpthreadport.c -void gc_collect_regs_and_stack(void); +MP_NOINLINE void gc_collect_regs_and_stack(void); -void gc_collect_regs_and_stack(void) { +// Explicitly mark this as noinline to make sure the regs variable +// is effectively at the top of the stack: otherwise, in builds where +// LTO is enabled and a lot of inlining takes place we risk a stack +// layout where regs is lower on the stack than pointers which have +// just been allocated but not yet marked, and get incorrectly sweeped. +MP_NOINLINE void gc_collect_regs_and_stack(void) { regs_t regs; gc_helper_get_regs(regs); // GC stack (and regs because we captured them) diff --git a/ports/unix/main.c b/ports/unix/main.c index 715ad56589..cc225e7d6a 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -653,6 +654,10 @@ MP_NOINLINE int main_(int argc, char **argv) { } #endif + #if MICROPY_PY_THREAD + mp_thread_deinit(); + #endif + #if defined(MICROPY_UNIX_COVERAGE) gc_sweep_all(); #endif diff --git a/ports/unix/modffi.c b/ports/unix/modffi.c index 894702330f..9e953ca81d 100644 --- a/ports/unix/modffi.c +++ b/ports/unix/modffi.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2018 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -141,7 +141,7 @@ STATIC ffi_type *char2ffi_type(char c) { } STATIC ffi_type *get_ffi_type(mp_obj_t o_in) { - if (MP_OBJ_IS_STR(o_in)) { + if (mp_obj_is_str(o_in)) { const char *s = mp_obj_str_get_str(o_in); ffi_type *t = char2ffi_type(*s); if (t != NULL) { @@ -365,6 +365,7 @@ STATIC void ffifunc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki } STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)n_kw; mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in); assert(n_kw == 0); assert(n_args == self->cif.nargs); @@ -386,9 +387,9 @@ STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const #endif } else if (a == mp_const_none) { values[i] = 0; - } else if (MP_OBJ_IS_INT(a)) { + } else if (mp_obj_is_int(a)) { values[i] = mp_obj_int_get_truncated(a); - } else if (MP_OBJ_IS_STR(a)) { + } else if (mp_obj_is_str(a)) { const char *s = mp_obj_str_get_str(a); values[i] = (ffi_arg)(intptr_t)s; } else if (((mp_obj_base_t *)MP_OBJ_TO_PTR(a))->type->buffer_p.get_buffer != NULL) { @@ -399,7 +400,7 @@ STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const goto error; } values[i] = (ffi_arg)(intptr_t)bufinfo.buf; - } else if (MP_OBJ_IS_TYPE(a, &fficallback_type)) { + } else if (mp_obj_is_type(a, &fficallback_type)) { mp_obj_fficallback_t *p = MP_OBJ_TO_PTR(a); values[i] = (ffi_arg)(intptr_t)p->func; } else { diff --git a/ports/unix/modjni.c b/ports/unix/modjni.c index 3ff5c61f50..4a9fdb4a58 100644 --- a/ports/unix/modjni.c +++ b/ports/unix/modjni.c @@ -658,12 +658,12 @@ STATIC mp_obj_t mod_jni_array(mp_obj_t type_in, mp_obj_t size_in) { mp_int_t size = mp_obj_get_int(size_in); jobject res = NULL; - if (MP_OBJ_IS_TYPE(type_in, &jclass_type)) { + if (mp_obj_is_type(type_in, &jclass_type)) { mp_obj_jclass_t *jcls = MP_OBJ_TO_PTR(type_in); res = JJ(NewObjectArray, size, jcls->cls, NULL); - } else if (MP_OBJ_IS_STR(type_in)) { + } else if (mp_obj_is_str(type_in)) { const char *type = mp_obj_str_get_str(type_in); switch (*type) { case 'Z': diff --git a/ports/unix/modmachine.c b/ports/unix/modmachine.c index af3a9d88fe..0871d84d02 100644 --- a/ports/unix/modmachine.c +++ b/ports/unix/modmachine.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2015 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -59,10 +60,11 @@ uintptr_t mod_machine_mem_get_addr(mp_obj_t addr_o, uint align) { static uintptr_t last_base = (uintptr_t)-1; static uintptr_t map_page; if (!fd) { - fd = open("/dev/mem", O_RDWR | O_SYNC); - if (fd == -1) { + int _fd = open("/dev/mem", O_RDWR | O_SYNC); + if (_fd == -1) { mp_raise_OSError(errno); } + fd = _fd; } uintptr_t cur_base = addr & ~MICROPY_PAGE_MASK; diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 43d7590518..6a6b8e5e61 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -3,8 +3,8 @@ * * The MIT License (MIT) * - * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2018 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/ports/unix/modtermios.c b/ports/unix/modtermios.c index bd723085de..0355a8ce73 100644 --- a/ports/unix/modtermios.c +++ b/ports/unix/modtermios.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-2015 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -77,7 +77,7 @@ STATIC mp_obj_t mod_termios_tcsetattr(mp_obj_t fd_in, mp_obj_t when_in, mp_obj_t when = TCSANOW; } - assert(MP_OBJ_IS_TYPE(attrs_in, &mp_type_list)); + assert(mp_obj_is_type(attrs_in, &mp_type_list)); mp_obj_list_t *attrs = MP_OBJ_TO_PTR(attrs_in); term.c_iflag = mp_obj_get_int(attrs->items[0]); diff --git a/ports/unix/modtime.c b/ports/unix/modtime.c index 94ae8d2f1e..6ea85359da 100644 --- a/ports/unix/modtime.c +++ b/ports/unix/modtime.c @@ -3,7 +3,8 @@ * * The MIT License (MIT) * - * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2017 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/ports/unix/moduselect.c b/ports/unix/moduselect.c index d4c6a8e179..299fa20039 100644 --- a/ports/unix/moduselect.c +++ b/ports/unix/moduselect.c @@ -66,7 +66,7 @@ typedef struct _mp_obj_poll_t { } mp_obj_poll_t; STATIC int get_fd(mp_obj_t fdlike) { - if (MP_OBJ_IS_OBJ(fdlike)) { + if (mp_obj_is_obj(fdlike)) { const mp_stream_p_t *stream_p = mp_get_stream_raise(fdlike, MP_STREAM_OP_IOCTL); int err; mp_uint_t res = stream_p->ioctl(fdlike, MP_STREAM_GET_FILENO, 0, &err); @@ -80,7 +80,7 @@ STATIC int get_fd(mp_obj_t fdlike) { /// \method register(obj[, eventmask]) STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) { mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); - bool is_fd = MP_OBJ_IS_INT(args[1]); + bool is_fd = mp_obj_is_int(args[1]); int fd = get_fd(args[1]); mp_uint_t flags; diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index 24778b6b55..984c6d914d 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -3,8 +3,8 @@ * * The MIT License (MIT) * - * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2018 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2019 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -162,7 +162,12 @@ STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(addr_in, &bufinfo, MP_BUFFER_READ); int r = connect(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len); - RAISE_ERRNO(r, errno); + int err = errno; + if (r == -1 && self->blocking && err == EINPROGRESS) { + // EINPROGRESS on a blocking socket means the operation timed out + err = MP_ETIMEDOUT; + } + RAISE_ERRNO(r, err); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); @@ -192,7 +197,12 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) { byte addr[32]; socklen_t addr_len = sizeof(addr); int fd = accept(self->fd, (struct sockaddr *)&addr, &addr_len); - RAISE_ERRNO(fd, errno); + int err = errno; + if (fd == -1 && self->blocking && err == EAGAIN) { + // EAGAIN on a blocking socket means the operation timed out + err = MP_ETIMEDOUT; + } + RAISE_ERRNO(fd, err); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); t->items[0] = MP_OBJ_FROM_PTR(socket_new(fd)); @@ -301,7 +311,7 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { const void *optval; socklen_t optlen; int val; - if (MP_OBJ_IS_INT(args[3])) { + if (mp_obj_is_int(args[3])) { val = mp_obj_int_get_truncated(args[3]); optval = &val; optlen = sizeof(val); @@ -339,10 +349,9 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { struct timeval tv = {0,}; bool new_blocking = true; - if (timeout_in == mp_const_none) { - setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, NULL, 0); - setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, NULL, 0); - } else { + // Timeout of None means no timeout, which in POSIX is signified with 0 timeout, + // and that's how 'tv' is initialized above + if (timeout_in != mp_const_none) { #if MICROPY_PY_BUILTINS_FLOAT mp_float_t val = mp_obj_get_float(timeout_in); double ipart; @@ -356,14 +365,17 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { // for Python API it means non-blocking. if (tv.tv_sec == 0 && tv.tv_usec == 0) { new_blocking = false; - } else { - setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, - &tv, sizeof(struct timeval)); - setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, - &tv, sizeof(struct timeval)); } } + if (new_blocking) { + int r; + r = setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); + RAISE_ERRNO(r, errno); + r = setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval)); + RAISE_ERRNO(r, errno); + } + if (self->blocking != new_blocking) { socket_setblocking(self_in, mp_obj_new_bool(new_blocking)); } @@ -393,13 +405,13 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, con int proto = 0; if (n_args > 0) { - assert(MP_OBJ_IS_SMALL_INT(args[0])); + assert(mp_obj_is_small_int(args[0])); family = MP_OBJ_SMALL_INT_VALUE(args[0]); if (n_args > 1) { - assert(MP_OBJ_IS_SMALL_INT(args[1])); + assert(mp_obj_is_small_int(args[1])); type = MP_OBJ_SMALL_INT_VALUE(args[1]); if (n_args > 2) { - assert(MP_OBJ_IS_SMALL_INT(args[2])); + assert(mp_obj_is_small_int(args[2])); proto = MP_OBJ_SMALL_INT_VALUE(args[2]); } } @@ -497,7 +509,7 @@ STATIC mp_obj_t mod_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) { memset(&hints, 0, sizeof(hints)); // getaddrinfo accepts port in string notation, so however // it may seem stupid, we need to convert int to str - if (MP_OBJ_IS_SMALL_INT(args[1])) { + if (mp_obj_is_small_int(args[1])) { unsigned port = (unsigned short)MP_OBJ_SMALL_INT_VALUE(args[1]); snprintf(buf, sizeof(buf), "%u", port); serv = buf; diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 01e5876b0b..a13b25090e 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -135,7 +135,7 @@ #ifndef MICROPY_PY_USELECT_POSIX #define MICROPY_PY_USELECT_POSIX (1) #endif -#define MICROPY_PY_WEBSOCKET (0) +#define MICROPY_PY_UWEBSOCKET (0) #define MICROPY_PY_MACHINE (0) #define MICROPY_PY_MACHINE_PULSE (0) #define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr @@ -144,7 +144,7 @@ #define MICROPY_FATFS_ENABLE_LFN (1) #define MICROPY_FATFS_RPATH (2) #define MICROPY_FATFS_MAX_SS (4096) -#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define MICROPY_VFS_FAT (0) // Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc. diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index 27086a167d..456968cf33 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -36,9 +36,12 @@ #define MICROPY_FLOAT_HIGH_QUALITY_HASH (1) #define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_READER_VFS (1) +#define MICROPY_WARNINGS_CATEGORY (1) #define MICROPY_MODULE_GETATTR (1) #define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE (1) +#define MICROPY_PY_BUILTINS_NEXT2 (1) #define MICROPY_PY_BUILTINS_RANGE_BINOP (1) #define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP_MODULES (1) @@ -58,6 +61,7 @@ #define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_UCRYPTOLIB (1) +#define MICROPY_PY_UCRYPTOLIB_CTR (1) // TODO these should be generic, not bound to fatfs #define mp_type_fileio mp_type_vfs_posix_fileio diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index 864cf795e7..40545485db 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -34,8 +34,10 @@ #if MICROPY_PY_THREAD +#include #include #include +#include // this structure forms a linked list, one node per active thread typedef struct _thread_t { @@ -53,7 +55,12 @@ STATIC thread_t *thread; // this is used to synchronise the signal handler of the thread // it's needed because we can't use any pthread calls in a signal handler -STATIC volatile int thread_signal_done; +#if defined(__APPLE__) +STATIC char thread_signal_done_name[25]; +STATIC sem_t *thread_signal_done_p; +#else +STATIC sem_t thread_signal_done; +#endif // this signal handler is used to scan the regs and stack of a thread STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) { @@ -70,7 +77,11 @@ STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) { void **ptrs = (void **)(void *)MP_STATE_THREAD(pystack_start); gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void *)); #endif - thread_signal_done = 1; + #if defined(__APPLE__) + sem_post(thread_signal_done_p); + #else + sem_post(&thread_signal_done); + #endif } } @@ -85,6 +96,13 @@ void mp_thread_init(void) { thread->arg = NULL; thread->next = NULL; + #if defined(__APPLE__) + snprintf(thread_signal_done_name, sizeof(thread_signal_done_name), "micropython_sem_%d", (int)thread->id); + thread_signal_done_p = sem_open(thread_signal_done_name, O_CREAT | O_EXCL, 0666, 0); + #else + sem_init(&thread_signal_done, 0, 0); + #endif + // enable signal handler for garbage collection struct sigaction sa; sa.sa_flags = SA_SIGINFO; @@ -93,6 +111,23 @@ void mp_thread_init(void) { sigaction(SIGUSR1, &sa, NULL); } +void mp_thread_deinit(void) { + pthread_mutex_lock(&thread_mutex); + while (thread->next != NULL) { + thread_t *th = thread; + thread = thread->next; + pthread_cancel(th->id); + free(th); + } + pthread_mutex_unlock(&thread_mutex); + #if defined(__APPLE__) + sem_close(thread_signal_done_p); + sem_unlink(thread_signal_done_name); + #endif + assert(thread->id == pthread_self()); + free(thread); +} + // This function scans all pointers that are external to the current thread. // It does this by signalling all other threads and getting them to scan their // own registers and stack. Note that there may still be some edge cases left @@ -109,11 +144,12 @@ void mp_thread_gc_others(void) { if (!th->ready) { continue; } - thread_signal_done = 0; pthread_kill(th->id, SIGUSR1); - while (thread_signal_done == 0) { - sched_yield(); - } + #if defined(__APPLE__) + sem_wait(thread_signal_done_p); + #else + sem_wait(&thread_signal_done); + #endif } pthread_mutex_unlock(&thread_mutex); } @@ -127,6 +163,7 @@ void mp_thread_set_state(void *state) { } void mp_thread_start(void) { + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_mutex_lock(&thread_mutex); for (thread_t *th = thread; th != NULL; th = th->next) { if (th->id == pthread_self()) { @@ -159,6 +196,11 @@ void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { goto er; } + ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (ret != 0) { + goto er; + } + pthread_mutex_lock(&thread_mutex); // create thread @@ -191,12 +233,18 @@ er: void mp_thread_finish(void) { pthread_mutex_lock(&thread_mutex); - // TODO unlink from list + thread_t *prev = NULL; for (thread_t *th = thread; th != NULL; th = th->next) { if (th->id == pthread_self()) { - th->ready = 0; + if (prev == NULL) { + thread = th->next; + } else { + prev->next = th->next; + } + free(th); break; } + prev = th; } pthread_mutex_unlock(&thread_mutex); } diff --git a/ports/unix/mpthreadport.h b/ports/unix/mpthreadport.h index bd712ebee0..c27144a9c8 100644 --- a/ports/unix/mpthreadport.h +++ b/ports/unix/mpthreadport.h @@ -29,4 +29,5 @@ typedef pthread_mutex_t mp_thread_mutex_t; void mp_thread_init(void); +void mp_thread_deinit(void); void mp_thread_gc_others(void); diff --git a/py/asmarm.c b/py/asmarm.c index 871f0bb486..5850b52073 100644 --- a/py/asmarm.c +++ b/py/asmarm.c @@ -197,7 +197,16 @@ void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src) { emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src)); } -void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) { +size_t asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) { + // Insert immediate into code and jump over it + emit_al(as, 0x59f0000 | (rd << 12)); // ldr rd, [pc] + emit_al(as, 0xa000000); // b pc + size_t loc = mp_asm_base_get_code_pos(&as->base); + emit(as, imm); + return loc; +} + +void asm_arm_mov_reg_i32_optimised(asm_arm_t *as, uint rd, int imm) { // TODO: There are more variants of immediate values if ((imm & 0xFF) == imm) { emit_al(as, asm_arm_op_mov_imm(rd, imm)); @@ -205,10 +214,7 @@ void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) { // mvn is "move not", not "move negative" emit_al(as, asm_arm_op_mvn_imm(rd, ~imm)); } else { - // Insert immediate into code and jump over it - emit_al(as, 0x59f0000 | (rd << 12)); // ldr rd, [pc] - emit_al(as, 0xa000000); // b pc - emit(as, imm); + asm_arm_mov_reg_i32(as, rd, imm); } } diff --git a/py/asmarm.h b/py/asmarm.h index 76850cb468..7ec4490599 100644 --- a/py/asmarm.h +++ b/py/asmarm.h @@ -81,7 +81,8 @@ void asm_arm_bkpt(asm_arm_t *as); // mov void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src); -void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm); +size_t asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm); +void asm_arm_mov_reg_i32_optimised(asm_arm_t *as, uint rd, int imm); void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd); void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num); void asm_arm_setcc_reg(asm_arm_t *as, uint rd, uint cond); @@ -177,7 +178,9 @@ void asm_arm_bx_reg(asm_arm_t *as, uint reg_src); #define ASM_CALL_IND(as, idx) asm_arm_bl_ind(as, idx, ASM_ARM_REG_R3) #define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_arm_mov_local_reg((as), (local_num), (reg_src)) -#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_arm_mov_reg_i32_optimised((as), (reg_dest), (imm)) +#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm)) #define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_arm_mov_reg_local((as), (reg_dest), (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_arm_mov_reg_reg((as), (reg_dest), (reg_src)) #define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_arm_mov_reg_local_addr((as), (reg_dest), (local_num)) diff --git a/py/asmthumb.c b/py/asmthumb.c index df7c88568c..3ea0163303 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -33,6 +33,8 @@ // wrapper around everything in this file #if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB +#include "py/mpstate.h" +#include "py/persistentcode.h" #include "py/mphal.h" #include "py/asmthumb.h" @@ -118,6 +120,21 @@ STATIC void asm_thumb_write_word32(asm_thumb_t *as, int w32) { void asm_thumb_entry(asm_thumb_t *as, int num_locals) { assert(num_locals >= 0); + // If this Thumb machine code is run from ARM state then add a prelude + // to switch to Thumb state for the duration of the function. + #if MICROPY_DYNAMIC_COMPILER || MICROPY_EMIT_ARM || (defined(__arm__) && !defined(__thumb2__)) + #if MICROPY_DYNAMIC_COMPILER + if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_ARMV6) + #endif + { + asm_thumb_op32(as, 0x4010, 0xe92d); // push {r4, lr} + asm_thumb_op32(as, 0xe009, 0xe28f); // add lr, pc, 8 + 1 + asm_thumb_op32(as, 0xff3e, 0xe12f); // blx lr + asm_thumb_op32(as, 0x4010, 0xe8bd); // pop {r4, lr} + asm_thumb_op32(as, 0xff1e, 0xe12f); // bx lr + } + #endif + // work out what to push and how many extra spaces to reserve on stack // so that we have enough for all locals and it's aligned an 8-byte boundary // we push extra regs (r1, r2, r3) to help do the stack adjustment @@ -225,10 +242,12 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) { } // if loading lo half with movw, the i16 value will be zero extended into the r32 register! -void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src) { +size_t asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src) { assert(reg_dest < ASM_THUMB_REG_R15); + size_t loc = mp_asm_base_get_code_pos(&as->base); // mov[wt] reg_dest, #i16_src asm_thumb_op32(as, mov_op | ((i16_src >> 1) & 0x0400) | ((i16_src >> 12) & 0xf), ((i16_src << 4) & 0x7000) | (reg_dest << 8) | (i16_src & 0xff)); + return loc; } #define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff)) @@ -271,12 +290,16 @@ bool asm_thumb_bl_label(asm_thumb_t *as, uint label) { return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT23(rel); } -void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) { +size_t asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) { // movw, movt does it in 8 bytes // ldr [pc, #], dw does it in 6 bytes, but we might not reach to end of code for dw + size_t loc = mp_asm_base_get_code_pos(&as->base); + asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32); asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVT, reg_dest, i32 >> 16); + + return loc; } void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) { diff --git a/py/asmthumb.h b/py/asmthumb.h index b4828b125d..c37358e886 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -263,14 +263,14 @@ static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uin #define ASM_THUMB_OP_MOVT (0xf2c0) void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src); -void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src); +size_t asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src); // these return true if the destination is in range, false otherwise bool asm_thumb_b_n_label(asm_thumb_t *as, uint label); bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide); bool asm_thumb_bl_label(asm_thumb_t *as, uint label); -void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience +size_t asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32_src); // convenience void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); // convenience void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience @@ -337,6 +337,8 @@ void asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp); // convenien #define ASM_MOV_LOCAL_REG(as, local_num, reg) asm_thumb_mov_local_reg((as), (local_num), (reg)) #define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_thumb_mov_reg_i32_optimised((as), (reg_dest), (imm)) +#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_thumb_mov_reg_i16((as), ASM_THUMB_OP_MOVW, (reg_dest), (imm)) +#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_thumb_mov_reg_i32((as), (reg_dest), (imm)) #define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_thumb_mov_reg_local((as), (reg_dest), (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_thumb_mov_reg_reg((as), (reg_dest), (reg_src)) #define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_thumb_mov_reg_local_addr((as), (reg_dest), (local_num)) diff --git a/py/asmx64.c b/py/asmx64.c index b881491121..723671d5a3 100644 --- a/py/asmx64.c +++ b/py/asmx64.c @@ -334,14 +334,16 @@ void asm_x64_mov_i8_to_r8(asm_x64_t *as, int src_i8, int dest_r64) { } */ -STATIC void asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64) { +size_t asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64) { // cpu defaults to i32 to r64, with zero extension if (dest_r64 < 8) { asm_x64_write_byte_1(as, OPCODE_MOV_I64_TO_R64 | dest_r64); } else { asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_MOV_I64_TO_R64 | (dest_r64 & 7)); } + size_t loc = mp_asm_base_get_code_pos(&as->base); asm_x64_write_word32(as, src_i32); + return loc; } void asm_x64_mov_i64_to_r64(asm_x64_t *as, int64_t src_i64, int dest_r64) { diff --git a/py/asmx64.h b/py/asmx64.h index ceea426d74..f4d36154f7 100644 --- a/py/asmx64.h +++ b/py/asmx64.h @@ -83,6 +83,7 @@ void asm_x64_nop(asm_x64_t *as); void asm_x64_push_r64(asm_x64_t *as, int src_r64); void asm_x64_pop_r64(asm_x64_t *as, int dest_r64); void asm_x64_mov_r64_r64(asm_x64_t *as, int dest_r64, int src_r64); +size_t asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64); void asm_x64_mov_i64_to_r64(asm_x64_t *as, int64_t src_i64, int dest_r64); void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64); void asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp); @@ -181,6 +182,8 @@ void asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r32); #define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x64_mov_r64_to_local((as), (reg_src), (local_num)) #define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x64_mov_i64_to_r64_optimised((as), (imm), (reg_dest)) +#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_x64_mov_i32_to_r64((as), (imm), (reg_dest)) +#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_x64_mov_i32_to_r64((as), (imm), (reg_dest)) #define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x64_mov_local_to_r64((as), (local_num), (reg_dest)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x64_mov_r64_r64((as), (reg_dest), (reg_src)) #define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x64_mov_local_addr_to_r64((as), (local_num), (reg_dest)) diff --git a/py/asmx86.c b/py/asmx86.c index b238321bda..c730a0c9a4 100644 --- a/py/asmx86.c +++ b/py/asmx86.c @@ -236,9 +236,11 @@ void asm_x86_mov_i8_to_r8(asm_x86_t *as, int src_i8, int dest_r32) { } #endif -void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32) { +size_t asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32) { asm_x86_write_byte_1(as, OPCODE_MOV_I32_TO_R32 | dest_r32); + size_t loc = mp_asm_base_get_code_pos(&as->base); asm_x86_write_word32(as, src_i32); + return loc; } void asm_x86_and_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { diff --git a/py/asmx86.h b/py/asmx86.h index 930350d11b..5c2d9df08c 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -83,7 +83,7 @@ static inline void asm_x86_end_pass(asm_x86_t *as) { } void asm_x86_mov_r32_r32(asm_x86_t *as, int dest_r32, int src_r32); -void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32); +size_t asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32); void asm_x86_mov_r8_to_mem8(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp); void asm_x86_mov_r16_to_mem16(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp); void asm_x86_mov_r32_to_mem32(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp); @@ -179,6 +179,8 @@ void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r #define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x86_mov_r32_to_local((as), (reg_src), (local_num)) #define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x86_mov_i32_to_r32((as), (imm), (reg_dest)) +#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_x86_mov_i32_to_r32((as), (imm), (reg_dest)) +#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_x86_mov_i32_to_r32((as), (imm), (reg_dest)) #define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x86_mov_local_to_r32((as), (local_num), (reg_dest)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x86_mov_r32_r32((as), (reg_dest), (reg_src)) #define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x86_mov_local_addr_to_r32((as), (local_num), (reg_dest)) diff --git a/py/asmxtensa.c b/py/asmxtensa.c index a8e3a2655c..e10fd17333 100644 --- a/py/asmxtensa.c +++ b/py/asmxtensa.c @@ -156,18 +156,24 @@ void asm_xtensa_setcc_reg_reg_reg(asm_xtensa_t *as, uint cond, uint reg_dest, ui asm_xtensa_op_movi_n(as, reg_dest, 0); } -void asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32) { +size_t asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32) { + // load the constant + uint32_t const_table_offset = (uint8_t *)as->const_table - as->base.code_base; + size_t loc = const_table_offset + as->cur_const * WORD_SIZE; + asm_xtensa_op_l32r(as, reg_dest, as->base.code_offset, loc); + // store the constant in the table + if (as->const_table != NULL) { + as->const_table[as->cur_const] = i32; + } + ++as->cur_const; + return loc; +} + +void asm_xtensa_mov_reg_i32_optimised(asm_xtensa_t *as, uint reg_dest, uint32_t i32) { if (SIGNED_FIT12(i32)) { asm_xtensa_op_movi(as, reg_dest, i32); } else { - // load the constant - uint32_t const_table_offset = (uint8_t *)as->const_table - as->base.code_base; - asm_xtensa_op_l32r(as, reg_dest, as->base.code_offset, const_table_offset + as->cur_const * WORD_SIZE); - // store the constant in the table - if (as->const_table != NULL) { - as->const_table[as->cur_const] = i32; - } - ++as->cur_const; + asm_xtensa_mov_reg_i32(as, reg_dest, i32); } } diff --git a/py/asmxtensa.h b/py/asmxtensa.h index 685b3f9492..48c27d557d 100644 --- a/py/asmxtensa.h +++ b/py/asmxtensa.h @@ -26,6 +26,7 @@ #ifndef MICROPY_INCLUDED_PY_ASMXTENSA_H #define MICROPY_INCLUDED_PY_ASMXTENSA_H +#include "py/misc.h" #include "py/asmbase.h" // calling conventions: @@ -238,7 +239,8 @@ void asm_xtensa_j_label(asm_xtensa_t *as, uint label); void asm_xtensa_bccz_reg_label(asm_xtensa_t *as, uint cond, uint reg, uint label); void asm_xtensa_bcc_reg_reg_label(asm_xtensa_t *as, uint cond, uint reg1, uint reg2, uint label); void asm_xtensa_setcc_reg_reg_reg(asm_xtensa_t *as, uint cond, uint reg_dest, uint reg_src1, uint reg_src2); -void asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32); +size_t asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32); +void asm_xtensa_mov_reg_i32_optimised(asm_xtensa_t *as, uint reg_dest, uint32_t i32); void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src); void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num); @@ -289,7 +291,9 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); #define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) #define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), (local_num), (reg_src)) -#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32_optimised((as), (reg_dest), (imm)) +#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) #define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_xtensa_mov_reg_local((as), (reg_dest), (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mov_n((as), (reg_dest), (reg_src)) #define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), (local_num)) diff --git a/py/bc.c b/py/bc.c index 1e2c0bbae1..f315dfe94f 100644 --- a/py/bc.c +++ b/py/bc.c @@ -192,7 +192,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw for (size_t i = 0; i < n_kw; i++) { // the keys in kwargs are expected to be qstr objects mp_obj_t wanted_arg_name = kwargs[2 * i]; - if (MP_UNLIKELY(!MP_OBJ_IS_QSTR(wanted_arg_name))) { + if (MP_UNLIKELY(!mp_obj_is_qstr(wanted_arg_name))) { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE mp_raise_TypeError(translate("unexpected keyword argument")); #else @@ -331,7 +331,7 @@ STATIC const byte opcode_format_table[64] = { OC4(O, O, U, U), // 0x38-0x3b OC4(U, O, B, O), // 0x3c-0x3f OC4(O, B, B, O), // 0x40-0x43 - OC4(B, B, O, B), // 0x44-0x47 + OC4(O, U, O, B), // 0x44-0x47 OC4(U, U, U, U), // 0x48-0x4b OC4(U, U, U, U), // 0x4c-0x4f OC4(V, V, U, V), // 0x50-0x53 @@ -392,7 +392,7 @@ STATIC const byte opcode_format_table[64] = { #undef V #undef O -uint mp_opcode_format(const byte *ip, size_t *opcode_size) { +uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint) { uint f = (opcode_format_table[*ip >> 2] >> (2 * (*ip & 3))) & 3; const byte *ip_start = ip; if (f == MP_OPCODE_QSTR) { @@ -413,7 +413,9 @@ uint mp_opcode_format(const byte *ip, size_t *opcode_size) { ); ip += 1; if (f == MP_OPCODE_VAR_UINT) { - while ((*ip++ & 0x80) != 0) { + if (count_var_uint) { + while ((*ip++ & 0x80) != 0) { + } } } else if (f == MP_OPCODE_OFFSET) { ip += 2; diff --git a/py/bc.h b/py/bc.h index 6f62711c87..a3c1a45b94 100644 --- a/py/bc.h +++ b/py/bc.h @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -114,7 +115,7 @@ const byte *mp_bytecode_print_str(const byte *ip); #define MP_OPCODE_VAR_UINT (2) #define MP_OPCODE_OFFSET (3) -uint mp_opcode_format(const byte *ip, size_t *opcode_size); +uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint); #endif diff --git a/py/bc0.h b/py/bc0.h index a031bcc88b..05fc2c3ee6 100644 --- a/py/bc0.h +++ b/py/bc0.h @@ -77,8 +77,7 @@ #define MP_BC_END_FINALLY (0x41) #define MP_BC_GET_ITER (0x42) #define MP_BC_FOR_ITER (0x43) // rel byte code offset, 16-bit unsigned -#define MP_BC_POP_BLOCK (0x44) -#define MP_BC_POP_EXCEPT (0x45) +#define MP_BC_POP_EXCEPT_JUMP (0x44) // rel byte code offset, 16-bit unsigned #define MP_BC_UNWIND_JUMP (0x46) // rel byte code offset, 16-bit signed, in excess; then a byte #define MP_BC_GET_ITER_STACK (0x47) diff --git a/py/binary.c b/py/binary.c index cd61d74fa8..15ad49e555 100644 --- a/py/binary.c +++ b/py/binary.c @@ -3,7 +3,8 @@ * * The MIT License (MIT) * - * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2017 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2019 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -348,7 +349,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte ** default: { bool signed_type = is_signed(val_type); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) { + if (mp_obj_is_type(val_in, &mp_type_int)) { // It's a longint. mp_obj_int_buffer_overflow_check(val_in, size, signed_type); mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p); @@ -395,7 +396,7 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v bool signed_type = is_signed(typecode); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) { + if (mp_obj_is_type(val_in, &mp_type_int)) { // It's a long int. mp_obj_int_buffer_overflow_check(val_in, size, signed_type); mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG, diff --git a/py/binary.h b/py/binary.h index 6c70d93339..f13eb9260b 100644 --- a/py/binary.h +++ b/py/binary.h @@ -3,7 +3,8 @@ * * The MIT License (MIT) * - * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/py/builtin.h b/py/builtin.h index 58c4c1e524..52aa8c2123 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -63,7 +63,11 @@ MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_len_obj); MP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_locals_obj); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_max_obj); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_min_obj); +#if MICROPY_PY_BUILTINS_NEXT2 +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_next_obj); +#else MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_next_obj); +#endif MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_oct_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_ord_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj); @@ -114,7 +118,7 @@ extern const mp_obj_module_t mp_module_ussl; extern const mp_obj_module_t mp_module_utimeq; extern const mp_obj_module_t mp_module_machine; extern const mp_obj_module_t mp_module_lwip; -extern const mp_obj_module_t mp_module_websocket; +extern const mp_obj_module_t mp_module_uwebsocket; extern const mp_obj_module_t mp_module_webrepl; extern const mp_obj_module_t mp_module_framebuf; extern const mp_obj_module_t mp_module_btree; diff --git a/py/builtinevex.c b/py/builtinevex.c index 5538ac783c..db2dcd5efe 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -54,7 +54,7 @@ STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_dict_t *globals, mp_obj // a bit of a hack: fun_bc will re-set globals, so need to make sure it's // the correct one - if (MP_OBJ_IS_TYPE(self->module_fun, &mp_type_fun_bc)) { + if (mp_obj_is_type(self->module_fun, &mp_type_fun_bc)) { mp_obj_fun_bc_t *fun_bc = MP_OBJ_TO_PTR(self->module_fun); fun_bc->globals = globals; } @@ -122,7 +122,7 @@ STATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_i mp_obj_dict_t *locals = mp_locals_get(); for (size_t i = 1; i < 3 && i < n_args; ++i) { if (args[i] != mp_const_none) { - if (!MP_OBJ_IS_TYPE(args[i], &mp_type_dict)) { + if (!mp_obj_is_type(args[i], &mp_type_dict)) { mp_raise_TypeError(NULL); } locals = MP_OBJ_TO_PTR(args[i]); @@ -133,7 +133,7 @@ STATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_i } #if MICROPY_PY_BUILTINS_COMPILE - if (MP_OBJ_IS_TYPE(args[0], &mp_type_code)) { + if (mp_obj_is_type(args[0], &mp_type_code)) { return code_execute(MP_OBJ_TO_PTR(args[0]), globals, locals); } #endif diff --git a/py/builtinhelp.c b/py/builtinhelp.c index 225126029e..828ab4feb8 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -60,7 +60,7 @@ STATIC void mp_help_print_info_about_object(mp_obj_t name_o, mp_obj_t value) { #if MICROPY_PY_BUILTINS_HELP_MODULES STATIC void mp_help_add_from_map(mp_obj_t list, const mp_map_t *map) { for (size_t i = 0; i < map->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { mp_obj_list_append(list, map->table[i].key); } } @@ -133,11 +133,13 @@ STATIC void mp_help_print_modules(void) { mp_print_str(MP_PYTHON_PRINTER, "\n"); } + #if MICROPY_ENABLE_EXTERNAL_IMPORT // let the user know there may be other modules available from the filesystem const compressed_string_t *compressed = translate("Plus any modules on the filesystem\n"); char decompressed[decompress_length(compressed)]; decompress(compressed, decompressed); mp_print_str(MP_PYTHON_PRINTER, decompressed); + #endif } #endif diff --git a/py/builtinimport.c b/py/builtinimport.c index 8462c146b1..0fa35f6e9f 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -122,7 +122,6 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d vstr_reset(dest); size_t p_len; const char *p = mp_obj_str_get_data(path_items[i], &p_len); - DEBUG_printf("Looking in path: %d =%s=\n", i, p); if (p_len > 0) { vstr_add_strn(dest, p, p_len); vstr_add_char(dest, PATH_SEP_CHAR); @@ -140,7 +139,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d #endif } -#if MICROPY_ENABLE_COMPILER +#if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) { #if MICROPY_PY___FILE__ qstr source_name = lex->source_name; @@ -192,7 +191,7 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, co #endif STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { - #if MICROPY_MODULE_FROZEN || MICROPY_PERSISTENT_CODE_LOAD || MICROPY_ENABLE_COMPILER + #if MICROPY_MODULE_FROZEN || MICROPY_ENABLE_COMPILER || (MICROPY_PERSISTENT_CODE_LOAD && MICROPY_HAS_FILE_READER) char *file_str = vstr_null_terminated_str(file); #endif @@ -230,7 +229,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { // If we support loading .mpy files then check if the file extension is of // the correct format and, if so, load and execute the file. - #if MICROPY_PERSISTENT_CODE_LOAD + #if MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD if (file_str[file->len - 3] == 'm') { mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str); do_execute_raw_code(module_obj, raw_code, file_str); @@ -246,7 +245,6 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { return; } #else - // If we get here then the file was not frozen and we can't compile scripts. mp_raise_ImportError(translate("script compilation not supported")); #endif @@ -421,7 +419,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { MP_MAP_LOOKUP); } - if (el != NULL && MP_OBJ_IS_TYPE(el->value, &mp_type_module)) { + if (el != NULL && mp_obj_is_type(el->value, &mp_type_module)) { module_obj = el->value; mp_module_call_init(mod_name, module_obj); } else { diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 5745c4f1d2..e550cdbbde 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -639,6 +639,19 @@ $(addprefix lib/,\ endif endif +SRC_CIRCUITPY_COMMON = \ + lib/libc/string0.c \ + lib/mp-readline/readline.c \ + lib/oofatfs/ff.c \ + lib/oofatfs/ffunicode.c \ + lib/timeutils/timeutils.c \ + lib/utils/buffer_helper.c \ + lib/utils/context_manager_helpers.c \ + lib/utils/interrupt_char.c \ + lib/utils/pyexec.c \ + lib/utils/stdout_helpers.c \ + lib/utils/sys_stdio_mphal.c + ifdef LD_TEMPLATE_FILE # Generate a linker script (.ld file) from a template, for those builds that use it. GENERATED_LD_FILE = $(BUILD)/$(notdir $(patsubst %.template.ld,%.ld,$(LD_TEMPLATE_FILE))) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 801e1867e7..fb14f2871b 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -130,7 +130,9 @@ // // 1 = SFN/ANSI 437=LFN/U.S.(OEM) #define MICROPY_FATFS_ENABLE_LFN (1) -#define MICROPY_FATFS_LFN_CODE_PAGE (437) +// Don't use parens on the value below because it gets combined with a prefix in +// the preprocessor. +#define MICROPY_FATFS_LFN_CODE_PAGE 437 #define MICROPY_FATFS_USE_LABEL (1) #define MICROPY_FATFS_RPATH (2) #define MICROPY_FATFS_MULTI_PARTITION (1) diff --git a/py/compile.c b/py/compile.c index a484022bb9..f0c9221db7 100644 --- a/py/compile.c +++ b/py/compile.c @@ -35,6 +35,7 @@ #include "py/compile.h" #include "py/runtime.h" #include "py/asmbase.h" +#include "py/persistentcode.h" #include "supervisor/shared/translate.h" @@ -80,7 +81,25 @@ typedef enum { #endif -#if MICROPY_EMIT_NATIVE +#if MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER + +#define NATIVE_EMITTER(f) emit_native_table[mp_dynamic_compiler.native_arch]->emit_##f +#define NATIVE_EMITTER_TABLE emit_native_table[mp_dynamic_compiler.native_arch] + +STATIC const emit_method_table_t *emit_native_table[] = { + NULL, + &emit_native_x86_method_table, + &emit_native_x64_method_table, + &emit_native_arm_method_table, + &emit_native_thumb_method_table, + &emit_native_thumb_method_table, + &emit_native_thumb_method_table, + &emit_native_thumb_method_table, + &emit_native_thumb_method_table, + &emit_native_xtensa_method_table, +}; + +#elif MICROPY_EMIT_NATIVE // define a macro to access external native emitter #if MICROPY_EMIT_X64 #define NATIVE_EMITTER(f) emit_native_x64_##f @@ -95,9 +114,28 @@ typedef enum { #else #error "unknown native emitter" #endif +#define NATIVE_EMITTER_TABLE &NATIVE_EMITTER(method_table) #endif -#if MICROPY_EMIT_INLINE_ASM +#if MICROPY_EMIT_INLINE_ASM && MICROPY_DYNAMIC_COMPILER + +#define ASM_EMITTER(f) emit_asm_table[mp_dynamic_compiler.native_arch]->asm_##f +#define ASM_EMITTER_TABLE emit_asm_table[mp_dynamic_compiler.native_arch] + +STATIC const emit_inline_asm_method_table_t *emit_asm_table[] = { + NULL, + NULL, + NULL, + &emit_inline_thumb_method_table, + &emit_inline_thumb_method_table, + &emit_inline_thumb_method_table, + &emit_inline_thumb_method_table, + &emit_inline_thumb_method_table, + &emit_inline_thumb_method_table, + &emit_inline_xtensa_method_table, +}; + +#elif MICROPY_EMIT_INLINE_ASM // define macros for inline assembler #if MICROPY_EMIT_INLINE_THUMB #define ASM_DECORATOR_QSTR MP_QSTR_asm_thumb @@ -108,6 +146,7 @@ typedef enum { #else #error "unknown asm emitter" #endif +#define ASM_EMITTER_TABLE &ASM_EMITTER(method_table) #endif #define EMIT_INLINE_ASM(fun) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm)) @@ -166,6 +205,7 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const com STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra); STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind); +STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *pns, bool create_map); STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn); STATIC uint comp_next_label(compiler_t *comp) { @@ -808,14 +848,32 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_ *emit_options = MP_EMIT_OPT_VIPER; #endif #if MICROPY_EMIT_INLINE_ASM - // @micropython.asm_thumb decorator. + #if MICROPY_DYNAMIC_COMPILER + } else if (attr == MP_QSTR_asm_thumb) { + *emit_options = MP_EMIT_OPT_ASM; + } else if (attr == MP_QSTR_asm_xtensa) { + *emit_options = MP_EMIT_OPT_ASM; + #else } else if (attr == ASM_DECORATOR_QSTR) { *emit_options = MP_EMIT_OPT_ASM; + #endif #endif } else { compile_syntax_error(comp, name_nodes[1], translate("invalid micropython decorator")); } + #if MICROPY_DYNAMIC_COMPILER + if (*emit_options == MP_EMIT_OPT_NATIVE_PYTHON || *emit_options == MP_EMIT_OPT_VIPER) { + if (emit_native_table[mp_dynamic_compiler.native_arch] == NULL) { + compile_syntax_error(comp, name_nodes[1], translate("invalid architecture")); + } + } else if (*emit_options == MP_EMIT_OPT_ASM) { + if (emit_asm_table[mp_dynamic_compiler.native_arch] == NULL) { + compile_syntax_error(comp, name_nodes[1], translate("invalid architecture")); + } + } + #endif + return true; } @@ -1545,8 +1603,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ compile_increase_except_level(comp, l1, MP_EMIT_SETUP_BLOCK_EXCEPT); compile_node(comp, pn_body); // body - EMIT(pop_block); - EMIT_ARG(jump, success_label); // jump over exception handler + EMIT_ARG(pop_except_jump, success_label, false); // jump over exception handler EMIT_ARG(label_assign, l1); // start of exception handler EMIT(start_except_handler); @@ -1593,26 +1650,31 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ compile_store_id(comp, qstr_exception_local); } + // If the exception is bound to a variable then the of the + // exception handler is wrapped in a try-finally so that the name can + // be deleted (per Python semantics) even if the has an exception. + // In such a case the generated code for the exception handler is: + // try: + // + // finally: + // = None + // del uint l3 = 0; if (qstr_exception_local != 0) { l3 = comp_next_label(comp); compile_increase_except_level(comp, l3, MP_EMIT_SETUP_BLOCK_FINALLY); } - compile_node(comp, pns_except->nodes[1]); - if (qstr_exception_local != 0) { - EMIT(pop_block); - } - EMIT(pop_except); + compile_node(comp, pns_except->nodes[1]); // the if (qstr_exception_local != 0) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT_ARG(label_assign, l3); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); compile_store_id(comp, qstr_exception_local); compile_delete_id(comp, qstr_exception_local); - compile_decrease_except_level(comp); } - EMIT_ARG(jump, l2); + + EMIT_ARG(pop_except_jump, l2, true); EMIT_ARG(label_assign, end_finally_label); EMIT_ARG(adjust_stack_size, 1); // stack adjust for the exception instance } @@ -1638,7 +1700,6 @@ STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n } else { compile_try_except(comp, pn_body, n_except, pn_except, pn_else); } - EMIT(pop_block); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT_ARG(label_assign, l_finally_block); compile_node(comp, pn_finally); @@ -1761,8 +1822,7 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns compile_load_id(comp, context); compile_await_object_method(comp, MP_QSTR___anext__); c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable - EMIT(pop_block); - EMIT_ARG(jump, try_else_label); + EMIT_ARG(pop_except_jump, try_else_label, false); EMIT_ARG(label_assign, try_exception_label); EMIT(start_except_handler); @@ -1771,8 +1831,7 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); EMIT_ARG(pop_jump_if, false, try_finally_label); EMIT(pop_top); // pop exception instance - EMIT(pop_except); - EMIT_ARG(jump, while_else_label); + EMIT_ARG(pop_except_jump, while_else_label, true); EMIT_ARG(label_assign, try_finally_label); EMIT_ARG(adjust_stack_size, 1); // if we jump here, the exc is on the stack @@ -1829,8 +1888,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body); EMIT_ARG(adjust_stack_size, -3); - // Finish the "try" block - EMIT(pop_block); + // We have now finished the "try" block and fall through to the "finally" // At this point, after the with body has executed, we have 3 cases: // 1. no exception, we just fall through to this point; stack: (..., ctx_mgr) @@ -1849,7 +1907,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod // Detect if TOS an exception or not EMIT(dup_top); - EMIT_LOAD_GLOBAL(MP_QSTR_Exception); + EMIT_LOAD_GLOBAL(MP_QSTR_BaseException); EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); EMIT_ARG(pop_jump_if, false, l_ret_unwind_jump); // if not an exception then we have case 3 @@ -2327,6 +2385,20 @@ STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *p EMIT_ARG(call_function, 2, 0, 0); i = 1; } + + #if MICROPY_COMP_CONST_LITERAL && MICROPY_PY_COLLECTIONS_ORDEREDDICT + // handle special OrderedDict constructor + } else if (MP_PARSE_NODE_IS_ID(pns->nodes[0]) + && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_OrderedDict + && MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_trailer_paren + && MP_PARSE_NODE_IS_STRUCT_KIND(pns_trail[0]->nodes[0], PN_atom_brace)) { + // at this point we have matched "OrderedDict({...})" + + EMIT_ARG(call_function, 0, 0, 0); + mp_parse_node_struct_t *pns_dict = (mp_parse_node_struct_t *)pns_trail[0]->nodes[0]; + compile_atom_brace_helper(comp, pns_dict, false); + i = 1; + #endif } // compile the remaining trailers @@ -2535,16 +2607,20 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) } } -STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { +STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *pns, bool create_map) { mp_parse_node_t pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { // empty dict - EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); + if (create_map) { + EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); + } } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { pns = (mp_parse_node_struct_t *)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker_item) { // dict with one element - EMIT_ARG(build, 1, MP_EMIT_BUILD_MAP); + if (create_map) { + EMIT_ARG(build, 1, MP_EMIT_BUILD_MAP); + } compile_node(comp, pn); EMIT(store_map); } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) { @@ -2561,7 +2637,9 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { bool is_dict; if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) { // a dictionary - EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP); + if (create_map) { + EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP); + } compile_node(comp, pns->nodes[0]); EMIT(store_map); is_dict = true; @@ -2631,6 +2709,10 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { } } +STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { + compile_atom_brace_helper(comp, pns, true); +} + STATIC void compile_trailer_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_trailer_paren_helper(comp, pns->nodes[0], false, 0); } @@ -2769,9 +2851,6 @@ STATIC mp_obj_t get_const_object(mp_parse_node_struct_t *pns) { } STATIC void compile_const_object(compiler_t *comp, mp_parse_node_struct_t *pns) { - #if MICROPY_EMIT_NATIVE - comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; - #endif EMIT_ARG(load_const_obj, get_const_object(pns)); } @@ -2806,9 +2885,6 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) { } else { EMIT_ARG(load_const_obj, mp_obj_new_int_from_ll(arg)); } - #if MICROPY_EMIT_NATIVE - comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; - #endif } #else EMIT_ARG(load_const_small_int, arg); @@ -2831,9 +2907,6 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) { const byte *data = qstr_data(arg, &len); EMIT_ARG(load_const_obj, mp_obj_new_bytes(data, len)); } - #if MICROPY_EMIT_NATIVE - comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; - #endif break; case MP_PARSE_NODE_TOKEN: default: @@ -2875,6 +2948,8 @@ STATIC int compile_viper_type_annotation(compiler_t *comp, mp_parse_node_t pn_an #endif STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star) { + (void)pn_dbl_star; + // check that **kw is last if ((comp->scope_cur->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { compile_syntax_error(comp, pn, translate("invalid syntax")); @@ -3038,7 +3113,7 @@ STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) { if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]) == MP_PARSE_NODE_STRING) || (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_const_object) - && MP_OBJ_IS_STR(get_const_object((mp_parse_node_struct_t *)pns->nodes[0])))) { + && mp_obj_is_str(get_const_object((mp_parse_node_struct_t *)pns->nodes[0])))) { // compile the doc string compile_node(comp, pns->nodes[0]); // store the doc string @@ -3364,7 +3439,11 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind void *f = mp_asm_base_get_code((mp_asm_base_t *)comp->emit_inline_asm); mp_emit_glue_assign_native(comp->scope_cur->raw_code, MP_CODE_NATIVE_ASM, f, mp_asm_base_get_code_size((mp_asm_base_t *)comp->emit_inline_asm), - NULL, comp->scope_cur->num_pos_args, 0, type_sig); + NULL, + #if MICROPY_PERSISTENT_CODE_SAVE + 0, 0, 0, 0, NULL, + #endif + comp->scope_cur->num_pos_args, 0, type_sig); } } @@ -3495,12 +3574,12 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f #endif uint max_num_labels = 0; for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { - if (false) { #if MICROPY_EMIT_INLINE_ASM - } else if (s->emit_options == MP_EMIT_OPT_ASM) { + if (s->emit_options == MP_EMIT_OPT_ASM) { compile_scope_inline_asm(comp, s, MP_PASS_SCOPE); + } else #endif - } else { + { compile_scope(comp, s, MP_PASS_SCOPE); // Check if any implicitly declared variables should be closed over @@ -3531,30 +3610,32 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f emit_t *emit_native = NULL; #endif for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { - if (false) { - // dummy - #if MICROPY_EMIT_INLINE_ASM - } else if (s->emit_options == MP_EMIT_OPT_ASM) { + if (s->emit_options == MP_EMIT_OPT_ASM) { // inline assembly if (comp->emit_inline_asm == NULL) { comp->emit_inline_asm = ASM_EMITTER(new)(max_num_labels); } comp->emit = NULL; - comp->emit_inline_asm_method_table = &ASM_EMITTER(method_table); + comp->emit_inline_asm_method_table = ASM_EMITTER_TABLE; compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); #if MICROPY_EMIT_INLINE_XTENSA // Xtensa requires an extra pass to compute size of l32r const table // TODO this can be improved by calculating it during SCOPE pass // but that requires some other structural changes to the asm emitters - compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); + #if MICROPY_DYNAMIC_COMPILER + if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_XTENSA) + #endif + { + compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); + } #endif if (comp->compile_error == MP_OBJ_NULL) { compile_scope_inline_asm(comp, s, MP_PASS_EMIT); } + } else #endif - - } else { + { // choose the emit type @@ -3566,7 +3647,7 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f if (emit_native == NULL) { emit_native = NATIVE_EMITTER(new)(&comp->compile_error, &comp->next_label, max_num_labels); } - comp->emit_method_table = &NATIVE_EMITTER(method_table); + comp->emit_method_table = NATIVE_EMITTER_TABLE; comp->emit = emit_native; break; #endif // MICROPY_EMIT_NATIVE diff --git a/py/emit.h b/py/emit.h index 24a31f8e23..63911fc593 100644 --- a/py/emit.h +++ b/py/emit.h @@ -98,6 +98,11 @@ typedef struct _mp_emit_method_table_id_ops_t { } mp_emit_method_table_id_ops_t; typedef struct _emit_method_table_t { + #if MICROPY_DYNAMIC_COMPILER + emit_t *(*emit_new)(mp_obj_t * error_slot, uint *label_slot, mp_uint_t max_num_labels); + void (*emit_free)(emit_t *emit); + #endif + void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope); void (*end_pass)(emit_t *emit); bool (*last_emit_was_return_value)(emit_t *emit); @@ -134,8 +139,7 @@ typedef struct _emit_method_table_t { void (*get_iter)(emit_t *emit, bool use_stack); void (*for_iter)(emit_t *emit, mp_uint_t label); void (*for_iter_end)(emit_t *emit); - void (*pop_block)(emit_t *emit); - void (*pop_except)(emit_t *emit); + void (*pop_except_jump)(emit_t *emit, mp_uint_t label, bool within_exc_handler); void (*unary_op)(emit_t *emit, mp_unary_op_t op); void (*binary_op)(emit_t *emit, mp_binary_op_t op); void (*build)(emit_t *emit, mp_uint_t n_args, int kind); @@ -157,8 +161,6 @@ typedef struct _emit_method_table_t { void (*end_except_handler)(emit_t *emit); } emit_method_table_t; -int mp_native_type_from_qstr(qstr qst); - static inline void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) { scope_find_or_add_id(scope, qst, ID_INFO_KIND_GLOBAL_IMPLICIT); } @@ -232,8 +234,7 @@ void mp_emit_bc_end_finally(emit_t *emit); void mp_emit_bc_get_iter(emit_t *emit, bool use_stack); void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label); void mp_emit_bc_for_iter_end(emit_t *emit); -void mp_emit_bc_pop_block(emit_t *emit); -void mp_emit_bc_pop_except(emit_t *emit); +void mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler); void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op); void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op); void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind); @@ -254,6 +255,11 @@ void mp_emit_bc_end_except_handler(emit_t *emit); typedef struct _emit_inline_asm_t emit_inline_asm_t; typedef struct _emit_inline_asm_method_table_t { + #if MICROPY_DYNAMIC_COMPILER + emit_inline_asm_t *(*asm_new)(mp_uint_t max_num_labels); + void (*asm_free)(emit_inline_asm_t *emit); + #endif + void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot); void (*end_pass)(emit_inline_asm_t *emit, mp_uint_t type_sig); mp_uint_t (*count_params)(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params); diff --git a/py/emitbc.c b/py/emitbc.c index 7e2989276f..740d7e24e9 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -744,7 +744,6 @@ void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind) { } void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { - mp_emit_bc_pop_block(emit); mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE); mp_emit_bc_label_assign(emit, label); emit_bc_pre(emit, 2); // ensure we have enough stack space to call the __exit__ method @@ -771,14 +770,10 @@ void mp_emit_bc_for_iter_end(emit_t *emit) { emit_bc_pre(emit, -MP_OBJ_ITER_BUF_NSLOTS); } -void mp_emit_bc_pop_block(emit_t *emit) { +void mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) { + (void)within_exc_handler; emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_POP_BLOCK); -} - -void mp_emit_bc_pop_except(emit_t *emit) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_POP_EXCEPT); + emit_write_bytecode_byte_unsigned_label(emit, MP_BC_POP_EXCEPT_JUMP, label); } void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) { @@ -920,6 +915,11 @@ void mp_emit_bc_end_except_handler(emit_t *emit) { #if MICROPY_EMIT_NATIVE const emit_method_table_t emit_bc_method_table = { + #if MICROPY_DYNAMIC_COMPILER + NULL, + NULL, + #endif + mp_emit_bc_start_pass, mp_emit_bc_end_pass, mp_emit_bc_last_emit_was_return_value, @@ -965,8 +965,7 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_get_iter, mp_emit_bc_for_iter, mp_emit_bc_for_iter_end, - mp_emit_bc_pop_block, - mp_emit_bc_pop_except, + mp_emit_bc_pop_except_jump, mp_emit_bc_unary_op, mp_emit_bc_binary_op, mp_emit_bc_build, diff --git a/py/emitglue.c b/py/emitglue.c index 4949053410..f821af3150 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -67,12 +67,12 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, rc->kind = MP_CODE_BYTECODE; rc->scope_flags = scope_flags; - rc->data.u_byte.bytecode = code; - rc->data.u_byte.const_table = const_table; + rc->fun_data = code; + rc->const_table = const_table; #if MICROPY_PERSISTENT_CODE_SAVE - rc->data.u_byte.bc_len = len; - rc->data.u_byte.n_obj = n_obj; - rc->data.u_byte.n_raw_code = n_raw_code; + rc->fun_data_len = len; + rc->n_obj = n_obj; + rc->n_raw_code = n_raw_code; #endif #ifdef DEBUG_PRINT @@ -89,14 +89,31 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, } #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM -void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig) { +void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + uint16_t prelude_offset, + uint16_t n_obj, uint16_t n_raw_code, + uint16_t n_qstr, mp_qstr_link_entry_t *qstr_link, + #endif + mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig) { + assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM); + rc->kind = kind; rc->scope_flags = scope_flags; rc->n_pos_args = n_pos_args; - rc->data.u_native.fun_data = fun_data; - rc->data.u_native.const_table = const_table; - rc->data.u_native.type_sig = type_sig; + rc->fun_data = fun_data; + rc->const_table = const_table; + rc->type_sig = type_sig; + + #if MICROPY_PERSISTENT_CODE_SAVE + rc->fun_data_len = fun_len; + rc->prelude_offset = prelude_offset; + rc->n_obj = n_obj; + rc->n_raw_code = n_raw_code; + rc->n_qstr = n_qstr; + rc->qstr_link = qstr_link; + #endif #ifdef DEBUG_PRINT DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, n_pos_args, (uint)scope_flags); @@ -124,10 +141,10 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar assert(rc != NULL); // def_args must be MP_OBJ_NULL or a tuple - assert(def_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_args, &mp_type_tuple)); + assert(def_args == MP_OBJ_NULL || mp_obj_is_type(def_args, &mp_type_tuple)); // def_kw_args must be MP_OBJ_NULL or a dict - assert(def_kw_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_kw_args, &mp_type_dict)); + assert(def_kw_args == MP_OBJ_NULL || mp_obj_is_type(def_kw_args, &mp_type_dict)); // make the function, depending on the raw code kind mp_obj_t fun; @@ -135,20 +152,19 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar #if MICROPY_EMIT_NATIVE case MP_CODE_NATIVE_PY: case MP_CODE_NATIVE_VIPER: - fun = mp_obj_new_fun_native(def_args, def_kw_args, rc->data.u_native.fun_data, rc->data.u_native.const_table); + fun = mp_obj_new_fun_native(def_args, def_kw_args, rc->fun_data, rc->const_table); break; #endif #if MICROPY_EMIT_INLINE_ASM case MP_CODE_NATIVE_ASM: - fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig); + fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->fun_data, rc->type_sig); break; #endif - case MP_CODE_BYTECODE: - fun = mp_obj_new_fun_bc(def_args, def_kw_args, rc->data.u_byte.bytecode, rc->data.u_byte.const_table); - break; default: - // All other kinds are invalid. - mp_raise_RuntimeError(translate("Corrupt raw code")); + // rc->kind should always be set and BYTECODE is the only remaining case + assert(rc->kind == MP_CODE_BYTECODE); + fun = mp_obj_new_fun_bc(def_args, def_kw_args, rc->fun_data, rc->const_table); + break; } // check for generator functions and if so wrap in generator object diff --git a/py/emitglue.h b/py/emitglue.h index fc352fdbab..d8a8f4ba64 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -48,26 +48,30 @@ typedef enum { MP_CODE_NATIVE_ASM, } mp_raw_code_kind_t; +typedef struct _mp_qstr_link_entry_t { + uint16_t off; + uint16_t qst; +} mp_qstr_link_entry_t; + typedef struct _mp_raw_code_t { mp_uint_t kind : 3; // of type mp_raw_code_kind_t mp_uint_t scope_flags : 7; mp_uint_t n_pos_args : 11; - union { - struct { - const byte *bytecode; - const mp_uint_t *const_table; - #if MICROPY_PERSISTENT_CODE_SAVE - mp_uint_t bc_len; - uint16_t n_obj; - uint16_t n_raw_code; - #endif - } u_byte; - struct { - void *fun_data; - const mp_uint_t *const_table; - mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc - } u_native; - } data; + const void *fun_data; + const mp_uint_t *const_table; + #if MICROPY_PERSISTENT_CODE_SAVE + size_t fun_data_len; + uint16_t n_obj; + uint16_t n_raw_code; + #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM + uint16_t prelude_offset; + uint16_t n_qstr; + mp_qstr_link_entry_t *qstr_link; + #endif + #endif + #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM + mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc + #endif } mp_raw_code_t; mp_raw_code_t *mp_emit_glue_new_raw_code(void); @@ -81,7 +85,15 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, uint16_t n_obj, uint16_t n_raw_code, #endif mp_uint_t scope_flags); -void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig); + +void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, + const mp_uint_t *const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + uint16_t prelude_offset, + uint16_t n_obj, uint16_t n_raw_code, + uint16_t n_qstr, mp_qstr_link_entry_t *qstr_link, + #endif + mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig); mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args); mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args); diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 1faeccbd27..1602f505b3 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -824,6 +824,11 @@ branch_not_in_range: } const emit_inline_asm_method_table_t emit_inline_thumb_method_table = { + #if MICROPY_DYNAMIC_COMPILER + emit_inline_thumb_new, + emit_inline_thumb_free, + #endif + emit_inline_thumb_start_pass, emit_inline_thumb_end_pass, emit_inline_thumb_count_params, diff --git a/py/emitinlinextensa.c b/py/emitinlinextensa.c index 8094c0befa..e6f7e755bf 100644 --- a/py/emitinlinextensa.c +++ b/py/emitinlinextensa.c @@ -337,6 +337,11 @@ branch_not_in_range: } const emit_inline_asm_method_table_t emit_inline_xtensa_method_table = { + #if MICROPY_DYNAMIC_COMPILER + emit_inline_xtensa_new, + emit_inline_xtensa_free, + #endif + emit_inline_xtensa_start_pass, emit_inline_xtensa_end_pass, emit_inline_xtensa_count_params, diff --git a/py/emitnative.c b/py/emitnative.c index bcf7793c86..98788d992b 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -156,29 +156,6 @@ typedef enum { VTYPE_BUILTIN_CAST = 0x70 | MP_NATIVE_TYPE_OBJ, } vtype_kind_t; -int mp_native_type_from_qstr(qstr qst) { - switch (qst) { - case MP_QSTR_object: - return MP_NATIVE_TYPE_OBJ; - case MP_QSTR_bool: - return MP_NATIVE_TYPE_BOOL; - case MP_QSTR_int: - return MP_NATIVE_TYPE_INT; - case MP_QSTR_uint: - return MP_NATIVE_TYPE_UINT; - case MP_QSTR_ptr: - return MP_NATIVE_TYPE_PTR; - case MP_QSTR_ptr8: - return MP_NATIVE_TYPE_PTR8; - case MP_QSTR_ptr16: - return MP_NATIVE_TYPE_PTR16; - case MP_QSTR_ptr32: - return MP_NATIVE_TYPE_PTR32; - default: - return -1; - } -} - STATIC qstr vtype_to_qstr(vtype_kind_t vtype) { switch (vtype) { case VTYPE_PYOBJ: @@ -253,6 +230,11 @@ struct _emit_t { uint16_t const_table_cur_raw_code; mp_uint_t *const_table; + #if MICROPY_PERSISTENT_CODE_SAVE + uint16_t qstr_link_cur; + mp_qstr_link_entry_t *qstr_link; + #endif + bool last_emit_was_return_value; scope_t *scope; @@ -264,6 +246,7 @@ STATIC const uint8_t reg_local_table[REG_LOCAL_NUM] = {REG_LOCAL_1, REG_LOCAL_2, STATIC void emit_native_global_exc_entry(emit_t *emit); STATIC void emit_native_global_exc_exit(emit_t *emit); +STATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj); emit_t *EXPORT_FUN(new)(mp_obj_t * error_slot, uint *label_slot, mp_uint_t max_num_labels) { emit_t *emit = m_new0(emit_t, 1); @@ -318,6 +301,32 @@ STATIC void emit_native_mov_reg_state_addr(emit_t *emit, int reg_dest, int local } } +STATIC void emit_native_mov_reg_qstr(emit_t *emit, int arg_reg, qstr qst) { + #if MICROPY_PERSISTENT_CODE_SAVE + size_t loc = ASM_MOV_REG_IMM_FIX_U16(emit->as, arg_reg, qst); + size_t link_idx = emit->qstr_link_cur++; + if (emit->pass == MP_PASS_EMIT) { + emit->qstr_link[link_idx].off = loc << 2 | 1; + emit->qstr_link[link_idx].qst = qst; + } + #else + ASM_MOV_REG_IMM(emit->as, arg_reg, qst); + #endif +} + +STATIC void emit_native_mov_reg_qstr_obj(emit_t *emit, int reg_dest, qstr qst) { + #if MICROPY_PERSISTENT_CODE_SAVE + size_t loc = ASM_MOV_REG_IMM_FIX_WORD(emit->as, reg_dest, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); + size_t link_idx = emit->qstr_link_cur++; + if (emit->pass == MP_PASS_EMIT) { + emit->qstr_link[link_idx].off = loc << 2 | 2; + emit->qstr_link[link_idx].qst = qst; + } + #else + ASM_MOV_REG_IMM(emit->as, reg_dest, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); + #endif +} + #define emit_native_mov_state_imm_via(emit, local_num, imm, reg_temp) \ do { \ ASM_MOV_REG_IMM((emit)->as, (reg_temp), (imm)); \ @@ -330,8 +339,11 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->pass = pass; emit->do_viper_types = scope->emit_options == MP_EMIT_OPT_VIPER; emit->stack_size = 0; - emit->const_table_cur_obj = 1; // first entry is for mp_fun_table + emit->const_table_cur_obj = 0; emit->const_table_cur_raw_code = 0; + #if MICROPY_PERSISTENT_CODE_SAVE + emit->qstr_link_cur = 0; + #endif emit->last_emit_was_return_value = false; emit->scope = scope; @@ -619,7 +631,7 @@ STATIC void emit_native_end_pass(emit_t *emit) { assert(emit->pass <= MP_PASS_STACK_SIZE || (emit->const_table_num_obj == emit->const_table_cur_obj)); emit->const_table_num_obj = emit->const_table_cur_obj; if (emit->pass == MP_PASS_CODE_SIZE) { - size_t const_table_alloc = emit->const_table_num_obj + emit->const_table_cur_raw_code; + size_t const_table_alloc = 1 + emit->const_table_num_obj + emit->const_table_cur_raw_code; size_t nqstr = 0; if (!emit->do_viper_types) { // Add room for qstr names of arguments @@ -629,6 +641,13 @@ STATIC void emit_native_end_pass(emit_t *emit) { emit->const_table = m_new(mp_uint_t, const_table_alloc); // Store mp_fun_table pointer just after qstrs emit->const_table[nqstr] = (mp_uint_t)(uintptr_t)mp_fun_table; + + #if MICROPY_PERSISTENT_CODE_SAVE + size_t qstr_link_alloc = emit->qstr_link_cur; + if (qstr_link_alloc > 0) { + emit->qstr_link = m_new(mp_qstr_link_entry_t, qstr_link_alloc); + } + #endif } if (emit->pass == MP_PASS_EMIT) { @@ -638,6 +657,11 @@ STATIC void emit_native_end_pass(emit_t *emit) { mp_emit_glue_assign_native(emit->scope->raw_code, emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, f, f_len, emit->const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + emit->prelude_offset, + emit->const_table_cur_obj, emit->const_table_cur_raw_code, + emit->qstr_link_cur, emit->qstr_link, + #endif emit->scope->num_pos_args, emit->scope->scope_flags, 0); } } @@ -922,6 +946,12 @@ STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, mp_i ASM_CALL_IND(emit->as, fun_kind); } +STATIC void emit_call_with_qstr_arg(emit_t *emit, mp_fun_kind_t fun_kind, qstr qst, int arg_reg) { + need_reg_all(emit); + emit_native_mov_reg_qstr(emit, arg_reg, qst); + ASM_CALL_IND(emit->as, fun_kind); +} + // vtype of all n_pop objects is VTYPE_PYOBJ // Will convert any items that are not VTYPE_PYOBJ to this type and put them back on the stack. // If any conversions of non-immediate values are needed, then it uses REG_ARG_1, REG_ARG_2 and REG_RET. @@ -1038,12 +1068,14 @@ STATIC void emit_load_reg_with_ptr(emit_t *emit, int reg, mp_uint_t ptr, size_t } STATIC void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj) { - size_t table_off = emit->const_table_cur_obj++; + // First entry is for mp_fun_table + size_t table_off = 1 + emit->const_table_cur_obj++; emit_load_reg_with_ptr(emit, reg, (mp_uint_t)obj, table_off); } STATIC void emit_load_reg_with_raw_code(emit_t *emit, int reg, mp_raw_code_t *rc) { - size_t table_off = emit->const_table_num_obj + emit->const_table_cur_raw_code++; + // First entry is for mp_fun_table, then constant objects + size_t table_off = 1 + emit->const_table_num_obj + emit->const_table_cur_raw_code++; emit_load_reg_with_ptr(emit, reg, (mp_uint_t)rc, table_off); } @@ -1220,7 +1252,7 @@ STATIC void emit_native_import_name(emit_t *emit, qstr qst) { assert(vtype_level == VTYPE_PYOBJ); emit->do_viper_types = orig_do_viper_types; - emit_call_with_imm_arg(emit, MP_F_IMPORT_NAME, qst, REG_ARG_1); // arg1 = import name + emit_call_with_qstr_arg(emit, MP_F_IMPORT_NAME, qst, REG_ARG_1); // arg1 = import name emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1230,7 +1262,7 @@ STATIC void emit_native_import_from(emit_t *emit, qstr qst) { vtype_kind_t vtype_module; emit_access_stack(emit, 1, &vtype_module, REG_ARG_1); // arg1 = module assert(vtype_module == VTYPE_PYOBJ); - emit_call_with_imm_arg(emit, MP_F_IMPORT_FROM, qst, REG_ARG_2); // arg2 = import name + emit_call_with_qstr_arg(emit, MP_F_IMPORT_FROM, qst, REG_ARG_2); // arg2 = import name emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1256,7 +1288,11 @@ STATIC void emit_native_import(emit_t *emit, qstr qst, int kind) { STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) { DEBUG_printf("load_const_tok(tok=%u)\n", tok); if (tok == MP_TOKEN_ELLIPSIS) { + #if MICROPY_PERSISTENT_CODE_SAVE + emit_native_load_const_obj(emit, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); + #else emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); + #endif } else { emit_native_pre(emit); if (tok == MP_TOKEN_KW_NONE) { @@ -1284,11 +1320,14 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qst) { } else */ { - emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); + need_reg_single(emit, REG_TEMP0, 0); + emit_native_mov_reg_qstr_obj(emit, REG_TEMP0, qst); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_TEMP0); } } STATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj) { + emit->scope->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; emit_native_pre(emit); need_reg_single(emit, REG_RET, 0); emit_load_reg_with_object(emit, REG_RET, obj); @@ -1347,13 +1386,13 @@ STATIC void emit_native_load_global(emit_t *emit, qstr qst, int kind) { if (emit->do_viper_types) { // check for builtin casting operators int native_type = mp_native_type_from_qstr(qst); - if (native_type >= MP_NATIVE_TYPE_INT) { + if (native_type >= MP_NATIVE_TYPE_BOOL) { emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, native_type); return; } } } - emit_call_with_imm_arg(emit, MP_F_LOAD_NAME + kind, qst, REG_ARG_1); + emit_call_with_qstr_arg(emit, MP_F_LOAD_NAME + kind, qst, REG_ARG_1); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1365,7 +1404,7 @@ STATIC void emit_native_load_attr(emit_t *emit, qstr qst) { vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base assert(vtype_base == VTYPE_PYOBJ); - emit_call_with_imm_arg(emit, MP_F_LOAD_ATTR, qst, REG_ARG_2); // arg2 = attribute name + emit_call_with_qstr_arg(emit, MP_F_LOAD_ATTR, qst, REG_ARG_2); // arg2 = attribute name emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1373,13 +1412,13 @@ STATIC void emit_native_load_method(emit_t *emit, qstr qst, bool is_super) { if (is_super) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, 3); // arg2 = dest ptr emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, 2); // arg2 = dest ptr - emit_call_with_imm_arg(emit, MP_F_LOAD_SUPER_METHOD, qst, REG_ARG_1); // arg1 = method name + emit_call_with_qstr_arg(emit, MP_F_LOAD_SUPER_METHOD, qst, REG_ARG_1); // arg1 = method name } else { vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base assert(vtype_base == VTYPE_PYOBJ); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr - emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name + emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name } } @@ -1586,7 +1625,7 @@ STATIC void emit_native_store_global(emit_t *emit, qstr qst, int kind) { ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); } } - emit_call_with_imm_arg(emit, MP_F_STORE_NAME + kind, qst, REG_ARG_1); // arg1 = name + emit_call_with_qstr_arg(emit, MP_F_STORE_NAME + kind, qst, REG_ARG_1); // arg1 = name emit_post(emit); } @@ -1595,7 +1634,7 @@ STATIC void emit_native_store_attr(emit_t *emit, qstr qst) { emit_pre_pop_reg_reg(emit, &vtype_base, REG_ARG_1, &vtype_val, REG_ARG_3); // arg1 = base, arg3 = value assert(vtype_base == VTYPE_PYOBJ); assert(vtype_val == VTYPE_PYOBJ); - emit_call_with_imm_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name + emit_call_with_qstr_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name emit_post(emit); } @@ -1792,7 +1831,7 @@ STATIC void emit_native_delete_global(emit_t *emit, qstr qst, int kind) { MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_DELETE_NAME); MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_DELETE_GLOBAL); emit_native_pre(emit); - emit_call_with_imm_arg(emit, MP_F_DELETE_NAME + kind, qst, REG_ARG_1); + emit_call_with_qstr_arg(emit, MP_F_DELETE_NAME + kind, qst, REG_ARG_1); emit_post(emit); } @@ -1800,7 +1839,8 @@ STATIC void emit_native_delete_attr(emit_t *emit, qstr qst) { vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base assert(vtype_base == VTYPE_PYOBJ); - emit_call_with_2_imm_args(emit, MP_F_STORE_ATTR, qst, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); // arg2 = attribute name, arg3 = value (null for delete) + ASM_XOR_REG_REG(emit->as, REG_ARG_3, REG_ARG_3); // arg3 = value (null for delete) + emit_call_with_qstr_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name emit_post(emit); } @@ -1955,7 +1995,7 @@ STATIC void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t exc prev_finally->unwind_label = UNWIND_LABEL_DO_FINAL_UNWIND; ASM_MOV_REG_PCREL(emit->as, REG_RET, label & ~MP_EMIT_BREAK_FROM_FOR); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_RET); - // Cancel any active exception (see also emit_native_pop_except) + // Cancel any active exception (see also emit_native_pop_except_jump) emit_native_mov_reg_const(emit, REG_RET, MP_F_CONST_NONE_OBJ); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_RET); // Jump to the innermost active finally @@ -1974,7 +2014,7 @@ STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) { emit_access_stack(emit, 1, &vtype, REG_ARG_1); // arg1 = ctx_mgr assert(vtype == VTYPE_PYOBJ); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr - emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___exit__, REG_ARG_2); + emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___exit__, REG_ARG_2); // stack: (..., ctx_mgr, __exit__, self) emit_pre_pop_reg(emit, &vtype, REG_ARG_3); // self @@ -1987,7 +2027,7 @@ STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) { // get __enter__ method emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr - emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___enter__, REG_ARG_2); // arg2 = method name + emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___enter__, REG_ARG_2); // arg2 = method name // stack: (..., __exit__, self, __enter__, self) // call __enter__ method @@ -2133,12 +2173,12 @@ STATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, MP_OBJ_ITER_BUF_NSLOTS); adjust_stack(emit, MP_OBJ_ITER_BUF_NSLOTS); emit_call(emit, MP_F_NATIVE_ITERNEXT); - #ifdef NDEBUG - MP_STATIC_ASSERT(MP_OBJ_STOP_ITERATION == 0); - ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label, false); - #else + #if MICROPY_DEBUG_MP_OBJ_SENTINELS ASM_MOV_REG_IMM(emit->as, REG_TEMP1, (mp_uint_t)MP_OBJ_STOP_ITERATION); ASM_JUMP_IF_REG_EQ(emit->as, REG_RET, REG_TEMP1, label); + #else + MP_STATIC_ASSERT(MP_OBJ_STOP_ITERATION == 0); + ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label, false); #endif emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -2150,18 +2190,15 @@ STATIC void emit_native_for_iter_end(emit_t *emit) { emit_post(emit); } -STATIC void emit_native_pop_block(emit_t *emit) { - emit_native_pre(emit); - if (!emit->exc_stack[emit->exc_stack_size - 1].is_finally) { +STATIC void emit_native_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) { + if (within_exc_handler) { + // Cancel any active exception so subsequent handlers don't see it + emit_native_mov_reg_const(emit, REG_TEMP0, MP_F_CONST_NONE_OBJ); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); + } else { emit_native_leave_exc_stack(emit, false); } - emit_post(emit); -} - -STATIC void emit_native_pop_except(emit_t *emit) { - // Cancel any active exception so subsequent handlers don't see it - emit_native_mov_reg_const(emit, REG_TEMP0, MP_F_CONST_NONE_OBJ); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); + emit_native_jump(emit, label); } STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) { @@ -2220,17 +2257,16 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { int reg_rhs = REG_ARG_3; emit_pre_pop_reg_flexible(emit, &vtype_rhs, ®_rhs, REG_RET, REG_ARG_2); emit_pre_pop_reg(emit, &vtype_lhs, REG_ARG_2); - if (0) { - // dummy #if !(N_X64 || N_X86) - } else if (op == MP_BINARY_OP_LSHIFT) { + if (op == MP_BINARY_OP_LSHIFT) { ASM_LSL_REG_REG(emit->as, REG_ARG_2, reg_rhs); emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); } else if (op == MP_BINARY_OP_RSHIFT) { ASM_ASR_REG_REG(emit->as, REG_ARG_2, reg_rhs); emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); + } else #endif - } else if (op == MP_BINARY_OP_OR) { + if (op == MP_BINARY_OP_OR) { ASM_OR_REG_REG(emit->as, REG_ARG_2, reg_rhs); emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); } else if (op == MP_BINARY_OP_XOR) { @@ -2613,6 +2649,7 @@ STATIC void emit_native_return_value(emit_t *emit) { } STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) { + (void)n_args; assert(n_args == 1); vtype_kind_t vtype_exc; emit_pre_pop_reg(emit, &vtype_exc, REG_ARG_1); // arg1 = object to raise @@ -2719,6 +2756,11 @@ STATIC void emit_native_end_except_handler(emit_t *emit) { } const emit_method_table_t EXPORT_FUN(method_table) = { + #if MICROPY_DYNAMIC_COMPILER + EXPORT_FUN(new), + EXPORT_FUN(free), + #endif + emit_native_start_pass, emit_native_end_pass, emit_native_last_emit_was_return_value, @@ -2764,8 +2806,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_get_iter, emit_native_for_iter, emit_native_for_iter_end, - emit_native_pop_block, - emit_native_pop_except, + emit_native_pop_except_jump, emit_native_unary_op, emit_native_binary_op, emit_native_build, diff --git a/py/enum.c b/py/enum.c index 8dc83a9fba..5e77f42827 100644 --- a/py/enum.c +++ b/py/enum.c @@ -39,7 +39,7 @@ mp_obj_t cp_enum_find(const mp_obj_type_t *type, int value) { } int cp_enum_value(const mp_obj_type_t *type, mp_obj_t *obj) { - if (!MP_OBJ_IS_TYPE(obj, type)) { + if (!mp_obj_is_type(obj, type)) { mp_raise_TypeError_varg(translate("Expected a %q"), type->name); } return ((cp_enum_obj_t *)MP_OBJ_TO_PTR(obj))->value; diff --git a/py/frozenmod.h b/py/frozenmod.h index 668b7ac17e..51c86f29f8 100644 --- a/py/frozenmod.h +++ b/py/frozenmod.h @@ -3,7 +3,8 @@ * * The MIT License (MIT) * - * SPDX-FileCopyrightText: Copyright (c) 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2015 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/py/gc.c b/py/gc.c index c29624c3af..003ab6c30f 100644 --- a/py/gc.c +++ b/py/gc.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/py/gc_long_lived.c b/py/gc_long_lived.c index 8ee8a4a4e1..df3f72e3cd 100644 --- a/py/gc_long_lived.c +++ b/py/gc_long_lived.c @@ -46,8 +46,8 @@ mp_obj_fun_bc_t *make_fun_bc_long_lived(mp_obj_fun_bc_t *fun_bc, uint8_t max_dep // Try to detect raw code. mp_raw_code_t *raw_code = MP_OBJ_TO_PTR(fun_bc->const_table[i]); if (raw_code->kind == MP_CODE_BYTECODE) { - raw_code->data.u_byte.bytecode = gc_make_long_lived((byte *)raw_code->data.u_byte.bytecode); - raw_code->data.u_byte.const_table = gc_make_long_lived((byte *)raw_code->data.u_byte.const_table); + raw_code->fun_data = gc_make_long_lived((byte *)raw_code->fun_data); + raw_code->const_table = gc_make_long_lived((byte *)raw_code->const_table); } ((mp_uint_t *)fun_bc->const_table)[i] = (mp_uint_t)make_obj_long_lived( (mp_obj_t)fun_bc->const_table[i], max_depth - 1); @@ -62,7 +62,7 @@ mp_obj_fun_bc_t *make_fun_bc_long_lived(mp_obj_fun_bc_t *fun_bc, uint8_t max_dep if (fun_bc->extra_args[i] == NULL) { continue; } - if (MP_OBJ_IS_TYPE(fun_bc->extra_args[i], &mp_type_dict)) { + if (mp_obj_is_type(fun_bc->extra_args[i], &mp_type_dict)) { fun_bc->extra_args[i] = make_dict_long_lived(fun_bc->extra_args[i], max_depth - 1); } else { fun_bc->extra_args[i] = make_obj_long_lived(fun_bc->extra_args[i], max_depth - 1); @@ -103,7 +103,7 @@ mp_obj_dict_t *make_dict_long_lived(mp_obj_dict_t *dict, uint8_t max_depth) { // copies. dict->map.table = gc_make_long_lived(dict->map.table); for (size_t i = 0; i < dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { + if (mp_map_slot_is_filled(&dict->map, i)) { mp_obj_t value = dict->map.table[i].value; dict->map.table[i].value = make_obj_long_lived(value, max_depth - 1); } @@ -131,16 +131,16 @@ mp_obj_t make_obj_long_lived(mp_obj_t obj, uint8_t max_depth) { if (!VERIFY_PTR((void *)obj)) { return obj; } - if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_bc)) { + if (mp_obj_is_type(obj, &mp_type_fun_bc)) { mp_obj_fun_bc_t *fun_bc = MP_OBJ_TO_PTR(obj); return MP_OBJ_FROM_PTR(make_fun_bc_long_lived(fun_bc, max_depth)); - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_property)) { + } else if (mp_obj_is_type(obj, &mp_type_property)) { mp_obj_property_t *prop = MP_OBJ_TO_PTR(obj); return MP_OBJ_FROM_PTR(make_property_long_lived(prop, max_depth)); - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_str) || MP_OBJ_IS_TYPE(obj, &mp_type_bytes)) { + } else if (mp_obj_is_type(obj, &mp_type_str) || mp_obj_is_type(obj, &mp_type_bytes)) { mp_obj_str_t *str = MP_OBJ_TO_PTR(obj); return MP_OBJ_FROM_PTR(make_str_long_lived(str)); - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_type)) { + } else if (mp_obj_is_type(obj, &mp_type_type)) { // Types are already long lived during creation. return obj; } else { diff --git a/py/makemoduledefs.py b/py/makemoduledefs.py index 7745607131..e20bff1eb0 100644 --- a/py/makemoduledefs.py +++ b/py/makemoduledefs.py @@ -8,6 +8,7 @@ from __future__ import print_function import re +import io import os import argparse @@ -46,7 +47,7 @@ def find_module_registrations(c_file): # No c file to match the object file, skip return set() - with open(c_file) as c_file_obj: + with io.open(c_file, encoding="utf-8") as c_file_obj: return set(re.findall(pattern, c_file_obj.read())) @@ -60,6 +61,7 @@ def generate_module_table_header(modules): # Print header file for all external modules. mod_defs = [] print("// Automatically generated by makemoduledefs.py.\n") + print("#include \"py/mpconfig.h\"") for module_name, obj_module, enabled_define in modules: mod_def = "MODULE_DEF_{}".format(module_name.upper()) mod_defs.append(mod_def) diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 6a6125fe20..40942ed106 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -82,6 +82,176 @@ C_ESCAPES = { '"': '\\"', } +# static qstrs, should be sorted +# These are qstrs that are always included and always have the same number. It allows mpy files to omit them. +static_qstr_list = [ + "", + "__dir__", # Put __dir__ after empty qstr for builtin dir() to work + "\n", + " ", + "*", + "/", + "", + "_", + "__call__", + "__class__", + "__delitem__", + "__enter__", + "__exit__", + "__getattr__", + "__getitem__", + "__hash__", + "__init__", + "__int__", + "__iter__", + "__len__", + "__main__", + "__module__", + "__name__", + "__new__", + "__next__", + "__qualname__", + "__repr__", + "__setitem__", + "__str__", + "ArithmeticError", + "AssertionError", + "AttributeError", + "BaseException", + "EOFError", + "Ellipsis", + "Exception", + "GeneratorExit", + "ImportError", + "IndentationError", + "IndexError", + "KeyError", + "KeyboardInterrupt", + "LookupError", + "MemoryError", + "NameError", + "NoneType", + "NotImplementedError", + "OSError", + "OverflowError", + "RuntimeError", + "StopIteration", + "SyntaxError", + "SystemExit", + "TypeError", + "ValueError", + "ZeroDivisionError", + "abs", + "all", + "any", + "append", + "args", + "bool", + "builtins", + "bytearray", + "bytecode", + "bytes", + "callable", + "chr", + "classmethod", + "clear", + "close", + "const", + "copy", + "count", + "dict", + "dir", + "divmod", + "end", + "endswith", + "eval", + "exec", + "extend", + "find", + "format", + "from_bytes", + "get", + "getattr", + "globals", + "hasattr", + "hash", + "id", + "index", + "insert", + "int", + "isalpha", + "isdigit", + "isinstance", + "islower", + "isspace", + "issubclass", + "isupper", + "items", + "iter", + "join", + "key", + "keys", + "len", + "list", + "little", + "locals", + "lower", + "lstrip", + "main", + "map", + "micropython", + "next", + "object", + "open", + "ord", + "pop", + "popitem", + "pow", + "print", + "range", + "read", + "readinto", + "readline", + "remove", + "replace", + "repr", + "reverse", + "rfind", + "rindex", + "round", + "rsplit", + "rstrip", + "self", + "send", + "sep", + "set", + "setattr", + "setdefault", + "sort", + "sorted", + "split", + "start", + "startswith", + "staticmethod", + "step", + "stop", + "str", + "strip", + "sum", + "super", + "throw", + "to_bytes", + "tuple", + "type", + "update", + "upper", + "utf-8", + "value", + "values", + "write", + "zip", +] + # this must match the equivalent function in qstr.c def compute_hash(qstr, bytes_hash): hash = 5381 @@ -385,10 +555,23 @@ def qstr_escape(qst): def parse_input_headers(infiles): - # read the qstrs in from the input files qcfgs = {} qstrs = {} i18ns = set() + + # add static qstrs + for qstr in static_qstr_list: + # work out the corresponding qstr name + ident = qstr_escape(qstr) + + # don't add duplicates + assert ident not in qstrs + + # add the qstr to the list, with order number to retain original order in file + order = len(qstrs) - 300000 + qstrs[ident] = (order, ident, qstr) + + # read the qstrs in from the input files for infile in infiles: with open(infile, "rt") as f: for line in f: @@ -486,6 +669,7 @@ def print_qstr_data(encoding_table, qcfgs, qstrs, i18ns): for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]): qbytes = make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr) print("QDEF(MP_QSTR_%s, %s)" % (ident, qbytes)) + total_qstr_size += len(qstr) total_text_size = 0 @@ -531,6 +715,7 @@ def print_qstr_enums(qstrs): print("QENUM(MP_QSTR_%s)" % (ident,)) + if __name__ == "__main__": import argparse diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py index e6c0033113..c143a0bedc 100644 --- a/py/makeqstrdefs.py +++ b/py/makeqstrdefs.py @@ -9,6 +9,7 @@ from __future__ import print_function import re import sys +import io import os # Python 2/3 compatibility: @@ -175,7 +176,7 @@ if __name__ == "__main__": pass if args.command == "split": - with open(args.input_filename) as infile: + with io.open(args.input_filename, encoding="utf-8") as infile: process_file(infile) if args.command == "cat": diff --git a/py/makeversionhdr.py b/py/makeversionhdr.py index 41e5956542..1ab15ecd95 100644 --- a/py/makeversionhdr.py +++ b/py/makeversionhdr.py @@ -65,6 +65,7 @@ def get_version_info_from_git(): return git_tag, git_hash, ver + def get_version_info_from_docs_conf(): with open(os.path.join(os.path.dirname(sys.argv[0]), "..", "conf.py")) as f: for line in f: diff --git a/py/map.c b/py/map.c index 06695c8de8..2f2c11c639 100644 --- a/py/map.c +++ b/py/map.c @@ -152,9 +152,9 @@ mp_map_elem_t *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_m // Work out if we can compare just pointers bool compare_only_ptrs = map->all_keys_are_qstrs; if (compare_only_ptrs) { - if (MP_OBJ_IS_QSTR(index)) { + if (mp_obj_is_qstr(index)) { // Index is a qstr, so can just do ptr comparison. - } else if (MP_OBJ_IS_TYPE(index, &mp_type_str)) { + } else if (mp_obj_is_type(index, &mp_type_str)) { // Index is a non-interned string. // We can either intern the string, or force a full equality comparison. // We chose the latter, since interning costs time and potentially RAM, @@ -199,7 +199,7 @@ mp_map_elem_t *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_m } mp_map_elem_t *elem = map->table + map->used++; elem->key = index; - if (!MP_OBJ_IS_QSTR(index)) { + if (!mp_obj_is_qstr(index)) { map->all_keys_are_qstrs = 0; } return elem; @@ -220,7 +220,7 @@ mp_map_elem_t *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_m // get hash of index, with fast path for common case of qstr mp_uint_t hash; - if (MP_OBJ_IS_QSTR(index)) { + if (mp_obj_is_qstr(index)) { hash = qstr_hash(MP_OBJ_QSTR_VALUE(index)); } else { hash = MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, index)); @@ -240,7 +240,7 @@ mp_map_elem_t *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_m } avail_slot->key = index; avail_slot->value = MP_OBJ_NULL; - if (!MP_OBJ_IS_QSTR(index)) { + if (!mp_obj_is_qstr(index)) { map->all_keys_are_qstrs = 0; } return avail_slot; @@ -280,7 +280,7 @@ mp_map_elem_t *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_m map->used++; avail_slot->key = index; avail_slot->value = MP_OBJ_NULL; - if (!MP_OBJ_IS_QSTR(index)) { + if (!mp_obj_is_qstr(index)) { map->all_keys_are_qstrs = 0; } return avail_slot; @@ -397,7 +397,7 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku mp_obj_t mp_set_remove_first(mp_set_t *set) { for (size_t pos = 0; pos < set->alloc; pos++) { - if (MP_SET_SLOT_IS_FILLED(set, pos)) { + if (mp_set_slot_is_filled(set, pos)) { mp_obj_t elem = set->table[pos]; // delete element set->used--; diff --git a/py/misc.h b/py/misc.h index cb7192a56f..1d107f6d96 100644 --- a/py/misc.h +++ b/py/misc.h @@ -49,8 +49,8 @@ typedef unsigned int uint; #endif // Classical double-indirection stringification of preprocessor macro's value -#define _MP_STRINGIFY(x) #x -#define MP_STRINGIFY(x) _MP_STRINGIFY(x) +#define MP_STRINGIFY_HELPER(x) #x +#define MP_STRINGIFY(x) MP_STRINGIFY_HELPER(x) // Static assertion macro #define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)])) diff --git a/py/mkenv.mk b/py/mkenv.mk index 7e99f59c10..80f9b4eac1 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -44,6 +44,7 @@ BUILD ?= build ECHO = @echo +CAT = cat CD = cd CP = cp FIND = find @@ -55,6 +56,7 @@ PYTHON3 ?= python3 RM = rm RSYNC = rsync SED = sed +TOUCH = touch # Linux has 'nproc', macOS has 'sysctl -n hw.logicalcpu', this is cross-platform NPROC = $(PYTHON3) -c 'import multiprocessing as mp; print(mp.cpu_count())' diff --git a/py/mkrules.mk b/py/mkrules.mk index 2721d293e0..d05f28bf40 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -79,7 +79,7 @@ $(OBJ): | $(HEADER_BUILD)/qstrdefs.enum.h $(HEADER_BUILD)/mpversion.h $(HEADER_BUILD)/qstr.split: $(SRC_QSTR) $(SRC_QSTR_PREPROCESSOR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h $(PY_SRC)/genlast.py $(STEPECHO) "GEN $@" $(Q)$(PYTHON3) $(PY_SRC)/genlast.py $(HEADER_BUILD)/qstr $(if $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(if $?,$?,$^)) -- $(SRC_QSTR_PREPROCESSOR) -- $(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) - $(Q)touch $@ + $(Q)$(TOUCH) $@ $(QSTR_DEFS_COLLECTED): $(HEADER_BUILD)/qstr.split $(PY_SRC)/makeqstrdefs.py $(STEPECHO) "GEN $@" @@ -197,7 +197,7 @@ print-cfg: print-def: @$(ECHO) "The following defines are built into the $(CC) compiler" - touch __empty__.c + $(TOUCH) __empty__.c @$(CC) -E -Wp,-dM __empty__.c @$(RM) -f __empty__.c diff --git a/py/modarray.c b/py/modarray.c index a47684bf97..daae34662b 100644 --- a/py/modarray.c +++ b/py/modarray.c @@ -40,4 +40,6 @@ const mp_obj_module_t mp_module_array = { .globals = (mp_obj_dict_t *)&mp_module_array_globals, }; +MP_REGISTER_MODULE(MP_QSTR_array, mp_module_array, MICROPY_PY_ARRAY); + #endif diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 49d88f728e..3b962e678e 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -181,7 +181,7 @@ STATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { // Make a list of names in the local namespace mp_obj_dict_t *dict = mp_locals_get(); for (size_t i = 0; i < dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { + if (mp_map_slot_is_filled(&dict->map, i)) { mp_obj_list_append(dir, dict->map.table[i].key); } } @@ -319,6 +319,22 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_min_obj, 1, mp_builtin_min); #endif +#if MICROPY_PY_BUILTINS_NEXT2 +STATIC mp_obj_t mp_builtin_next(size_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + mp_obj_t ret = mp_iternext_allow_raise(args[0]); + if (ret == MP_OBJ_STOP_ITERATION) { + nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); + } else { + return ret; + } + } else { + mp_obj_t ret = mp_iternext(args[0]); + return ret == MP_OBJ_STOP_ITERATION ? args[1] : ret; + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_next_obj, 1, 2, mp_builtin_next); +#else STATIC mp_obj_t mp_builtin_next(mp_obj_t o) { mp_obj_t ret = mp_iternext_allow_raise(o); if (ret == MP_OBJ_STOP_ITERATION) { @@ -328,6 +344,7 @@ STATIC mp_obj_t mp_builtin_next(mp_obj_t o) { } } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_next_obj, mp_builtin_next); +#endif STATIC mp_obj_t mp_builtin_oct(mp_obj_t o_in) { #if MICROPY_PY_BUILTINS_STR_OP_MODULO @@ -343,7 +360,7 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { size_t len; const byte *str = (const byte *)mp_obj_str_get_data(o_in, &len); #if MICROPY_PY_BUILTINS_STR_UNICODE - if (MP_OBJ_IS_STR(o_in)) { + if (mp_obj_is_str(o_in)) { len = utf8_charlen(str, len); if (len == 1) { return mp_obj_new_int(utf8_get_char(str)); @@ -462,7 +479,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr); STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) { mp_obj_t o_in = args[0]; - if (MP_OBJ_IS_INT(o_in)) { + if (mp_obj_is_int(o_in)) { if (n_args <= 1) { return o_in; } diff --git a/py/modio.c b/py/modio.c index e88a9b04f3..9585ed021a 100644 --- a/py/modio.c +++ b/py/modio.c @@ -148,6 +148,7 @@ STATIC mp_uint_t bufwriter_write(mp_obj_t self_in, const void *buf, mp_uint_t si buf = (byte *)buf + rem; size -= rem; mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->alloc, errcode); + (void)out_sz; if (*errcode != 0) { return MP_STREAM_ERROR; } @@ -166,6 +167,7 @@ STATIC mp_obj_t bufwriter_flush(mp_obj_t self_in) { if (self->len != 0) { int err; mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->len, &err); + (void)out_sz; // TODO: try to recover from a case of non-blocking stream, e.g. move // remaining chunk to the beginning of buffer. assert(out_sz == self->len); diff --git a/py/modmath.c b/py/modmath.c index 9df345a564..206d6057fd 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -171,7 +171,7 @@ MATH_FUN_1(gamma, tgamma) // lgamma(x): return the natural logarithm of the gamma function of x MATH_FUN_1(lgamma, lgamma) #endif -// TODO: factorial, fsum +// TODO: fsum // Function that takes a variable number of arguments diff --git a/py/modthread.c b/py/modthread.c index 89b4f3fb66..84b12f7fb1 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -244,7 +244,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) th_args->n_kw = map->used; // copy across the keyword arguments for (size_t i = 0, n = pos_args_len; i < map->alloc; ++i) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { th_args->args[n++] = map->table[i].key; th_args->args[n++] = map->table[i].value; } diff --git a/py/moduerrno.c b/py/moduerrno.c index 6ead6a8054..e8a3bb9b97 100644 --- a/py/moduerrno.c +++ b/py/moduerrno.c @@ -142,7 +142,7 @@ const char *mp_errno_to_str(mp_obj_t errno_val) { // For commonly encountered errors, return human readable strings, otherwise try errno name const char *mp_common_errno_to_str(mp_obj_t errno_val, char *buf, size_t len) { - if (!MP_OBJ_IS_SMALL_INT(errno_val)) { + if (!mp_obj_is_small_int(errno_val)) { return NULL; } diff --git a/py/mpconfig.h b/py/mpconfig.h index 6badacaf6c..8172510008 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -358,6 +358,11 @@ #define MICROPY_COMP_CONST_FOLDING (1) #endif +// Whether to enable optimisations for constant literals, eg OrderedDict +#ifndef MICROPY_COMP_CONST_LITERAL +#define MICROPY_COMP_CONST_LITERAL (1) +#endif + // Whether to enable lookup of constants in modules; eg module.CONST #ifndef MICROPY_COMP_MODULE_CONST #define MICROPY_COMP_MODULE_CONST (0) @@ -416,6 +421,11 @@ #define MICROPY_DEBUG_VERBOSE (0) #endif +// Whether to enable debugging versions of MP_OBJ_NULL/STOP_ITERATION/SENTINEL +#ifndef MICROPY_DEBUG_MP_OBJ_SENTINELS +#define MICROPY_DEBUG_MP_OBJ_SENTINELS (0) +#endif + // Whether to enable a simple VM stack overflow check #ifndef MICROPY_DEBUG_VM_STACK_OVERFLOW #define MICROPY_DEBUG_VM_STACK_OVERFLOW (0) @@ -479,6 +489,11 @@ #define MICROPY_READER_VFS (0) #endif +// Whether any readers have been defined +#ifndef MICROPY_HAS_FILE_READER +#define MICROPY_HAS_FILE_READER (MICROPY_READER_POSIX || MICROPY_READER_VFS) +#endif + // Number of VFS mounts to persist across soft-reset. #ifndef MICROPY_FATFS_NUM_PERSISTENT #define MICROPY_FATFS_NUM_PERSISTENT (0) @@ -618,6 +633,11 @@ typedef long long mp_longint_impl_t; #define MICROPY_WARNINGS (0) #endif +// Whether to support warning categories +#ifndef MICROPY_WARNINGS_CATEGORY +#define MICROPY_WARNINGS_CATEGORY (0) +#endif + // This macro is used when printing runtime warnings and errors #ifndef MICROPY_ERROR_PRINTER #define MICROPY_ERROR_PRINTER (&mp_plat_print) @@ -861,6 +881,11 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_MEMORYVIEW (0) #endif +// Whether to support memoryview.itemsize attribute +#ifndef MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE +#define MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE (0) +#endif + // Whether to support set object #ifndef MICROPY_PY_BUILTINS_SET #define MICROPY_PY_BUILTINS_SET (1) @@ -901,16 +926,16 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_RANGE_BINOP (0) #endif +// Support for callling next() with second argument +#ifndef MICROPY_PY_BUILTINS_NEXT2 +#define MICROPY_PY_BUILTINS_NEXT2 (0) +#endif + // Whether to support rounding of integers (incl bignum); eg round(123,-1)=120 #ifndef MICROPY_PY_BUILTINS_ROUND_INT #define MICROPY_PY_BUILTINS_ROUND_INT (0) #endif -// Whether to support timeout exceptions (like socket.timeout) -#ifndef MICROPY_PY_BUILTINS_TIMEOUTERROR -#define MICROPY_PY_BUILTINS_TIMEOUTERROR (0) -#endif - // Whether to support complete set of special methods for user // classes, or only the most used ones. "Inplace" methods are // controlled by MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS below. @@ -1291,6 +1316,11 @@ typedef double mp_float_t; #define MICROPY_PY_UCRYPTOLIB (0) #endif +// Depends on MICROPY_PY_UCRYPTOLIB +#ifndef MICROPY_PY_UCRYPTOLIB_CTR +#define MICROPY_PY_UCRYPTOLIB_CTR (0) +#endif + #ifndef MICROPY_PY_UCRYPTOLIB_CONSTS #define MICROPY_PY_UCRYPTOLIB_CONSTS (0) #endif @@ -1336,8 +1366,8 @@ typedef double mp_float_t; #define MICROPY_PY_USSL_FINALISER (0) #endif -#ifndef MICROPY_PY_WEBSOCKET -#define MICROPY_PY_WEBSOCKET (0) +#ifndef MICROPY_PY_UWEBSOCKET +#define MICROPY_PY_UWEBSOCKET (0) #endif #ifndef MICROPY_PY_FRAMEBUF @@ -1371,17 +1401,17 @@ typedef double mp_float_t; /*****************************************************************************/ /* Hooks for a port to add builtins */ -// Additional builtin function definitions - see builtintables.c:builtin_object_table for format. +// Additional builtin function definitions - see modbuiltins.c:mp_module_builtins_globals_table for format. #ifndef MICROPY_PORT_BUILTINS #define MICROPY_PORT_BUILTINS #endif -// Additional builtin module definitions - see builtintables.c:builtin_module_table for format. +// Additional builtin module definitions - see objmodule.c:mp_builtin_module_table for format. #ifndef MICROPY_PORT_BUILTIN_MODULES #define MICROPY_PORT_BUILTIN_MODULES #endif -// Any module weak links - see builtintables.c:mp_builtin_module_weak_links_table. +// Any module weak links - see objmodule.c:mp_builtin_module_weak_links_table. #ifndef MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS #endif @@ -1562,4 +1592,15 @@ typedef double mp_float_t; #endif #endif +// Warning categories are by default implemented as strings, though +// hook is left for a port to define them as something else. +#if MICROPY_WARNINGS_CATEGORY +#ifndef MP_WARN_CAT +#define MP_WARN_CAT(x) #x +#endif +#else +#undef MP_WARN_CAT +#define MP_WARN_CAT(x) (NULL) +#endif + #endif // MICROPY_INCLUDED_PY_MPCONFIG_H diff --git a/py/mpprint.c b/py/mpprint.c index 032ce8e97b..1ba44279f7 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -207,7 +207,7 @@ int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char // If needed this function could be generalised to handle other values. assert(base == 2 || base == 8 || base == 10 || base == 16); - if (!MP_OBJ_IS_INT(x)) { + if (!mp_obj_is_int(x)) { // This will convert booleans to int, or raise an error for // non-integer types. x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x)); @@ -505,22 +505,28 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { chrs += mp_print_strn(print, str, prec, flags, fill, width); break; } + case 'd': { + mp_int_t val; + if (long_arg) { + val = va_arg(args, long int); + } else { + val = va_arg(args, int); + } + chrs += mp_print_int(print, val, 1, 10, 'a', flags, fill, width); + break; + } case 'u': - chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 10, 'a', flags, fill, width); - break; - case 'd': - chrs += mp_print_int(print, va_arg(args, int), 1, 10, 'a', flags, fill, width); - break; case 'x': case 'X': { - char fmt_c = *fmt - 'X' + 'A'; + int base = 16 - ((*fmt + 1) & 6); // maps char u/x/X to base 10/16/16 + char fmt_c = (*fmt & 0xf0) - 'P' + 'A'; // maps char u/x/X to char a/a/A mp_uint_t val; if (long_arg) { val = va_arg(args, unsigned long int); } else { val = va_arg(args, unsigned int); } - chrs += mp_print_int(print, val, 0, 16, fmt_c, flags, fill, width); + chrs += mp_print_int(print, val, 0, base, fmt_c, flags, fill, width); break; } case 'p': diff --git a/py/mpstate.h b/py/mpstate.h index 0c57563acc..ce26593fdb 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -46,6 +46,7 @@ typedef struct mp_dynamic_compiler_t { uint8_t small_int_bits; // must be <= host small_int_bits bool opt_cache_map_lookup_in_bytecode; bool py_builtins_str_unicode; + uint8_t native_arch; } mp_dynamic_compiler_t; extern mp_dynamic_compiler_t mp_dynamic_compiler; #endif @@ -217,7 +218,8 @@ typedef struct _mp_state_vm_t { #if MICROPY_ENABLE_SCHEDULER volatile int16_t sched_state; - uint16_t sched_sp; + uint8_t sched_len; + uint8_t sched_idx; #endif #if MICROPY_PY_THREAD_GIL diff --git a/py/nativeglue.c b/py/nativeglue.c index 7662aaeaf6..a3841efb1d 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -41,13 +41,37 @@ #if MICROPY_EMIT_NATIVE +int mp_native_type_from_qstr(qstr qst) { + switch (qst) { + case MP_QSTR_object: + return MP_NATIVE_TYPE_OBJ; + case MP_QSTR_bool: + return MP_NATIVE_TYPE_BOOL; + case MP_QSTR_int: + return MP_NATIVE_TYPE_INT; + case MP_QSTR_uint: + return MP_NATIVE_TYPE_UINT; + case MP_QSTR_ptr: + return MP_NATIVE_TYPE_PTR; + case MP_QSTR_ptr8: + return MP_NATIVE_TYPE_PTR8; + case MP_QSTR_ptr16: + return MP_NATIVE_TYPE_PTR16; + case MP_QSTR_ptr32: + return MP_NATIVE_TYPE_PTR32; + default: + return -1; + } +} + // convert a MicroPython object to a valid native value based on type -mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) { - DEBUG_printf("mp_convert_obj_to_native(%p, " UINT_FMT ")\n", obj, type); +mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) { + DEBUG_printf("mp_native_from_obj(%p, " UINT_FMT ")\n", obj, type); switch (type & 0xf) { case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj; case MP_NATIVE_TYPE_BOOL: + return mp_obj_is_true(obj); case MP_NATIVE_TYPE_INT: case MP_NATIVE_TYPE_UINT: return mp_obj_get_int_truncated(obj); @@ -68,8 +92,8 @@ mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) { #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM // convert a native value to a MicroPython object based on type -mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type) { - DEBUG_printf("mp_convert_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type); +mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { + DEBUG_printf("mp_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type); switch (type & 0xf) { case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val; @@ -184,8 +208,8 @@ const void *const mp_fun_table[MP_F_NUMBER_OF] = { &mp_const_none_obj, &mp_const_false_obj, &mp_const_true_obj, - mp_convert_obj_to_native, - mp_convert_native_to_obj, + mp_native_from_obj, + mp_native_to_obj, mp_native_swap_globals, mp_load_name, mp_load_global, diff --git a/py/obj.c b/py/obj.c index 6b2dded57e..dd0aa4e93e 100644 --- a/py/obj.c +++ b/py/obj.c @@ -44,9 +44,9 @@ #include "supervisor/shared/translate.h" mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) { - if (MP_OBJ_IS_SMALL_INT(o_in)) { + if (mp_obj_is_small_int(o_in)) { return (mp_obj_type_t *)&mp_type_int; - } else if (MP_OBJ_IS_QSTR(o_in)) { + } else if (mp_obj_is_qstr(o_in)) { return (mp_obj_type_t *)&mp_type_str; #if MICROPY_PY_BUILTINS_FLOAT } else if (mp_obj_is_float(o_in)) { @@ -144,7 +144,7 @@ bool PLACE_IN_ITCM(mp_obj_is_true)(mp_obj_t arg) { return 1; } else if (arg == mp_const_none) { return 0; - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { if (MP_OBJ_SMALL_INT_VALUE(arg) == 0) { return 0; } else { @@ -199,7 +199,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { && !mp_obj_is_float(o1) #endif #if MICROPY_PY_BUILTINS_COMPLEX - && !MP_OBJ_IS_TYPE(o1, &mp_type_complex) + && !mp_obj_is_type(o1, &mp_type_complex) #endif ) { return true; @@ -209,8 +209,8 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { } // fast path for small ints - if (MP_OBJ_IS_SMALL_INT(o1)) { - if (MP_OBJ_IS_SMALL_INT(o2)) { + if (mp_obj_is_small_int(o1)) { + if (mp_obj_is_small_int(o2)) { // both SMALL_INT, and not equal if we get here return false; } else { @@ -223,20 +223,20 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { } // fast path for strings - if (MP_OBJ_IS_STR(o1)) { - if (MP_OBJ_IS_STR(o2)) { + if (mp_obj_is_str(o1)) { + if (mp_obj_is_str(o2)) { // both strings, use special function return mp_obj_str_equal(o1, o2); } else { // a string is never equal to anything else goto str_cmp_err; } - } else if (MP_OBJ_IS_STR(o2)) { + } else if (mp_obj_is_str(o2)) { // o1 is not a string (else caught above), so the objects are not equal str_cmp_err: #if MICROPY_PY_STR_BYTES_CMP_WARN - if (MP_OBJ_IS_TYPE(o1, &mp_type_bytes) || MP_OBJ_IS_TYPE(o2, &mp_type_bytes)) { - mp_warning("Comparison between bytes and str"); + if (mp_obj_is_type(o1, &mp_type_bytes) || mp_obj_is_type(o2, &mp_type_bytes)) { + mp_warning(MP_WARN_CAT(BytesWarning), "Comparison between bytes and str"); } #endif return false; @@ -264,9 +264,9 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) { return 0; } else if (arg == mp_const_true) { return 1; - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { return MP_OBJ_SMALL_INT_VALUE(arg); - } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + } else if (mp_obj_is_type(arg, &mp_type_int)) { return mp_obj_int_get_checked(arg); } else { mp_obj_t res = mp_unary_op(MP_UNARY_OP_INT, (mp_obj_t)arg); @@ -275,7 +275,7 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) { } mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) { - if (MP_OBJ_IS_INT(arg)) { + if (mp_obj_is_int(arg)) { return mp_obj_int_get_truncated(arg); } else { return mp_obj_get_int(arg); @@ -290,9 +290,9 @@ bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value) { *value = 0; } else if (arg == mp_const_true) { *value = 1; - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { *value = MP_OBJ_SMALL_INT_VALUE(arg); - } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + } else if (mp_obj_is_type(arg, &mp_type_int)) { *value = mp_obj_int_get_checked(arg); } else { return false; @@ -308,10 +308,10 @@ bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value) { val = 0; } else if (arg == mp_const_true) { val = 1; - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { val = MP_OBJ_SMALL_INT_VALUE(arg); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + } else if (mp_obj_is_type(arg, &mp_type_int)) { val = mp_obj_int_as_float_impl(arg); #endif } else if (mp_obj_is_float(arg)) { @@ -347,18 +347,18 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { } else if (arg == mp_const_true) { *real = 1; *imag = 0; - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { *real = MP_OBJ_SMALL_INT_VALUE(arg); *imag = 0; #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + } else if (mp_obj_is_type(arg, &mp_type_int)) { *real = mp_obj_int_as_float_impl(arg); *imag = 0; #endif } else if (mp_obj_is_float(arg)) { *real = mp_obj_float_get(arg); *imag = 0; - } else if (MP_OBJ_IS_TYPE(arg, &mp_type_complex)) { + } else if (mp_obj_is_type(arg, &mp_type_complex)) { mp_obj_complex_get(arg, real, imag); } else { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE @@ -374,9 +374,9 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { // note: returned value in *items may point to the interior of a GC block void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) { - if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) { + if (mp_obj_is_type(o, &mp_type_tuple)) { mp_obj_tuple_get(o, len, items); - } else if (MP_OBJ_IS_TYPE(o, &mp_type_list)) { + } else if (mp_obj_is_type(o, &mp_type_list)) { mp_obj_list_get(o, len, items); } else { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE @@ -405,7 +405,7 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) { // is_slice determines whether the index is a slice index size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice) { mp_int_t i; - if (MP_OBJ_IS_SMALL_INT(index)) { + if (mp_obj_is_small_int(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE @@ -443,7 +443,7 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool mp_obj_t mp_obj_id(mp_obj_t o_in) { mp_int_t id = (mp_int_t)o_in; - if (!MP_OBJ_IS_OBJ(o_in)) { + if (!mp_obj_is_obj(o_in)) { return mp_obj_new_int(id); } else if (id >= 0) { // Many OSes and CPUs have affinity for putting "user" memories @@ -479,9 +479,9 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { if ( #if !MICROPY_PY_BUILTINS_STR_UNICODE // It's simple - unicode is slow, non-unicode is fast - MP_OBJ_IS_STR(o_in) || + mp_obj_is_str(o_in) || #endif - MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) { + mp_obj_is_type(o_in, &mp_type_bytes)) { GET_STR_LEN(o_in, l); return MP_OBJ_NEW_SMALL_INT(l); } else { diff --git a/py/obj.h b/py/obj.h index 4e32ce8b0e..b7d7bdfd7f 100644 --- a/py/obj.h +++ b/py/obj.h @@ -69,14 +69,14 @@ typedef struct _mp_obj_base_t mp_obj_base_t; // For debugging purposes they are all different. For non-debug mode, we alias // as many as we can to MP_OBJ_NULL because it's cheaper to load/compare 0. -#ifdef NDEBUG -#define MP_OBJ_NULL (MP_OBJ_FROM_PTR((void *)0)) -#define MP_OBJ_STOP_ITERATION (MP_OBJ_FROM_PTR((void *)0)) -#define MP_OBJ_SENTINEL (MP_OBJ_FROM_PTR((void *)4)) -#else +#if MICROPY_DEBUG_MP_OBJ_SENTINELS #define MP_OBJ_NULL (MP_OBJ_FROM_PTR((void *)0)) #define MP_OBJ_STOP_ITERATION (MP_OBJ_FROM_PTR((void *)4)) #define MP_OBJ_SENTINEL (MP_OBJ_FROM_PTR((void *)8)) +#else +#define MP_OBJ_NULL (MP_OBJ_FROM_PTR((void *)0)) +#define MP_OBJ_STOP_ITERATION (MP_OBJ_FROM_PTR((void *)0)) +#define MP_OBJ_SENTINEL (MP_OBJ_FROM_PTR((void *)4)) #endif // These macros/inline functions operate on objects and depend on the @@ -85,13 +85,13 @@ typedef struct _mp_obj_base_t mp_obj_base_t; #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A -static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { +static inline bool mp_obj_is_small_int(mp_const_obj_t o) { return (((mp_int_t)(o)) & 1) != 0; } #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1) #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1)) -static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { +static inline bool mp_obj_is_qstr(mp_const_obj_t o) { return (((mp_int_t)(o)) & 3) == 2; } #define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2) @@ -103,24 +103,24 @@ static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { extern const struct _mp_obj_float_t mp_const_float_e_obj; extern const struct _mp_obj_float_t mp_const_float_pi_obj; -#define mp_obj_is_float(o) MP_OBJ_IS_TYPE((o), &mp_type_float) +#define mp_obj_is_float(o) mp_obj_is_type((o), &mp_type_float) mp_float_t mp_obj_float_get(mp_obj_t self_in); mp_obj_t mp_obj_new_float(mp_float_t value); #endif -static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { +static inline bool mp_obj_is_obj(mp_const_obj_t o) { return (((mp_int_t)(o)) & 3) == 0; } #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B -static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { +static inline bool mp_obj_is_small_int(mp_const_obj_t o) { return (((mp_int_t)(o)) & 3) == 1; } #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 2) #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 2) | 1)) -static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { +static inline bool mp_obj_is_qstr(mp_const_obj_t o) { return (((mp_int_t)(o)) & 3) == 3; } #define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2) @@ -132,18 +132,18 @@ static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { extern const struct _mp_obj_float_t mp_const_float_e_obj; extern const struct _mp_obj_float_t mp_const_float_pi_obj; -#define mp_obj_is_float(o) MP_OBJ_IS_TYPE((o), &mp_type_float) +#define mp_obj_is_float(o) mp_obj_is_type((o), &mp_type_float) mp_float_t mp_obj_float_get(mp_obj_t self_in); mp_obj_t mp_obj_new_float(mp_float_t value); #endif -static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { +static inline bool mp_obj_is_obj(mp_const_obj_t o) { return (((mp_int_t)(o)) & 1) == 0; } #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C -static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { +static inline bool mp_obj_is_small_int(mp_const_obj_t o) { return (((mp_int_t)(o)) & 1) != 0; } #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1) @@ -172,25 +172,25 @@ static inline mp_obj_t mp_obj_new_float(mp_float_t f) { } #endif -static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { +static inline bool mp_obj_is_qstr(mp_const_obj_t o) { return (((mp_uint_t)(o)) & 0xff800007) == 0x00000006; } #define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 0x00000006)) -static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { +static inline bool mp_obj_is_obj(mp_const_obj_t o) { return (((mp_int_t)(o)) & 3) == 0; } #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D -static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { +static inline bool mp_obj_is_small_int(mp_const_obj_t o) { return (((uint64_t)(o)) & 0xffff000000000000) == 0x0001000000000000; } #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)((o) << 16)) >> 17) #define MP_OBJ_NEW_SMALL_INT(small_int) (((((uint64_t)(small_int)) & 0x7fffffffffff) << 1) | 0x0001000000000001) -static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { +static inline bool mp_obj_is_qstr(mp_const_obj_t o) { return (((uint64_t)(o)) & 0xffff000000000000) == 0x0002000000000000; } #define MP_OBJ_QSTR_VALUE(o) ((((uint32_t)(o)) >> 1) & 0xffffffff) @@ -224,7 +224,7 @@ static inline mp_obj_t mp_obj_new_float(mp_float_t f) { } #endif -static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { +static inline bool mp_obj_is_obj(mp_const_obj_t o) { return (((uint64_t)(o)) & 0xffff000000000000) == 0x0000000000000000; } #define MP_OBJ_TO_PTR(o) ((void *)(uintptr_t)(o)) @@ -275,17 +275,6 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; */ #endif -// The macros below are derived from the ones above and are used to -// check for more specific object types. -// Note: these are kept as macros because inline functions sometimes use much -// more code space than the equivalent macros, depending on the compiler. - -#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that -#define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)) -#define MP_OBJ_IS_STR(o) (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)) -#define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op)) -#define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function)) - // These macros are used to declare and define constant function objects // You can put "static" in front of the definitions to make them local @@ -433,7 +422,7 @@ typedef enum _mp_map_lookup_kind_t { extern const mp_map_t mp_const_empty_map; -static inline bool MP_MAP_SLOT_IS_FILLED(const mp_map_t *map, size_t pos) { +static inline bool mp_map_slot_is_filled(const mp_map_t *map, size_t pos) { return (map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL; } @@ -454,7 +443,7 @@ typedef struct _mp_set_t { mp_obj_t *table; } mp_set_t; -static inline bool MP_SET_SLOT_IS_FILLED(const mp_set_t *set, size_t pos) { +static inline bool mp_set_slot_is_filled(const mp_set_t *set, size_t pos) { return (set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL; } @@ -700,6 +689,16 @@ extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj; // General API for objects +// These macros are derived from more primitive ones and are used to +// check for more specific object types. +// Note: these are kept as macros because inline functions sometimes use much +// more code space than the equivalent macros, depending on the compiler. +#define mp_obj_is_type(o, t) (mp_obj_is_obj(o) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that +#define mp_obj_is_int(o) (mp_obj_is_small_int(o) || mp_obj_is_type(o, &mp_type_int)) +#define mp_obj_is_str(o) (mp_obj_is_qstr(o) || mp_obj_is_type(o, &mp_type_str)) +#define mp_obj_is_str_or_bytes(o) (mp_obj_is_qstr(o) || (mp_obj_is_obj(o) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op)) +#define mp_obj_is_fun(o) (mp_obj_is_obj(o) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function)) + mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict); static inline mp_obj_t mp_obj_new_bool(mp_int_t x) { return x ? mp_const_true : mp_const_false; @@ -732,8 +731,8 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const comp mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, va_list ap); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!) mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table); mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table); -mp_obj_t mp_obj_new_fun_viper(size_t n_args, void *fun_data, mp_uint_t type_sig); -mp_obj_t mp_obj_new_fun_asm(size_t n_args, void *fun_data, mp_uint_t type_sig); +mp_obj_t mp_obj_new_fun_viper(size_t n_args, const void *fun_data, mp_uint_t type_sig); +mp_obj_t mp_obj_new_fun_asm(size_t n_args, const void *fun_data, mp_uint_t type_sig); mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun, bool is_coroutine); mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed); mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); @@ -762,7 +761,7 @@ bool mp_obj_is_callable(mp_obj_t o_in); bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2); static inline bool mp_obj_is_integer(mp_const_obj_t o) { - return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); + return mp_obj_is_int(o) || mp_obj_is_type(o, &mp_type_bool); } // returns true if o is bool, small int or long int mp_int_t mp_obj_get_int(mp_const_obj_t arg); mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg); diff --git a/py/objarray.c b/py/objarray.c index 7864d79867..216b94b298 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -128,8 +128,8 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) { if (((MICROPY_PY_BUILTINS_BYTEARRAY && typecode == BYTEARRAY_TYPECODE) || (MICROPY_PY_ARRAY - && (MP_OBJ_IS_TYPE(initializer, &mp_type_bytes) - || (MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(initializer, &mp_type_bytearray))))) + && (mp_obj_is_type(initializer, &mp_type_bytes) + || (MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(initializer, &mp_type_bytearray))))) && mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) { // construct array from raw bytes size_t sz = mp_binary_get_size('@', typecode, NULL); @@ -194,7 +194,7 @@ STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args, if (n_args == 0) { // no args: construct an empty bytearray return MP_OBJ_FROM_PTR(array_new(BYTEARRAY_TYPECODE, 0)); - } else if (MP_OBJ_IS_INT(args[0])) { + } else if (mp_obj_is_int(args[0])) { // 1 arg, an integer: construct a blank bytearray of that length mp_uint_t len = mp_obj_get_int(args[0]); mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len); @@ -261,6 +261,19 @@ STATIC mp_obj_t memoryview_cast(const mp_obj_t self_in, const mp_obj_t typecode_ } STATIC MP_DEFINE_CONST_FUN_OBJ_2(memoryview_cast_obj, memoryview_cast); #endif + +#if MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE +STATIC void memoryview_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + return; + } + if (attr == MP_QSTR_itemsize) { + mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); + dest[0] = MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->typecode & TYPECODE_MASK, NULL)); + } +} +#endif + #endif STATIC mp_obj_t array_unary_op(mp_unary_op_t op, mp_obj_t o_in) { @@ -280,7 +293,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs switch (op) { case MP_BINARY_OP_MULTIPLY: case MP_BINARY_OP_INPLACE_MULTIPLY: { - if (!MP_OBJ_IS_INT(rhs_in)) { + if (!mp_obj_is_int(rhs_in)) { return MP_OBJ_NULL; // op not supported } mp_uint_t repeat = mp_obj_get_int(rhs_in); @@ -346,7 +359,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs mp_buffer_info_t lhs_bufinfo; mp_buffer_info_t rhs_bufinfo; if (mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) { - if (!MP_OBJ_IS_TYPE(lhs_in, &mp_type_bytearray)) { + if (!mp_obj_is_type(lhs_in, &mp_type_bytearray)) { return mp_const_false; } array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ); @@ -356,7 +369,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs #endif // Otherwise, can only look for a scalar numeric value in an array - if (MP_OBJ_IS_INT(rhs_in) || mp_obj_is_float(rhs_in)) { + if (mp_obj_is_int(rhs_in) || mp_obj_is_float(rhs_in)) { mp_raise_NotImplementedError(NULL); } @@ -381,8 +394,8 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) { // self is not a memoryview, so we don't need to use (& TYPECODE_MASK) - assert((MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray)) - || (MICROPY_PY_ARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_array))); + assert((MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(self_in, &mp_type_bytearray)) + || (MICROPY_PY_ARRAY && mp_obj_is_type(self_in, &mp_type_array))); mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); if (self->free == 0) { @@ -402,8 +415,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_append_obj, array_append); STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) { // self is not a memoryview, so we don't need to use (& TYPECODE_MASK) - assert((MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray)) - || (MICROPY_PY_ARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_array))); + assert((MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(self_in, &mp_type_bytearray)) + || (MICROPY_PY_ARRAY && mp_obj_is_type(self_in, &mp_type_array))); mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); // allow to extend by anything that has the buffer protocol (extension to CPython) @@ -435,7 +448,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_extend_obj, array_extend); #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_CPYTHON_COMPAT STATIC mp_obj_t buffer_finder(size_t n_args, const mp_obj_t *args, int direction, bool is_index) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_bytearray)); + mp_check_self(mp_obj_is_type(args[0], &mp_type_bytearray)); const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); mp_buffer_info_t haystack_bufinfo; @@ -502,9 +515,8 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value return MP_OBJ_NULL; // op not supported } else { mp_obj_array_t *o = MP_OBJ_TO_PTR(self_in); - if (0) { #if MICROPY_PY_BUILTINS_SLICE - } else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { + if (mp_obj_is_type(index_in, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) { mp_raise_NotImplementedError(translate("only slices with step=1 (aka None) are supported")); @@ -515,7 +527,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value size_t src_len; void *src_items; size_t item_sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL); - if (MP_OBJ_IS_OBJ(value) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) { + if (mp_obj_is_obj(value) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) { // value is array, bytearray or memoryview mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value); if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) { @@ -525,11 +537,11 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value src_len = src_slice->len; src_items = src_slice->items; #if MICROPY_PY_BUILTINS_MEMORYVIEW - if (MP_OBJ_IS_TYPE(value, &mp_type_memoryview)) { + if (mp_obj_is_type(value, &mp_type_memoryview)) { src_items = (uint8_t *)src_items + (src_slice->memview_offset * item_sz); } #endif - } else if (MP_OBJ_IS_TYPE(value, &mp_type_bytes)) { + } else if (mp_obj_is_type(value, &mp_type_bytes)) { if (item_sz != 1) { goto compat_error; } @@ -585,22 +597,22 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_obj_array_t *res; size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL); assert(sz > 0); - if (0) { - // dummy #if MICROPY_PY_BUILTINS_MEMORYVIEW - } else if (o->base.type == &mp_type_memoryview) { + if (o->base.type == &mp_type_memoryview) { res = m_new_obj(mp_obj_array_t); *res = *o; res->memview_offset += slice.start; res->len = slice.stop - slice.start; + } else #endif - } else { + { res = array_new(o->typecode, slice.stop - slice.start); memcpy(res->items, (uint8_t *)o->items + slice.start * sz, (slice.stop - slice.start) * sz); } return MP_OBJ_FROM_PTR(res); + } else #endif - } else { + { size_t index = mp_get_index(o->base.type, o->len, index_in, false); #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { @@ -664,6 +676,9 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(array_decode_obj, 1, 3, array_decode); STATIC const mp_rom_map_elem_t array_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&array_append_obj) }, { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&array_extend_obj) }, + #if MICROPY_CPYTHON_COMPAT + { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&bytes_decode_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table); @@ -735,6 +750,9 @@ const mp_obj_type_t mp_type_memoryview = { .getiter = array_iterator_new, .unary_op = array_unary_op, .binary_op = array_binary_op, + #if MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE + .attr = memoryview_attr, + #endif .subscr = array_subscr, .buffer_p = { .get_buffer = array_get_buffer }, #if MICROPY_CPYTHON_COMPAT diff --git a/py/objcomplex.c b/py/objcomplex.c index 5e80826c69..5f2c4105a9 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -84,12 +84,12 @@ STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, co return mp_obj_new_complex(0, 0); case 1: - if (MP_OBJ_IS_STR(args[0])) { + if (mp_obj_is_str(args[0])) { // a string, parse it size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_decimal(s, l, true, true, NULL); - } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) { + } else if (mp_obj_is_type(args[0], &mp_type_complex)) { // a complex, just return it return args[0]; } else { @@ -100,13 +100,13 @@ STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, co case 2: default: { mp_float_t real, imag; - if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) { + if (mp_obj_is_type(args[0], &mp_type_complex)) { mp_obj_complex_get(args[0], &real, &imag); } else { real = mp_obj_get_float(args[0]); imag = 0; } - if (MP_OBJ_IS_TYPE(args[1], &mp_type_complex)) { + if (mp_obj_is_type(args[1], &mp_type_complex)) { mp_float_t real2, imag2; mp_obj_complex_get(args[1], &real2, &imag2); real -= imag2; @@ -174,7 +174,7 @@ mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) { } void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_complex)); + assert(mp_obj_is_type(self_in, &mp_type_complex)); mp_obj_complex_t *self = MP_OBJ_TO_PTR(self_in); *real = self->real; *imag = self->imag; diff --git a/py/objdict.c b/py/objdict.c index 4394af9edb..6f494f54f3 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,7 +35,7 @@ #include "supervisor/linker.h" #include "supervisor/shared/translate.h" -#define MP_OBJ_IS_DICT_TYPE(o) (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->make_new == dict_make_new) +#define mp_obj_is_dict_type(o) (mp_obj_is_obj(o) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->make_new == dict_make_new) STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); @@ -46,7 +47,7 @@ STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur) { mp_map_t *map = &dict->map; for (size_t i = *cur; i < max; i++) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { *cur = i + 1; return &(map->table[i]); } @@ -128,7 +129,7 @@ STATIC mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_ } case MP_BINARY_OP_EQUAL: { #if MICROPY_PY_COLLECTIONS_ORDEREDDICT - if (MP_UNLIKELY(MP_OBJ_IS_TYPE(lhs_in, &mp_type_ordereddict) && MP_OBJ_IS_TYPE(rhs_in, &mp_type_ordereddict))) { + if (MP_UNLIKELY(mp_obj_is_type(lhs_in, &mp_type_ordereddict) && mp_obj_is_type(rhs_in, &mp_type_ordereddict))) { // Iterate through both dictionaries simultaneously and compare keys and values. mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in); size_t c1 = 0, c2 = 0; @@ -141,7 +142,7 @@ STATIC mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_ return e1 == NULL && e2 == NULL ? mp_const_true : mp_const_false; } else #endif - if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) { + if (mp_obj_is_type(rhs_in, &mp_type_dict)) { mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in); if (o->map.used != rhs->map.used) { return mp_const_false; @@ -209,7 +210,7 @@ STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) { } STATIC mp_obj_t dict_clear(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(mp_obj_is_dict_type(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_ensure_not_fixed(self); @@ -220,7 +221,7 @@ STATIC mp_obj_t dict_clear(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_clear_obj, dict_clear); STATIC mp_obj_t dict_copy(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(mp_obj_is_dict_type(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t other_out = mp_obj_new_dict(self->map.alloc); mp_obj_dict_t *other = MP_OBJ_TO_PTR(other_out); @@ -267,7 +268,7 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromk #endif STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) { - mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); + mp_check_self(mp_obj_is_dict_type(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); if (lookup_kind != MP_MAP_LOOKUP) { mp_ensure_not_fixed(self); @@ -312,7 +313,7 @@ STATIC mp_obj_t dict_setdefault(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setdefault); STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(mp_obj_is_dict_type(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_ensure_not_fixed(self); size_t cur = 0; @@ -331,7 +332,7 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem); STATIC mp_obj_t PLACE_IN_ITCM(dict_update)(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); + mp_check_self(mp_obj_is_dict_type(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); mp_ensure_not_fixed(self); @@ -340,7 +341,7 @@ STATIC mp_obj_t PLACE_IN_ITCM(dict_update)(size_t n_args, const mp_obj_t *args, if (n_args == 2) { // given a positional argument - if (MP_OBJ_IS_DICT_TYPE(args[1])) { + if (mp_obj_is_dict_type(args[1])) { // update from other dictionary (make sure other is not self) if (args[1] != args[0]) { size_t cur = 0; @@ -371,7 +372,7 @@ STATIC mp_obj_t PLACE_IN_ITCM(dict_update)(size_t n_args, const mp_obj_t *args, // update the dict with any keyword args for (size_t i = 0; i < kwargs->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + if (mp_map_slot_is_filled(kwargs, i)) { mp_map_lookup(&self->map, kwargs->table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = kwargs->table[i].value; } } @@ -409,7 +410,7 @@ typedef struct _mp_obj_dict_view_t { } mp_obj_dict_view_t; STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &dict_view_it_type)); + mp_check_self(mp_obj_is_type(self_in, &dict_view_it_type)); mp_obj_dict_view_it_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur); @@ -439,7 +440,7 @@ STATIC const mp_obj_type_t dict_view_it_type = { STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t)); - mp_check_self(MP_OBJ_IS_TYPE(view_in, &dict_view_type)); + mp_check_self(mp_obj_is_type(view_in, &dict_view_type)); mp_obj_dict_view_t *view = MP_OBJ_TO_PTR(view_in); mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t *)iter_buf; o->base.type = &dict_view_it_type; @@ -451,7 +452,7 @@ STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in, mp_obj_iter_buf_t *iter_buf) STATIC void dict_view_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; - mp_check_self(MP_OBJ_IS_TYPE(self_in, &dict_view_type)); + mp_check_self(mp_obj_is_type(self_in, &dict_view_type)); mp_obj_dict_view_t *self = MP_OBJ_TO_PTR(self_in); bool first = true; mp_print_str(print, mp_dict_view_names[self->kind]); @@ -498,7 +499,7 @@ STATIC mp_obj_t mp_obj_new_dict_view(mp_obj_t dict, mp_dict_view_kind_t kind) { } STATIC mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) { - mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(mp_obj_is_dict_type(self_in)); return mp_obj_new_dict_view(self_in, kind); } @@ -522,7 +523,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values); STATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t)); - mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(mp_obj_is_dict_type(self_in)); mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t *)iter_buf; o->base.type = &dict_view_it_type; o->kind = MP_DICT_VIEW_KEYS; @@ -599,7 +600,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in) { } mp_obj_t PLACE_IN_ITCM(mp_obj_dict_store)(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) { - mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(mp_obj_is_dict_type(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_ensure_not_fixed(self); mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; diff --git a/py/objenumerate.c b/py/objenumerate.c index 2c2131ad4f..e052ebfe3e 100644 --- a/py/objenumerate.c +++ b/py/objenumerate.c @@ -78,7 +78,7 @@ const mp_obj_type_t mp_type_enumerate = { }; STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_enumerate)); + assert(mp_obj_is_type(self_in, &mp_type_enumerate)); mp_obj_enumerate_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t next = mp_iternext(self->iter); if (next == MP_OBJ_STOP_ITERATION) { diff --git a/py/objexcept.c b/py/objexcept.c index 2ea1dc7c79..9aa2dde7ff 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2016 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -124,7 +125,7 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin mp_print_str(print, ""); return; } - if (MP_OBJ_IS_SMALL_INT(o->args->items[0]) && + if (mp_obj_is_small_int(o->args->items[0]) && mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(o->base.type), MP_OBJ_FROM_PTR(&mp_type_OSError)) && o->args->len <= 2) { // try to provide a nice OSError error message @@ -465,7 +466,7 @@ mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const com // return true if the given object is an exception type bool mp_obj_is_exception_type(mp_obj_t self_in) { - if (MP_OBJ_IS_TYPE(self_in, &mp_type_type)) { + if (mp_obj_is_type(self_in, &mp_type_type)) { // optimisation when self_in is a builtin exception mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); if (self->make_new == mp_obj_exception_make_new) { diff --git a/py/objfilter.c b/py/objfilter.c index 0e02f4b5ef..7fd9d6124c 100644 --- a/py/objfilter.c +++ b/py/objfilter.c @@ -44,7 +44,7 @@ STATIC mp_obj_t filter_make_new(const mp_obj_type_t *type, size_t n_args, const } STATIC mp_obj_t filter_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_filter)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_filter)); mp_obj_filter_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t next; while ((next = mp_iternext(self->iter)) != MP_OBJ_STOP_ITERATION) { diff --git a/py/objfloat.c b/py/objfloat.c index 3bdfa0b757..67cb8514ee 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -186,7 +186,7 @@ STATIC mp_obj_t float_unary_op(mp_unary_op_t op, mp_obj_t o_in) { STATIC mp_obj_t float_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_float_t lhs_val = mp_obj_float_get(lhs_in); #if MICROPY_PY_BUILTINS_COMPLEX - if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) { + if (mp_obj_is_type(rhs_in, &mp_type_complex)) { return mp_obj_complex_binary_op(op, lhs_val, 0, rhs_in); } else #endif diff --git a/py/objfun.c b/py/objfun.c index 5e4792a7dd..c5fb267ad6 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -52,7 +52,7 @@ STATIC mp_obj_t fun_builtin_0_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)args; - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_0)); + assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_0)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num_kw_array(n_args, n_kw, 0, 0, false); return self->fun._0(); @@ -66,7 +66,7 @@ const mp_obj_type_t mp_type_fun_builtin_0 = { }; STATIC mp_obj_t fun_builtin_1_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_1)); + assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_1)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num_kw_array(n_args, n_kw, 1, 1, false); return self->fun._1(args[0]); @@ -80,7 +80,7 @@ const mp_obj_type_t mp_type_fun_builtin_1 = { }; STATIC mp_obj_t fun_builtin_2_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_2)); + assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_2)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num_kw_array(n_args, n_kw, 2, 2, false); return self->fun._2(args[0], args[1]); @@ -94,7 +94,7 @@ const mp_obj_type_t mp_type_fun_builtin_2 = { }; STATIC mp_obj_t fun_builtin_3_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_3)); + assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_3)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_check_num_kw_array(n_args, n_kw, 3, 3, false); return self->fun._3(args[0], args[1], args[2]); @@ -108,7 +108,7 @@ const mp_obj_type_t mp_type_fun_builtin_3 = { }; STATIC mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_var)); + assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_var)); mp_obj_fun_builtin_var_t *self = MP_OBJ_TO_PTR(self_in); // check number of arguments @@ -371,7 +371,7 @@ mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args_in, mp_obj_t def_kw_args, const byt size_t n_extra_args = 0; mp_obj_tuple_t *def_args = MP_OBJ_TO_PTR(def_args_in); if (def_args_in != MP_OBJ_NULL) { - assert(MP_OBJ_IS_TYPE(def_args_in, &mp_type_tuple)); + assert(mp_obj_is_type(def_args_in, &mp_type_tuple)); n_def_args = def_args->len; n_extra_args = def_args->len; } @@ -427,7 +427,7 @@ mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const typedef struct _mp_obj_fun_asm_t { mp_obj_base_t base; size_t n_args; - void *fun_data; // GC must be able to trace this pointer + const void *fun_data; // GC must be able to trace this pointer mp_uint_t type_sig; } mp_obj_fun_asm_t; @@ -440,7 +440,7 @@ typedef mp_uint_t (*inline_asm_fun_4_t)(mp_uint_t, mp_uint_t, mp_uint_t, mp_uint // convert a MicroPython object to a sensible value for inline asm STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { // TODO for byte_array, pass pointer to the array - if (MP_OBJ_IS_SMALL_INT(obj)) { + if (mp_obj_is_small_int(obj)) { return MP_OBJ_SMALL_INT_VALUE(obj); } else if (obj == mp_const_none) { return 0; @@ -448,21 +448,21 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { return 0; } else if (obj == mp_const_true) { return 1; - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) { + } else if (mp_obj_is_type(obj, &mp_type_int)) { return mp_obj_int_get_truncated(obj); - } else if (MP_OBJ_IS_STR(obj)) { + } else if (mp_obj_is_str(obj)) { // pointer to the string (it's probably constant though!) size_t l; return (mp_uint_t)mp_obj_str_get_data(obj, &l); } else { mp_obj_type_t *type = mp_obj_get_type(obj); - if (0) { #if MICROPY_PY_BUILTINS_FLOAT - } else if (type == &mp_type_float) { + if (type == &mp_type_float) { // convert float to int (could also pass in float registers) return (mp_int_t)mp_obj_float_get(obj); + } else #endif - } else if (type == &mp_type_tuple || type == &mp_type_list) { + if (type == &mp_type_tuple || type == &mp_type_list) { // pointer to start of tuple (could pass length, but then could use len(x) for that) size_t len; mp_obj_t *items; @@ -486,7 +486,7 @@ STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_arg_check_num_kw_array(n_args, n_kw, self->n_args, self->n_args, false); - void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data); + const void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data); mp_uint_t ret; if (n_args == 0) { @@ -508,7 +508,7 @@ STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const ); } - return mp_convert_native_to_obj(ret, self->type_sig); + return mp_native_to_obj(ret, self->type_sig); } STATIC const mp_obj_type_t mp_type_fun_asm = { @@ -518,7 +518,7 @@ STATIC const mp_obj_type_t mp_type_fun_asm = { .unary_op = mp_generic_unary_op, }; -mp_obj_t mp_obj_new_fun_asm(size_t n_args, void *fun_data, mp_uint_t type_sig) { +mp_obj_t mp_obj_new_fun_asm(size_t n_args, const void *fun_data, mp_uint_t type_sig) { mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t); o->base.type = &mp_type_fun_asm; o->n_args = n_args; diff --git a/py/objgenerator.c b/py/objgenerator.c index 5336f7f36a..518944e26b 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -3,8 +3,8 @@ * * The MIT License (MIT) * - * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014-2017 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2013-2019 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -174,7 +174,7 @@ STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_pri mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { MP_STACK_CHECK(); - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_gen_instance)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_gen_instance)); mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); if (self->code_state.ip == 0) { // Trying to resume already stopped generator @@ -297,7 +297,6 @@ STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) { return ret; } } - STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send); #if MICROPY_PY_ASYNC_AWAIT @@ -317,7 +316,22 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_await_obj, gen_instance_await); STATIC mp_obj_t gen_instance_close(mp_obj_t self_in); STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) { - mp_obj_t exc = (n_args == 2) ? args[1] : args[2]; + // The signature of this function is: throw(type[, value[, traceback]]) + // CPython will pass all given arguments through the call chain and process them + // at the point they are used (native generators will handle them differently to + // user-defined generators with a throw() method). To save passing multiple + // values, MicroPython instead does partial processing here to reduce it down to + // one argument and passes that through: + // - if only args[1] is given, or args[2] is given but is None, args[1] is + // passed through (in the standard case it is an exception class or instance) + // - if args[2] is given and not None it is passed through (in the standard + // case it would be an exception instance and args[1] its corresponding class) + // - args[3] is always ignored + + mp_obj_t exc = args[1]; + if (n_args > 2 && args[2] != mp_const_none) { + exc = args[2]; + } mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, exc); if (ret == MP_OBJ_STOP_ITERATION) { @@ -326,7 +340,6 @@ STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) { return ret; } } - STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_instance_throw); STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { @@ -348,7 +361,6 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { return mp_const_none; } } - STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close); STATIC mp_obj_t gen_instance_pend_throw(mp_obj_t self_in, mp_obj_t exc_in) { diff --git a/py/objint.c b/py/objint.c index ac9eb70591..5921db6b31 100644 --- a/py/objint.c +++ b/py/objint.c @@ -51,10 +51,10 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, return MP_OBJ_NEW_SMALL_INT(0); case 1: - if (MP_OBJ_IS_INT(args[0])) { + if (mp_obj_is_int(args[0])) { // already an int (small or long), just return it return args[0]; - } else if (MP_OBJ_IS_STR_OR_BYTES(args[0])) { + } else if (mp_obj_is_str_or_bytes(args[0])) { // a string, parse it size_t l; const char *s = mp_obj_str_get_data(args[0], &l); @@ -226,11 +226,11 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co // Only have small ints; get the integer value to format. num = MP_OBJ_SMALL_INT_VALUE(self_in); #else - if (MP_OBJ_IS_SMALL_INT(self_in)) { + if (mp_obj_is_small_int(self_in)) { // A small int; get the integer value to format. num = MP_OBJ_SMALL_INT_VALUE(self_in); } else { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); // Not a small int. #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG const mp_obj_int_t *self = self_in; @@ -446,7 +446,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp // true acts as 0 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1)); } else if (op == MP_BINARY_OP_MULTIPLY) { - if (MP_OBJ_IS_STR_OR_BYTES(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) { + if (mp_obj_is_str_or_bytes(rhs_in) || mp_obj_is_type(rhs_in, &mp_type_tuple) || mp_obj_is_type(rhs_in, &mp_type_list)) { // multiply is commutative for these types, so delegate to them return mp_binary_op(op, rhs_in, lhs_in); } @@ -457,7 +457,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp #if MICROPY_CPYTHON_COMPAT STATIC mp_obj_t int_bit_length(mp_obj_t self_in) { #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - if (!MP_OBJ_IS_SMALL_INT(self_in)) { + if (!mp_obj_is_small_int(self_in)) { return mp_obj_int_bit_length_impl(self_in); } else #endif @@ -533,7 +533,7 @@ STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t * memset(data, 0, len); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - if (!MP_OBJ_IS_SMALL_INT(self)) { + if (!mp_obj_is_small_int(self)) { mp_obj_int_buffer_overflow_check(self, len, signed_); mp_obj_int_to_bytes_impl(self, big_endian, len, data); } else diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 63e3464a1a..aa452a4bcf 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -46,7 +46,7 @@ const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; #endif mp_obj_t mp_obj_int_bit_length_impl(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); mp_obj_int_t *self = self_in; long long val = self->val; return MP_OBJ_NEW_SMALL_INT( @@ -71,7 +71,7 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf } void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); mp_obj_int_t *self = self_in; long long val = self->val; if (big_endian) { @@ -90,7 +90,7 @@ void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byt int mp_obj_int_sign(mp_obj_t self_in) { mp_longint_impl_t val; - if (MP_OBJ_IS_SMALL_INT(self_in)) { + if (mp_obj_is_small_int(self_in)) { val = MP_OBJ_SMALL_INT_VALUE(self_in); } else { mp_obj_int_t *self = self_in; @@ -141,16 +141,16 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i long long lhs_val; long long rhs_val; - if (MP_OBJ_IS_SMALL_INT(lhs_in)) { + if (mp_obj_is_small_int(lhs_in)) { lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in); } else { - assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)); + assert(mp_obj_is_type(lhs_in, &mp_type_int)); lhs_val = ((mp_obj_int_t *)lhs_in)->val; } - if (MP_OBJ_IS_SMALL_INT(rhs_in)) { + if (mp_obj_is_small_int(rhs_in)) { rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs_in); - } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) { + } else if (mp_obj_is_type(rhs_in, &mp_type_int)) { rhs_val = ((mp_obj_int_t *)rhs_in)->val; } else { // delegate to generic function to check for extra cases @@ -285,7 +285,7 @@ mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, uns } mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { - if (MP_OBJ_IS_SMALL_INT(self_in)) { + if (mp_obj_is_small_int(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); } else { const mp_obj_int_t *self = self_in; @@ -300,7 +300,7 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); mp_obj_int_t *self = self_in; return self->val; } diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 3d8de47985..80564cf095 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -92,7 +92,7 @@ mp_obj_int_t *mp_obj_int_new_mpz(void) { // This particular routine should only be called for the mpz representation of the int. char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); size_t needed_size = mp_int_format_size(mpz_max_num_bits(&self->mpz), base, prefix, comma); @@ -108,7 +108,7 @@ char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, } mp_obj_t mp_obj_int_bit_length_impl(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); return MP_OBJ_NEW_SMALL_INT(mpz_num_bits(&self->mpz)); } @@ -120,14 +120,14 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf } void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); memset(buf, 0, len); mpz_as_bytes(&self->mpz, big_endian, len, buf); } int mp_obj_int_sign(mp_obj_t self_in) { - if (MP_OBJ_IS_SMALL_INT(self_in)) { + if (mp_obj_is_small_int(self_in)) { mp_int_t val = MP_OBJ_SMALL_INT_VALUE(self_in); if (val < 0) { return -1; @@ -185,25 +185,25 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i mpz_dig_t z_int_dig[MPZ_NUM_DIG_FOR_INT]; // lhs could be a small int (eg small-int + mpz) - if (MP_OBJ_IS_SMALL_INT(lhs_in)) { + if (mp_obj_is_small_int(lhs_in)) { mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(lhs_in)); zlhs = &z_int; } else { - assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)); + assert(mp_obj_is_type(lhs_in, &mp_type_int)); zlhs = &((mp_obj_int_t *)MP_OBJ_TO_PTR(lhs_in))->mpz; } // if rhs is small int, then lhs was not (otherwise mp_binary_op handles it) - if (MP_OBJ_IS_SMALL_INT(rhs_in)) { + if (mp_obj_is_small_int(rhs_in)) { mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(rhs_in)); zrhs = &z_int; - } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) { + } else if (mp_obj_is_type(rhs_in, &mp_type_int)) { zrhs = &((mp_obj_int_t *)MP_OBJ_TO_PTR(rhs_in))->mpz; #if MICROPY_PY_BUILTINS_FLOAT } else if (mp_obj_is_float(rhs_in)) { return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in); #if MICROPY_PY_BUILTINS_COMPLEX - } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) { + } else if (mp_obj_is_type(rhs_in, &mp_type_complex)) { return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in); #endif #endif @@ -212,18 +212,18 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); } - if (0) { #if MICROPY_PY_BUILTINS_FLOAT - } else if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) { + if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) { if (mpz_is_zero(zrhs)) { goto zero_division_error; } mp_float_t flhs = mpz_as_float(zlhs); mp_float_t frhs = mpz_as_float(zrhs); return mp_obj_new_float(flhs / frhs); + } else #endif - } else if (op >= MP_BINARY_OP_INPLACE_OR && op < MP_BINARY_OP_CONTAINS) { + if (op >= MP_BINARY_OP_INPLACE_OR && op < MP_BINARY_OP_CONTAINS) { mp_obj_int_t *res = mp_obj_int_new_mpz(); switch (op) { @@ -340,7 +340,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i #if MICROPY_PY_BUILTINS_POW3 STATIC mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) { - if (MP_OBJ_IS_SMALL_INT(arg)) { + if (mp_obj_is_small_int(arg)) { mpz_init_from_int(temp, MP_OBJ_SMALL_INT_VALUE(arg)); return temp; } else { @@ -350,7 +350,7 @@ STATIC mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) { } mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus) { - if (!MP_OBJ_IS_INT(base) || !MP_OBJ_IS_INT(exponent) || !MP_OBJ_IS_INT(modulus)) { + if (!mp_obj_is_int(base) || !mp_obj_is_int(exponent) || !mp_obj_is_int(modulus)) { mp_raise_TypeError(translate("pow() with 3 arguments requires integers")); } else { mp_obj_t result = mp_obj_new_int_from_ull(0); // Use the _from_ull version as this forces an mpz int @@ -417,7 +417,7 @@ mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, uns } mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { - if (MP_OBJ_IS_SMALL_INT(self_in)) { + if (mp_obj_is_small_int(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); } else { const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); @@ -427,7 +427,7 @@ mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { } mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { - if (MP_OBJ_IS_SMALL_INT(self_in)) { + if (mp_obj_is_small_int(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); } else { const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); @@ -443,7 +443,7 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + assert(mp_obj_is_type(self_in, &mp_type_int)); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); return mpz_as_float(&self->mpz); } diff --git a/py/objlist.c b/py/objlist.c index d8b0870e57..8a7a6509b4 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -114,7 +114,7 @@ STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_list_t *o = mp_instance_cast_to_native_base(lhs, &mp_type_list); switch (op) { case MP_BINARY_OP_ADD: { - if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { + if (!mp_obj_is_type(rhs, &mp_type_list)) { return MP_OBJ_NULL; // op not supported } mp_obj_list_t *p = MP_OBJ_TO_PTR(rhs); @@ -144,7 +144,7 @@ STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_LESS_EQUAL: case MP_BINARY_OP_MORE: case MP_BINARY_OP_MORE_EQUAL: { - if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { + if (!mp_obj_is_type(rhs, &mp_type_list)) { if (op == MP_BINARY_OP_EQUAL) { return mp_const_false; } @@ -166,7 +166,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_NULL) { // delete #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { mp_raise_NotImplementedError(NULL); @@ -188,7 +188,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } else if (value == MP_OBJ_SENTINEL) { // load #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { return mp_seq_extract_slice(self->len, self->items, &slice); @@ -202,7 +202,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { return self->items[index_val]; } else { #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { size_t value_len; mp_obj_t *value_items; mp_obj_get_array(value, &value_len, &value_items); @@ -242,7 +242,7 @@ STATIC mp_obj_t list_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { } mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list); if (self->len >= self->alloc) { self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2); @@ -254,8 +254,8 @@ mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { } STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); - if (MP_OBJ_IS_TYPE(arg_in, &mp_type_list)) { + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); + if (mp_obj_is_type(arg_in, &mp_type_list)) { mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list); mp_obj_list_t *arg = mp_instance_cast_to_native_base(arg_in, &mp_type_list); @@ -291,7 +291,7 @@ inline mp_obj_t mp_obj_list_pop(mp_obj_list_t *self, size_t index) { } STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); + mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); mp_obj_list_t *self = mp_instance_cast_to_native_base(args[0], &mp_type_list); size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); return mp_obj_list_pop(self, index); @@ -343,7 +343,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args); - mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &mp_type_list)); + mp_check_self(mp_obj_is_type(pos_args[0], &mp_type_list)); mp_obj_list_t *self = mp_instance_cast_to_native_base(pos_args[0], &mp_type_list); if (self->len > 1) { @@ -356,7 +356,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ } mp_obj_t mp_obj_list_clear(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list); self->len = 0; self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC); @@ -366,19 +366,19 @@ mp_obj_t mp_obj_list_clear(mp_obj_t self_in) { } STATIC mp_obj_t list_copy(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list); return mp_obj_new_list(self->len, self->items); } STATIC mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list); return mp_seq_count_obj(self->items, self->len, value); } STATIC mp_obj_t list_index(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); + mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); mp_obj_list_t *self = mp_instance_cast_to_native_base(args[0], &mp_type_list); return mp_seq_index_obj(self->items, self->len, n_args, args); } @@ -393,7 +393,7 @@ inline void mp_obj_list_insert(mp_obj_list_t *self, size_t index, mp_obj_t obj) } STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list); // insert has its own strange index logic mp_int_t index = MP_OBJ_SMALL_INT_VALUE(idx); @@ -411,7 +411,7 @@ STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { } mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_t args[] = {self_in, value}; args[1] = list_index(2, args); list_pop(2, args); @@ -420,7 +420,7 @@ mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) { } STATIC mp_obj_t list_reverse(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list); mp_int_t len = self->len; diff --git a/py/objmap.c b/py/objmap.c index 5cf975f492..d1844b8ac7 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -49,7 +49,7 @@ STATIC mp_obj_t map_make_new(const mp_obj_type_t *type, size_t n_args, const mp_ } STATIC mp_obj_t map_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_map)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_map)); mp_obj_map_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t *nextses = m_new(mp_obj_t, self->n_iters); diff --git a/py/objmodule.c b/py/objmodule.c index efe4650157..ae53faf58e 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2015 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -141,13 +142,13 @@ mp_obj_t mp_obj_new_module(qstr module_name) { } mp_obj_dict_t *mp_obj_module_get_globals(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_module)); + assert(mp_obj_is_type(self_in, &mp_type_module)); mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); return self->globals; } void mp_obj_module_set_globals(mp_obj_t self_in, mp_obj_dict_t *globals) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_module)); + assert(mp_obj_is_type(self_in, &mp_type_module)); mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); self->globals = globals; } @@ -259,18 +260,6 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { #if MICROPY_PY_USELECT { MP_ROM_QSTR(MP_QSTR_uselect), MP_ROM_PTR(&mp_module_uselect) }, #endif - #if MICROPY_PY_USSL - { MP_ROM_QSTR(MP_QSTR_ussl), MP_ROM_PTR(&mp_module_ussl) }, - #endif - #if MICROPY_PY_LWIP - { MP_ROM_QSTR(MP_QSTR_lwip), MP_ROM_PTR(&mp_module_lwip) }, - #endif - #if MICROPY_PY_WEBSOCKET - { MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&mp_module_websocket) }, - #endif - #if MICROPY_PY_WEBREPL - { MP_ROM_QSTR(MP_QSTR__webrepl), MP_ROM_PTR(&mp_module_webrepl) }, - #endif #if MICROPY_PY_FRAMEBUF { MP_ROM_QSTR(MP_QSTR_framebuf), MP_ROM_PTR(&mp_module_framebuf) }, #endif diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index d1ca17c502..3a94d58a32 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -185,7 +185,7 @@ STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) { size_t n_fields; mp_obj_t *fields; #if MICROPY_CPYTHON_COMPAT - if (MP_OBJ_IS_STR(fields_in)) { + if (mp_obj_is_str(fields_in)) { fields_in = mp_obj_str_split(1, &fields_in); } #endif diff --git a/py/objobject.c b/py/objobject.c index b3a6a171a0..8ad49d5188 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -51,7 +51,7 @@ STATIC mp_obj_t object___init__(mp_obj_t self) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__); STATIC mp_obj_t object___new__(mp_obj_t cls) { - if (!MP_OBJ_IS_TYPE(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t *)MP_OBJ_TO_PTR(cls))) { + if (!mp_obj_is_type(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t *)MP_OBJ_TO_PTR(cls))) { mp_raise_TypeError(translate("__new__ arg must be a user-type")); } // This executes only "__new__" part of instance creation. diff --git a/py/objproperty.c b/py/objproperty.c index f249d79a1d..06ecfc8837 100644 --- a/py/objproperty.c +++ b/py/objproperty.c @@ -96,7 +96,7 @@ const mp_obj_type_t mp_type_property = { }; const mp_obj_t *mp_obj_property_get(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_property)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_property)); mp_obj_property_t *self = MP_OBJ_TO_PTR(self_in); return self->proxy; } diff --git a/py/objrange.c b/py/objrange.c index fcc0ede98b..a3e05ce446 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -145,7 +145,7 @@ STATIC mp_obj_t range_unary_op(mp_unary_op_t op, mp_obj_t self_in) { #if MICROPY_PY_BUILTINS_RANGE_BINOP STATIC mp_obj_t range_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { - if (!MP_OBJ_IS_TYPE(rhs_in, &mp_type_range) || op != MP_BINARY_OP_EQUAL) { + if (!mp_obj_is_type(rhs_in, &mp_type_range) || op != MP_BINARY_OP_EQUAL) { return MP_OBJ_NULL; // op not supported } mp_obj_range_t *lhs = MP_OBJ_TO_PTR(lhs_in); @@ -167,7 +167,7 @@ STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t len = range_len(self); #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; mp_seq_get_fast_slice_indexes(len, index, &slice); mp_obj_range_t *o = m_new_obj(mp_obj_range_t); diff --git a/py/objreversed.c b/py/objreversed.c index 63d122b5db..31fea2ec64 100644 --- a/py/objreversed.c +++ b/py/objreversed.c @@ -56,7 +56,7 @@ STATIC mp_obj_t reversed_make_new(const mp_obj_type_t *type, size_t n_args, cons } STATIC mp_obj_t reversed_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_reversed)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_reversed)); mp_obj_reversed_t *self = MP_OBJ_TO_PTR(self_in); // "raise" stop iteration if we are at the end (the start) of the sequence diff --git a/py/objset.c b/py/objset.c index 6089f91814..f2ead23914 100644 --- a/py/objset.c +++ b/py/objset.c @@ -47,18 +47,16 @@ typedef struct _mp_obj_set_it_t { size_t cur; } mp_obj_set_it_t; -STATIC mp_obj_t set_it_iternext(mp_obj_t self_in); - STATIC bool is_set_or_frozenset(mp_obj_t o) { - return MP_OBJ_IS_TYPE(o, &mp_type_set) + return mp_obj_is_type(o, &mp_type_set) #if MICROPY_PY_BUILTINS_FROZENSET - || MP_OBJ_IS_TYPE(o, &mp_type_frozenset) + || mp_obj_is_type(o, &mp_type_frozenset) #endif ; } // This macro is shorthand for mp_check_self to verify the argument is a set. -#define check_set(o) mp_check_self(MP_OBJ_IS_TYPE(o, &mp_type_set)) +#define check_set(o) mp_check_self(mp_obj_is_type(o, &mp_type_set)) // This macro is shorthand for mp_check_self to verify the argument is a // set or frozenset for methods that operate on both of these types. @@ -68,7 +66,7 @@ STATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t (void)kind; mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); #if MICROPY_PY_BUILTINS_FROZENSET - bool is_frozen = MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset); + bool is_frozen = mp_obj_is_type(self_in, &mp_type_frozenset); #endif if (self->set.used == 0) { #if MICROPY_PY_BUILTINS_FROZENSET @@ -87,7 +85,7 @@ STATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t #endif mp_print_str(print, "{"); for (size_t i = 0; i < self->set.alloc; i++) { - if (MP_SET_SLOT_IS_FILLED(&self->set, i)) { + if (mp_set_slot_is_filled(&self->set, i)) { if (!first) { mp_print_str(print, ", "); } @@ -137,7 +135,7 @@ STATIC mp_obj_t set_it_iternext(mp_obj_t self_in) { mp_set_t *set = &self->set->set; for (size_t i = self->cur; i < max; i++) { - if (MP_SET_SLOT_IS_FILLED(set, i)) { + if (mp_set_slot_is_filled(set, i)) { self->cur = i + 1; return set->table[i]; } @@ -156,7 +154,6 @@ STATIC mp_obj_t set_getiter(mp_obj_t set_in, mp_obj_iter_buf_t *iter_buf) { return MP_OBJ_FROM_PTR(o); } - /******************************************************************************/ /* set methods */ @@ -171,9 +168,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_add_obj, set_add); STATIC mp_obj_t set_clear(mp_obj_t self_in) { check_set(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); - mp_set_clear(&self->set); - return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_clear_obj, set_clear); @@ -334,6 +329,7 @@ STATIC mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool } return out; } + STATIC mp_obj_t set_issubset(mp_obj_t self_in, mp_obj_t other_in) { return set_issubset_internal(self_in, other_in, false); } @@ -438,14 +434,14 @@ STATIC mp_obj_t set_unary_op(mp_unary_op_t op, mp_obj_t self_in) { return MP_OBJ_NEW_SMALL_INT(self->set.used); #if MICROPY_PY_BUILTINS_FROZENSET case MP_UNARY_OP_HASH: - if (MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset)) { + if (mp_obj_is_type(self_in, &mp_type_frozenset)) { // start hash with unique value mp_int_t hash = (mp_int_t)(uintptr_t)&mp_type_frozenset; size_t max = self->set.alloc; mp_set_t *set = &self->set; for (size_t i = 0; i < max; i++) { - if (MP_SET_SLOT_IS_FILLED(set, i)) { + if (mp_set_slot_is_filled(set, i)) { hash += MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, set->table[i])); } } @@ -461,7 +457,7 @@ STATIC mp_obj_t set_unary_op(mp_unary_op_t op, mp_obj_t self_in) { STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_t args[] = {lhs, rhs}; #if MICROPY_PY_BUILTINS_FROZENSET - bool update = MP_OBJ_IS_TYPE(lhs, &mp_type_set); + bool update = mp_obj_is_type(lhs, &mp_type_set); #else bool update = true; #endif @@ -524,7 +520,6 @@ STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { /******************************************************************************/ /* set constructors & public C API */ - STATIC const mp_rom_map_elem_t set_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&set_add_obj) }, { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&set_clear_obj) }, @@ -545,7 +540,6 @@ STATIC const mp_rom_map_elem_t set_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&set_update_obj) }, { MP_ROM_QSTR(MP_QSTR___contains__), MP_ROM_PTR(&mp_op_contains_obj) }, }; - STATIC MP_DEFINE_CONST_DICT(set_locals_dict, set_locals_dict_table); const mp_obj_type_t mp_type_set = { @@ -596,7 +590,7 @@ mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) { } void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_set)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_set)); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); } diff --git a/py/objslice.c b/py/objslice.c index 9bccde76db..a5d21578a1 100644 --- a/py/objslice.c +++ b/py/objslice.c @@ -60,7 +60,7 @@ STATIC void slice_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t #if MICROPY_PY_BUILTINS_SLICE_ATTRS STATIC mp_obj_t slice_indices(mp_obj_t self_in, mp_obj_t length_obj) { mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); - if (!MP_OBJ_IS_SMALL_INT(length_obj)) { + if (!mp_obj_is_small_int(length_obj)) { mp_raise_TypeError(translate("Length must be an int")); } @@ -243,7 +243,7 @@ STATIC mp_obj_t slice_make_new(const mp_obj_type_t *type, #endif void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_slice)); + assert(mp_obj_is_type(self_in, &mp_type_slice)); mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); *start = self->start; *stop = self->stop; diff --git a/py/objstr.c b/py/objstr.c index a1c611e381..ad1f2b5043 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2018 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -127,7 +127,7 @@ STATIC void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t } #endif #if !MICROPY_PY_BUILTINS_STR_UNICODE - bool is_bytes = MP_OBJ_IS_TYPE(self_in, &mp_type_bytes); + bool is_bytes = mp_obj_is_type(self_in, &mp_type_bytes); #else bool is_bytes = true; #endif @@ -164,7 +164,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, const mp_ default: // 2 or 3 args // TODO: validate 2nd/3rd args - if (MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) { + if (mp_obj_is_type(args[0], &mp_type_bytes)) { GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); if (str_hash == 0) { @@ -214,7 +214,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, cons return mp_const_empty_bytes; } - if (MP_OBJ_IS_STR(args[0])) { + if (mp_obj_is_str(args[0])) { if (n_args < 2 || n_args > 3) { goto wrong_args; } @@ -229,7 +229,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, cons return MP_OBJ_FROM_PTR(o); } - if (MP_OBJ_IS_SMALL_INT(args[0])) { + if (mp_obj_is_small_int(args[0])) { mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]); if (len < 0) { mp_raise_ValueError(NULL); @@ -315,7 +315,7 @@ const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, // Note: this function is used to check if an object is a str or bytes, which // works because both those types use it as their binary_op method. Revisit -// MP_OBJ_IS_STR_OR_BYTES if this fact changes. +// mp_obj_is_str_or_bytes if this fact changes. mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // check for modulo if (op == MP_BINARY_OP_MODULO) { @@ -323,10 +323,10 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i mp_obj_t *args = &rhs_in; size_t n_args = 1; mp_obj_t dict = MP_OBJ_NULL; - if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple)) { + if (mp_obj_is_type(rhs_in, &mp_type_tuple)) { // TODO: Support tuple subclasses? mp_obj_tuple_get(rhs_in, &n_args, &args); - } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) { + } else if (mp_obj_is_type(rhs_in, &mp_type_dict)) { dict = rhs_in; } return str_modulo_format(lhs_in, n_args, args, dict); @@ -451,7 +451,7 @@ STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_SENTINEL) { // load #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self_len, index, &slice)) { mp_raise_NotImplementedError(translate("only slices with step=1 (aka None) are supported")); @@ -472,7 +472,7 @@ STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(self_in)); + mp_check_self(mp_obj_is_str_or_bytes(self_in)); const mp_obj_type_t *self_type = mp_obj_get_type(self_in); // get separation string @@ -482,7 +482,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { size_t seq_len; mp_obj_t *seq_items; - if (!MP_OBJ_IS_TYPE(arg, &mp_type_list) && !MP_OBJ_IS_TYPE(arg, &mp_type_tuple)) { + if (!mp_obj_is_type(arg, &mp_type_list) && !mp_obj_is_type(arg, &mp_type_tuple)) { // arg is not a list nor a tuple, try to convert it to a list // TODO: Try to optimize? arg = mp_type_list.make_new(&mp_type_list, 1, &arg, NULL); @@ -718,7 +718,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit); STATIC mp_obj_t str_finder(size_t n_args, const mp_obj_t *args, int direction, bool is_index) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(mp_obj_is_str_or_bytes(args[0])); // check argument type if (mp_obj_get_type(args[1]) != self_type) { @@ -816,7 +816,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith); enum { LSTRIP, RSTRIP, STRIP }; STATIC mp_obj_t str_uni_strip(int type, size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(mp_obj_is_str_or_bytes(args[0])); const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); const byte *chars_to_del; @@ -942,7 +942,7 @@ STATIC bool istype(char ch) { } STATIC bool arg_looks_integer(mp_obj_t arg) { - return MP_OBJ_IS_TYPE(arg, &mp_type_bool) || MP_OBJ_IS_INT(arg); + return mp_obj_is_type(arg, &mp_type_bool) || mp_obj_is_int(arg); } STATIC bool arg_looks_numeric(mp_obj_t arg) { @@ -1419,7 +1419,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar } mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(mp_obj_is_str_or_bytes(args[0])); GET_STR_DATA_LEN(args[0], str, len); int arg_i = 0; @@ -1430,11 +1430,11 @@ MP_DEFINE_CONST_FUN_OBJ_KW(str_format_obj, 1, mp_obj_str_format); #if MICROPY_PY_BUILTINS_STR_OP_MODULO STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(pattern)); + mp_check_self(mp_obj_is_str_or_bytes(pattern)); GET_STR_DATA_LEN(pattern, str, len); const byte *start_str = str; - bool is_bytes = MP_OBJ_IS_TYPE(pattern, &mp_type_bytes); + bool is_bytes = mp_obj_is_type(pattern, &mp_type_bytes); size_t arg_i = 0; vstr_t vstr; mp_print_t print; @@ -1544,7 +1544,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ } switch (*str) { case 'c': - if (MP_OBJ_IS_STR(arg)) { + if (mp_obj_is_str(arg)) { size_t slen; const char *s = mp_obj_str_get_data(arg, &slen); if (slen != 1) { @@ -1589,7 +1589,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ mp_print_t arg_print; vstr_init_print(&arg_vstr, 16, &arg_print); mp_print_kind_t print_kind = (*str == 'r' ? PRINT_REPR : PRINT_STR); - if (print_kind == PRINT_STR && is_bytes && MP_OBJ_IS_TYPE(arg, &mp_type_bytes)) { + if (print_kind == PRINT_STR && is_bytes && mp_obj_is_type(arg, &mp_type_bytes)) { // If we have something like b"%s" % b"1", bytes arg should be // printed undecorated. print_kind = PRINT_RAW; @@ -1634,7 +1634,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ // The implementation is optimized, returning the original string if there's // nothing to replace. STATIC mp_obj_t str_replace(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(mp_obj_is_str_or_bytes(args[0])); mp_int_t max_rep = -1; if (n_args == 4) { @@ -1742,7 +1742,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace); #if MICROPY_PY_BUILTINS_STR_COUNT STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(mp_obj_is_str_or_bytes(args[0])); // check argument type if (mp_obj_get_type(args[1]) != self_type) { @@ -1784,7 +1784,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count); #if MICROPY_PY_BUILTINS_STR_PARTITION STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, int direction) { - mp_check_self(MP_OBJ_IS_STR_OR_BYTES(self_in)); + mp_check_self(mp_obj_is_str_or_bytes(self_in)); mp_obj_type_t *self_type = mp_obj_get_type(self_in); if (self_type != mp_obj_get_type(arg)) { bad_implicit_conversion(arg); @@ -2142,7 +2142,7 @@ mp_obj_t mp_obj_new_bytes_of_zeros(size_t len) { bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { - if (MP_OBJ_IS_QSTR(s1) && MP_OBJ_IS_QSTR(s2)) { + if (mp_obj_is_qstr(s1) && mp_obj_is_qstr(s2)) { return s1 == s2; } else { GET_STR_HASH(s1, h1); @@ -2173,9 +2173,9 @@ STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) { // use this if you will anyway convert the string to a qstr // will be more efficient for the case where it's already a qstr qstr mp_obj_str_get_qstr(mp_obj_t self_in) { - if (MP_OBJ_IS_QSTR(self_in)) { + if (mp_obj_is_qstr(self_in)) { return MP_OBJ_QSTR_VALUE(self_in); - } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_str)) { + } else if (mp_obj_is_type(self_in, &mp_type_str)) { mp_obj_str_t *self = MP_OBJ_TO_PTR(self_in); return qstr_from_strn((char *)self->data, self->len); } else { @@ -2186,7 +2186,7 @@ qstr mp_obj_str_get_qstr(mp_obj_t self_in) { // only use this function if you need the str data to be zero terminated // at the moment all strings are zero terminated to help with C ASCIIZ compatibility const char *mp_obj_str_get_str(mp_obj_t self_in) { - if (MP_OBJ_IS_STR_OR_BYTES(self_in)) { + if (mp_obj_is_str_or_bytes(self_in)) { GET_STR_DATA_LEN(self_in, s, l); (void)l; // len unused return (const char *)s; @@ -2196,7 +2196,7 @@ const char *mp_obj_str_get_str(mp_obj_t self_in) { } const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) { - if (MP_OBJ_IS_STR_OR_BYTES(self_in)) { + if (mp_obj_is_str_or_bytes(self_in)) { GET_STR_DATA_LEN(self_in, s, l); *len = l; return (const char *)s; @@ -2207,7 +2207,7 @@ const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) { #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len) { - if (MP_OBJ_IS_QSTR(self_in)) { + if (mp_obj_is_qstr(self_in)) { return qstr_data(MP_OBJ_QSTR_VALUE(self_in), len); } else { *len = ((mp_obj_str_t *)self_in)->len; diff --git a/py/objstr.h b/py/objstr.h index e1698ca592..3672fe5d8a 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -41,12 +41,12 @@ typedef struct _mp_obj_str_t { // use this macro to extract the string hash // warning: the hash can be 0, meaning invalid, and must then be explicitly computed from the data #define GET_STR_HASH(str_obj_in, str_hash) \ - mp_uint_t str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + mp_uint_t str_hash; if (mp_obj_is_qstr(str_obj_in)) \ { str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t *)MP_OBJ_TO_PTR(str_obj_in))->hash; } // use this macro to extract the string length #define GET_STR_LEN(str_obj_in, str_len) \ - size_t str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + size_t str_len; if (mp_obj_is_qstr(str_obj_in)) \ { str_len = qstr_len(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_len = ((mp_obj_str_t *)MP_OBJ_TO_PTR(str_obj_in))->len; } // use this macro to extract the string data and length @@ -56,7 +56,7 @@ const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len); size_t str_len; const byte *str_data = mp_obj_str_get_data_no_check(str_obj_in, &str_len); #else #define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \ - const byte *str_data; size_t str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + const byte *str_data; size_t str_len; if (mp_obj_is_qstr(str_obj_in)) \ { str_data = qstr_data(MP_OBJ_QSTR_VALUE(str_obj_in), &str_len); } \ else { str_len = ((mp_obj_str_t *)MP_OBJ_TO_PTR(str_obj_in))->len; str_data = ((mp_obj_str_t *)MP_OBJ_TO_PTR(str_obj_in))->data; } #endif @@ -107,5 +107,6 @@ MP_DECLARE_CONST_FUN_OBJ_1(str_isalpha_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_isdigit_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_isupper_obj); MP_DECLARE_CONST_FUN_OBJ_1(str_islower_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj); #endif // MICROPY_INCLUDED_PY_OBJSTR_H diff --git a/py/objstringio.c b/py/objstringio.c index 793ec84f31..3d2ff14828 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -198,7 +198,7 @@ STATIC mp_obj_t stringio_make_new(const mp_obj_type_t *type_in, size_t n_args, c if (n_args > 0) { mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); - if (MP_OBJ_IS_STR_OR_BYTES(args[0])) { + if (mp_obj_is_str_or_bytes(args[0])) { o->vstr = m_new_obj(vstr_t); vstr_init_fixed_buf(o->vstr, bufinfo.len, bufinfo.buf); o->vstr->len = bufinfo.len; diff --git a/py/objstrunicode.c b/py/objstrunicode.c index d77bbeebcd..898339569e 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2016 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -148,7 +148,7 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s // Copied from mp_get_index; I don't want bounds checking, just give me // the integer as-is. (I can't bounds-check without scanning the whole // string; an out-of-bounds index will be caught in the loops below.) - if (MP_OBJ_IS_SMALL_INT(index)) { + if (mp_obj_is_small_int(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { mp_raise_TypeError_varg(translate("string indices must be integers, not %q"), mp_obj_get_type_qstr(index)); @@ -203,7 +203,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_SENTINEL) { // load #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_obj_t ostart, ostop, ostep; mp_obj_slice_get(index, &ostart, &ostop, &ostep); if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { diff --git a/py/objtuple.c b/py/objtuple.c index fea4728230..8d1c22be83 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -73,7 +74,7 @@ STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_arg case 1: default: { // 1 argument, an iterable from which we make a new tuple - if (MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)) { + if (mp_obj_is_type(args[0], &mp_type_tuple)) { return args[0]; } @@ -191,7 +192,7 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } #if MICROPY_PY_BUILTINS_SLICE - if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { mp_raise_NotImplementedError(translate("only slices with step=1 (aka None) are supported")); @@ -209,14 +210,14 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } STATIC mp_obj_t tuple_count(mp_obj_t self_in, mp_obj_t value) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); return mp_seq_count_obj(self->items, self->len, value); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(tuple_count_obj, tuple_count); STATIC mp_obj_t tuple_index(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)); + mp_check_self(mp_obj_is_type(args[0], &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(args[0]); return mp_seq_index_obj(self->items, self->len, n_args, args); } @@ -268,7 +269,7 @@ void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { } void mp_obj_tuple_del(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); + assert(mp_obj_is_type(self_in, &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); m_del_var(mp_obj_tuple_t, mp_obj_t, self->len, self); } diff --git a/py/objtype.c b/py/objtype.c index 1f9bc386ad..42c616b75e 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013-2018 Damien P. George - * Copyright (c) 2014-2016 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014-2018 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -76,7 +76,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t const mp_obj_t *item = parent_tuple->items; const mp_obj_t *top = item + parent_tuple->len; for (; item < top; ++item) { - assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); + assert(mp_obj_is_type(*item, &mp_type_type)); const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(*item); count += instance_count_native_bases(bt, last_native_base); } @@ -182,7 +182,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_t // do a lookup, not a (base) type in which we found the class method. const mp_obj_type_t *org_type = (const mp_obj_type_t *)lookup->obj; mp_convert_member_lookup(MP_OBJ_NULL, org_type, elem->value, lookup->dest); - } else if (MP_OBJ_IS_TYPE(elem->value, &mp_type_property)) { + } else if (mp_obj_is_type(elem->value, &mp_type_property)) { lookup->dest[0] = elem->value; return; } else { @@ -223,7 +223,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_t const mp_obj_t *item = parent_tuple->items; const mp_obj_t *top = item + parent_tuple->len - 1; for (; item < top; ++item) { - assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); + assert(mp_obj_is_type(*item, &mp_type_type)); mp_obj_type_t *bt = (mp_obj_type_t *)MP_OBJ_TO_PTR(*item); if (bt == &mp_type_object) { // Not a "real" type @@ -236,7 +236,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_t } // search last base (simple tail recursion elimination) - assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); + assert(mp_obj_is_type(*item, &mp_type_type)); type = (mp_obj_type_t *)MP_OBJ_TO_PTR(*item); #endif } else { @@ -455,7 +455,7 @@ STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) { break; case MP_UNARY_OP_INT: // Must return int - if (!MP_OBJ_IS_INT(val)) { + if (!mp_obj_is_int(val)) { mp_raise_TypeError(NULL); } break; @@ -619,7 +619,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des mp_map_t *map = &self->members; mp_obj_t attr_dict = mp_obj_new_dict(map->used); for (size_t i = 0; i < map->alloc; ++i) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { mp_obj_dict_store(attr_dict, map->table[i].key, map->table[i].value); } } @@ -644,7 +644,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des } #if MICROPY_PY_BUILTINS_PROPERTY - if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { + if (mp_obj_is_type(member, &mp_type_property)) { // object member is a property; delegate the load to the property // Note: This is an optimisation for code size and execution time. // The proper way to do it is have the functionality just below @@ -724,7 +724,7 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val if (member[0] != MP_OBJ_NULL) { #if MICROPY_PY_BUILTINS_PROPERTY - if (MP_OBJ_IS_TYPE(member[0], &mp_type_property)) { + if (mp_obj_is_type(member[0], &mp_type_property)) { // attribute exists and is a property; delegate the store/delete // Note: This is an optimisation for code size and execution time. // The proper way to do it is have the functionality just below in @@ -962,7 +962,7 @@ STATIC bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) { } #endif #if MICROPY_PY_BUILTINS_PROPERTY - if (MP_OBJ_IS_TYPE(value, &mp_type_property)) { + if (mp_obj_is_type(value, &mp_type_property)) { return true; } #endif @@ -986,7 +986,7 @@ STATIC bool map_has_special_accessors(const mp_map_t *map) { return false; } for (size_t i = 0; i < map->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { const mp_map_elem_t *elem = &map->table[i]; if (check_for_special_accessors(elem->key, elem->value)) { return true; @@ -1046,7 +1046,7 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp } STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type)); + assert(mp_obj_is_type(self_in, &mp_type_type)); mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); if (dest[0] == MP_OBJ_NULL) { @@ -1116,10 +1116,10 @@ const mp_obj_type_t mp_type_type = { mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { // Verify input objects have expected type - if (!MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)) { + if (!mp_obj_is_type(bases_tuple, &mp_type_tuple)) { mp_raise_TypeError(NULL); } - if (!MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)) { + if (!mp_obj_is_type(locals_dict, &mp_type_dict)) { mp_raise_TypeError(NULL); } @@ -1131,7 +1131,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) mp_obj_t *bases_items; mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items); for (size_t i = 0; i < bases_len; i++) { - if (!MP_OBJ_IS_TYPE(bases_items[i], &mp_type_type)) { + if (!mp_obj_is_type(bases_items[i], &mp_type_type)) { mp_raise_TypeError(translate("type is not an acceptable base type")); } mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]); @@ -1209,7 +1209,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP); if (elem != NULL) { // __new__ slot exists; check if it is a function - if (MP_OBJ_IS_FUN(elem->value)) { + if (mp_obj_is_fun(elem->value)) { // __new__ is a function, wrap it in a staticmethod decorator elem->value = static_class_method_make_new(&mp_type_staticmethod, 1, &elem->value, NULL); } @@ -1242,7 +1242,7 @@ STATIC mp_obj_t super_make_new(const mp_obj_type_t *type_in, size_t n_args, cons // 0 arguments are turned into 2 in the compiler // 1 argument is not yet implemented mp_arg_check_num(n_args, kw_args, 2, 2, false); - if (!MP_OBJ_IS_TYPE(args[0], &mp_type_type)) { + if (!mp_obj_is_type(args[0], &mp_type_type)) { mp_raise_TypeError(translate("first argument to super() must be type")); } mp_obj_super_t *o = m_new_obj(mp_obj_super_t); @@ -1256,10 +1256,10 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { return; } - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_super)); + assert(mp_obj_is_type(self_in, &mp_type_super)); mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in); - assert(MP_OBJ_IS_TYPE(self->type, &mp_type_type)); + assert(mp_obj_is_type(self->type, &mp_type_type)); mp_obj_type_t *type = MP_OBJ_TO_PTR(self->type); @@ -1284,7 +1284,7 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { size_t len = parent_tuple->len; const mp_obj_t *items = parent_tuple->items; for (size_t i = 0; i < len; i++) { - assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); + assert(mp_obj_is_type(items[i], &mp_type_type)); if (MP_OBJ_TO_PTR(items[i]) == &mp_type_object) { // The "object" type will be searched at the end of this function, // and we don't want to lookup native methods in object. @@ -1310,7 +1310,7 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { // changes to mp_obj_instance_load_attr may require changes // here... #if MICROPY_PY_BUILTINS_PROPERTY - if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { + if (mp_obj_is_type(member, &mp_type_property)) { const mp_obj_t *proxy = mp_obj_property_get(member); if (proxy[0] == mp_const_none) { mp_raise_AttributeError(translate("unreadable attribute")); @@ -1366,7 +1366,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { // not equivalent classes, keep searching base classes // object should always be a type object, but just return false if it's not - if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { + if (!mp_obj_is_type(object, &mp_type_type)) { return false; } @@ -1402,10 +1402,10 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { size_t len; mp_obj_t *items; - if (MP_OBJ_IS_TYPE(classinfo, &mp_type_type)) { + if (mp_obj_is_type(classinfo, &mp_type_type)) { len = 1; items = &classinfo; - } else if (MP_OBJ_IS_TYPE(classinfo, &mp_type_tuple)) { + } else if (mp_obj_is_type(classinfo, &mp_type_tuple)) { mp_obj_tuple_get(classinfo, &len, &items); } else { mp_raise_TypeError(translate("issubclass() arg 2 must be a class or a tuple of classes")); @@ -1421,7 +1421,7 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { } STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) { - if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { + if (!mp_obj_is_type(object, &mp_type_type)) { mp_raise_TypeError(translate("issubclass() arg 1 must be a class")); } return mp_obj_is_subclass(object, classinfo); diff --git a/py/objzip.c b/py/objzip.c index 885e464418..c7aa88eb7c 100644 --- a/py/objzip.c +++ b/py/objzip.c @@ -49,7 +49,7 @@ STATIC mp_obj_t zip_make_new(const mp_obj_type_t *type, size_t n_args, const mp_ } STATIC mp_obj_t zip_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_zip)); + mp_check_self(mp_obj_is_type(self_in, &mp_type_zip)); mp_obj_zip_t *self = MP_OBJ_TO_PTR(self_in); if (self->n_iters == 0) { return MP_OBJ_STOP_ITERATION; diff --git a/py/parse.c b/py/parse.c index c8a975e0d2..b829a3a386 100644 --- a/py/parse.c +++ b/py/parse.c @@ -344,7 +344,7 @@ bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) { #else *o = (mp_obj_t)pns->nodes[0]; #endif - return MP_OBJ_IS_INT(*o); + return mp_obj_is_int(*o); } else { return false; } @@ -493,7 +493,7 @@ STATIC void push_result_token(parser_t *parser, uint8_t rule_id) { mp_map_elem_t *elem; if (rule_id == RULE_atom && (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) { - if (MP_OBJ_IS_SMALL_INT(elem->value)) { + if (mp_obj_is_small_int(elem->value)) { pn = mp_parse_node_new_small_int_checked(parser, elem->value); } else { pn = make_node_const_object(parser, lex->tok_line, elem->value); @@ -507,7 +507,7 @@ STATIC void push_result_token(parser_t *parser, uint8_t rule_id) { #endif } else if (lex->tok_kind == MP_TOKEN_INTEGER) { mp_obj_t o = mp_parse_num_integer(lex->vstr.buf, lex->vstr.len, 0, lex); - if (MP_OBJ_IS_SMALL_INT(o)) { + if (mp_obj_is_small_int(o)) { pn = mp_parse_node_new_small_int_checked(parser, o); } else { pn = make_node_const_object(parser, lex->tok_line, o); @@ -784,7 +784,7 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { } mp_obj_t dest[2]; mp_load_method_maybe(elem->value, q_attr, dest); - if (!(dest[0] != MP_OBJ_NULL && MP_OBJ_IS_INT(dest[0]) && dest[1] == MP_OBJ_NULL)) { + if (!(dest[0] != MP_OBJ_NULL && mp_obj_is_int(dest[0]) && dest[1] == MP_OBJ_NULL)) { return false; } arg0 = dest[0]; @@ -799,7 +799,7 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { for (size_t i = num_args; i > 0; i--) { pop_result(parser); } - if (MP_OBJ_IS_SMALL_INT(arg0)) { + if (mp_obj_is_small_int(arg0)) { push_result_node(parser, mp_parse_node_new_small_int_checked(parser, arg0)); } else { // TODO reuse memory for parse node struct? diff --git a/py/persistentcode.c b/py/persistentcode.c index 4e352ce7a4..13447e931f 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -40,10 +40,17 @@ #include "py/smallint.h" -// The current version of .mpy files -#define MPY_VERSION (3) +#define QSTR_LAST_STATIC MP_QSTR_zip -// The feature flags byte encodes the compile-time config options that +// Macros to encode/decode flags to/from the feature byte +#define MPY_FEATURE_ENCODE_FLAGS(flags) (flags) +#define MPY_FEATURE_DECODE_FLAGS(feat) ((feat) & 3) + +// Macros to encode/decode native architecture to/from the feature byte +#define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2) +#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2) + +// The feature flag bits encode the compile-time config options that // affect the generate bytecode. #define MPY_FEATURE_FLAGS ( \ ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \ @@ -55,6 +62,27 @@ | ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \ ) +// Define the host architecture +#if MICROPY_EMIT_X86 +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) +#elif MICROPY_EMIT_X64 +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) +#elif MICROPY_EMIT_THUMB +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7M) +#elif MICROPY_EMIT_ARM +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) +#elif MICROPY_EMIT_XTENSA +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) +#else +#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) +#endif + +#if MICROPY_DYNAMIC_COMPILER +#define MPY_FEATURE_ARCH_DYNAMIC mp_dynamic_compiler.native_arch +#else +#define MPY_FEATURE_ARCH_DYNAMIC MPY_FEATURE_ARCH +#endif + #if MICROPY_PERSISTENT_CODE_LOAD || (MICROPY_PERSISTENT_CODE_SAVE && !MICROPY_DYNAMIC_COMPILER) // The bytecode will depend on the number of bits in a small-int, and // this function computes that (could make it a fixed constant, but it @@ -70,6 +98,57 @@ STATIC int mp_small_int_bits(void) { } #endif +#define QSTR_WINDOW_SIZE (32) + +typedef struct _qstr_window_t { + uint16_t idx; // indexes the head of the window + uint16_t window[QSTR_WINDOW_SIZE]; +} qstr_window_t; + +// Push a qstr to the head of the window, and the tail qstr is overwritten +STATIC void qstr_window_push(qstr_window_t *qw, qstr qst) { + qw->idx = (qw->idx + 1) % QSTR_WINDOW_SIZE; + qw->window[qw->idx] = qst; +} + +// Pull an existing qstr from within the window to the head of the window +STATIC qstr qstr_window_pull(qstr_window_t *qw, size_t idx) { + qstr qst = qw->window[idx]; + if (idx > qw->idx) { + memmove(&qw->window[idx], &qw->window[idx + 1], (QSTR_WINDOW_SIZE - idx - 1) * sizeof(uint16_t)); + qw->window[QSTR_WINDOW_SIZE - 1] = qw->window[0]; + idx = 0; + } + memmove(&qw->window[idx], &qw->window[idx + 1], (qw->idx - idx) * sizeof(uint16_t)); + qw->window[qw->idx] = qst; + return qst; +} + +#if MICROPY_PERSISTENT_CODE_LOAD + +// Access a qstr at the given index, relative to the head of the window (0=head) +STATIC qstr qstr_window_access(qstr_window_t *qw, size_t idx) { + return qstr_window_pull(qw, (qw->idx + QSTR_WINDOW_SIZE - idx) % QSTR_WINDOW_SIZE); +} + +#endif + +#if MICROPY_PERSISTENT_CODE_SAVE + +// Insert a qstr at the head of the window, either by pulling an existing one or pushing a new one +STATIC size_t qstr_window_insert(qstr_window_t *qw, qstr qst) { + for (size_t idx = 0; idx < QSTR_WINDOW_SIZE; ++idx) { + if (qw->window[idx] == qst) { + qstr_window_pull(qw, idx); + return (qw->idx + QSTR_WINDOW_SIZE - idx) % QSTR_WINDOW_SIZE; + } + } + qstr_window_push(qw, qst); + return QSTR_WINDOW_SIZE; +} + +#endif + typedef struct _bytecode_prelude_t { uint n_state; uint n_exc_stack; @@ -80,6 +159,8 @@ typedef struct _bytecode_prelude_t { uint code_info_size; } bytecode_prelude_t; +#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_EMIT_NATIVE + // ip will point to start of opcodes // ip2 will point to simple_name, source_file qstrs STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_t *prelude) { @@ -96,40 +177,69 @@ STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_ } } +#endif + #endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE #if MICROPY_PERSISTENT_CODE_LOAD #include "py/parsenum.h" -STATIC void raise_corrupt_mpy(void) { - mp_raise_RuntimeError(translate("Corrupt .mpy file")); +#if MICROPY_EMIT_NATIVE + +#if MICROPY_EMIT_THUMB +STATIC void asm_thumb_rewrite_mov(uint8_t *pc, uint16_t val) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + // high part + *(uint16_t *)pc = (*(uint16_t *)pc & 0xfbf0) | (val >> 1 & 0x0400) | (val >> 12); + // low part + *(uint16_t *)(pc + 2) = (*(uint16_t *)(pc + 2) & 0x0f00) | (val << 4 & 0x7000) | (val & 0x00ff); +#pragma GCC diagnostic pop +} +#endif + +STATIC void arch_link_qstr(uint8_t *pc, bool is_obj, qstr qst) { + mp_uint_t val = qst; + if (is_obj) { + val = (mp_uint_t)MP_OBJ_NEW_QSTR(qst); + } + #if MICROPY_EMIT_X86 || MICROPY_EMIT_X64 || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA + pc[0] = val & 0xff; + pc[1] = (val >> 8) & 0xff; + pc[2] = (val >> 16) & 0xff; + pc[3] = (val >> 24) & 0xff; + #elif MICROPY_EMIT_THUMB + if (is_obj) { + // qstr object, movw and movt + asm_thumb_rewrite_mov(pc, val); // movw + asm_thumb_rewrite_mov(pc + 4, val >> 16); // movt + } else { + // qstr number, movw instruction + asm_thumb_rewrite_mov(pc, val); // movw + } + #endif } +#endif + STATIC int read_byte(mp_reader_t *reader) { - mp_uint_t b = reader->readbyte(reader->data); - if (b == MP_READER_EOF) { - raise_corrupt_mpy(); - } - return b; + return reader->readbyte(reader->data); } STATIC void read_bytes(mp_reader_t *reader, byte *buf, size_t len) { while (len-- > 0) { - mp_uint_t b = reader->readbyte(reader->data); - if (b == MP_READER_EOF) { - raise_corrupt_mpy(); - } - *buf++ = b; + *buf++ = reader->readbyte(reader->data); } } -STATIC size_t read_uint(mp_reader_t *reader) { +STATIC size_t read_uint(mp_reader_t *reader, byte **out) { size_t unum = 0; for (;;) { - mp_uint_t b = reader->readbyte(reader->data); - if (b == MP_READER_EOF) { - raise_corrupt_mpy(); + byte b = reader->readbyte(reader->data); + if (out != NULL) { + **out = b; + ++*out; } unum = (unum << 7) | (b & 0x7f); if ((b & 0x80) == 0) { @@ -139,11 +249,22 @@ STATIC size_t read_uint(mp_reader_t *reader) { return unum; } -STATIC qstr load_qstr(mp_reader_t *reader) { - size_t len = read_uint(reader); - char str[len]; +STATIC qstr load_qstr(mp_reader_t *reader, qstr_window_t *qw) { + size_t len = read_uint(reader, NULL); + if (len == 0) { + // static qstr + return read_byte(reader); + } + if (len & 1) { + // qstr in window + return qstr_window_access(qw, len >> 1); + } + len >>= 1; + char *str = m_new(char, len); read_bytes(reader, (byte *)str, len); qstr qst = qstr_from_strn(str, len); + m_del(char, str, len); + qstr_window_push(qw, qst); return qst; } @@ -152,7 +273,7 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) { if (obj_type == 'e') { return MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj); } else { - size_t len = read_uint(reader); + size_t len = read_uint(reader, NULL); vstr_t vstr; vstr_init_len(&vstr, len); read_bytes(reader, (byte *)vstr.buf, len); @@ -160,74 +281,202 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) { return mp_obj_new_str_from_vstr(obj_type == 's' ? &mp_type_str : &mp_type_bytes, &vstr); } else if (obj_type == 'i') { return mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL); - } else if (obj_type == 'f' || obj_type == 'c') { + } else { + assert(obj_type == 'f' || obj_type == 'c'); return mp_parse_num_decimal(vstr.buf, vstr.len, obj_type == 'c', false, NULL); } } - raise_corrupt_mpy(); - return MP_OBJ_FROM_PTR(&mp_const_none_obj); } -STATIC void load_bytecode_qstrs(mp_reader_t *reader, byte *ip, byte *ip_top) { +STATIC void load_prelude(mp_reader_t *reader, byte **ip, byte **ip2, bytecode_prelude_t *prelude) { + prelude->n_state = read_uint(reader, ip); + prelude->n_exc_stack = read_uint(reader, ip); + read_bytes(reader, *ip, 4); + prelude->scope_flags = *(*ip)++; + prelude->n_pos_args = *(*ip)++; + prelude->n_kwonly_args = *(*ip)++; + prelude->n_def_pos_args = *(*ip)++; + *ip2 = *ip; + prelude->code_info_size = read_uint(reader, ip2); + read_bytes(reader, *ip2, prelude->code_info_size - (*ip2 - *ip)); + *ip += prelude->code_info_size; + while ((*(*ip)++ = read_byte(reader)) != 255) { + } +} + +STATIC void load_bytecode(mp_reader_t *reader, qstr_window_t *qw, byte *ip, byte *ip_top) { while (ip < ip_top) { + *ip = read_byte(reader); size_t sz; - uint f = mp_opcode_format(ip, &sz); + uint f = mp_opcode_format(ip, &sz, false); + ++ip; + --sz; if (f == MP_OPCODE_QSTR) { - qstr qst = load_qstr(reader); - ip[1] = qst; - ip[2] = qst >> 8; + qstr qst = load_qstr(reader, qw); + *ip++ = qst; + *ip++ = qst >> 8; + sz -= 2; + } else if (f == MP_OPCODE_VAR_UINT) { + while ((*ip++ = read_byte(reader)) & 0x80) { + } } + read_bytes(reader, ip, sz); ip += sz; } } -STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader) { - // load bytecode - size_t bc_len = read_uint(reader); - byte *bytecode = m_new(byte, bc_len); - read_bytes(reader, bytecode, bc_len); +STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { + // Load function kind and data length + size_t kind_len = read_uint(reader, NULL); + int kind = (kind_len & 3) + MP_CODE_BYTECODE; + size_t fun_data_len = kind_len >> 2; - // extract prelude - const byte *ip = bytecode; - const byte *ip2; - bytecode_prelude_t prelude; - extract_prelude(&ip, &ip2, &prelude); - - // load qstrs and link global qstr ids into bytecode - qstr simple_name = load_qstr(reader); - qstr source_file = load_qstr(reader); - ((byte *)ip2)[0] = simple_name; - ((byte *)ip2)[1] = simple_name >> 8; - ((byte *)ip2)[2] = source_file; - ((byte *)ip2)[3] = source_file >> 8; - load_bytecode_qstrs(reader, (byte *)ip, bytecode + bc_len); - - // load constant table - size_t n_obj = read_uint(reader); - size_t n_raw_code = read_uint(reader); - mp_uint_t *const_table = m_new(mp_uint_t, prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code); - mp_uint_t *ct = const_table; - for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { - *ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader)); + #if !MICROPY_EMIT_NATIVE + if (kind != MP_CODE_BYTECODE) { + mp_raise_ValueError(translate("incompatible .mpy file")); } - for (size_t i = 0; i < n_obj; ++i) { - *ct++ = (mp_uint_t)load_obj(reader); - } - for (size_t i = 0; i < n_raw_code; ++i) { - *ct++ = (mp_uint_t)(uintptr_t)load_raw_code(reader); + #endif + + uint8_t *fun_data = NULL; + byte *ip2; + bytecode_prelude_t prelude = {0}; + #if MICROPY_EMIT_NATIVE + size_t prelude_offset; + mp_uint_t type_sig = 0; + size_t n_qstr_link = 0; + #endif + + if (kind == MP_CODE_BYTECODE) { + // Allocate memory for the bytecode + fun_data = m_new(uint8_t, fun_data_len); + + // Load prelude + byte *ip = fun_data; + load_prelude(reader, &ip, &ip2, &prelude); + + // Load bytecode + load_bytecode(reader, qw, ip, fun_data + fun_data_len); + + #if MICROPY_EMIT_NATIVE + } else { + // Allocate memory for native data and load it + size_t fun_alloc; + MP_PLAT_ALLOC_EXEC(fun_data_len, (void **)&fun_data, &fun_alloc); + read_bytes(reader, fun_data, fun_data_len); + + if (kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER) { + // Parse qstr link table and link native code + n_qstr_link = read_uint(reader, NULL); + for (size_t i = 0; i < n_qstr_link; ++i) { + size_t off = read_uint(reader, NULL); + qstr qst = load_qstr(reader, qw); + uint8_t *dest = fun_data + (off >> 2); + if ((off & 3) == 0) { + // Generic 16-bit link + dest[0] = qst & 0xff; + dest[1] = (qst >> 8) & 0xff; + } else { + // Architecture-specific link + arch_link_qstr(dest, (off & 3) == 2, qst); + } + } + } + + if (kind == MP_CODE_NATIVE_PY) { + // Extract prelude for later use + prelude_offset = read_uint(reader, NULL); + const byte *ip = fun_data + prelude_offset; + extract_prelude(&ip, (const byte **)&ip2, &prelude); + } else { + // Load basic scope info for viper and asm + prelude.scope_flags = read_uint(reader, NULL); + prelude.n_pos_args = 0; + prelude.n_kwonly_args = 0; + if (kind == MP_CODE_NATIVE_ASM) { + prelude.n_pos_args = read_uint(reader, NULL); + type_sig = read_uint(reader, NULL); + } + } + #endif } - // create raw_code and return it + if (kind == MP_CODE_BYTECODE || kind == MP_CODE_NATIVE_PY) { + // Load qstrs in prelude + qstr simple_name = load_qstr(reader, qw); + qstr source_file = load_qstr(reader, qw); + ip2[0] = simple_name; + ip2[1] = simple_name >> 8; + ip2[2] = source_file; + ip2[3] = source_file >> 8; + } + + mp_uint_t *const_table = NULL; + if (kind != MP_CODE_NATIVE_ASM) { + // Load constant table for bytecode, native and viper + + // Number of entries in constant table + size_t n_obj = read_uint(reader, NULL); + size_t n_raw_code = read_uint(reader, NULL); + + // Allocate constant table + size_t n_alloc = prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code; + if (kind != MP_CODE_BYTECODE) { + ++n_alloc; // additional entry for mp_fun_table + } + const_table = m_new(mp_uint_t, n_alloc); + mp_uint_t *ct = const_table; + + // Load function argument names (initial entries in const_table) + // (viper has n_pos_args=n_kwonly_args=0 so doesn't load any qstrs here) + for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { + *ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader, qw)); + } + + #if MICROPY_EMIT_NATIVE + if (kind != MP_CODE_BYTECODE) { + // Populate mp_fun_table entry + *ct++ = (mp_uint_t)(uintptr_t)mp_fun_table; + } + #endif + + // Load constant objects and raw code children + for (size_t i = 0; i < n_obj; ++i) { + *ct++ = (mp_uint_t)load_obj(reader); + } + for (size_t i = 0; i < n_raw_code; ++i) { + *ct++ = (mp_uint_t)(uintptr_t)load_raw_code(reader, qw); + } + } + + // Create raw_code and return it mp_raw_code_t *rc = mp_emit_glue_new_raw_code(); - mp_emit_glue_assign_bytecode(rc, bytecode, - #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS - bc_len, + if (kind == MP_CODE_BYTECODE) { + mp_emit_glue_assign_bytecode(rc, fun_data, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + fun_data_len, + #endif + const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + n_obj, n_raw_code, + #endif + prelude.scope_flags); + + #if MICROPY_EMIT_NATIVE + } else { + #if defined(MP_PLAT_COMMIT_EXEC) + fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len); #endif - const_table, - #if MICROPY_PERSISTENT_CODE_SAVE - n_obj, n_raw_code, - #endif - prelude.scope_flags); + + mp_emit_glue_assign_native(rc, kind, + fun_data, fun_data_len, const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + prelude_offset, + n_obj, n_raw_code, + n_qstr_link, NULL, + #endif + prelude.n_pos_args, prelude.scope_flags, type_sig); + #endif + } return rc; } @@ -236,11 +485,18 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { read_bytes(reader, header, sizeof(header)); if (header[0] != 'M' || header[1] != MPY_VERSION - || header[2] != MPY_FEATURE_FLAGS - || header[3] > mp_small_int_bits()) { + || MPY_FEATURE_DECODE_FLAGS(header[2]) != MPY_FEATURE_FLAGS + || header[3] > mp_small_int_bits() + || read_uint(reader, NULL) > QSTR_WINDOW_SIZE) { mp_raise_MpyError(translate("Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info.")); } - mp_raw_code_t *rc = load_raw_code(reader); + if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE + && MPY_FEATURE_DECODE_ARCH(header[2]) != MPY_FEATURE_ARCH) { + mp_raise_ValueError(translate("incompatible native .mpy architecture")); + } + qstr_window_t qw; + qw.idx = 0; + mp_raw_code_t *rc = load_raw_code(reader, &qw); reader->close(reader->data); return rc; } @@ -251,12 +507,16 @@ mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len) { return mp_raw_code_load(&reader); } +#if MICROPY_HAS_FILE_READER + mp_raw_code_t *mp_raw_code_load_file(const char *filename) { mp_reader_t reader; mp_reader_new_file(&reader, filename); return mp_raw_code_load(&reader); } +#endif // MICROPY_HAS_FILE_READER + #endif // MICROPY_PERSISTENT_CODE_LOAD #if MICROPY_PERSISTENT_CODE_SAVE @@ -279,22 +539,34 @@ STATIC void mp_print_uint(mp_print_t *print, size_t n) { print->print_strn(print->data, (char *)p, buf + sizeof(buf) - p); } -STATIC void save_qstr(mp_print_t *print, qstr qst) { +STATIC void save_qstr(mp_print_t *print, qstr_window_t *qw, qstr qst) { + if (qst <= QSTR_LAST_STATIC) { + // encode static qstr + byte buf[2] = {0, qst & 0xff}; + mp_print_bytes(print, buf, 2); + return; + } + size_t idx = qstr_window_insert(qw, qst); + if (idx < QSTR_WINDOW_SIZE) { + // qstr found in window, encode index to it + mp_print_uint(print, idx << 1 | 1); + return; + } size_t len; const byte *str = qstr_data(qst, &len); - mp_print_uint(print, len); + mp_print_uint(print, len << 1); mp_print_bytes(print, str, len); } STATIC void save_obj(mp_print_t *print, mp_obj_t o) { - if (MP_OBJ_IS_STR_OR_BYTES(o)) { + if (mp_obj_is_str_or_bytes(o)) { byte obj_type; - if (MP_OBJ_IS_STR(o)) { + if (mp_obj_is_str(o)) { obj_type = 's'; } else { obj_type = 'b'; } - mp_uint_t len; + size_t len; const char *str = mp_obj_str_get_data(o, &len); mp_print_bytes(print, &obj_type, 1); mp_print_uint(print, len); @@ -306,10 +578,10 @@ STATIC void save_obj(mp_print_t *print, mp_obj_t o) { // we save numbers using a simplistic text representation // TODO could be improved byte obj_type; - if (MP_OBJ_IS_TYPE(o, &mp_type_int)) { + if (mp_obj_is_type(o, &mp_type_int)) { obj_type = 'i'; #if MICROPY_PY_BUILTINS_COMPLEX - } else if (MP_OBJ_IS_TYPE(o, &mp_type_complex)) { + } else if (mp_obj_is_type(o, &mp_type_complex)) { obj_type = 'c'; #endif } else { @@ -327,52 +599,127 @@ STATIC void save_obj(mp_print_t *print, mp_obj_t o) { } } -STATIC void save_bytecode_qstrs(mp_print_t *print, const byte *ip, const byte *ip_top) { +STATIC void save_bytecode(mp_print_t *print, qstr_window_t *qw, const byte *ip, const byte *ip_top) { while (ip < ip_top) { size_t sz; - uint f = mp_opcode_format(ip, &sz); + uint f = mp_opcode_format(ip, &sz, true); if (f == MP_OPCODE_QSTR) { + mp_print_bytes(print, ip, 1); qstr qst = ip[1] | (ip[2] << 8); - save_qstr(print, qst); + save_qstr(print, qw, qst); + ip += 3; + sz -= 3; } + mp_print_bytes(print, ip, sz); ip += sz; } } -STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc) { - if (rc->kind != MP_CODE_BYTECODE) { - mp_raise_ValueError(translate("can only save bytecode")); +STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *qstr_window) { + // Save function kind and data length + mp_print_uint(print, (rc->fun_data_len << 2) | (rc->kind - MP_CODE_BYTECODE)); + + const byte *ip2; + bytecode_prelude_t prelude; + + if (rc->kind == MP_CODE_BYTECODE) { + // Save prelude + const byte *ip = rc->fun_data; + extract_prelude(&ip, &ip2, &prelude); + size_t prelude_len = ip - (const byte *)rc->fun_data; + const byte *ip_top = (const byte *)rc->fun_data + rc->fun_data_len; + mp_print_bytes(print, rc->fun_data, prelude_len); + + // Save bytecode + save_bytecode(print, qstr_window, ip, ip_top); + } else { + // Save native code + mp_print_bytes(print, rc->fun_data, rc->fun_data_len); + + if (rc->kind == MP_CODE_NATIVE_PY || rc->kind == MP_CODE_NATIVE_VIPER) { + // Save qstr link table for native code + mp_print_uint(print, rc->n_qstr); + for (size_t i = 0; i < rc->n_qstr; ++i) { + mp_print_uint(print, rc->qstr_link[i].off); + save_qstr(print, qstr_window, rc->qstr_link[i].qst); + } + } + + if (rc->kind == MP_CODE_NATIVE_PY) { + // Save prelude size, and extract prelude for later use + mp_print_uint(print, rc->prelude_offset); + const byte *ip = (const byte *)rc->fun_data + rc->prelude_offset; + extract_prelude(&ip, &ip2, &prelude); + } else { + // Save basic scope info for viper and asm + mp_print_uint(print, rc->scope_flags); + prelude.n_pos_args = 0; + prelude.n_kwonly_args = 0; + if (rc->kind == MP_CODE_NATIVE_ASM) { + mp_print_uint(print, rc->n_pos_args); + mp_print_uint(print, rc->type_sig); + } + } } - // save bytecode - mp_print_uint(print, rc->data.u_byte.bc_len); - mp_print_bytes(print, rc->data.u_byte.bytecode, rc->data.u_byte.bc_len); + if (rc->kind == MP_CODE_BYTECODE || rc->kind == MP_CODE_NATIVE_PY) { + // Save qstrs in prelude + save_qstr(print, qstr_window, ip2[0] | (ip2[1] << 8)); // simple_name + save_qstr(print, qstr_window, ip2[2] | (ip2[3] << 8)); // source_file + } - // extract prelude - const byte *ip = rc->data.u_byte.bytecode; + if (rc->kind != MP_CODE_NATIVE_ASM) { + // Save constant table for bytecode, native and viper + + // Number of entries in constant table + mp_print_uint(print, rc->n_obj); + mp_print_uint(print, rc->n_raw_code); + + const mp_uint_t *const_table = rc->const_table; + + // Save function argument names (initial entries in const_table) + // (viper has n_pos_args=n_kwonly_args=0 so doesn't save any qstrs here) + for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { + mp_obj_t o = (mp_obj_t)*const_table++; + save_qstr(print, qstr_window, MP_OBJ_QSTR_VALUE(o)); + } + + if (rc->kind != MP_CODE_BYTECODE) { + // Skip saving mp_fun_table entry + ++const_table; + } + + // Save constant objects and raw code children + for (size_t i = 0; i < rc->n_obj; ++i) { + save_obj(print, (mp_obj_t)*const_table++); + } + for (size_t i = 0; i < rc->n_raw_code; ++i) { + save_raw_code(print, (mp_raw_code_t *)(uintptr_t)*const_table++, qstr_window); + } + } +} + +STATIC bool mp_raw_code_has_native(mp_raw_code_t *rc) { + if (rc->kind != MP_CODE_BYTECODE) { + return true; + } + + const byte *ip = rc->fun_data; const byte *ip2; bytecode_prelude_t prelude; extract_prelude(&ip, &ip2, &prelude); - // save qstrs - save_qstr(print, ip2[0] | (ip2[1] << 8)); // simple_name - save_qstr(print, ip2[2] | (ip2[3] << 8)); // source_file - save_bytecode_qstrs(print, ip, rc->data.u_byte.bytecode + rc->data.u_byte.bc_len); + const mp_uint_t *const_table = rc->const_table + + prelude.n_pos_args + prelude.n_kwonly_args + + rc->n_obj; - // save constant table - mp_print_uint(print, rc->data.u_byte.n_obj); - mp_print_uint(print, rc->data.u_byte.n_raw_code); - const mp_uint_t *const_table = rc->data.u_byte.const_table; - for (uint i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { - mp_obj_t o = (mp_obj_t)*const_table++; - save_qstr(print, MP_OBJ_QSTR_VALUE(o)); - } - for (uint i = 0; i < rc->data.u_byte.n_obj; ++i) { - save_obj(print, (mp_obj_t)*const_table++); - } - for (uint i = 0; i < rc->data.u_byte.n_raw_code; ++i) { - save_raw_code(print, (mp_raw_code_t *)(uintptr_t)*const_table++); + for (size_t i = 0; i < rc->n_raw_code; ++i) { + if (mp_raw_code_has_native((mp_raw_code_t *)(uintptr_t)*const_table++)) { + return true; + } } + + return false; } void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) { @@ -381,16 +728,27 @@ void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) { // byte version // byte feature flags // byte number of bits in a small int - byte header[4] = {'M', MPY_VERSION, MPY_FEATURE_FLAGS_DYNAMIC, - #if MICROPY_DYNAMIC_COMPILER - mp_dynamic_compiler.small_int_bits, - #else - mp_small_int_bits(), - #endif + // uint size of qstr window + byte header[4] = { + 'M', + MPY_VERSION, + MPY_FEATURE_ENCODE_FLAGS(MPY_FEATURE_FLAGS_DYNAMIC), + #if MICROPY_DYNAMIC_COMPILER + mp_dynamic_compiler.small_int_bits, + #else + mp_small_int_bits(), + #endif }; + if (mp_raw_code_has_native(rc)) { + header[2] |= MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC); + } mp_print_bytes(print, header, sizeof(header)); + mp_print_uint(print, QSTR_WINDOW_SIZE); - save_raw_code(print, rc); + qstr_window_t qw; + qw.idx = 0; + memset(qw.window, 0, sizeof(qw.window)); + save_raw_code(print, rc, &qw); } // here we define mp_raw_code_save_file depending on the port diff --git a/py/persistentcode.h b/py/persistentcode.h index cbb300e4b3..8ecaea1140 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -30,6 +30,22 @@ #include "py/reader.h" #include "py/emitglue.h" +// The current version of .mpy files +#define MPY_VERSION 4 + +enum { + MP_NATIVE_ARCH_NONE = 0, + MP_NATIVE_ARCH_X86, + MP_NATIVE_ARCH_X64, + MP_NATIVE_ARCH_ARMV6, + MP_NATIVE_ARCH_ARMV6M, + MP_NATIVE_ARCH_ARMV7M, + MP_NATIVE_ARCH_ARMV7EM, + MP_NATIVE_ARCH_ARMV7EMSP, + MP_NATIVE_ARCH_ARMV7EMDP, + MP_NATIVE_ARCH_XTENSA, +}; + mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader); mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len); mp_raw_code_t *mp_raw_code_load_file(const char *filename); diff --git a/py/py.mk b/py/py.mk index f61bad1faf..73c093bd64 100644 --- a/py/py.mk +++ b/py/py.mk @@ -37,19 +37,19 @@ LDFLAGS_MOD += -L$(TOP)/lib/mbedtls/library -lmbedx509 -lmbedtls -lmbedcrypto endif endif -#ifeq ($(MICROPY_PY_LWIP),1) -#CFLAGS_MOD += -DMICROPY_PY_LWIP=1 -I../lib/lwip/src/include -I../lib/lwip/src/include/ipv4 -I../extmod/lwip-include -#endif - ifeq ($(MICROPY_PY_LWIP),1) +# A port should add an include path where lwipopts.h can be found (eg extmod/lwip-include) LWIP_DIR = lib/lwip/src -INC += -I$(TOP)/lib/lwip/src/include -I$(TOP)/lib/lwip/src/include/ipv4 -I$(TOP)/extmod/lwip-include +INC += -I$(TOP)/$(LWIP_DIR)/include CFLAGS_MOD += -DMICROPY_PY_LWIP=1 +$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS_MOD += -Wno-address SRC_MOD += extmod/modlwip.c lib/netutils/netutils.c SRC_MOD += $(addprefix $(LWIP_DIR)/,\ core/def.c \ core/dns.c \ + core/inet_chksum.c \ core/init.c \ + core/ip.c \ core/mem.c \ core/memp.c \ core/netif.c \ @@ -60,16 +60,26 @@ SRC_MOD += $(addprefix $(LWIP_DIR)/,\ core/tcp.c \ core/tcp_in.c \ core/tcp_out.c \ - core/timers.c \ + core/timeouts.c \ core/udp.c \ core/ipv4/autoip.c \ + core/ipv4/dhcp.c \ + core/ipv4/etharp.c \ core/ipv4/icmp.c \ core/ipv4/igmp.c \ - core/ipv4/inet.c \ - core/ipv4/inet_chksum.c \ - core/ipv4/ip_addr.c \ - core/ipv4/ip.c \ - core/ipv4/ip_frag.c \ + core/ipv4/ip4_addr.c \ + core/ipv4/ip4.c \ + core/ipv4/ip4_frag.c \ + core/ipv6/dhcp6.c \ + core/ipv6/ethip6.c \ + core/ipv6/icmp6.c \ + core/ipv6/inet6.c \ + core/ipv6/ip6_addr.c \ + core/ipv6/ip6.c \ + core/ipv6/ip6_frag.c \ + core/ipv6/mld6.c \ + core/ipv6/nd6.c \ + netif/ethernet.c \ ) ifeq ($(MICROPY_PY_LWIP_SLIP),1) CFLAGS_MOD += -DMICROPY_PY_LWIP_SLIP=1 @@ -299,7 +309,7 @@ endif # Sources that may contain qstrings SRC_QSTR_IGNORE = py/nlr% SRC_QSTR_EMITNATIVE = py/emitn% -SRC_QSTR = $(SRC_MOD) $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) $(PY_EXTMOD_O_BASENAME:.o=.c) +SRC_QSTR += $(SRC_MOD) $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) $(PY_EXTMOD_O_BASENAME:.o=.c) # Sources that only hold QSTRs after pre-processing. SRC_QSTR_PREPROCESSOR = $(addprefix $(TOP)/, $(filter $(SRC_QSTR_EMITNATIVE),$(PY_CORE_O_BASENAME:.o=.c))) diff --git a/py/runtime.c b/py/runtime.c index 72eb2fa4c5..35c6f79319 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2018 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -70,7 +71,8 @@ void mp_init(void) { MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; #if MICROPY_ENABLE_SCHEDULER MP_STATE_VM(sched_state) = MP_SCHED_IDLE; - MP_STATE_VM(sched_sp) = 0; + MP_STATE_VM(sched_idx) = 0; + MP_STATE_VM(sched_len) = 0; #endif #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF @@ -232,7 +234,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { if (op == MP_UNARY_OP_NOT) { // "not x" is the negative of whether "x" is true per Python semantics return mp_obj_new_bool(mp_obj_is_true(arg) == 0); - } else if (MP_OBJ_IS_SMALL_INT(arg)) { + } else if (mp_obj_is_small_int(arg)) { mp_int_t val = MP_OBJ_SMALL_INT_VALUE(arg); switch (op) { case MP_UNARY_OP_BOOL: @@ -262,7 +264,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { assert(op == MP_UNARY_OP_INVERT); return MP_OBJ_NEW_SMALL_INT(~val); } - } else if (op == MP_UNARY_OP_HASH && MP_OBJ_IS_STR_OR_BYTES(arg)) { + } else if (op == MP_UNARY_OP_HASH && mp_obj_is_str_or_bytes(arg)) { // fast path for hashing str/bytes GET_STR_HASH(arg, h); if (h == 0) { @@ -340,7 +342,7 @@ mp_obj_t PLACE_IN_ITCM(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t r } else { return mp_const_false; } - } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_tuple)) { + } else if (mp_obj_is_type(rhs, &mp_type_tuple)) { mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(rhs); for (size_t i = 0; i < tuple->len; i++) { rhs = tuple->items[i]; @@ -356,9 +358,9 @@ mp_obj_t PLACE_IN_ITCM(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t r goto unsupported_op; } - if (MP_OBJ_IS_SMALL_INT(lhs)) { + if (mp_obj_is_small_int(lhs)) { mp_int_t lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs); - if (MP_OBJ_IS_SMALL_INT(rhs)) { + if (mp_obj_is_small_int(rhs)) { mp_int_t rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs); // This is a binary operation: lhs_val op rhs_val // We need to be careful to handle overflow; see CERT INT32-C @@ -477,8 +479,7 @@ mp_obj_t PLACE_IN_ITCM(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t r case MP_BINARY_OP_INPLACE_POWER: if (rhs_val < 0) { #if MICROPY_PY_BUILTINS_FLOAT - lhs = mp_obj_new_float(lhs_val); - goto generic_binary_op; + return mp_obj_float_binary_op(op, lhs_val, rhs); #else mp_raise_ValueError(translate("negative power with no float support")); #endif @@ -547,7 +548,7 @@ mp_obj_t PLACE_IN_ITCM(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t r return res; } #if MICROPY_PY_BUILTINS_COMPLEX - } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_complex)) { + } else if (mp_obj_is_type(rhs, &mp_type_complex)) { mp_obj_t res = mp_obj_complex_binary_op(op, lhs_val, 0, rhs); if (res == MP_OBJ_NULL) { goto unsupported_op; @@ -693,7 +694,7 @@ void PLACE_IN_ITCM(mp_call_prepare_args_n_kw_var)(bool have_self, size_t n_args_ // Try to get a hint for the size of the kw_dict uint kw_dict_len = 0; - if (kw_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) { + if (kw_dict != MP_OBJ_NULL && mp_obj_is_type(kw_dict, &mp_type_dict)) { kw_dict_len = mp_obj_dict_len(kw_dict); } @@ -715,7 +716,7 @@ void PLACE_IN_ITCM(mp_call_prepare_args_n_kw_var)(bool have_self, size_t n_args_ mp_seq_copy(args2 + args2_len, args, n_args, mp_obj_t); args2_len += n_args; - } else if (MP_OBJ_IS_TYPE(pos_seq, &mp_type_tuple) || MP_OBJ_IS_TYPE(pos_seq, &mp_type_list)) { + } else if (mp_obj_is_type(pos_seq, &mp_type_tuple) || mp_obj_is_type(pos_seq, &mp_type_list)) { // optimise the case of a tuple and list // get the items @@ -776,15 +777,15 @@ void PLACE_IN_ITCM(mp_call_prepare_args_n_kw_var)(bool have_self, size_t n_args_ // Note that it can be arbitrary iterator. if (kw_dict == MP_OBJ_NULL) { // pass - } else if (MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) { + } else if (mp_obj_is_type(kw_dict, &mp_type_dict)) { // dictionary mp_map_t *map = mp_obj_dict_get_map(kw_dict); assert(args2_len + 2 * map->used <= args2_alloc); // should have enough, since kw_dict_len is in this case hinted correctly above for (size_t i = 0; i < map->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { // the key must be a qstr, so intern it if it's a string mp_obj_t key = map->table[i].key; - if (!MP_OBJ_IS_QSTR(key)) { + if (!mp_obj_is_qstr(key)) { key = mp_obj_str_intern_checked(key); } args2[args2_len++] = key; @@ -814,7 +815,7 @@ void PLACE_IN_ITCM(mp_call_prepare_args_n_kw_var)(bool have_self, size_t n_args_ } // the key must be a qstr, so intern it if it's a string - if (!MP_OBJ_IS_QSTR(key)) { + if (!mp_obj_is_qstr(key)) { key = mp_obj_str_intern_checked(key); } @@ -849,7 +850,7 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ob // unpacked items are stored in reverse order into the array pointed to by items void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { size_t seq_len; - if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) { + if (mp_obj_is_type(seq_in, &mp_type_tuple) || mp_obj_is_type(seq_in, &mp_type_list)) { mp_obj_t *seq_items; mp_obj_get_array(seq_in, &seq_len, &seq_items); if (seq_len < num) { @@ -899,9 +900,13 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { size_t num_right = (num_in >> 8) & 0xff; DEBUG_OP_printf("unpack ex " UINT_FMT " " UINT_FMT "\n", num_left, num_right); size_t seq_len; - if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) { + if (mp_obj_is_type(seq_in, &mp_type_tuple) || mp_obj_is_type(seq_in, &mp_type_list)) { + // Make the seq variable volatile so the compiler keeps a reference to it, + // since if it's a tuple then seq_items points to the interior of the GC cell + // and mp_obj_new_list may trigger a GC which doesn't trace this and reclaims seq. + volatile mp_obj_t seq = seq_in; mp_obj_t *seq_items; - mp_obj_get_array(seq_in, &seq_len, &seq_items); + mp_obj_get_array(seq, &seq_len, &seq_items); if (seq_len < num_left + num_right) { goto too_short; } @@ -912,6 +917,7 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { for (size_t i = 0; i < num_left; i++) { items[num_right + 1 + i] = seq_items[num_left - 1 - i]; } + seq = MP_OBJ_NULL; } else { // Generic iterable; this gets a bit messy: we unpack known left length to the // items destination array, then the rest to a dynamically created list. Once the @@ -1013,10 +1019,10 @@ STATIC mp_obj_t mp_obj_new_checked_fun(const mp_obj_type_t *type, mp_obj_t fun) // Conversion means dealing with static/class methods, callables, and values. // see http://docs.python.org/3/howto/descriptor.html void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) { - if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) { + if (mp_obj_is_type(member, &mp_type_staticmethod)) { // return just the function dest[0] = ((mp_obj_static_class_method_t *)MP_OBJ_TO_PTR(member))->fun; - } else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) { + } else if (mp_obj_is_type(member, &mp_type_classmethod)) { // return a bound method, with self being the type of this object // this type should be the type of the original instance, not the base // type (which is what is passed in the 'type' argument to this function) @@ -1025,11 +1031,11 @@ void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t } dest[0] = ((mp_obj_static_class_method_t *)MP_OBJ_TO_PTR(member))->fun; dest[1] = MP_OBJ_FROM_PTR(type); - } else if (MP_OBJ_IS_TYPE(member, &mp_type_type)) { + } else if (mp_obj_is_type(member, &mp_type_type)) { // Don't try to bind types (even though they're callable) dest[0] = member; - } else if (MP_OBJ_IS_FUN(member) - || (MP_OBJ_IS_OBJ(member) + } else if (mp_obj_is_fun(member) + || (mp_obj_is_obj(member) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(member))->type->name == MP_QSTR_closure || ((mp_obj_base_t *)MP_OBJ_TO_PTR(member))->type->name == MP_QSTR_generator))) { // only functions, closures and generators objects can be bound to self @@ -1053,7 +1059,7 @@ void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t } #if MICROPY_PY_BUILTINS_PROPERTY // If self is MP_OBJ_NULL, we looking at the class itself, not an instance. - } else if (MP_OBJ_IS_TYPE(member, &mp_type_property) && mp_obj_is_native_type(type) && self != MP_OBJ_NULL) { + } else if (mp_obj_is_type(member, &mp_type_property) && mp_obj_is_native_type(type) && self != MP_OBJ_NULL) { // object member is a property; delegate the load to the property // Note: This is an optimisation for code size and execution time. // The proper way to do it is have the functionality just below @@ -1086,14 +1092,13 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { mp_obj_type_t *type = mp_obj_get_type(obj); // look for built-in names - if (0) { #if MICROPY_CPYTHON_COMPAT - } else if (attr == MP_QSTR___class__) { + if (attr == MP_QSTR___class__) { // a.__class__ is equivalent to type(a) dest[0] = MP_OBJ_FROM_PTR(type); + } else #endif - - } else if (attr == MP_QSTR___next__ && type->iternext != NULL) { + if (attr == MP_QSTR___next__ && type->iternext != NULL) { dest[0] = MP_OBJ_FROM_PTR(&mp_builtin_next_obj); dest[1] = obj; @@ -1124,7 +1129,7 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { mp_raise_AttributeError(translate("no such attribute")); #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED // following CPython, we give a more detailed error message for type objects - if (MP_OBJ_IS_TYPE(base, &mp_type_type)) { + if (mp_obj_is_type(base, &mp_type_type)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, translate("type object '%q' has no attribute '%q'"), ((mp_obj_type_t *)MP_OBJ_TO_PTR(base))->name, attr)); @@ -1175,7 +1180,7 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { mp_map_t *locals_map = &type->locals_dict->map; mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); // If base is MP_OBJ_NULL, we looking at the class itself, not an instance. - if (elem != NULL && MP_OBJ_IS_TYPE(elem->value, &mp_type_property) && base != MP_OBJ_NULL) { + if (elem != NULL && mp_obj_is_type(elem->value, &mp_type_property) && base != MP_OBJ_NULL) { // attribute exists and is a property; delegate the store/delete // Note: This is an optimisation for code size and execution time. // The proper way to do it is have the functionality just below in @@ -1464,7 +1469,7 @@ void mp_import_all(mp_obj_t module) { // TODO: Support __all__ mp_map_t *map = &mp_obj_module_get_globals(module)->map; for (size_t i = 0; i < map->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { // Entry in module global scope may be generated programmatically // (and thus be not a qstr for longer names). Avoid turning it in // qstr if it has '_' and was used exactly to save memory. diff --git a/py/runtime.h b/py/runtime.h index c30252a946..9c35cf6392 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -73,7 +73,7 @@ void mp_handle_pending_tail(mp_uint_t atomic_state); void mp_sched_lock(void); void mp_sched_unlock(void); static inline unsigned int mp_sched_num_pending(void) { - return MP_STATE_VM(sched_sp); + return MP_STATE_VM(sched_len); } bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg); #endif @@ -197,8 +197,9 @@ NORETURN void mp_raise_recursion_depth(void); #endif // helper functions for native/viper code -mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type); -mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type); +int mp_native_type_from_qstr(qstr qst); +mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type); +mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type); mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals); mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args); void mp_native_raise(mp_obj_t o); @@ -207,7 +208,9 @@ void mp_native_raise(mp_obj_t o); #define mp_sys_argv (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_argv_obj))) #if MICROPY_WARNINGS -void mp_warning(const char *msg, ...); +#ifndef mp_warning +void mp_warning(const char *category, const char *msg, ...); +#endif #else #define mp_warning(...) #endif diff --git a/py/scheduler.c b/py/scheduler.c index fea7e0153d..75fa2e5fdd 100644 --- a/py/scheduler.c +++ b/py/scheduler.c @@ -30,6 +30,19 @@ #if MICROPY_ENABLE_SCHEDULER +#define IDX_MASK(i) ((i) & (MICROPY_SCHEDULER_DEPTH - 1)) + +static inline bool mp_sched_full(void) { + MP_STATIC_ASSERT(MICROPY_SCHEDULER_DEPTH <= 255); // MICROPY_SCHEDULER_DEPTH must fit in 8 bits + MP_STATIC_ASSERT((IDX_MASK(MICROPY_SCHEDULER_DEPTH) == 0)); // MICROPY_SCHEDULER_DEPTH must be a power of 2 + + return mp_sched_num_pending() == MICROPY_SCHEDULER_DEPTH; +} + +static inline bool mp_sched_empty(void) { + return mp_sched_num_pending() == 0; +} + // A variant of this is inlined in the VM at the pending exception check void mp_handle_pending(void) { if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) { @@ -51,8 +64,10 @@ void mp_handle_pending(void) { // or by the VM's inlined version of that function. void mp_handle_pending_tail(mp_uint_t atomic_state) { MP_STATE_VM(sched_state) = MP_SCHED_LOCKED; - if (MP_STATE_VM(sched_sp) > 0) { - mp_sched_item_t item = MP_STATE_VM(sched_stack)[--MP_STATE_VM(sched_sp)]; + if (!mp_sched_empty()) { + mp_sched_item_t item = MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_idx)]; + MP_STATE_VM(sched_idx) = IDX_MASK(MP_STATE_VM(sched_idx) + 1); + --MP_STATE_VM(sched_len); MICROPY_END_ATOMIC_SECTION(atomic_state); mp_call_function_1_protected(item.func, item.arg); } else { @@ -87,13 +102,13 @@ void mp_sched_unlock(void) { bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); bool ret; - if (MP_STATE_VM(sched_sp) < MICROPY_SCHEDULER_DEPTH) { + if (!mp_sched_full()) { if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { MP_STATE_VM(sched_state) = MP_SCHED_PENDING; } - MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_sp)].func = function; - MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_sp)].arg = arg; - ++MP_STATE_VM(sched_sp); + uint8_t iput = IDX_MASK(MP_STATE_VM(sched_idx) + MP_STATE_VM(sched_len)++); + MP_STATE_VM(sched_stack)[iput].func = function; + MP_STATE_VM(sched_stack)[iput].arg = arg; ret = true; } else { // schedule stack is full diff --git a/py/showbc.c b/py/showbc.c index a94b2b3a57..b8ba9b706f 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -401,14 +401,9 @@ const byte *mp_bytecode_print_str(const byte *ip) { printf("FOR_ITER " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; - case MP_BC_POP_BLOCK: - // pops block and restores the stack - printf("POP_BLOCK"); - break; - - case MP_BC_POP_EXCEPT: - // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate - printf("POP_EXCEPT"); + case MP_BC_POP_EXCEPT_JUMP: + DECODE_ULABEL; // these labels are always forward + printf("POP_EXCEPT_JUMP " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); break; case MP_BC_BUILD_TUPLE: diff --git a/py/stream.c b/py/stream.c index 35cbc4e211..0b01c3d8c5 100644 --- a/py/stream.c +++ b/py/stream.c @@ -3,8 +3,8 @@ * * The MIT License (MIT) * - * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2016 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -257,7 +257,7 @@ void mp_stream_write_adaptor(void *self, const char *buf, size_t len) { STATIC mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); - if (!mp_get_stream(args[0])->is_text && MP_OBJ_IS_STR(args[1])) { + if (!mp_get_stream(args[0])->is_text && mp_obj_is_str(args[1])) { mp_raise_ValueError(translate("string not supported; use bytes or bytearray")); } size_t max_len = (size_t)-1; diff --git a/py/stream.h b/py/stream.h index 3aa0245be1..adfa190b13 100644 --- a/py/stream.h +++ b/py/stream.h @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2016 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/py/vm.c b/py/vm.c index 615a550304..17ac860e6e 100644 --- a/py/vm.c +++ b/py/vm.c @@ -3,8 +3,8 @@ * * The MIT License (MIT) * - * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * SPDX-FileCopyrightText: Copyright (c) 2013-2019 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014-2015 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -102,13 +102,11 @@ DECODE_ULABEL; /* except labels are always forward */ \ ++exc_sp; \ exc_sp->handler = ip + ulab; \ - exc_sp->val_sp = MP_TAGPTR_MAKE(sp, ((with_or_finally) << 1) | currently_in_except_block); \ + exc_sp->val_sp = MP_TAGPTR_MAKE(sp, ((with_or_finally) << 1)); \ exc_sp->prev_exc = NULL; \ - currently_in_except_block = 0; /* in a try block now */ \ } while (0) #define POP_EXC_BLOCK() \ - currently_in_except_block = MP_TAGPTR_TAG0(exc_sp->val_sp); /* restore previous state */ \ exc_sp--; /* pop back to previous exception handler */ \ CLEAR_SYS_EXC_INFO() /* just clear sys.exc_info(), not compliant, but it shouldn't be used in 1st place */ @@ -129,26 +127,16 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st #endif #if MICROPY_OPT_COMPUTED_GOTO #include "py/vmentrytable.h" - #if MICROPY_OPT_COMPUTED_GOTO_SAVE_SPACE - #define ONE_TRUE_DISPATCH() one_true_dispatch : do { \ - TRACE(ip); \ - MARK_EXC_IP_GLOBAL(); \ - goto *(void *)((char *) && entry_MP_BC_LOAD_CONST_FALSE + entry_table[*ip++]); \ -} while (0) - #define DISPATCH() do { goto one_true_dispatch; } while (0) - #else #define DISPATCH() do { \ TRACE(ip); \ MARK_EXC_IP_GLOBAL(); \ goto *entry_table[*ip++]; \ } while (0) - #define ONE_TRUE_DISPATCH() DISPATCH() - #endif #define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check #define ENTRY(op) entry_##op #define ENTRY_DEFAULT entry_default #else - #define DISPATCH() break + #define DISPATCH() goto dispatch_loop #define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check #define ENTRY(op) case op #define ENTRY_DEFAULT default @@ -174,7 +162,6 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st } // variables that are visible to the exception handler (declared volatile) - volatile bool currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack #if MICROPY_PY_THREAD_GIL && MICROPY_PY_THREAD_GIL_VM_DIVISOR @@ -210,7 +197,7 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st for (;;) { dispatch_loop: #if MICROPY_OPT_COMPUTED_GOTO - ONE_TRUE_DISPATCH(); + DISPATCH(); #else TRACE(ip); MARK_EXC_IP_GLOBAL(); @@ -617,7 +604,7 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st sp -= 2; mp_call_method_n_kw(3, 0, sp); SET_TOP(mp_const_none); - } else if (MP_OBJ_IS_SMALL_INT(TOP())) { + } else if (mp_obj_is_small_int(TOP())) { // Getting here there are two distinct cases: // - unwind return, stack: (..., __exit__, ctx_mgr, ret_val, SMALL_INT(-1)) // - unwind jump, stack: (..., __exit__, ctx_mgr, dest_ip, SMALL_INT(num_exc)) @@ -646,8 +633,6 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st // replacing it with None, which signals END_FINALLY to just // execute the finally handler normally. SET_TOP(mp_const_none); - assert(exc_sp >= exc_stack); - POP_EXC_BLOCK(); } else { // We need to re-raise the exception. We pop __exit__ handler // by copying the exception instance down to the new top-of-stack. @@ -667,7 +652,7 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st while ((unum & 0x7f) > 0) { unum -= 1; assert(exc_sp >= exc_stack); - if (MP_TAGPTR_TAG1(exc_sp->val_sp)) { + if (MP_TAGPTR_TAG1(exc_sp->val_sp) && exc_sp->handler > ip) { // Getting here the stack looks like: // (..., X, dest_ip) // where X is pointed to by exc_sp->val_sp and in the case @@ -693,7 +678,6 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st DISPATCH_WITH_PEND_EXC_CHECK(); } - // matched against: POP_BLOCK or POP_EXCEPT (anything else?) ENTRY(MP_BC_SETUP_EXCEPT) : ENTRY(MP_BC_SETUP_FINALLY) : { MARK_EXC_IP_SELECTIVE(); @@ -711,8 +695,10 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st // if TOS is an integer, finishes coroutine and returns control to caller // if TOS is an exception, reraises the exception if (TOP() == mp_const_none) { + assert(exc_sp >= exc_stack); + POP_EXC_BLOCK(); sp--; - } else if (MP_OBJ_IS_SMALL_INT(TOP())) { + } else if (mp_obj_is_small_int(TOP())) { // We finished "finally" coroutine and now dispatch back // to our caller, based on TOS value mp_int_t cause = MP_OBJ_SMALL_INT_VALUE(POP()); @@ -774,19 +760,13 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st DISPATCH_WITH_PEND_EXC_CHECK(); } - // matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH - ENTRY(MP_BC_POP_BLOCK) : - // we are exiting an exception handler, so pop the last one of the exception-stack + ENTRY(MP_BC_POP_EXCEPT_JUMP) : { assert(exc_sp >= exc_stack); - POP_EXC_BLOCK(); - DISPATCH(); - - // matched against: SETUP_EXCEPT - ENTRY(MP_BC_POP_EXCEPT) : - assert(exc_sp >= exc_stack); - assert(currently_in_except_block); - POP_EXC_BLOCK(); - DISPATCH(); + POP_EXC_BLOCK(); + DECODE_ULABEL; + ip += ulab; + DISPATCH_WITH_PEND_EXC_CHECK(); + } ENTRY(MP_BC_BUILD_TUPLE) : { MARK_EXC_IP_SELECTIVE(); @@ -919,7 +899,7 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); #if !MICROPY_ENABLE_PYSTACK if (new_state == NULL) { @@ -955,7 +935,7 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(false, unum, sp, &out_args); @@ -998,7 +978,7 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); size_t n_args = unum & 0xff; size_t n_kw = (unum >> 8) & 0xff; @@ -1038,7 +1018,7 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(true, unum, sp, &out_args); @@ -1076,7 +1056,7 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st unwind_return: // Search for and execute finally handlers that aren't already active while (exc_sp >= exc_stack) { - if (!currently_in_except_block && MP_TAGPTR_TAG1(exc_sp->val_sp)) { + if (MP_TAGPTR_TAG1(exc_sp->val_sp) && exc_sp->handler > ip) { // Found a finally handler that isn't active. // Getting here the stack looks like: // (..., X, [iter0, iter1, ...,] ret_val) @@ -1129,7 +1109,7 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st mp_uint_t unum = *ip; mp_obj_t obj; if (unum == 2) { - mp_warning("exception chaining not supported"); + mp_warning(NULL, "exception chaining not supported"); // ignore (pop) "from" argument sp--; } @@ -1158,12 +1138,12 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st nlr_pop(); code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); return MP_VM_RETURN_YIELD; ENTRY(MP_BC_YIELD_FROM) : { MARK_EXC_IP_SELECTIVE(); -// #define EXC_MATCH(exc, type) MP_OBJ_IS_TYPE(exc, type) +// #define EXC_MATCH(exc, type) mp_obj_is_type(exc, type) #define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type) #define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { mp_obj_t raise_t = mp_make_raise_obj(t); RAISE(raise_t); \ } @@ -1433,7 +1413,8 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st mp_obj_exception_add_traceback(MP_OBJ_FROM_PTR(nlr.ret_val), source_file, source_line, block_name); } - while (currently_in_except_block) { + while (exc_sp >= exc_stack && exc_sp->handler <= code_state->ip) { + // nested exception assert(exc_sp >= exc_stack); @@ -1446,9 +1427,6 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st } if (exc_sp >= exc_stack) { - // set flag to indicate that we are now handling an exception - currently_in_except_block = 1; - // catch exception and pass to byte code code_state->ip = exc_sp->handler; mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp); @@ -1474,7 +1452,6 @@ mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t * code_st fastn = &code_state->state[n_state - 1]; exc_stack = (mp_exc_stack_t *)(code_state->state + n_state); // variables that are visible to the exception handler (declared volatile) - currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack goto unwind_loop; diff --git a/py/vmentrytable.h b/py/vmentrytable.h index 0f6c5e96d3..ce88d3a789 100644 --- a/py/vmentrytable.h +++ b/py/vmentrytable.h @@ -86,8 +86,7 @@ static entry_table_type const PLACE_IN_DTCM_DATA(entry_table[256]) = { [MP_BC_GET_ITER] = COMPUTE_ENTRY(&& entry_MP_BC_GET_ITER), [MP_BC_GET_ITER_STACK] = COMPUTE_ENTRY(&& entry_MP_BC_GET_ITER_STACK), [MP_BC_FOR_ITER] = COMPUTE_ENTRY(&& entry_MP_BC_FOR_ITER), - [MP_BC_POP_BLOCK] = COMPUTE_ENTRY(&& entry_MP_BC_POP_BLOCK), - [MP_BC_POP_EXCEPT] = COMPUTE_ENTRY(&& entry_MP_BC_POP_EXCEPT), + [MP_BC_POP_EXCEPT_JUMP] = COMPUTE_ENTRY(&& entry_MP_BC_POP_EXCEPT_JUMP), [MP_BC_BUILD_TUPLE] = COMPUTE_ENTRY(&& entry_MP_BC_BUILD_TUPLE), [MP_BC_BUILD_LIST] = COMPUTE_ENTRY(&& entry_MP_BC_BUILD_LIST), [MP_BC_BUILD_MAP] = COMPUTE_ENTRY(&& entry_MP_BC_BUILD_MAP), diff --git a/py/vstr.c b/py/vstr.c index 2b78fc5c83..acc957e778 100644 --- a/py/vstr.c +++ b/py/vstr.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/py/warning.c b/py/warning.c index d516eabddf..71a3ac59ab 100644 --- a/py/warning.c +++ b/py/warning.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * SPDX-FileCopyrightText: Copyright (c) 2014 Damien P. George + * SPDX-FileCopyrightText: Copyright (c) 2015-2018 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,10 +33,15 @@ #if MICROPY_WARNINGS -void mp_warning(const char *msg, ...) { +void mp_warning(const char *category, const char *msg, ...) { + if (category == NULL) { + category = "Warning"; + } + mp_print_str(MICROPY_ERROR_PRINTER, category); + mp_print_str(MICROPY_ERROR_PRINTER, ": "); + va_list args; va_start(args, msg); - mp_print_str(MICROPY_ERROR_PRINTER, "Warning: "); mp_vprintf(MICROPY_ERROR_PRINTER, msg, args); mp_print_str(MICROPY_ERROR_PRINTER, "\n"); va_end(args); @@ -43,7 +49,7 @@ void mp_warning(const char *msg, ...) { void mp_emitter_warning(pass_kind_t pass, const char *msg) { if (pass == MP_PASS_CODE_SIZE) { - mp_warning(msg, NULL); + mp_warning(NULL, msg); } } diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 5cacfa0691..c2f367e21f 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -96,14 +96,14 @@ STATIC mp_obj_t bleio_adapter_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); busio_uart_obj_t *uart = args[ARG_uart].u_obj; - if (!MP_OBJ_IS_TYPE(uart, &busio_uart_type)) { + if (!mp_obj_is_type(uart, &busio_uart_type)) { mp_raise_ValueError(translate("Expected a UART")); } digitalio_digitalinout_obj_t *rts = args[ARG_rts].u_obj; digitalio_digitalinout_obj_t *cts = args[ARG_cts].u_obj; - if (!MP_OBJ_IS_TYPE(rts, &digitalio_digitalinout_type) || - !MP_OBJ_IS_TYPE(cts, &digitalio_digitalinout_type)) { + if (!mp_obj_is_type(rts, &digitalio_digitalinout_type) || + !mp_obj_is_type(cts, &digitalio_digitalinout_type)) { mp_raise_ValueError(translate("Expected a DigitalInOut")); } @@ -431,7 +431,7 @@ STATIC mp_obj_t bleio_adapter_connect(mp_uint_t n_args, const mp_obj_t *pos_args mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - if (!MP_OBJ_IS_TYPE(args[ARG_address].u_obj, &bleio_address_type)) { + if (!mp_obj_is_type(args[ARG_address].u_obj, &bleio_address_type)) { mp_raise_TypeError(translate("Expected an Address")); } diff --git a/shared-bindings/_bleio/Address.c b/shared-bindings/_bleio/Address.c index 56e8a013ff..15d5d2bda3 100644 --- a/shared-bindings/_bleio/Address.c +++ b/shared-bindings/_bleio/Address.c @@ -136,7 +136,7 @@ STATIC mp_obj_t bleio_address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_o switch (op) { // Two Addresses are equal if their address bytes and address_type are equal case MP_BINARY_OP_EQUAL: - if (MP_OBJ_IS_TYPE(rhs_in, &bleio_address_type)) { + if (mp_obj_is_type(rhs_in, &bleio_address_type)) { bleio_address_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in); bleio_address_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in); return mp_obj_new_bool( diff --git a/shared-bindings/_bleio/Characteristic.c b/shared-bindings/_bleio/Characteristic.c index b69b71d0c9..35bb58d270 100644 --- a/shared-bindings/_bleio/Characteristic.c +++ b/shared-bindings/_bleio/Characteristic.c @@ -89,12 +89,12 @@ STATIC mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); const mp_obj_t service_obj = args[ARG_service].u_obj; - if (!MP_OBJ_IS_TYPE(service_obj, &bleio_service_type)) { + if (!mp_obj_is_type(service_obj, &bleio_service_type)) { mp_raise_TypeError(translate("Expected a Service")); } const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { + if (!mp_obj_is_type(uuid_obj, &bleio_uuid_type)) { mp_raise_TypeError(translate("Expected a UUID")); } diff --git a/shared-bindings/_bleio/CharacteristicBuffer.c b/shared-bindings/_bleio/CharacteristicBuffer.c index ddc0c42253..149c060ac2 100644 --- a/shared-bindings/_bleio/CharacteristicBuffer.c +++ b/shared-bindings/_bleio/CharacteristicBuffer.c @@ -80,7 +80,7 @@ STATIC mp_obj_t bleio_characteristic_buffer_make_new(const mp_obj_type_t *type, mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_buffer_size); } - if (!MP_OBJ_IS_TYPE(characteristic, &bleio_characteristic_type)) { + if (!mp_obj_is_type(characteristic, &bleio_characteristic_type)) { mp_raise_TypeError(translate("Expected a Characteristic")); } diff --git a/shared-bindings/_bleio/Descriptor.c b/shared-bindings/_bleio/Descriptor.c index 0eee9d7040..d79c9dbf31 100644 --- a/shared-bindings/_bleio/Descriptor.c +++ b/shared-bindings/_bleio/Descriptor.c @@ -85,12 +85,12 @@ STATIC mp_obj_t bleio_descriptor_add_to_characteristic(size_t n_args, const mp_o mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); const mp_obj_t characteristic_obj = args[ARG_characteristic].u_obj; - if (!MP_OBJ_IS_TYPE(characteristic_obj, &bleio_characteristic_type)) { + if (!mp_obj_is_type(characteristic_obj, &bleio_characteristic_type)) { mp_raise_TypeError(translate("Expected a Characteristic")); } const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { + if (!mp_obj_is_type(uuid_obj, &bleio_uuid_type)) { mp_raise_TypeError(translate("Expected a UUID")); } diff --git a/shared-bindings/_bleio/PacketBuffer.c b/shared-bindings/_bleio/PacketBuffer.c index b54a48230b..e9e9a64a7a 100644 --- a/shared-bindings/_bleio/PacketBuffer.c +++ b/shared-bindings/_bleio/PacketBuffer.c @@ -78,7 +78,7 @@ STATIC mp_obj_t bleio_packet_buffer_make_new(const mp_obj_type_t *type, size_t n mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_buffer_size); } - if (!MP_OBJ_IS_TYPE(characteristic, &bleio_characteristic_type)) { + if (!mp_obj_is_type(characteristic, &bleio_characteristic_type)) { mp_raise_TypeError(translate("Expected a Characteristic")); } diff --git a/shared-bindings/_bleio/ScanResults.c b/shared-bindings/_bleio/ScanResults.c index 9dca90c38a..7cf77b61aa 100644 --- a/shared-bindings/_bleio/ScanResults.c +++ b/shared-bindings/_bleio/ScanResults.c @@ -37,7 +37,7 @@ //| by a `_bleio.Adapter`: it has no user-visible constructor.""" //| STATIC mp_obj_t scanresults_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &bleio_scanresults_type)); + mp_check_self(mp_obj_is_type(self_in, &bleio_scanresults_type)); bleio_scanresults_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t scan_entry = common_hal_bleio_scanresults_next(self); if (scan_entry != mp_const_none) { diff --git a/shared-bindings/_bleio/Service.c b/shared-bindings/_bleio/Service.c index 6657c7e73f..913e70b28a 100644 --- a/shared-bindings/_bleio/Service.c +++ b/shared-bindings/_bleio/Service.c @@ -59,7 +59,7 @@ STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { + if (!mp_obj_is_type(uuid_obj, &bleio_uuid_type)) { mp_raise_TypeError(translate("Expected a UUID")); } diff --git a/shared-bindings/_bleio/UUID.c b/shared-bindings/_bleio/UUID.c index 2da54c1d5d..d4adbd3d83 100644 --- a/shared-bindings/_bleio/UUID.c +++ b/shared-bindings/_bleio/UUID.c @@ -60,7 +60,7 @@ STATIC mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, co const mp_obj_t value = pos_args[0]; uint8_t uuid128[16]; - if (MP_OBJ_IS_INT(value)) { + if (mp_obj_is_int(value)) { mp_int_t uuid16 = mp_obj_get_int(value); if (uuid16 < 0 || uuid16 > 0xffff) { mp_raise_ValueError(translate("UUID integer value must be 0-0xffff")); @@ -70,7 +70,7 @@ STATIC mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, co common_hal_bleio_uuid_construct(self, uuid16, NULL); } else { - if (MP_OBJ_IS_STR(value)) { + if (mp_obj_is_str(value)) { // 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' GET_STR_DATA_LEN(value, chars, len); char hex[32]; @@ -256,7 +256,7 @@ STATIC mp_obj_t bleio_uuid_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_ switch (op) { // Two UUID's are equal if their uuid16 values match or their uuid128 values match. case MP_BINARY_OP_EQUAL: - if (MP_OBJ_IS_TYPE(rhs_in, &bleio_uuid_type)) { + if (mp_obj_is_type(rhs_in, &bleio_uuid_type)) { if (common_hal_bleio_uuid_get_size(lhs_in) == 16 && common_hal_bleio_uuid_get_size(rhs_in) == 16) { return mp_obj_new_bool(common_hal_bleio_uuid_get_uuid16(lhs_in) == diff --git a/shared-bindings/_bleio/__init__.c b/shared-bindings/_bleio/__init__.c index b9d68abaed..06c9da7b85 100644 --- a/shared-bindings/_bleio/__init__.c +++ b/shared-bindings/_bleio/__init__.c @@ -117,7 +117,7 @@ STATIC mp_obj_dict_t bleio_module_globals; //| mp_obj_t bleio_set_adapter(mp_obj_t adapter_obj) { #if CIRCUITPY_BLEIO_HCI - if (adapter_obj != mp_const_none && !MP_OBJ_IS_TYPE(adapter_obj, &bleio_adapter_type)) { + if (adapter_obj != mp_const_none && !mp_obj_is_type(adapter_obj, &bleio_adapter_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), bleio_adapter_type.name); } diff --git a/shared-bindings/_pew/PewPew.c b/shared-bindings/_pew/PewPew.c index b98a124600..2441e3ba5e 100644 --- a/shared-bindings/_pew/PewPew.c +++ b/shared-bindings/_pew/PewPew.c @@ -92,7 +92,7 @@ STATIC mp_obj_t pewpew_make_new(const mp_obj_type_t *type, size_t n_args, } for (size_t i = 0; i < rows_size; ++i) { - if (!MP_OBJ_IS_TYPE(rows[i], &digitalio_digitalinout_type)) { + if (!mp_obj_is_type(rows[i], &digitalio_digitalinout_type)) { mp_raise_TypeError(translate("Row entry must be digitalio.DigitalInOut")); } digitalio_digitalinout_obj_t *pin = MP_OBJ_TO_PTR(rows[i]); @@ -102,7 +102,7 @@ STATIC mp_obj_t pewpew_make_new(const mp_obj_type_t *type, size_t n_args, } for (size_t i = 0; i < cols_size; ++i) { - if (!MP_OBJ_IS_TYPE(cols[i], &digitalio_digitalinout_type)) { + if (!mp_obj_is_type(cols[i], &digitalio_digitalinout_type)) { mp_raise_TypeError(translate("Column entry must be digitalio.DigitalInOut")); } digitalio_digitalinout_obj_t *pin = MP_OBJ_TO_PTR(cols[i]); @@ -111,7 +111,7 @@ STATIC mp_obj_t pewpew_make_new(const mp_obj_type_t *type, size_t n_args, } } - if (!MP_OBJ_IS_TYPE(args[ARG_buttons].u_obj, + if (!mp_obj_is_type(args[ARG_buttons].u_obj, &digitalio_digitalinout_type)) { mp_raise_TypeError(translate("buttons must be digitalio.DigitalInOut")); } diff --git a/shared-bindings/_pixelbuf/PixelBuf.c b/shared-bindings/_pixelbuf/PixelBuf.c index 22923e97d5..2597ca972b 100644 --- a/shared-bindings/_pixelbuf/PixelBuf.c +++ b/shared-bindings/_pixelbuf/PixelBuf.c @@ -120,7 +120,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_make_new(const mp_obj_type_t *type, size_t n_a } static void parse_byteorder(mp_obj_t byteorder_obj, pixelbuf_byteorder_details_t *parsed) { - if (!MP_OBJ_IS_STR(byteorder_obj)) { + if (!mp_obj_is_str(byteorder_obj)) { mp_raise_TypeError(translate("byteorder is not a string")); } @@ -306,7 +306,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp if (0) { #if MICROPY_PY_BUILTINS_SLICE - } else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { + } else if (mp_obj_is_type(index_in, &mp_type_slice)) { mp_bound_slice_t slice; size_t length = common_hal__pixelbuf_pixelbuf_get_len(self_in); diff --git a/shared-bindings/_pixelbuf/__init__.c b/shared-bindings/_pixelbuf/__init__.c index 5e87bacab1..4c1b138f36 100644 --- a/shared-bindings/_pixelbuf/__init__.c +++ b/shared-bindings/_pixelbuf/__init__.c @@ -51,7 +51,7 @@ //| STATIC mp_obj_t pixelbuf_colorwheel(mp_obj_t n) { - return MP_OBJ_NEW_SMALL_INT(colorwheel(MP_OBJ_IS_SMALL_INT(n) ? MP_OBJ_SMALL_INT_VALUE(n) : mp_obj_get_float(n))); + return MP_OBJ_NEW_SMALL_INT(colorwheel(mp_obj_is_small_int(n) ? MP_OBJ_SMALL_INT_VALUE(n) : mp_obj_get_float(n))); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pixelbuf_colorwheel_obj, pixelbuf_colorwheel); diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c index 0e3f08da59..2c286ca8de 100644 --- a/shared-bindings/_stage/__init__.c +++ b/shared-bindings/_stage/__init__.c @@ -77,7 +77,7 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { mp_obj_t native_display = mp_instance_cast_to_native_base(args[6], &displayio_display_type); - if (!MP_OBJ_IS_TYPE(native_display, &displayio_display_type)) { + if (!mp_obj_is_type(native_display, &displayio_display_type)) { mp_raise_TypeError(translate("argument num/types mismatch")); } displayio_display_obj_t *display = MP_OBJ_TO_PTR(native_display); diff --git a/shared-bindings/aesio/aes.c b/shared-bindings/aesio/aes.c index f021e9abc5..89c0177051 100644 --- a/shared-bindings/aesio/aes.c +++ b/shared-bindings/aesio/aes.c @@ -162,7 +162,7 @@ STATIC void validate_length(aesio_aes_obj_t *self, size_t src_length, //| STATIC mp_obj_t aesio_aes_encrypt_into(mp_obj_t aesio_obj, mp_obj_t src, mp_obj_t dest) { - if (!MP_OBJ_IS_TYPE(aesio_obj, &aesio_aes_type)) { + if (!mp_obj_is_type(aesio_obj, &aesio_aes_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), aesio_aes_type.name); } // Convert parameters into expected types. @@ -192,7 +192,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(aesio_aes_encrypt_into_obj, //| STATIC mp_obj_t aesio_aes_decrypt_into(mp_obj_t aesio_obj, mp_obj_t src, mp_obj_t dest) { - if (!MP_OBJ_IS_TYPE(aesio_obj, &aesio_aes_type)) { + if (!mp_obj_is_type(aesio_obj, &aesio_aes_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), aesio_aes_type.name); } // Convert parameters into expected types. @@ -214,7 +214,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(aesio_aes_decrypt_into_obj, aesio_aes_decrypt_into); STATIC mp_obj_t aesio_aes_get_mode(mp_obj_t aesio_obj) { - if (!MP_OBJ_IS_TYPE(aesio_obj, &aesio_aes_type)) { + if (!mp_obj_is_type(aesio_obj, &aesio_aes_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), aesio_aes_type.name); } aesio_aes_obj_t *self = MP_OBJ_TO_PTR(aesio_obj); @@ -223,7 +223,7 @@ STATIC mp_obj_t aesio_aes_get_mode(mp_obj_t aesio_obj) { MP_DEFINE_CONST_FUN_OBJ_1(aesio_aes_get_mode_obj, aesio_aes_get_mode); STATIC mp_obj_t aesio_aes_set_mode(mp_obj_t aesio_obj, mp_obj_t mode_obj) { - if (!MP_OBJ_IS_TYPE(aesio_obj, &aesio_aes_type)) { + if (!mp_obj_is_type(aesio_obj, &aesio_aes_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), aesio_aes_type.name); } aesio_aes_obj_t *self = MP_OBJ_TO_PTR(aesio_obj); diff --git a/shared-bindings/alarm/SleepMemory.c b/shared-bindings/alarm/SleepMemory.c index 9ca0ec0472..18226eb9db 100644 --- a/shared-bindings/alarm/SleepMemory.c +++ b/shared-bindings/alarm/SleepMemory.c @@ -104,7 +104,7 @@ STATIC mp_obj_t alarm_sleep_memory_subscr(mp_obj_t self_in, mp_obj_t index_in, m alarm_sleep_memory_obj_t *self = MP_OBJ_TO_PTR(self_in); if (0) { #if MICROPY_PY_BUILTINS_SLICE - } else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { + } else if (mp_obj_is_type(index_in, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(common_hal_alarm_sleep_memory_get_length(self), index_in, &slice)) { mp_raise_NotImplementedError(translate("only slices with step=1 (aka None) are supported")); @@ -114,10 +114,10 @@ STATIC mp_obj_t alarm_sleep_memory_subscr(mp_obj_t self_in, mp_obj_t index_in, m // Assign size_t src_len = slice.stop - slice.start; uint8_t *src_items; - if (MP_OBJ_IS_TYPE(value, &mp_type_array) || - MP_OBJ_IS_TYPE(value, &mp_type_bytearray) || - MP_OBJ_IS_TYPE(value, &mp_type_memoryview) || - MP_OBJ_IS_TYPE(value, &mp_type_bytes)) { + if (mp_obj_is_type(value, &mp_type_array) || + mp_obj_is_type(value, &mp_type_bytearray) || + mp_obj_is_type(value, &mp_type_memoryview) || + mp_obj_is_type(value, &mp_type_bytes)) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ); if (bufinfo.len != src_len) { diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c index 11b96ff240..74ec765ef4 100644 --- a/shared-bindings/alarm/__init__.c +++ b/shared-bindings/alarm/__init__.c @@ -72,9 +72,9 @@ void validate_objs_are_alarms(size_t n_args, const mp_obj_t *objs) { for (size_t i = 0; i < n_args; i++) { - if (MP_OBJ_IS_TYPE(objs[i], &alarm_pin_pinalarm_type) || - MP_OBJ_IS_TYPE(objs[i], &alarm_time_timealarm_type) || - MP_OBJ_IS_TYPE(objs[i], &alarm_touch_touchalarm_type)) { + if (mp_obj_is_type(objs[i], &alarm_pin_pinalarm_type) || + mp_obj_is_type(objs[i], &alarm_time_timealarm_type) || + mp_obj_is_type(objs[i], &alarm_touch_touchalarm_type)) { continue; } mp_raise_TypeError_varg(translate("Expected an alarm")); diff --git a/shared-bindings/audiobusio/PDMIn.c b/shared-bindings/audiobusio/PDMIn.c index 5a648e1651..4fc42c3412 100644 --- a/shared-bindings/audiobusio/PDMIn.c +++ b/shared-bindings/audiobusio/PDMIn.c @@ -188,13 +188,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiobusio_pdmin___exit___obj, 4, 4, STATIC mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destination, mp_obj_t destination_length) { audiobusio_pdmin_obj_t *self = MP_OBJ_TO_PTR(self_obj); check_for_deinit(self); - if (!MP_OBJ_IS_SMALL_INT(destination_length) || MP_OBJ_SMALL_INT_VALUE(destination_length) < 0) { + if (!mp_obj_is_small_int(destination_length) || MP_OBJ_SMALL_INT_VALUE(destination_length) < 0) { mp_raise_TypeError(translate("destination_length must be an int >= 0")); } uint32_t length = MP_OBJ_SMALL_INT_VALUE(destination_length); mp_buffer_info_t bufinfo; - if (MP_OBJ_IS_TYPE(destination, &mp_type_fileio)) { + if (mp_obj_is_type(destination, &mp_type_fileio)) { mp_raise_NotImplementedError(translate("Cannot record to a file")); } else if (mp_get_buffer(destination, &bufinfo, MP_BUFFER_WRITE)) { if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { diff --git a/shared-bindings/audiocore/WaveFile.c b/shared-bindings/audiocore/WaveFile.c index 5cf6deb2ed..5164b25491 100644 --- a/shared-bindings/audiocore/WaveFile.c +++ b/shared-bindings/audiocore/WaveFile.c @@ -74,7 +74,7 @@ STATIC mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_ar audioio_wavefile_obj_t *self = m_new_obj(audioio_wavefile_obj_t); self->base.type = &audioio_wavefile_type; - if (!MP_OBJ_IS_TYPE(args[0], &mp_type_fileio)) { + if (!mp_obj_is_type(args[0], &mp_type_fileio)) { mp_raise_TypeError(translate("file must be a file opened in byte mode")); } uint8_t *buffer = NULL; diff --git a/shared-bindings/audiomp3/MP3Decoder.c b/shared-bindings/audiomp3/MP3Decoder.c index bdbd14e9e0..28f71f17c7 100644 --- a/shared-bindings/audiomp3/MP3Decoder.c +++ b/shared-bindings/audiomp3/MP3Decoder.c @@ -72,7 +72,7 @@ STATIC mp_obj_t audiomp3_mp3file_make_new(const mp_obj_type_t *type, size_t n_ar audiomp3_mp3file_obj_t *self = m_new_obj(audiomp3_mp3file_obj_t); self->base.type = &audiomp3_mp3file_type; - if (!MP_OBJ_IS_TYPE(args[0], &mp_type_fileio)) { + if (!mp_obj_is_type(args[0], &mp_type_fileio)) { mp_raise_TypeError(translate("file must be a file opened in byte mode")); } uint8_t *buffer = NULL; @@ -137,7 +137,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_file_obj, audiomp3_mp3file_obj_ge STATIC mp_obj_t audiomp3_mp3file_obj_set_file(mp_obj_t self_in, mp_obj_t file) { audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - if (!MP_OBJ_IS_TYPE(file, &mp_type_fileio)) { + if (!mp_obj_is_type(file, &mp_type_fileio)) { mp_raise_TypeError(translate("file must be a file opened in byte mode")); } common_hal_audiomp3_mp3file_set_file(self, file); diff --git a/shared-bindings/bitmaptools/__init__.c b/shared-bindings/bitmaptools/__init__.c index 3d352e45c2..2a5195d1a4 100644 --- a/shared-bindings/bitmaptools/__init__.c +++ b/shared-bindings/bitmaptools/__init__.c @@ -50,7 +50,7 @@ STATIC void extract_tuple(mp_obj_t xy_tuple, int16_t *x, int16_t *y, int16_t x_d if (xy_tuple == mp_const_none) { *x = x_default; *y = y_default; - } else if (!MP_OBJ_IS_OBJ(xy_tuple)) { + } else if (!mp_obj_is_obj(xy_tuple)) { mp_raise_ValueError(translate("clip point must be (x,y) tuple")); } else { mp_obj_t *items; @@ -401,7 +401,7 @@ STATIC mp_obj_t bitmaptools_arrayblit(size_t n_args, const mp_obj_t *pos_args, m mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - if (!MP_OBJ_IS_TYPE(args[ARG_bitmap].u_obj, &displayio_bitmap_type)) { + if (!mp_obj_is_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type)) { mp_raise_TypeError(NULL); } displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj); @@ -471,12 +471,12 @@ STATIC mp_obj_t bitmaptools_readinto(size_t n_args, const mp_obj_t *pos_args, mp mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - if (!MP_OBJ_IS_TYPE(args[ARG_bitmap].u_obj, &displayio_bitmap_type)) { + if (!mp_obj_is_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type)) { mp_raise_TypeError(NULL); } displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj); - if (!MP_OBJ_IS_TYPE(args[ARG_file].u_obj, &mp_type_fileio)) { + if (!mp_obj_is_type(args[ARG_file].u_obj, &mp_type_fileio)) { mp_raise_TypeError(NULL); } pyb_file_obj_t *file = MP_OBJ_TO_PTR(args[ARG_file].u_obj); diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index e64f17b145..9bffdf7656 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -424,7 +424,7 @@ const mp_obj_type_t busio_spi_type = { }; busio_spi_obj_t *validate_obj_is_spi_bus(mp_obj_t obj) { - if (!MP_OBJ_IS_TYPE(obj, &busio_spi_type)) { + if (!mp_obj_is_type(obj, &busio_spi_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), busio_spi_type.name); } return MP_OBJ_TO_PTR(obj); diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c index 0874bed550..ca88a5a74b 100644 --- a/shared-bindings/digitalio/DigitalInOut.c +++ b/shared-bindings/digitalio/DigitalInOut.c @@ -381,7 +381,7 @@ const mp_obj_type_t digitalio_digitalinout_type = { // Helper for validating digitalio.DigitalInOut arguments digitalio_digitalinout_obj_t *assert_digitalinout(mp_obj_t obj) { - if (!MP_OBJ_IS_TYPE(obj, &digitalio_digitalinout_type)) { + if (!mp_obj_is_type(obj, &digitalio_digitalinout_type)) { mp_raise_TypeError(translate("argument num/types mismatch")); } digitalio_digitalinout_obj_t *pin = MP_OBJ_TO_PTR(obj); diff --git a/shared-bindings/displayio/Bitmap.c b/shared-bindings/displayio/Bitmap.c index 900428b6e4..058b8db670 100644 --- a/shared-bindings/displayio/Bitmap.c +++ b/shared-bindings/displayio/Bitmap.c @@ -150,7 +150,7 @@ STATIC mp_obj_t bitmap_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t val displayio_bitmap_t *self = MP_OBJ_TO_PTR(self_in); - if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) { + if (mp_obj_is_type(index_obj, &mp_type_slice)) { // TODO(tannewt): Implement subscr after slices support start, stop and step tuples. mp_raise_NotImplementedError(translate("Slices not supported")); return mp_const_none; @@ -158,7 +158,7 @@ STATIC mp_obj_t bitmap_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t val uint16_t x = 0; uint16_t y = 0; - if (MP_OBJ_IS_SMALL_INT(index_obj)) { + if (mp_obj_is_small_int(index_obj)) { mp_int_t i = MP_OBJ_SMALL_INT_VALUE(index_obj); uint16_t width = common_hal_displayio_bitmap_get_width(self); x = i % width; diff --git a/shared-bindings/displayio/Group.c b/shared-bindings/displayio/Group.c index 75e210db89..0eed34d574 100644 --- a/shared-bindings/displayio/Group.c +++ b/shared-bindings/displayio/Group.c @@ -309,7 +309,7 @@ STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) { STATIC mp_obj_t group_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value) { displayio_group_t *self = native_group(self_in); - if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) { + if (mp_obj_is_type(index_obj, &mp_type_slice)) { mp_raise_NotImplementedError(translate("Slices not supported")); } else { size_t index = mp_get_index(&displayio_group_type, common_hal_displayio_group_get_len(self), index_obj, false); diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c index ae0948b879..d304374664 100644 --- a/shared-bindings/displayio/I2CDisplay.c +++ b/shared-bindings/displayio/I2CDisplay.c @@ -98,7 +98,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(displayio_i2cdisplay_reset_obj, displayio_i2cdisplay_o //| STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_obj_t data_obj) { mp_int_t command_int = MP_OBJ_SMALL_INT_VALUE(command_obj); - if (!MP_OBJ_IS_SMALL_INT(command_obj) || command_int > 255 || command_int < 0) { + if (!mp_obj_is_small_int(command_obj) || command_int > 255 || command_int < 0) { mp_raise_ValueError(translate("Command must be an int between 0 and 255")); } uint8_t command = command_int; diff --git a/shared-bindings/displayio/OnDiskBitmap.c b/shared-bindings/displayio/OnDiskBitmap.c index e41f54edfb..71591868d4 100644 --- a/shared-bindings/displayio/OnDiskBitmap.c +++ b/shared-bindings/displayio/OnDiskBitmap.c @@ -78,7 +78,7 @@ STATIC mp_obj_t displayio_ondiskbitmap_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_arg_check_num(n_args, kw_args, 1, 1, false); - if (!MP_OBJ_IS_TYPE(pos_args[0], &mp_type_fileio)) { + if (!mp_obj_is_type(pos_args[0], &mp_type_fileio)) { mp_raise_TypeError(translate("file must be a file opened in byte mode")); } diff --git a/shared-bindings/displayio/Palette.c b/shared-bindings/displayio/Palette.c index dc71c0560c..eeb0db4736 100644 --- a/shared-bindings/displayio/Palette.c +++ b/shared-bindings/displayio/Palette.c @@ -109,7 +109,7 @@ STATIC mp_obj_t palette_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t val return MP_OBJ_NULL; // op not supported } // Slicing not supported. Use a duplicate Palette to swap multiple colors atomically. - if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { + if (mp_obj_is_type(index_in, &mp_type_slice)) { return MP_OBJ_NULL; } displayio_palette_t *self = MP_OBJ_TO_PTR(self_in); @@ -120,8 +120,8 @@ STATIC mp_obj_t palette_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t val } // Convert a tuple or list to a bytearray. - if (MP_OBJ_IS_TYPE(value, &mp_type_tuple) || - MP_OBJ_IS_TYPE(value, &mp_type_list)) { + if (mp_obj_is_type(value, &mp_type_tuple) || + mp_obj_is_type(value, &mp_type_list)) { value = mp_type_bytes.make_new(&mp_type_bytes, 1, &value, NULL); } diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c index 084628328d..efa64dddf4 100644 --- a/shared-bindings/displayio/ParallelBus.c +++ b/shared-bindings/displayio/ParallelBus.c @@ -110,7 +110,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(displayio_parallelbus_reset_obj, displayio_parallelbus //| STATIC mp_obj_t displayio_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_obj_t data_obj) { mp_int_t command_int = MP_OBJ_SMALL_INT_VALUE(command_obj); - if (!MP_OBJ_IS_SMALL_INT(command_obj) || command_int > 255 || command_int < 0) { + if (!mp_obj_is_small_int(command_obj) || command_int > 255 || command_int < 0) { mp_raise_ValueError(translate("Command must be an int between 0 and 255")); } uint8_t command = command_int; diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c index dee0d7a686..fbacd361af 100644 --- a/shared-bindings/displayio/TileGrid.c +++ b/shared-bindings/displayio/TileGrid.c @@ -90,12 +90,12 @@ STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_ displayio_shape_t *bmp = MP_OBJ_TO_PTR(native); bitmap_width = bmp->width; bitmap_height = bmp->height; - } else if (MP_OBJ_IS_TYPE(bitmap, &displayio_bitmap_type)) { + } else if (mp_obj_is_type(bitmap, &displayio_bitmap_type)) { displayio_bitmap_t *bmp = MP_OBJ_TO_PTR(bitmap); native = bitmap; bitmap_width = bmp->width; bitmap_height = bmp->height; - } else if (MP_OBJ_IS_TYPE(bitmap, &displayio_ondiskbitmap_type)) { + } else if (mp_obj_is_type(bitmap, &displayio_ondiskbitmap_type)) { displayio_ondiskbitmap_t *bmp = MP_OBJ_TO_PTR(bitmap); native = bitmap; bitmap_width = bmp->width; @@ -104,8 +104,8 @@ STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_ mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_bitmap); } mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj; - if (!MP_OBJ_IS_TYPE(pixel_shader, &displayio_colorconverter_type) && - !MP_OBJ_IS_TYPE(pixel_shader, &displayio_palette_type)) { + if (!mp_obj_is_type(pixel_shader, &displayio_colorconverter_type) && + !mp_obj_is_type(pixel_shader, &displayio_palette_type)) { mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_pixel_shader); } uint16_t tile_width = args[ARG_tile_width].u_int; @@ -300,7 +300,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_pixel_shader_obj, displayio_til STATIC mp_obj_t displayio_tilegrid_obj_set_pixel_shader(mp_obj_t self_in, mp_obj_t pixel_shader) { displayio_tilegrid_t *self = native_tilegrid(self_in); - if (!MP_OBJ_IS_TYPE(pixel_shader, &displayio_palette_type) && !MP_OBJ_IS_TYPE(pixel_shader, &displayio_colorconverter_type)) { + if (!mp_obj_is_type(pixel_shader, &displayio_palette_type) && !mp_obj_is_type(pixel_shader, &displayio_colorconverter_type)) { mp_raise_TypeError(translate("pixel_shader must be displayio.Palette or displayio.ColorConverter")); } @@ -343,12 +343,12 @@ STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t v displayio_tilegrid_t *self = native_tilegrid(self_in); - if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) { + if (mp_obj_is_type(index_obj, &mp_type_slice)) { mp_raise_NotImplementedError(translate("Slices not supported")); } else { uint16_t x = 0; uint16_t y = 0; - if (MP_OBJ_IS_SMALL_INT(index_obj)) { + if (mp_obj_is_small_int(index_obj)) { mp_int_t i = MP_OBJ_SMALL_INT_VALUE(index_obj); uint16_t width = common_hal_displayio_tilegrid_get_width(self); x = i % width; diff --git a/shared-bindings/gamepad/GamePad.c b/shared-bindings/gamepad/GamePad.c index 367f1ccce4..0776839939 100644 --- a/shared-bindings/gamepad/GamePad.c +++ b/shared-bindings/gamepad/GamePad.c @@ -111,7 +111,7 @@ STATIC mp_obj_t gamepad_make_new(const mp_obj_type_t *type, size_t n_args, } gamepad_obj_t *gamepad_singleton = MP_STATE_VM(gamepad_singleton); if (!gamepad_singleton || - !MP_OBJ_IS_TYPE(MP_OBJ_FROM_PTR(gamepad_singleton), &gamepad_type)) { + !mp_obj_is_type(MP_OBJ_FROM_PTR(gamepad_singleton), &gamepad_type)) { gamepad_singleton = m_new_ll_obj(gamepad_obj_t); gamepad_singleton->base.type = &gamepad_type; if (!MP_STATE_VM(gamepad_singleton)) { diff --git a/shared-bindings/gamepadshift/GamePadShift.c b/shared-bindings/gamepadshift/GamePadShift.c index 18f9876b77..17dbb63053 100644 --- a/shared-bindings/gamepadshift/GamePadShift.c +++ b/shared-bindings/gamepadshift/GamePadShift.c @@ -69,7 +69,7 @@ STATIC mp_obj_t gamepadshift_make_new(const mp_obj_type_t *type, size_t n_args, gamepadshift_obj_t *gamepad_singleton = MP_STATE_VM(gamepad_singleton); if (!gamepad_singleton || - !MP_OBJ_IS_TYPE(MP_OBJ_FROM_PTR(gamepad_singleton), + !mp_obj_is_type(MP_OBJ_FROM_PTR(gamepad_singleton), &gamepadshift_type)) { gamepad_singleton = m_new_ll_obj(gamepadshift_obj_t); gamepad_singleton->base.type = &gamepadshift_type; diff --git a/shared-bindings/gnss/GNSS.c b/shared-bindings/gnss/GNSS.c index a3563b7fd6..2578e9fdca 100644 --- a/shared-bindings/gnss/GNSS.c +++ b/shared-bindings/gnss/GNSS.c @@ -48,14 +48,14 @@ STATIC mp_obj_t gnss_make_new(const mp_obj_type_t *type, size_t n_args, const mp mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); unsigned long selection = 0; - if (MP_OBJ_IS_TYPE(args[ARG_system].u_obj, &gnss_satellitesystem_type)) { + if (mp_obj_is_type(args[ARG_system].u_obj, &gnss_satellitesystem_type)) { selection |= gnss_satellitesystem_obj_to_type(args[ARG_system].u_obj); - } else if (MP_OBJ_IS_TYPE(args[ARG_system].u_obj, &mp_type_list)) { + } else if (mp_obj_is_type(args[ARG_system].u_obj, &mp_type_list)) { size_t systems_size = 0; mp_obj_t *systems; mp_obj_list_get(args[ARG_system].u_obj, &systems_size, &systems); for (size_t i = 0; i < systems_size; ++i) { - if (!MP_OBJ_IS_TYPE(systems[i], &gnss_satellitesystem_type)) { + if (!mp_obj_is_type(systems[i], &gnss_satellitesystem_type)) { mp_raise_TypeError(translate("System entry must be gnss.SatelliteSystem")); } selection |= gnss_satellitesystem_obj_to_type(systems[i]); diff --git a/shared-bindings/i2cperipheral/I2CPeripheral.c b/shared-bindings/i2cperipheral/I2CPeripheral.c index 9192d61ec5..ac136d7e18 100644 --- a/shared-bindings/i2cperipheral/I2CPeripheral.c +++ b/shared-bindings/i2cperipheral/I2CPeripheral.c @@ -108,7 +108,7 @@ STATIC mp_obj_t i2cperipheral_i2c_peripheral_make_new(const mp_obj_type_t *type, //| ... //| STATIC mp_obj_t i2cperipheral_i2c_peripheral_obj_deinit(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_type)); + mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_type)); i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_i2cperipheral_i2c_peripheral_deinit(self); return mp_const_none; @@ -127,7 +127,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(i2cperipheral_i2c_peripheral_deinit_obj, i2cperipheral //| ... //| STATIC mp_obj_t i2cperipheral_i2c_peripheral_obj___exit__(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_type)); + mp_check_self(mp_obj_is_type(args[0], &i2cperipheral_i2c_peripheral_type)); i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(args[0]); common_hal_i2cperipheral_i2c_peripheral_deinit(self); return mp_const_none; @@ -142,7 +142,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral___exit__ //| :rtype: ~i2cperipheral.I2CPeripheralRequest""" //| STATIC mp_obj_t i2cperipheral_i2c_peripheral_request(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &i2cperipheral_i2c_peripheral_type)); + mp_check_self(mp_obj_is_type(pos_args[0], &i2cperipheral_i2c_peripheral_type)); i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); if (common_hal_i2cperipheral_i2c_peripheral_deinited(self)) { raise_deinited_error(); @@ -253,7 +253,7 @@ STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_make_new(const mp_obj_type_ //| ... //| STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_obj___exit__(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_request_type)); + mp_check_self(mp_obj_is_type(args[0], &i2cperipheral_i2c_peripheral_request_type)); i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(args[0]); common_hal_i2cperipheral_i2c_peripheral_close(self->peripheral); return mp_const_none; @@ -264,7 +264,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral_request_ //| """The I2C address of the request.""" //| STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_address(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_request_type)); i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_int(self->address); } @@ -274,7 +274,7 @@ MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_address_obj, i2cpe //| """The I2C main controller is reading from this peripheral.""" //| STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_is_read(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_request_type)); i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_bool(self->is_read); } @@ -284,7 +284,7 @@ MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_is_read_obj, i2cpe //| """Is Repeated Start Condition.""" //| STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_is_restart(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_request_type)); i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_bool(self->is_restart); } @@ -300,7 +300,7 @@ MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_is_restart_obj, i2 //| ... //| STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &i2cperipheral_i2c_peripheral_request_type)); + mp_check_self(mp_obj_is_type(pos_args[0], &i2cperipheral_i2c_peripheral_request_type)); i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); enum { ARG_n, ARG_ack }; static const mp_arg_t allowed_args[] = { @@ -358,7 +358,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(i2cperipheral_i2c_peripheral_request_read_obj, 1, i2c //| ... //| STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_write(mp_obj_t self_in, mp_obj_t buf_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_request_type)); i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!self->is_read) { @@ -392,7 +392,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(i2cperipheral_i2c_peripheral_request_write_obj, //| ... //| STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_ack(uint n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_request_type)); + mp_check_self(mp_obj_is_type(args[0], &i2cperipheral_i2c_peripheral_request_type)); i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(args[0]); bool ack = (n_args == 1) ? true : mp_obj_is_true(args[1]); @@ -406,7 +406,7 @@ STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_ack(uint n_args, const mp_o MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral_request_ack_obj, 1, 2, i2cperipheral_i2c_peripheral_request_ack); STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_close(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_request_type)); i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_i2cperipheral_i2c_peripheral_close(self->peripheral); diff --git a/shared-bindings/ipaddress/IPv4Address.c b/shared-bindings/ipaddress/IPv4Address.c index 62a54560ef..cef4c7c4ce 100644 --- a/shared-bindings/ipaddress/IPv4Address.c +++ b/shared-bindings/ipaddress/IPv4Address.c @@ -61,7 +61,7 @@ STATIC mp_obj_t ipaddress_ipv4address_make_new(const mp_obj_type_t *type, size_t if (mp_obj_get_int_maybe(address, (mp_int_t *)&value)) { // We're done. buf = (uint8_t *)value; - } else if (MP_OBJ_IS_STR(address)) { + } else if (mp_obj_is_str(address)) { GET_STR_DATA_LEN(address, str_data, str_len); if (!ipaddress_parse_ipv4address((const char *)str_data, str_len, &value)) { mp_raise_ValueError(translate("Not a valid IP string")); @@ -134,7 +134,7 @@ STATIC mp_obj_t ipaddress_ipv4address_binary_op(mp_binary_op_t op, mp_obj_t lhs_ switch (op) { // Two Addresses are equal if their address bytes and address_type are equal case MP_BINARY_OP_EQUAL: - if (MP_OBJ_IS_TYPE(rhs_in, &ipaddress_ipv4address_type)) { + if (mp_obj_is_type(rhs_in, &ipaddress_ipv4address_type)) { ipaddress_ipv4address_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in); ipaddress_ipv4address_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in); return mp_obj_new_bool( diff --git a/shared-bindings/ipaddress/__init__.c b/shared-bindings/ipaddress/__init__.c index f768ec0ba6..ee12f5f0d2 100644 --- a/shared-bindings/ipaddress/__init__.c +++ b/shared-bindings/ipaddress/__init__.c @@ -85,7 +85,7 @@ STATIC mp_obj_t ipaddress_ip_address(mp_obj_t ip_in) { uint32_t value; if (mp_obj_get_int_maybe(ip_in, (mp_int_t *)&value)) { // We're done. - } else if (MP_OBJ_IS_STR(ip_in)) { + } else if (mp_obj_is_str(ip_in)) { GET_STR_DATA_LEN(ip_in, str_data, str_len); if (!ipaddress_parse_ipv4address((const char *)str_data, str_len, &value)) { mp_raise_ValueError(translate("Not a valid IP string")); diff --git a/shared-bindings/memorymonitor/AllocationSize.c b/shared-bindings/memorymonitor/AllocationSize.c index ea6a1db3ce..ca4690d4e6 100644 --- a/shared-bindings/memorymonitor/AllocationSize.c +++ b/shared-bindings/memorymonitor/AllocationSize.c @@ -150,7 +150,7 @@ STATIC mp_obj_t memorymonitor_allocationsize_subscr(mp_obj_t self_in, mp_obj_t i } else { memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) { + if (mp_obj_is_type(index_obj, &mp_type_slice)) { mp_raise_NotImplementedError(translate("Slices not supported")); } else { size_t index = mp_get_index(&memorymonitor_allocationsize_type, common_hal_memorymonitor_allocationsize_get_len(self), index_obj, false); diff --git a/shared-bindings/microcontroller/Pin.c b/shared-bindings/microcontroller/Pin.c index 289d890172..deba9bec6b 100644 --- a/shared-bindings/microcontroller/Pin.c +++ b/shared-bindings/microcontroller/Pin.c @@ -85,7 +85,7 @@ const mp_obj_type_t mcu_pin_type = { }; mcu_pin_obj_t *validate_obj_is_pin(mp_obj_t obj) { - if (!MP_OBJ_IS_TYPE(obj, &mcu_pin_type)) { + if (!mp_obj_is_type(obj, &mcu_pin_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), mcu_pin_type.name); } return MP_OBJ_TO_PTR(obj); diff --git a/shared-bindings/msgpack/__init__.c b/shared-bindings/msgpack/__init__.c index 0bd1d86e20..c4852f5427 100644 --- a/shared-bindings/msgpack/__init__.c +++ b/shared-bindings/msgpack/__init__.c @@ -31,7 +31,7 @@ #include "shared-module/msgpack/__init__.h" #include "shared-bindings/msgpack/ExtType.h" -#define MP_OBJ_IS_METH(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_bound_method)) +#define MP_OBJ_IS_METH(o) (mp_obj_is_obj(o) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_bound_method)) //| """Pack object in msgpack format //| @@ -105,7 +105,7 @@ STATIC mp_obj_t mod_msgpack_pack(size_t n_args, const mp_obj_t *pos_args, mp_map mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t handler = args[ARG_default].u_obj; - if (handler != mp_const_none && !MP_OBJ_IS_FUN(handler) && !MP_OBJ_IS_METH(handler)) { + if (handler != mp_const_none && !mp_obj_is_fun(handler) && !MP_OBJ_IS_METH(handler)) { mp_raise_ValueError(translate("default is not a function")); } @@ -138,7 +138,7 @@ STATIC mp_obj_t mod_msgpack_unpack(size_t n_args, const mp_obj_t *pos_args, mp_m mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t hook = args[ARG_ext_hook].u_obj; - if (hook != mp_const_none && !MP_OBJ_IS_FUN(hook) && !MP_OBJ_IS_METH(hook)) { + if (hook != mp_const_none && !mp_obj_is_fun(hook) && !MP_OBJ_IS_METH(hook)) { mp_raise_ValueError(translate("ext_hook is not a function")); } diff --git a/shared-bindings/neopixel_write/__init__.c b/shared-bindings/neopixel_write/__init__.c index da4f28a137..a1f01e506f 100644 --- a/shared-bindings/neopixel_write/__init__.c +++ b/shared-bindings/neopixel_write/__init__.c @@ -57,7 +57,7 @@ //| :param ~_typing.ReadableBuffer buf: The bytes to clock out. No assumption is made about color order""" //| ... STATIC mp_obj_t neopixel_write_neopixel_write_(mp_obj_t digitalinout_obj, mp_obj_t buf) { - if (!MP_OBJ_IS_TYPE(digitalinout_obj, &digitalio_digitalinout_type)) { + if (!mp_obj_is_type(digitalinout_obj, &digitalio_digitalinout_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), digitalio_digitalinout_type.name); } // Convert parameters into expected types. diff --git a/shared-bindings/nvm/ByteArray.c b/shared-bindings/nvm/ByteArray.c index 0a2ef3389f..c56e3b5cce 100644 --- a/shared-bindings/nvm/ByteArray.c +++ b/shared-bindings/nvm/ByteArray.c @@ -98,7 +98,7 @@ STATIC mp_obj_t nvm_bytearray_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj nvm_bytearray_obj_t *self = MP_OBJ_TO_PTR(self_in); if (0) { #if MICROPY_PY_BUILTINS_SLICE - } else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { + } else if (mp_obj_is_type(index_in, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(common_hal_nvm_bytearray_get_length(self), index_in, &slice)) { mp_raise_NotImplementedError(translate("only slices with step=1 (aka None) are supported")); @@ -108,10 +108,10 @@ STATIC mp_obj_t nvm_bytearray_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj // Assign size_t src_len = slice.stop - slice.start; uint8_t *src_items; - if (MP_OBJ_IS_TYPE(value, &mp_type_array) || - MP_OBJ_IS_TYPE(value, &mp_type_bytearray) || - MP_OBJ_IS_TYPE(value, &mp_type_memoryview) || - MP_OBJ_IS_TYPE(value, &mp_type_bytes)) { + if (mp_obj_is_type(value, &mp_type_array) || + mp_obj_is_type(value, &mp_type_bytearray) || + mp_obj_is_type(value, &mp_type_memoryview) || + mp_obj_is_type(value, &mp_type_bytes)) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ); if (bufinfo.len != src_len) { diff --git a/shared-bindings/ps2io/Ps2.c b/shared-bindings/ps2io/Ps2.c index dd6ca83fbe..c2d3c59de4 100644 --- a/shared-bindings/ps2io/Ps2.c +++ b/shared-bindings/ps2io/Ps2.c @@ -116,7 +116,7 @@ STATIC void check_for_deinit(ps2io_ps2_obj_t *self) { //| ... //| STATIC mp_obj_t ps2io_ps2_obj___exit__(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &ps2io_ps2_type)); + mp_check_self(mp_obj_is_type(args[0], &ps2io_ps2_type)); ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(args[0]); common_hal_ps2io_ps2_deinit(self); return mp_const_none; diff --git a/shared-bindings/pulseio/PulseIn.c b/shared-bindings/pulseio/PulseIn.c index 18a5d3f3e5..e502c933c7 100644 --- a/shared-bindings/pulseio/PulseIn.c +++ b/shared-bindings/pulseio/PulseIn.c @@ -276,7 +276,7 @@ STATIC mp_obj_t pulsein_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t va pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) { + if (mp_obj_is_type(index_obj, &mp_type_slice)) { mp_raise_NotImplementedError(translate("Slices not supported")); } else { size_t index = mp_get_index(&pulseio_pulsein_type, common_hal_pulseio_pulsein_get_len(self), index_obj, false); diff --git a/shared-bindings/pulseio/PulseOut.c b/shared-bindings/pulseio/PulseOut.c index 61614889fb..ccea353386 100644 --- a/shared-bindings/pulseio/PulseOut.c +++ b/shared-bindings/pulseio/PulseOut.c @@ -70,7 +70,7 @@ STATIC mp_obj_t pulseio_pulseout_make_new(const mp_obj_type_t *type, size_t n_ar self->base.type = &pulseio_pulseout_type; mp_obj_t carrier_obj = pos_args[0]; - if (MP_OBJ_IS_TYPE(carrier_obj, &pwmio_pwmout_type)) { + if (mp_obj_is_type(carrier_obj, &pwmio_pwmout_type)) { // Use a PWMOut Carrier mp_arg_check_num(n_args, kw_args, 1, 1, false); common_hal_pulseio_pulseout_construct(self, (pwmio_pwmout_obj_t *)MP_OBJ_TO_PTR(carrier_obj), NULL, 0, 0); diff --git a/shared-bindings/storage/__init__.c b/shared-bindings/storage/__init__.c index 7b436a4df1..8e8fe73beb 100644 --- a/shared-bindings/storage/__init__.c +++ b/shared-bindings/storage/__init__.c @@ -88,7 +88,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(storage_mount_obj, 2, storage_mount); //| ... //| mp_obj_t storage_umount(mp_obj_t mnt_in) { - if (MP_OBJ_IS_STR(mnt_in)) { + if (mp_obj_is_str(mnt_in)) { common_hal_storage_umount_path(mp_obj_str_get_str(mnt_in)); } else { common_hal_storage_umount_object(mnt_in); diff --git a/shared-bindings/synthio/__init__.c b/shared-bindings/synthio/__init__.c index d5165001fc..90055ff0e4 100644 --- a/shared-bindings/synthio/__init__.c +++ b/shared-bindings/synthio/__init__.c @@ -69,7 +69,7 @@ STATIC mp_obj_t synthio_from_file(size_t n_args, const mp_obj_t *pos_args, mp_ma }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - if (!MP_OBJ_IS_TYPE(args[ARG_file].u_obj, &mp_type_fileio)) { + if (!mp_obj_is_type(args[ARG_file].u_obj, &mp_type_fileio)) { mp_raise_TypeError(translate("file must be a file opened in byte mode")); } pyb_file_obj_t *file = MP_OBJ_TO_PTR(args[ARG_file].u_obj); diff --git a/shared-bindings/terminalio/Terminal.c b/shared-bindings/terminalio/Terminal.c index b1d3cce653..3432fc9e5c 100644 --- a/shared-bindings/terminalio/Terminal.c +++ b/shared-bindings/terminalio/Terminal.c @@ -56,12 +56,12 @@ STATIC mp_obj_t terminalio_terminal_make_new(const mp_obj_type_t *type, size_t n mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t tilegrid = args[ARG_tilegrid].u_obj; - if (!MP_OBJ_IS_TYPE(tilegrid, &displayio_tilegrid_type)) { + if (!mp_obj_is_type(tilegrid, &displayio_tilegrid_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), displayio_tilegrid_type.name); } mp_obj_t font = args[ARG_font].u_obj; - if (!MP_OBJ_IS_TYPE(font, &fontio_builtinfont_type)) { + if (!mp_obj_is_type(font, &fontio_builtinfont_type)) { mp_raise_TypeError_varg(translate("Expected a %q"), fontio_builtinfont_type.name); } terminalio_terminal_obj_t *self = m_new_obj(terminalio_terminal_obj_t); diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 87f766db26..3243fbc2d9 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -164,7 +164,7 @@ void struct_time_to_tm(mp_obj_t t, timeutils_struct_time_t *tm) { mp_obj_t *elems; size_t len; - if (!MP_OBJ_IS_TYPE(t, &mp_type_tuple) && !MP_OBJ_IS_TYPE(t, MP_OBJ_FROM_PTR(&struct_time_type_obj))) { + if (!mp_obj_is_type(t, &mp_type_tuple) && !mp_obj_is_type(t, MP_OBJ_FROM_PTR(&struct_time_type_obj))) { mp_raise_TypeError(translate("Tuple or struct_time argument required")); } @@ -273,7 +273,7 @@ STATIC mp_obj_t time_mktime(mp_obj_t t) { mp_obj_t *elem; size_t len; - if (!MP_OBJ_IS_TYPE(t, &mp_type_tuple) && !MP_OBJ_IS_TYPE(t, MP_OBJ_FROM_PTR(&struct_time_type_obj))) { + if (!mp_obj_is_type(t, &mp_type_tuple) && !mp_obj_is_type(t, MP_OBJ_FROM_PTR(&struct_time_type_obj))) { mp_raise_TypeError(translate("Tuple or struct_time argument required")); } diff --git a/shared-bindings/vectorio/Polygon.c b/shared-bindings/vectorio/Polygon.c index 737476c5ef..d6bc6087d1 100644 --- a/shared-bindings/vectorio/Polygon.c +++ b/shared-bindings/vectorio/Polygon.c @@ -29,7 +29,7 @@ static mp_obj_t vectorio_polygon_make_new(const mp_obj_type_t *type, size_t n_ar mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - if (!MP_OBJ_IS_TYPE(args[ARG_points_list].u_obj, &mp_type_list)) { + if (!mp_obj_is_type(args[ARG_points_list].u_obj, &mp_type_list)) { mp_raise_TypeError_varg(translate("%q list must be a list"), MP_QSTR_point); } diff --git a/shared-bindings/vectorio/VectorShape.c b/shared-bindings/vectorio/VectorShape.c index 7c7f467b09..859d025ada 100644 --- a/shared-bindings/vectorio/VectorShape.c +++ b/shared-bindings/vectorio/VectorShape.c @@ -41,8 +41,8 @@ STATIC mp_obj_t vectorio_vector_shape_make_new(const mp_obj_type_t *type, size_t mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj; - if (!MP_OBJ_IS_TYPE(pixel_shader, &displayio_colorconverter_type) && - !MP_OBJ_IS_TYPE(pixel_shader, &displayio_palette_type)) { + if (!mp_obj_is_type(pixel_shader, &displayio_colorconverter_type) && + !mp_obj_is_type(pixel_shader, &displayio_palette_type)) { mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_pixel_shader); } @@ -52,15 +52,15 @@ STATIC mp_obj_t vectorio_vector_shape_make_new(const mp_obj_type_t *type, size_t mp_obj_t shape = args[ARG_shape].u_obj; vectorio_ishape_t ishape; // Wire up shape functions - if (MP_OBJ_IS_TYPE(shape, &vectorio_polygon_type)) { + if (mp_obj_is_type(shape, &vectorio_polygon_type)) { ishape.shape = shape; ishape.get_area = &common_hal_vectorio_polygon_get_area; ishape.get_pixel = &common_hal_vectorio_polygon_get_pixel; - } else if (MP_OBJ_IS_TYPE(shape, &vectorio_rectangle_type)) { + } else if (mp_obj_is_type(shape, &vectorio_rectangle_type)) { ishape.shape = shape; ishape.get_area = &common_hal_vectorio_rectangle_get_area; ishape.get_pixel = &common_hal_vectorio_rectangle_get_pixel; - } else if (MP_OBJ_IS_TYPE(shape, &vectorio_circle_type)) { + } else if (mp_obj_is_type(shape, &vectorio_circle_type)) { ishape.shape = shape; ishape.get_area = &common_hal_vectorio_circle_get_area; ishape.get_pixel = &common_hal_vectorio_circle_get_pixel; @@ -80,10 +80,10 @@ STATIC mp_obj_t vectorio_vector_shape_make_new(const mp_obj_type_t *type, size_t .event = &common_hal_vectorio_vector_shape_set_dirty }; - if (MP_OBJ_IS_TYPE(shape, &vectorio_polygon_type)) { + if (mp_obj_is_type(shape, &vectorio_polygon_type)) { common_hal_vectorio_polygon_set_on_dirty(self->ishape.shape, on_dirty); - } else if (MP_OBJ_IS_TYPE(shape, &vectorio_rectangle_type)) { - } else if (MP_OBJ_IS_TYPE(shape, &vectorio_circle_type)) { + } else if (mp_obj_is_type(shape, &vectorio_rectangle_type)) { + } else if (mp_obj_is_type(shape, &vectorio_circle_type)) { common_hal_vectorio_circle_set_on_dirty(self->ishape.shape, on_dirty); } else { mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_shape); @@ -156,7 +156,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vectorio_vector_shape_get_pixel_shader_obj, vectorio_v STATIC mp_obj_t vectorio_vector_shape_obj_set_pixel_shader(mp_obj_t self_in, mp_obj_t pixel_shader) { vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(self_in); - if (!MP_OBJ_IS_TYPE(pixel_shader, &displayio_palette_type) && !MP_OBJ_IS_TYPE(pixel_shader, &displayio_colorconverter_type)) { + if (!mp_obj_is_type(pixel_shader, &displayio_palette_type) && !mp_obj_is_type(pixel_shader, &displayio_colorconverter_type)) { mp_raise_TypeError(translate("pixel_shader must be displayio.Palette or displayio.ColorConverter")); } diff --git a/shared-bindings/wifi/ScannedNetworks.c b/shared-bindings/wifi/ScannedNetworks.c index 9316faa45b..277679b8df 100644 --- a/shared-bindings/wifi/ScannedNetworks.c +++ b/shared-bindings/wifi/ScannedNetworks.c @@ -37,7 +37,7 @@ //| by a `wifi.Radio`: it has no user-visible constructor.""" //| STATIC mp_obj_t scannednetworks_iternext(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &wifi_scannednetworks_type)); + mp_check_self(mp_obj_is_type(self_in, &wifi_scannednetworks_type)); wifi_scannednetworks_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t network = common_hal_wifi_scannednetworks_next(self); if (network != mp_const_none) { diff --git a/shared-module/_pixelbuf/PixelBuf.c b/shared-module/_pixelbuf/PixelBuf.c index df160b1ffa..10f1b4ec5f 100644 --- a/shared-module/_pixelbuf/PixelBuf.c +++ b/shared-module/_pixelbuf/PixelBuf.c @@ -141,9 +141,9 @@ void common_hal__pixelbuf_pixelbuf_set_brightness(mp_obj_t self_in, mp_float_t b } uint8_t _pixelbuf_get_as_uint8(mp_obj_t obj) { - if (MP_OBJ_IS_SMALL_INT(obj)) { + if (mp_obj_is_small_int(obj)) { return MP_OBJ_SMALL_INT_VALUE(obj); - } else if (MP_OBJ_IS_INT(obj)) { + } else if (mp_obj_is_int(obj)) { return mp_obj_get_int_truncated(obj); } else if (mp_obj_is_float(obj)) { return (uint8_t)mp_obj_get_float(obj); @@ -162,8 +162,8 @@ void _pixelbuf_parse_color(pixelbuf_pixelbuf_obj_t *self, mp_obj_t color, uint8_ *w = 0; } - if (MP_OBJ_IS_INT(color) || mp_obj_is_float(color)) { - mp_int_t value = MP_OBJ_IS_INT(color) ? mp_obj_get_int_truncated(color) : mp_obj_get_float(color); + if (mp_obj_is_int(color) || mp_obj_is_float(color)) { + mp_int_t value = mp_obj_is_int(color) ? mp_obj_get_int_truncated(color) : mp_obj_get_float(color); *r = value >> 16 & 0xff; *g = (value >> 8) & 0xff; *b = value & 0xff; diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index a623a10de5..68436ba67f 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -449,20 +449,20 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c // We always want to read bitmap pixels by row first and then transpose into the destination // buffer because most bitmaps are row associated. - if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { + if (mp_obj_is_type(self->bitmap, &displayio_bitmap_type)) { input_pixel.pixel = common_hal_displayio_bitmap_get_pixel(self->bitmap, input_pixel.tile_x, input_pixel.tile_y); - } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) { + } else if (mp_obj_is_type(self->bitmap, &displayio_shape_type)) { input_pixel.pixel = common_hal_displayio_shape_get_pixel(self->bitmap, input_pixel.tile_x, input_pixel.tile_y); - } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) { + } else if (mp_obj_is_type(self->bitmap, &displayio_ondiskbitmap_type)) { input_pixel.pixel = common_hal_displayio_ondiskbitmap_get_pixel(self->bitmap, input_pixel.tile_x, input_pixel.tile_y); } output_pixel.opaque = true; if (self->pixel_shader == mp_const_none) { output_pixel.pixel = input_pixel.pixel; - } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type)) { + } else if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) { output_pixel.opaque = displayio_palette_get_color(self->pixel_shader, colorspace, input_pixel.pixel, &output_pixel.pixel); - } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) { + } else if (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type)) { displayio_colorconverter_convert(self->pixel_shader, colorspace, &input_pixel, &output_pixel); } if (!output_pixel.opaque) { @@ -512,16 +512,16 @@ void displayio_tilegrid_finish_refresh(displayio_tilegrid_t *self) { self->moved = false; self->full_change = false; self->partial_change = false; - if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type)) { + if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) { displayio_palette_finish_refresh(self->pixel_shader); - } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) { + } else if (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type)) { displayio_colorconverter_finish_refresh(self->pixel_shader); } - if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { + if (mp_obj_is_type(self->bitmap, &displayio_bitmap_type)) { displayio_bitmap_finish_refresh(self->bitmap); - } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) { + } else if (mp_obj_is_type(self->bitmap, &displayio_shape_type)) { displayio_shape_finish_refresh(self->bitmap); - } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) { + } else if (mp_obj_is_type(self->bitmap, &displayio_ondiskbitmap_type)) { // OnDiskBitmap changes will trigger a complete reload so no need to // track changes. } @@ -552,7 +552,7 @@ displayio_area_t *displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel } // If we have an in-memory bitmap, then check it for modifications. - if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { + if (mp_obj_is_type(self->bitmap, &displayio_bitmap_type)) { displayio_area_t *refresh_area = displayio_bitmap_get_refresh_areas(self->bitmap, tail); if (refresh_area != tail) { // Special case a TileGrid that shows a full bitmap and use its @@ -564,7 +564,7 @@ displayio_area_t *displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel self->full_change = true; } } - } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) { + } else if (mp_obj_is_type(self->bitmap, &displayio_shape_type)) { displayio_area_t *refresh_area = displayio_shape_get_refresh_areas(self->bitmap, tail); if (refresh_area != tail) { displayio_area_copy(refresh_area, &self->dirty_area); @@ -573,9 +573,9 @@ displayio_area_t *displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel } self->full_change = self->full_change || - (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type) && + (mp_obj_is_type(self->pixel_shader, &displayio_palette_type) && displayio_palette_needs_refresh(self->pixel_shader)) || - (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type) && + (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type) && displayio_colorconverter_needs_refresh(self->pixel_shader)); if (self->full_change || first_draw) { self->current_area.next = tail; diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index a0b3afa0ee..5b4b20b344 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -61,19 +61,19 @@ void displayio_display_core_construct(displayio_display_core_t *self, // (framebufferdisplay already validated its 'bus' is a buffer-protocol object) if (bus) { - if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { + if (mp_obj_is_type(bus, &displayio_parallelbus_type)) { self->bus_reset = common_hal_displayio_parallelbus_reset; self->bus_free = common_hal_displayio_parallelbus_bus_free; self->begin_transaction = common_hal_displayio_parallelbus_begin_transaction; self->send = common_hal_displayio_parallelbus_send; self->end_transaction = common_hal_displayio_parallelbus_end_transaction; - } else if (MP_OBJ_IS_TYPE(bus, &displayio_fourwire_type)) { + } else if (mp_obj_is_type(bus, &displayio_fourwire_type)) { self->bus_reset = common_hal_displayio_fourwire_reset; self->bus_free = common_hal_displayio_fourwire_bus_free; self->begin_transaction = common_hal_displayio_fourwire_begin_transaction; self->send = common_hal_displayio_fourwire_send; self->end_transaction = common_hal_displayio_fourwire_end_transaction; - } else if (MP_OBJ_IS_TYPE(bus, &displayio_i2cdisplay_type)) { + } else if (mp_obj_is_type(bus, &displayio_i2cdisplay_type)) { self->bus_reset = common_hal_displayio_i2cdisplay_reset; self->bus_free = common_hal_displayio_i2cdisplay_bus_free; self->begin_transaction = common_hal_displayio_i2cdisplay_begin_transaction; diff --git a/shared-module/gamepad/__init__.c b/shared-module/gamepad/__init__.c index c707886065..50e3edd9cf 100644 --- a/shared-module/gamepad/__init__.c +++ b/shared-module/gamepad/__init__.c @@ -39,7 +39,7 @@ void gamepad_tick(void) { uint8_t bit = 1; void *singleton = MP_STATE_VM(gamepad_singleton); - if (singleton == NULL || !MP_OBJ_IS_TYPE(MP_OBJ_FROM_PTR(singleton), &gamepad_type)) { + if (singleton == NULL || !mp_obj_is_type(MP_OBJ_FROM_PTR(singleton), &gamepad_type)) { return; } diff --git a/shared-module/gamepadshift/__init__.c b/shared-module/gamepadshift/__init__.c index 44cf3be812..eadd3034f6 100644 --- a/shared-module/gamepadshift/__init__.c +++ b/shared-module/gamepadshift/__init__.c @@ -31,7 +31,7 @@ void gamepadshift_tick(void) { void *singleton = MP_STATE_VM(gamepad_singleton); - if (singleton == NULL || !MP_OBJ_IS_TYPE(MP_OBJ_FROM_PTR(singleton), &gamepadshift_type)) { + if (singleton == NULL || !mp_obj_is_type(MP_OBJ_FROM_PTR(singleton), &gamepadshift_type)) { return; } diff --git a/shared-module/msgpack/__init__.c b/shared-module/msgpack/__init__.c index 61547fde3a..1e865385d7 100644 --- a/shared-module/msgpack/__init__.c +++ b/shared-module/msgpack/__init__.c @@ -174,7 +174,7 @@ STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur) { mp_map_t *map = &dict->map; for (size_t i = *cur; i < max; i++) { - if (MP_MAP_SLOT_IS_FILLED(map, i)) { + if (mp_map_slot_is_filled(map, i)) { *cur = i + 1; return &(map->table[i]); } @@ -263,35 +263,35 @@ STATIC void pack_dict(msgpack_stream_t *s, size_t len) { } STATIC void pack(mp_obj_t obj, msgpack_stream_t *s, mp_obj_t default_handler) { - if (MP_OBJ_IS_SMALL_INT(obj)) { + if (mp_obj_is_small_int(obj)) { // int int32_t x = MP_OBJ_SMALL_INT_VALUE(obj); pack_int(s, x); - } else if (MP_OBJ_IS_STR(obj)) { + } else if (mp_obj_is_str(obj)) { // string size_t len; const char *data = mp_obj_str_get_data(obj, &len); pack_str(s, data, len); - } else if (MP_OBJ_IS_TYPE(obj, &mod_msgpack_exttype_type)) { + } else if (mp_obj_is_type(obj, &mod_msgpack_exttype_type)) { mod_msgpack_extype_obj_t *ext = MP_OBJ_TO_PTR(obj); mp_buffer_info_t bufinfo; mp_get_buffer_raise(ext->data, &bufinfo, MP_BUFFER_READ); pack_ext(s, ext->code, bufinfo.buf, bufinfo.len); - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_tuple)) { + } else if (mp_obj_is_type(obj, &mp_type_tuple)) { // tuple mp_obj_tuple_t *self = MP_OBJ_TO_PTR(obj); pack_array(s, self->len); for (size_t i = 0; i < self->len; i++) { pack(self->items[i], s, default_handler); } - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_list)) { + } else if (mp_obj_is_type(obj, &mp_type_list)) { // list (layout differs from tuple) mp_obj_list_t *self = MP_OBJ_TO_PTR(obj); pack_array(s, self->len); for (size_t i = 0; i < self->len; i++) { pack(self->items[i], s, default_handler); } - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_dict)) { + } else if (mp_obj_is_type(obj, &mp_type_dict)) { // dict mp_obj_dict_t *self = MP_OBJ_TO_PTR(obj); pack_dict(s, self->map.used); diff --git a/shared-module/uheap/__init__.c b/shared-module/uheap/__init__.c index fd8e31ec0d..bff571ad8c 100644 --- a/shared-module/uheap/__init__.c +++ b/shared-module/uheap/__init__.c @@ -53,7 +53,7 @@ static void indent(uint8_t levels) { static uint32_t object_size(uint8_t indent_level, mp_obj_t obj); static uint32_t int_size(uint8_t indent_level, mp_obj_t obj) { - if (MP_OBJ_IS_SMALL_INT(obj)) { + if (mp_obj_is_small_int(obj)) { return 0; } if (!VERIFY_PTR(obj)) { @@ -68,7 +68,7 @@ static uint32_t int_size(uint8_t indent_level, mp_obj_t obj) { } static uint32_t string_size(uint8_t indent_level, mp_obj_t obj) { - if (MP_OBJ_IS_QSTR(obj)) { + if (mp_obj_is_qstr(obj)) { qstr qs = MP_OBJ_QSTR_VALUE(obj); const char *s = qstr_str(qs); if (!VERIFY_PTR(s)) { @@ -77,7 +77,7 @@ static uint32_t string_size(uint8_t indent_level, mp_obj_t obj) { indent(indent_level); mp_printf(&mp_plat_print, "%s\n", s); return 0; - } else { // MP_OBJ_IS_TYPE(o, &mp_type_str) + } else { // mp_obj_is_type(o, &mp_type_str) mp_obj_str_t *s = MP_OBJ_TO_PTR(obj); return gc_nbytes(s) + gc_nbytes(s->data); } @@ -120,17 +120,17 @@ static uint32_t dict_size(uint8_t indent_level, mp_obj_dict_t *dict) { static uint32_t function_size(uint8_t indent_level, mp_obj_t obj) { // indent(indent_level); // mp_print_str(&mp_plat_print, "function\n"); - if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_0)) { + if (mp_obj_is_type(obj, &mp_type_fun_builtin_0)) { return 0; - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_1)) { + } else if (mp_obj_is_type(obj, &mp_type_fun_builtin_1)) { return 0; - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_2)) { + } else if (mp_obj_is_type(obj, &mp_type_fun_builtin_2)) { return 0; - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_3)) { + } else if (mp_obj_is_type(obj, &mp_type_fun_builtin_3)) { return 0; - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_var)) { + } else if (mp_obj_is_type(obj, &mp_type_fun_builtin_var)) { return 0; - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_bc)) { + } else if (mp_obj_is_type(obj, &mp_type_fun_bc)) { mp_obj_fun_bc_t *fn = MP_OBJ_TO_PTR(obj); uint32_t total_size = gc_nbytes(fn) + gc_nbytes(fn->bytecode) + gc_nbytes(fn->const_table); #if MICROPY_DEBUG_PRINTERS @@ -140,15 +140,15 @@ static uint32_t function_size(uint8_t indent_level, mp_obj_t obj) { #endif return total_size; #if MICROPY_EMIT_NATIVE - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_native)) { + } else if (mp_obj_is_type(obj, &mp_type_fun_native)) { return 0; #endif #if MICROPY_EMIT_NATIVE - } else if (MP_OBJ_IS_TYPE(obj, &mp_obj_fun_viper_t)) { + } else if (mp_obj_is_type(obj, &mp_obj_fun_viper_t)) { return 0; #endif #if MICROPY_EMIT_THUMB - } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_asm)) { + } else if (mp_obj_is_type(obj, &mp_type_fun_asm)) { return 0; #endif } @@ -250,11 +250,11 @@ static uint32_t object_size(uint8_t indent_level, mp_obj_t obj) { if (obj == NULL) { return 0; } - if (MP_OBJ_IS_INT(obj)) { + if (mp_obj_is_int(obj)) { return int_size(indent_level, MP_OBJ_TO_PTR(obj)); - } else if (MP_OBJ_IS_STR(obj)) { + } else if (mp_obj_is_str(obj)) { return string_size(indent_level, MP_OBJ_TO_PTR(obj)); - } else if (MP_OBJ_IS_FUN(obj)) { + } else if (mp_obj_is_fun(obj)) { return function_size(indent_level, MP_OBJ_TO_PTR(obj)); } if (!VERIFY_PTR(obj)) { @@ -274,7 +274,7 @@ static uint32_t object_size(uint8_t indent_level, mp_obj_t obj) { return array_size(indent_level, MP_OBJ_TO_PTR(obj)); } else if (type == &mp_type_memoryview) { return memoryview_size(indent_level, MP_OBJ_TO_PTR(obj)); - } else if (MP_OBJ_IS_OBJ(obj) && VERIFY_PTR(type)) { + } else if (mp_obj_is_obj(obj) && VERIFY_PTR(type)) { return instance_size(indent_level, MP_OBJ_TO_PTR(obj)); } diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index efc40d0356..f0b6a725c1 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -217,9 +217,9 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ output_pixel.opaque = true; if (self->pixel_shader == mp_const_none) { output_pixel.pixel = input_pixel.pixel; - } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type)) { + } else if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) { output_pixel.opaque = displayio_palette_get_color(self->pixel_shader, colorspace, input_pixel.pixel, &output_pixel.pixel); - } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) { + } else if (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type)) { displayio_colorconverter_convert(self->pixel_shader, colorspace, &input_pixel, &output_pixel); } if (!output_pixel.opaque) { @@ -281,9 +281,9 @@ void vectorio_vector_shape_finish_refresh(vectorio_vector_shape_t *self) { self->ephemeral_dirty_area.next = NULL; VECTORIO_SHAPE_DEBUG("%p finish_refresh now:{(%3d,%3d), (%3d,%3d)}\n", self, self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); - if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type)) { + if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) { displayio_palette_finish_refresh(self->pixel_shader); - } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) { + } else if (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type)) { displayio_colorconverter_finish_refresh(self->pixel_shader); } } @@ -292,8 +292,8 @@ void vectorio_vector_shape_finish_refresh(vectorio_vector_shape_t *self) { // Assembles a singly linked list of dirty areas from all components on the display. displayio_area_t *vectorio_vector_shape_get_refresh_areas(vectorio_vector_shape_t *self, displayio_area_t *tail) { if (self->dirty - || (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type) && displayio_palette_needs_refresh(self->pixel_shader)) - || (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type) && displayio_colorconverter_needs_refresh(self->pixel_shader)) + || (mp_obj_is_type(self->pixel_shader, &displayio_palette_type) && displayio_palette_needs_refresh(self->pixel_shader)) + || (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type) && displayio_colorconverter_needs_refresh(self->pixel_shader)) ) { VECTORIO_SHAPE_DEBUG("%p get_refresh_area dirty:%d {(%3d,%3d), (%3d,%3d)}", self, self->dirty, self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); common_hal_vectorio_vector_shape_set_dirty(self); diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index 874f258217..b8d9d8ae31 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -97,7 +97,7 @@ void filesystem_init(bool create_allowed, bool force_create) { if ((res == FR_NO_FILESYSTEM && create_allowed) || force_create) { // No filesystem so create a fresh one, or reformat has been requested. - uint8_t working_buf[_MAX_SS]; + uint8_t working_buf[FF_MAX_SS]; res = f_mkfs(&vfs_fat->fatfs, FM_FAT, 0, working_buf, sizeof(working_buf)); // Flush the new file system to make sure it's repaired immediately. supervisor_flash_flush(); diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index 409bf0ea6c..60e7c9cc24 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -161,11 +161,11 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t * // Since by getting here we assume the mount is read-only to // MicroPython let's update the cached FatFs sector if it's the one // we just wrote. - #if _MAX_SS != _MIN_SS + #if FF_MAX_SS != FF_MIN_SS if (vfs->ssize == MSC_FLASH_BLOCK_SIZE) { #else // The compiler can optimize this away. - if (_MAX_SS == FILESYSTEM_BLOCK_SIZE) { + if (FF_MAX_SS == FILESYSTEM_BLOCK_SIZE) { #endif if (lba == vfs->fatfs.winsect && lba > 0) { memcpy(vfs->fatfs.win, diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index c206ff96be..c6354205cf 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -7,6 +7,7 @@ SRC_SUPERVISOR = \ supervisor/shared/cpu.c \ supervisor/shared/filesystem.c \ supervisor/shared/flash.c \ + supervisor/shared/memory.c \ supervisor/shared/micropython.c \ supervisor/shared/rgb_led_status.c \ supervisor/shared/safe_mode.c \ diff --git a/tests/basics/async_with.py b/tests/basics/async_with.py index 5af0c5d955..f7774055cf 100644 --- a/tests/basics/async_with.py +++ b/tests/basics/async_with.py @@ -27,3 +27,13 @@ try: o.send(None) except ValueError: print('ValueError') + +# test raising BaseException to make sure it is handled by the async-with +async def h(): + async with AContext(): + raise BaseException +o = h() +try: + o.send(None) +except BaseException: + print('BaseException') diff --git a/tests/basics/async_with.py.exp b/tests/basics/async_with.py.exp index d00b18c969..6bbf84cb4b 100644 --- a/tests/basics/async_with.py.exp +++ b/tests/basics/async_with.py.exp @@ -6,3 +6,6 @@ enter 1 exit error ValueError +enter +exit +BaseException diff --git a/tests/basics/builtin_next_arg2.py b/tests/basics/builtin_next_arg2.py new file mode 100644 index 0000000000..b00155ec54 --- /dev/null +++ b/tests/basics/builtin_next_arg2.py @@ -0,0 +1,34 @@ +# test next(iter, default) + +try: + next(iter([]), 42) +except TypeError: # 2-argument version not supported + print('SKIP') + raise SystemExit + +print(next(iter([]), 42)) +print(next(iter(range(0)), 42)) +print(next((x for x in [0] if x == 1), 43)) + +def gen(): + yield 1 + yield 2 + +g = gen() +print(next(g, 42)) +print(next(g, 43)) +print(next(g, 44)) + +class Gen: + def __init__(self): + self.b = False + + def __next__(self): + if self.b: + raise StopIteration + self.b = True + return self.b + +g = Gen() +print(next(g, 44)) +print(next(g, 45)) diff --git a/tests/basics/bytearray_decode.py b/tests/basics/bytearray_decode.py new file mode 100644 index 0000000000..b5e1cb419b --- /dev/null +++ b/tests/basics/bytearray_decode.py @@ -0,0 +1,6 @@ +try: + print(bytearray(b'').decode()) + print(bytearray(b'abc').decode()) +except AttributeError: + print("SKIP") + raise SystemExit diff --git a/tests/basics/gen_yield_from_throw.py b/tests/basics/gen_yield_from_throw.py index 703158f4d4..804c53dda0 100644 --- a/tests/basics/gen_yield_from_throw.py +++ b/tests/basics/gen_yield_from_throw.py @@ -1,8 +1,8 @@ def gen(): try: yield 1 - except ValueError: - print("got ValueError from upstream!") + except ValueError as e: + print("got ValueError from upstream!", repr(e.args)) yield "str1" raise TypeError @@ -16,3 +16,21 @@ try: print(next(g)) except TypeError: print("got TypeError from downstream!") + +# passing None as second argument to throw +g = gen2() +print(next(g)) +print(g.throw(ValueError, None)) +try: + print(next(g)) +except TypeError: + print("got TypeError from downstream!") + +# passing an exception instance as second argument to throw +g = gen2() +print(next(g)) +print(g.throw(ValueError, ValueError(123))) +try: + print(next(g)) +except TypeError: + print("got TypeError from downstream!") diff --git a/tests/basics/generator_throw.py b/tests/basics/generator_throw.py index 1a390f399d..067ab2b8eb 100644 --- a/tests/basics/generator_throw.py +++ b/tests/basics/generator_throw.py @@ -28,8 +28,8 @@ except StopIteration: def gen(): try: yield 123 - except GeneratorExit: - print('GeneratorExit') + except GeneratorExit as e: + print('GeneratorExit', repr(e.args)) yield 456 # thrown a class @@ -41,3 +41,13 @@ print(g.throw(GeneratorExit)) g = gen() print(next(g)) print(g.throw(GeneratorExit())) + +# thrown an instance with None as second arg +g = gen() +print(next(g)) +print(g.throw(GeneratorExit(), None)) + +# thrown a class and instance +g = gen() +print(next(g)) +print(g.throw(GeneratorExit, GeneratorExit(123))) diff --git a/tests/basics/memoryview1.py b/tests/basics/memoryview1.py index 3e5c86768c..a0ac9e3449 100644 --- a/tests/basics/memoryview1.py +++ b/tests/basics/memoryview1.py @@ -46,3 +46,57 @@ print(list(m)) print(list(m[1:-1])) m[2] = 6 print(a) + +# test slice assignment between memoryviews +b1 = bytearray(b'1234') +b2 = bytearray(b'5678') +b3 = bytearray(b'5678') +m1 = memoryview(b1) +m2 = memoryview(b2) +m3 = memoryview(b3) +m2[1:3] = m1[0:2] +print(b2) +b3[1:3] = m1[0:2] +print(b3) +m1[2:4] = b3[1:3] +print(b1) + +try: + m2[1:3] = b1[0:4] +except ValueError: + print("ValueError") + +try: + m2[1:3] = m1[0:4] +except ValueError: + print("ValueError") + +try: + m2[0:4] = m1[1:3] +except ValueError: + print("ValueError") + +# test memoryview of arrays with items sized larger than 1 +a1 = array.array('i', [0]*5) +m4 = memoryview(a1) +a2 = array.array('i', [3]*5) +m5 = memoryview(a2) +m4[1:3] = m5[1:3] +print(a1) + +try: + m4[1:3] = m2[1:3] +except ValueError: + print("ValueError") + +# invalid assignment on RHS +try: + memoryview(array.array('i'))[0:2] = b'1234' +except ValueError: + print('ValueError') + +# invalid attribute +try: + memoryview(b'a').noexist +except AttributeError: + print('AttributeError') diff --git a/tests/basics/memoryview_itemsize.py b/tests/basics/memoryview_itemsize.py new file mode 100644 index 0000000000..60cb823087 --- /dev/null +++ b/tests/basics/memoryview_itemsize.py @@ -0,0 +1,15 @@ +try: + memoryview(b'a').itemsize + from array import array +except: + print("SKIP") + raise SystemExit + +for code in ['b', 'h', 'i', 'l', 'q', 'f', 'd']: + print(memoryview(array(code)).itemsize) + +# shouldn't be able to store to the itemsize attribute +try: + memoryview(b'a').itemsize = 1 +except AttributeError: + print('AttributeError') diff --git a/tests/basics/sys1.py b/tests/basics/sys1.py index da11c88d3e..8adff04439 100644 --- a/tests/basics/sys1.py +++ b/tests/basics/sys1.py @@ -24,6 +24,11 @@ try: except SystemExit as e: print("SystemExit", e.args) +try: + sys.exit() +except SystemExit as e: + print("SystemExit", e.args) + try: sys.exit(42) except SystemExit as e: diff --git a/tests/basics/try_else.py b/tests/basics/try_else.py new file mode 100644 index 0000000000..677707ecd6 --- /dev/null +++ b/tests/basics/try_else.py @@ -0,0 +1,76 @@ +# test try-else statement + +# base case +try: + print(1) +except: + print(2) +else: + print(3) + +# basic case that should skip else +try: + print(1) + raise Exception +except: + print(2) +else: + print(3) + +# uncaught exception should skip else +try: + try: + print(1) + raise ValueError + except TypeError: + print(2) + else: + print(3) +except: + print('caught') + +# nested within outer try +try: + print(1) + try: + print(2) + raise Exception + except: + print(3) + else: + print(4) +except: + print(5) +else: + print(6) + +# nested within outer except, one else should be skipped +try: + print(1) + raise Exception +except: + print(2) + try: + print(3) + except: + print(4) + else: + print(5) +else: + print(6) + +# nested within outer except, both else should be skipped +try: + print(1) + raise Exception +except: + print(2) + try: + print(3) + raise Exception + except: + print(4) + else: + print(5) +else: + print(6) diff --git a/tests/basics/try_else_finally.py b/tests/basics/try_else_finally.py new file mode 100644 index 0000000000..87d98bbdaf --- /dev/null +++ b/tests/basics/try_else_finally.py @@ -0,0 +1,94 @@ +# test try-else-finally statement + +# base case +try: + print(1) +except: + print(2) +else: + print(3) +finally: + print(4) + +# basic case that should skip else +try: + print(1) + raise Exception +except: + print(2) +else: + print(3) +finally: + print(4) + +# uncaught exception should skip else +try: + try: + print(1) + raise ValueError + except TypeError: + print(2) + else: + print(3) + finally: + print(4) +except: + print('caught') + +# nested within outer try +try: + print(1) + try: + print(2) + raise Exception + except: + print(3) + else: + print(4) + finally: + print(5) +except: + print(6) +else: + print(7) +finally: + print(8) + +# nested within outer except, one else should be skipped +try: + print(1) + raise Exception +except: + print(2) + try: + print(3) + except: + print(4) + else: + print(5) + finally: + print(6) +else: + print(7) +finally: + print(8) + +# nested within outer except, both else should be skipped +try: + print(1) + raise Exception +except: + print(2) + try: + print(3) + raise Exception + except: + print(4) + else: + print(5) + finally: + print(6) +else: + print(7) +finally: + print(8) diff --git a/tests/basics/try_finally_break.py b/tests/basics/try_finally_break.py new file mode 100644 index 0000000000..ae7226637d --- /dev/null +++ b/tests/basics/try_finally_break.py @@ -0,0 +1,99 @@ +# test break within (nested) finally + +# basic case with break in finally +def f(): + for _ in range(2): + print(1) + try: + pass + finally: + print(2) + break + print(3) + print(4) + print(5) +f() + +# where the finally swallows an exception +def f(): + lst = [1, 2, 3] + for x in lst: + print('a', x) + try: + raise Exception + finally: + print(1) + break + print('b', x) +f() + +# basic nested finally with break in inner finally +def f(): + for i in range(2): + print('iter', i) + try: + raise TypeError + finally: + print(1) + try: + raise ValueError + finally: + break +print(f()) + +# similar to above but more nesting +def f(): + for i in range(2): + try: + raise ValueError + finally: + print(1) + try: + raise TypeError + finally: + print(2) + try: + pass + finally: + break +print(f()) + +# lots of nesting +def f(): + for i in range(2): + try: + raise ValueError + finally: + print(1) + try: + raise TypeError + finally: + print(2) + try: + raise Exception + finally: + break +print(f()) + +# basic case combined with try-else +def f(arg): + for _ in range(2): + print(1) + try: + if arg == 1: + raise ValueError + elif arg == 2: + raise TypeError + except ValueError: + print(2) + else: + print(3) + finally: + print(4) + break + print(5) + print(6) + print(7) +f(0) # no exception, else should execute +f(1) # exception caught, else should be skipped +f(2) # exception not caught, finally swallows exception, else should be skipped diff --git a/tests/basics/try_return.py b/tests/basics/try_return.py index 492c18d95c..a24290c4fb 100644 --- a/tests/basics/try_return.py +++ b/tests/basics/try_return.py @@ -1,5 +1,14 @@ # test use of return with try-except +def f(): + try: + print(1) + return + except: + print(2) + print(3) +f() + def f(l, i): try: return l[i] diff --git a/tests/cmdline/cmd_showbc.py b/tests/cmdline/cmd_showbc.py index 326f2373f6..8ef5e22f39 100644 --- a/tests/cmdline/cmd_showbc.py +++ b/tests/cmdline/cmd_showbc.py @@ -3,6 +3,7 @@ # fmt: off + def f(): # constants a = None + False + True diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index ac4cedd340..9b7691b7d2 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -7,7 +7,7 @@ arg names: (N_EXC_STACK 0) bc=-1 line=1 ######## - bc=\\d\+ line=164 + bc=\\d\+ line=165 00 MAKE_FUNCTION \.\+ \\d\+ STORE_NAME f \\d\+ MAKE_FUNCTION \.\+ @@ -40,7 +40,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): (INIT_CELL 16) bc=-4 line=1 ######## - bc=\\d\+ line=130 + bc=\\d\+ line=131 00 LOAD_CONST_NONE 01 LOAD_CONST_FALSE 02 BINARY_OP 26 __add__ @@ -257,15 +257,12 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ JUMP \\d\+ \\d\+ LOAD_FAST 0 \\d\+ POP_JUMP_IF_TRUE \\d\+ -\\d\+ POP_BLOCK -\\d\+ JUMP \\d\+ +\\d\+ POP_EXCEPT_JUMP \\d\+ \\d\+ POP_TOP \\d\+ LOAD_DEREF 14 \\d\+ POP_TOP -\\d\+ POP_EXCEPT -\\d\+ JUMP \\d\+ +\\d\+ POP_EXCEPT_JUMP \\d\+ \\d\+ END_FINALLY -\\d\+ POP_BLOCK \\d\+ LOAD_CONST_NONE \\d\+ LOAD_FAST 1 \\d\+ POP_TOP @@ -273,11 +270,9 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ JUMP \\d\+ \\d\+ SETUP_EXCEPT \\d\+ \\d\+ UNWIND_JUMP \\d\+ 1 -\\d\+ POP_BLOCK -\\d\+ JUMP \\d\+ +\\d\+ POP_EXCEPT_JUMP \\d\+ \\d\+ POP_TOP -\\d\+ POP_EXCEPT -\\d\+ JUMP \\d\+ +\\d\+ POP_EXCEPT_JUMP \\d\+ \\d\+ END_FINALLY \\d\+ LOAD_FAST 0 \\d\+ POP_JUMP_IF_TRUE \\d\+ @@ -286,7 +281,6 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ POP_TOP \\d\+ LOAD_DEREF 14 \\d\+ POP_TOP -\\d\+ POP_BLOCK \\d\+ LOAD_CONST_NONE \\d\+ WITH_CLEANUP \\d\+ END_FINALLY @@ -326,7 +320,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): (N_EXC_STACK 0) bc=-1 line=1 ######## - bc=\\d\+ line=137 + bc=\\d\+ line=138 00 LOAD_CONST_SMALL_INT 1 01 DUP_TOP 02 STORE_FAST 0 @@ -382,7 +376,7 @@ arg names: a (N_EXC_STACK 0) (INIT_CELL 0) ######## - bc=\\d\+ line=144 + bc=\\d\+ line=145 00 LOAD_CONST_SMALL_INT 2 01 BUILD_TUPLE 1 03 LOAD_NULL @@ -399,9 +393,9 @@ arg names: (N_STATE 2) (N_EXC_STACK 0) bc=-1 line=1 - bc=0 line=150 - bc=3 line=151 - bc=6 line=152 + bc=0 line=151 + bc=3 line=152 + bc=6 line=153 00 LOAD_CONST_NONE 01 YIELD_VALUE 02 POP_TOP @@ -423,7 +417,7 @@ arg names: (N_STATE 1) (N_EXC_STACK 0) bc=-1 line=1 - bc=13 line=157 + bc=13 line=158 00 LOAD_NAME __name__ (cache=0) 04 STORE_NAME __module__ 07 LOAD_CONST_STRING 'Class' @@ -438,7 +432,7 @@ arg names: self (N_STATE 4) (N_EXC_STACK 0) bc=-1 line=1 - bc=0 line=165 + bc=0 line=166 00 LOAD_GLOBAL super (cache=0) \\d\+ LOAD_GLOBAL __class__ (cache=0) \\d\+ LOAD_FAST 0 @@ -518,7 +512,7 @@ arg names: * (N_EXC_STACK 0) bc=-\\d\+ line=1 ######## - bc=\\d\+ line=117 + bc=\\d\+ line=118 00 LOAD_DEREF 0 02 LOAD_CONST_SMALL_INT 1 03 BINARY_OP 26 __add__ @@ -537,7 +531,7 @@ arg names: * b (N_EXC_STACK 0) bc=-\\d\+ line=1 ######## - bc=\\d\+ line=145 + bc=\\d\+ line=146 00 LOAD_FAST 1 01 LOAD_DEREF 0 03 BINARY_OP 26 __add__ diff --git a/tests/cmdline/repl_autocomplete.py b/tests/cmdline/repl_autocomplete.py index 43c49cdc25..27cad428f7 100644 --- a/tests/cmdline/repl_autocomplete.py +++ b/tests/cmdline/repl_autocomplete.py @@ -6,7 +6,4 @@ x = '123' 1, x.isdi () i = str i.lowe ('ABC') -x = 5 -x.  -x._ None.  diff --git a/tests/cmdline/repl_autocomplete.py.exp b/tests/cmdline/repl_autocomplete.py.exp index 0dabc90144..75002985e3 100644 --- a/tests/cmdline/repl_autocomplete.py.exp +++ b/tests/cmdline/repl_autocomplete.py.exp @@ -10,11 +10,5 @@ Use \.\+ >>> i = str >>> i.lower('ABC') 'abc' ->>> x = 5 ->>> x. -bit_length from_bytes to_bytes ->>> x. ->>> x.__class__ - >>> None. >>> diff --git a/tests/extmod/ucryptolib_aes128_ctr.py b/tests/extmod/ucryptolib_aes128_ctr.py new file mode 100644 index 0000000000..538d9606e9 --- /dev/null +++ b/tests/extmod/ucryptolib_aes128_ctr.py @@ -0,0 +1,28 @@ +try: + from ucryptolib import aes +except ImportError: + print("SKIP") + raise SystemExit + + +def _new(k, ctr_initial): + return aes(k, 6, ctr_initial) + + +try: + _new(b"x" * 16, b"x" * 16) +except ValueError as e: + # is CTR support disabled? + if e.args[0] == "mode": + print("SKIP") + raise SystemExit + raise e + +crypto = _new(b"1234" * 4, b"5678" * 4) +enc = crypto.encrypt(b"a") +print(enc) +enc += crypto.encrypt(b"b" * 1000) +print(enc) + +crypto = _new(b"1234" * 4, b"5678" * 4) +print(crypto.decrypt(enc)) diff --git a/tests/extmod/ucryptolib_aes128_ctr.py.exp b/tests/extmod/ucryptolib_aes128_ctr.py.exp new file mode 100644 index 0000000000..92e090fd39 --- /dev/null +++ b/tests/extmod/ucryptolib_aes128_ctr.py.exp @@ -0,0 +1,3 @@ +b'\x06' +b'\x06(F\x08\xc3hB\xfdO\x05;\xf6\x96\xfe\xad\xe0\xca\xe6\xd1\xa2m\t\x91v>|\xee\xe0q\xbc]\x9a`\xfal\x87\xa6e\xfb\x8a\xf4\xb2-\xc4x,\xfc@=,\x90\xf4\xe9h\xf0\xfc\xfb\xe6\x03\xf0d\xb6\xcdObZ\xde\x1b\xe2\x84-%=\xa9\xe4\x05\xab\xd7\x044\xf4$\xd0)\xfd\xd6\xdbL\xdd\xe6\x0cp\xca^p\xaaA\x8b\xb3!\xe3\x13\xfa\x7f#\xfa0\xbd\x0b\x9cX\xec\xed\x1c\xbc\x06\xa4\xa8\x17\xbfg\x98dW\xb9~\x04\xec\xe6lZ\xb0\xab\xd5\xc6v\xe4\x8f\x98G\xff\x9b\x8a\xae\xfd\xe5\xed\x96\x1b\xe2\x99u3\xeb\x9faYr;\xf0g\xf2\x9cq\x8dI\x1cL\xc9\xa8\xb0\xdeD\xd5\x06\x87u=\xcd\x10\x1c\xab\x14\x06n\x99\x13\x89\x9f5\xea\xd2\x08\x9e\xef$?\xb9\xdeQ\x0b\x90CH\xea@V\x94\x1a\xdd\x7f\x1dz\x82\xaay\xea$Lv\x07\x8e\xce\xb8oN\x15\xf8,\x05\x00\xd9H\xf4\xbe\xb8\xee\x0e\xd6Hjh\xc6\x11\xf8:\xfe\xed\xba_\xaf\x8e\'\x0c\x7fZ\xd5\xb7\xbc\xba\xd3+\xf1\x98i\xab\x0c-\xd9\xe6>\x9e\xd0\xe6>\x9f\xebn\xf0\x15\xd9:\xec\xf7aXa\xb2,CAB7\x18g\xcc#\xbc\xb8\xf9\xa7\xf4V\xba\x0baN\x88\xb1\xea\x94\x05\x0cV\x99_\xc4\xe6\xb2\xd1|\x92\x05*@U\xe4\\\x8dR\x98\xdf\xbfS\x97\x12^\tr\x1f\x12\x8f\xdfi\x8e=\xc4I\xfcB\r\x99f\xe3\xe31\xee\xa9\xcd\x91\x1a\x1ei\xfd\xf4\x84\xc6\xda\x9e\xf3\x8aKn\xaa\xf7\x9eS\xcc\xbaXZ\x0cpbk\x18\x1f\x9aAl>y\xad\xcb\xcf\xe1Wm\xe7\xdd\xcc\x10eW\xe4h\x1dY\xb5Zs\xf1\xe7\x16_\xdc:I1R\xd3\xfe\xb1)\t\xddE\xbax\x06R\xdc\x1dSdlu\xd1\x9c\x00\xaf\x87\x8d1\xbf$\x08\xc6/y\xdf\x1f\x97z(\xff\xb9\xcb\xf2,\x91\xd7\xa0W\xfc\xe3\xe2\x905\x17O\xaf\x18\xc7\xb8?\x94^\xf5@\x80\x8d\xaa*p\xbeR0i\x17\x1e\'-\xfa\xd9\xb2\x03\xb8\x1fY\x13\xc1{\x7f\xa9\x86\t\x99\xee\xa2\xba\xab\xc1\xbb\x07a\xa5J\x01\x98\xe8\x8e\xa1\x8aV\xc1)^A\xd9\xe7\xfej`\xb4\xe9\xd3C\xab\xd4\xdb\xb1\x8c\x83\xaa&\xf1\xe2\xfc\xa1Lb\xa8\xbb\xd6\x83\xb7\xd8\xc5\x9e\xb5\xed\x1b\xe6\x91\x90\xe4\xfa\xfdD\xc2\xcb\xb7U\xb3|?(\x86=\xc2\xff\xd3P\xd2\xc5y\x93\x13r\xcd>5\x80\xde\xdaJ\xdd\x8b\xfa\x14\xd1\x85\xa8P\x06(F\xb3?\xefm\x8e\xe5C\xfe\x98\xaf\xed\xd1!(\x1f.\xc6M\xba\x00\xcb\xbfg5\xc8\x9d\x97+\x14\x87\xf5\x9d4\xb4l\xd5\xc5>\x90\xf2\x06\xa2\xc1R\x89\xf0P\xb4\xe5\x97\xdb\x07\xd3\xc6q\x08\xb9\xe7\r\xf9\x13\x8215\xcb\x92\xed\x99\xc7"\x1e\xe3Zsh\x0e\xe7\xae\x10Xs&)\x1d\xe5\xd5\xbc\x95\x8e\xa3\xd6k[k\x9c\xa0%\xd4\x83%\x88}\x90\xf0\xa7\xc7\xa4(\xdaE\xb9~\xae\x05\xbd}\xe2\xd0\xa5Y\xc1aV[\xab\x93S\xa6\xacg\r\x14\xc6\xe2J\xd6\xcck"\xcc\xfb\xb3\x97\x14\x13\x0b\xd1\xf5\xe7)_\x1e\x0b\xbb\x01\xf7\x11u\x85b\xdf\xab\xe3\xbb:\x84zF\x14u\xfe\x89\x90\xbc\xcaF\x15y\xa3\xa4[\xce\xcf-\xae\x18\x97N\xaa\xed\x84A\xfc\x9e\xeb\xb3\xfcH\x8ej\xcc\x9f \x1b\xc1\x1f}\'q.\xc0^\xd99\x1e\x91b-\xf9\xed\xfd\x9a\x7f\xb6\rO\xea\xc8\x94\xea\xf6\xb4\xdb\xf5\xc7\xb3\xef\xf6D\x12>5\xf3\x9d*\xc9\xf8\x9f]\xb01{d\xe7\'\x8f\xc0\xfbKB\x8dd\xb1\x84\x804\xbe\xe2?AT\x14\xdb4eJ\x96\xc5\xb9%\xe5\x1c\xc0L\xae\xd6O\xde\x1fjJIRD\x96\xa2\xdb\xfc\xc6t\xce\xe6\xe8"\x81\xe6\xc7\x7fuz\xb3\x91\'D\xac\xb2\x93O\xee\x14\xaa7yT\xcf\x81p\x0b(\xa1d\xda\xf8\xcb\x01\x98\x07\'\xfe/\xe4\xca\xab\x03uR"zY\xfb\x1f\x02\xc5\x9c\xa0\'\x89\xffO\x88cK\xac\xb1+S0]%E\x1a\xeb\x04\xf7\x0b\xba\xa0\xbb\xbd|\x06@T\xee\xe7\x17\xa1T\xe3"\x07\x07q' +b'abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' diff --git a/tests/extmod/ujson_loads_float.py b/tests/extmod/ujson_loads_float.py index e368ca42e7..842718f37d 100644 --- a/tests/extmod/ujson_loads_float.py +++ b/tests/extmod/ujson_loads_float.py @@ -16,4 +16,5 @@ my_print(json.loads("1.2")) my_print(json.loads("1e2")) my_print(json.loads("-2.3")) my_print(json.loads("-2e3")) +my_print(json.loads("-2e+3")) my_print(json.loads("-2e-3")) diff --git a/tests/extmod/ussl_basic.py b/tests/extmod/ussl_basic.py index c8bdc81a48..b4e21c7dce 100644 --- a/tests/extmod/ussl_basic.py +++ b/tests/extmod/ussl_basic.py @@ -20,12 +20,13 @@ ss = ssl.wrap_socket(socket, server_side=1) # print print(repr(ss)[:12]) -# setblocking -try: - ss.setblocking(False) -except NotImplementedError: - print("setblocking: NotImplementedError") -ss.setblocking(True) +# setblocking() propagates call to the underlying stream object, and +# io.BytesIO doesn't have setblocking() (in CPython too). +# try: +# ss.setblocking(False) +# except NotImplementedError: +# print('setblocking: NotImplementedError') +# ss.setblocking(True) # write print(ss.write(b"aaaa")) diff --git a/tests/extmod/ussl_basic.py.exp b/tests/extmod/ussl_basic.py.exp index cb9c51f7a1..5282338319 100644 --- a/tests/extmod/ussl_basic.py.exp +++ b/tests/extmod/ussl_basic.py.exp @@ -1,7 +1,6 @@ ssl_handshake_status: -256 wrap_socket: OSError(5,) <_SSLSocket -setblocking: NotImplementedError 4 b'' read: OSError(-261,) diff --git a/tests/extmod/vfs_fat_ramdisklarge.py b/tests/extmod/vfs_fat_ramdisklarge.py new file mode 100644 index 0000000000..dcebd54288 --- /dev/null +++ b/tests/extmod/vfs_fat_ramdisklarge.py @@ -0,0 +1,70 @@ +# test making a FAT filesystem on a very large block device + +try: + import uos +except ImportError: + print("SKIP") + raise SystemExit + +try: + uos.VfsFat +except AttributeError: + print("SKIP") + raise SystemExit + + +class RAMBDevSparse: + + SEC_SIZE = 512 + + def __init__(self, blocks): + self.blocks = blocks + self.data = {} + + def readblocks(self, n, buf): + # print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + assert len(buf) == self.SEC_SIZE + if n not in self.data: + self.data[n] = bytearray(self.SEC_SIZE) + buf[:] = self.data[n] + + def writeblocks(self, n, buf): + # print("writeblocks(%s, %x)" % (n, id(buf))) + mv = memoryview(buf) + for off in range(0, len(buf), self.SEC_SIZE): + s = n + off // self.SEC_SIZE + if s not in self.data: + self.data[s] = bytearray(self.SEC_SIZE) + self.data[s][:] = mv[off : off + self.SEC_SIZE] + + def ioctl(self, op, arg): + # print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # BP_IOCTL_SEC_COUNT + return self.blocks + if op == 5: # BP_IOCTL_SEC_SIZE + return self.SEC_SIZE + + +try: + bdev = RAMBDevSparse(4 * 1024 * 1024 * 1024 // RAMBDevSparse.SEC_SIZE) + uos.VfsFat.mkfs(bdev) +except MemoryError: + print("SKIP") + raise SystemExit + +vfs = uos.VfsFat(bdev) +uos.mount(vfs, "/ramdisk") + +print("statvfs:", vfs.statvfs("/ramdisk")) + +f = open("/ramdisk/test.txt", "w") +f.write("test file") +f.close() + +print("statvfs:", vfs.statvfs("/ramdisk")) + +f = open("/ramdisk/test.txt") +print(f.read()) +f.close() + +uos.umount(vfs) diff --git a/tests/extmod/vfs_fat_ramdisklarge.py.exp b/tests/extmod/vfs_fat_ramdisklarge.py.exp new file mode 100644 index 0000000000..ea723e2249 --- /dev/null +++ b/tests/extmod/vfs_fat_ramdisklarge.py.exp @@ -0,0 +1,3 @@ +statvfs: (32768, 32768, 131054, 131053, 131053, 0, 0, 0, 0, 255) +statvfs: (32768, 32768, 131054, 131052, 131052, 0, 0, 0, 0, 255) +test file diff --git a/tests/extmod/websocket_basic.py b/tests/extmod/websocket_basic.py deleted file mode 100644 index 8c5cf58257..0000000000 --- a/tests/extmod/websocket_basic.py +++ /dev/null @@ -1,62 +0,0 @@ -try: - import uio - import uerrno - import websocket -except ImportError: - print("SKIP") - raise SystemExit - -# put raw data in the stream and do a websocket read -def ws_read(msg, sz): - ws = websocket.websocket(uio.BytesIO(msg)) - return ws.read(sz) - - -# do a websocket write and then return the raw data from the stream -def ws_write(msg, sz): - s = uio.BytesIO() - ws = websocket.websocket(s) - ws.write(msg) - s.seek(0) - return s.read(sz) - - -# basic frame -print(ws_read(b"\x81\x04ping", 4)) -print(ws_read(b"\x80\x04ping", 4)) # FRAME_CONT -print(ws_write(b"pong", 6)) - -# split frames are not supported -# print(ws_read(b"\x01\x04ping", 4)) - -# extended payloads -print(ws_read(b"\x81~\x00\x80" + b"ping" * 32, 128)) -print(ws_write(b"pong" * 32, 132)) - -# mask (returned data will be 'mask' ^ 'mask') -print(ws_read(b"\x81\x84maskmask", 4)) - -# close control frame -s = uio.BytesIO(b"\x88\x00") # FRAME_CLOSE -ws = websocket.websocket(s) -print(ws.read(1)) -s.seek(2) -print(s.read(4)) - -# misc control frames -print(ws_read(b"\x89\x00\x81\x04ping", 4)) # FRAME_PING -print(ws_read(b"\x8a\x00\x81\x04pong", 4)) # FRAME_PONG - -# close method -ws = websocket.websocket(uio.BytesIO()) -ws.close() - -# ioctl -ws = websocket.websocket(uio.BytesIO()) -print(ws.ioctl(8)) # GET_DATA_OPTS -print(ws.ioctl(9, 2)) # SET_DATA_OPTS -print(ws.ioctl(9)) -try: - ws.ioctl(-1) -except OSError as e: - print("ioctl: EINVAL:", e.args[0] == uerrno.EINVAL) diff --git a/tests/import/mpy_invalid.py b/tests/import/mpy_invalid.py index 188fb16127..3b416fc63c 100644 --- a/tests/import/mpy_invalid.py +++ b/tests/import/mpy_invalid.py @@ -56,6 +56,7 @@ user_files = { "/mod0.mpy": b"", # empty file "/mod1.mpy": b"M", # too short header "/mod2.mpy": b"M\x00\x00\x00", # bad version + "/mod3.mpy": b"M\x00\x00\x00\x7f", # qstr window too large } # create and mount a user filesystem diff --git a/tests/import/mpy_invalid.py.exp b/tests/import/mpy_invalid.py.exp index 197eb4f7b2..e7a7a89422 100644 --- a/tests/import/mpy_invalid.py.exp +++ b/tests/import/mpy_invalid.py.exp @@ -1,3 +1,4 @@ -mod0 RuntimeError Corrupt .mpy file -mod1 RuntimeError Corrupt .mpy file +mod0 MpyError Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info. +mod1 MpyError Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info. mod2 MpyError Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info. +mod3 MpyError Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info. diff --git a/tests/import/mpy_native.py b/tests/import/mpy_native.py new file mode 100644 index 0000000000..2499e3e206 --- /dev/null +++ b/tests/import/mpy_native.py @@ -0,0 +1,96 @@ +# test importing of .mpy files with native code (x64 only) + +import sys, uio + +try: + uio.IOBase + import uos + + uos.mount +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +if not (sys.platform == "linux" and sys.maxsize > 2 ** 32): + print("SKIP") + raise SystemExit + + +class UserFile(uio.IOBase): + def __init__(self, data): + self.data = data + self.pos = 0 + + def read(self): + return self.data + + def readinto(self, buf): + n = 0 + while n < len(buf) and self.pos < len(self.data): + buf[n] = self.data[self.pos] + n += 1 + self.pos += 1 + return n + + def ioctl(self, req, arg): + return 0 + + +class UserFS: + def __init__(self, files): + self.files = files + + def mount(self, readonly, mksfs): + pass + + def umount(self): + pass + + def stat(self, path): + if path in self.files: + return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0) + raise OSError + + def open(self, path, mode): + return UserFile(self.files[path]) + + +# these are the test .mpy files +user_files = { + # bad architecture + "/mod0.mpy": b"M\x04\xff\x00\x10", + # test loading of viper and asm + "/mod1.mpy": ( + b"M\x04\x0b\x1f\x20" # header + b"\x38" # n bytes, bytecode + b"\x01\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\xff" # prelude + b"\x11" # LOAD_CONST_NONE + b"\x5b" # RETURN_VALUE + b"\x02m\x02m\x00\x02" # simple_name, source_file, n_obj, n_raw_code + b"\x22" # n bytes, viper code + b"\x00\x00\x00\x00\x00\x00" # dummy machine code + b"\x00\x00" # qstr0 + b"\x01\x0c\x0aprint" # n_qstr, qstr0 + b"\x00\x00\x00" # scope_flags, n_obj, n_raw_code + b"\x23" # n bytes, asm code + b"\x00\x00\x00\x00\x00\x00\x00\x00" # dummy machine code + b"\x00\x00\x00" # scope_flags, n_pos_args, type_sig + ), +} + +# create and mount a user filesystem +uos.mount(UserFS(user_files), "/userfs") +sys.path.append("/userfs") + +# import .mpy files from the user filesystem +for i in range(len(user_files)): + mod = "mod%u" % i + try: + __import__(mod) + print(mod, "OK") + except ValueError as er: + print(mod, "ValueError", er) + +# unmount and undo path addition +uos.umount("/userfs") +sys.path.pop() diff --git a/tests/import/mpy_native.py.exp b/tests/import/mpy_native.py.exp new file mode 100644 index 0000000000..0b8958f5aa --- /dev/null +++ b/tests/import/mpy_native.py.exp @@ -0,0 +1,2 @@ +mod0 ValueError incompatible native .mpy architecture +mod1 OK diff --git a/tests/micropython/heapalloc_fail_bytearray.py b/tests/micropython/heapalloc_fail_bytearray.py new file mode 100644 index 0000000000..1bf7ddd600 --- /dev/null +++ b/tests/micropython/heapalloc_fail_bytearray.py @@ -0,0 +1,93 @@ +# test handling of failed heap allocation with bytearray + +import micropython + + +class GetSlice: + def __getitem__(self, idx): + return idx + + +sl = GetSlice()[:] + +# create bytearray +micropython.heap_lock() +try: + bytearray(4) +except MemoryError: + print("MemoryError: bytearray create") +micropython.heap_unlock() + +# create bytearray from bytes +micropython.heap_lock() +try: + bytearray(b"0123") +except MemoryError: + print("MemoryError: bytearray create from bytes") +micropython.heap_unlock() + +# create bytearray from iterator +r = range(4) +micropython.heap_lock() +try: + bytearray(r) +except MemoryError: + print("MemoryError: bytearray create from iter") +micropython.heap_unlock() + +# bytearray add +b = bytearray(4) +micropython.heap_lock() +try: + b + b"01" +except MemoryError: + print("MemoryError: bytearray.__add__") +micropython.heap_unlock() + +# bytearray iadd +b = bytearray(4) +micropython.heap_lock() +try: + b += b"01234567" +except MemoryError: + print("MemoryError: bytearray.__iadd__") +micropython.heap_unlock() +print(b) + +# bytearray append +b = bytearray(4) +micropython.heap_lock() +try: + for i in range(100): + b.append(1) +except MemoryError: + print("MemoryError: bytearray.append") +micropython.heap_unlock() + +# bytearray extend +b = bytearray(4) +micropython.heap_lock() +try: + b.extend(b"01234567") +except MemoryError: + print("MemoryError: bytearray.extend") +micropython.heap_unlock() + +# bytearray get with slice +b = bytearray(4) +micropython.heap_lock() +try: + b[sl] +except MemoryError: + print("MemoryError: bytearray subscr get") +micropython.heap_unlock() + +# extend bytearray using slice subscr +b = bytearray(4) +micropython.heap_lock() +try: + b[sl] = b"01234567" +except MemoryError: + print("MemoryError: bytearray subscr grow") +micropython.heap_unlock() +print(b) diff --git a/tests/micropython/heapalloc_fail_bytearray.py.exp b/tests/micropython/heapalloc_fail_bytearray.py.exp new file mode 100644 index 0000000000..57f6202f5e --- /dev/null +++ b/tests/micropython/heapalloc_fail_bytearray.py.exp @@ -0,0 +1,11 @@ +MemoryError: bytearray create +MemoryError: bytearray create from bytes +MemoryError: bytearray create from iter +MemoryError: bytearray.__add__ +MemoryError: bytearray.__iadd__ +bytearray(b'\x00\x00\x00\x00') +MemoryError: bytearray.append +MemoryError: bytearray.extend +MemoryError: bytearray subscr get +MemoryError: bytearray subscr grow +bytearray(b'\x00\x00\x00\x00') diff --git a/tests/micropython/heapalloc_fail_dict.py b/tests/micropython/heapalloc_fail_dict.py new file mode 100644 index 0000000000..ce2d158bd0 --- /dev/null +++ b/tests/micropython/heapalloc_fail_dict.py @@ -0,0 +1,21 @@ +# test handling of failed heap allocation with dict + +import micropython + +# create dict +x = 1 +micropython.heap_lock() +try: + {x: x} +except MemoryError: + print("MemoryError: create dict") +micropython.heap_unlock() + +# create dict view +x = {1: 1} +micropython.heap_lock() +try: + x.items() +except MemoryError: + print("MemoryError: dict.items") +micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_fail_dict.py.exp b/tests/micropython/heapalloc_fail_dict.py.exp new file mode 100644 index 0000000000..70cfc64ba4 --- /dev/null +++ b/tests/micropython/heapalloc_fail_dict.py.exp @@ -0,0 +1,2 @@ +MemoryError: create dict +MemoryError: dict.items diff --git a/tests/micropython/heapalloc_fail_list.py b/tests/micropython/heapalloc_fail_list.py new file mode 100644 index 0000000000..9a2e9a555f --- /dev/null +++ b/tests/micropython/heapalloc_fail_list.py @@ -0,0 +1,39 @@ +# test handling of failed heap allocation with list + +import micropython + + +class GetSlice: + def __getitem__(self, idx): + return idx + + +sl = GetSlice()[:] + +# create slice in VM +l = [1, 2, 3] +micropython.heap_lock() +try: + print(l[0:1]) +except MemoryError: + print("MemoryError: list index") +micropython.heap_unlock() + +# get from list using slice +micropython.heap_lock() +try: + l[sl] +except MemoryError: + print("MemoryError: list get slice") +micropython.heap_unlock() + +# extend list using slice subscr +l = [1, 2] +l2 = [3, 4, 5, 6, 7, 8, 9, 10] +micropython.heap_lock() +try: + l[sl] = l2 +except MemoryError: + print("MemoryError: list extend slice") +micropython.heap_unlock() +print(l) diff --git a/tests/micropython/heapalloc_fail_list.py.exp b/tests/micropython/heapalloc_fail_list.py.exp new file mode 100644 index 0000000000..0e1637476b --- /dev/null +++ b/tests/micropython/heapalloc_fail_list.py.exp @@ -0,0 +1,4 @@ +MemoryError: list index +MemoryError: list get slice +MemoryError: list extend slice +[1, 2] diff --git a/tests/micropython/heapalloc_fail_memoryview.py b/tests/micropython/heapalloc_fail_memoryview.py new file mode 100644 index 0000000000..da2d1abffa --- /dev/null +++ b/tests/micropython/heapalloc_fail_memoryview.py @@ -0,0 +1,28 @@ +# test handling of failed heap allocation with memoryview + +import micropython + + +class GetSlice: + def __getitem__(self, idx): + return idx + + +sl = GetSlice()[:] + +# create memoryview +micropython.heap_lock() +try: + memoryview(b"") +except MemoryError: + print("MemoryError: memoryview create") +micropython.heap_unlock() + +# memoryview get with slice +m = memoryview(b"") +micropython.heap_lock() +try: + m[sl] +except MemoryError: + print("MemoryError: memoryview subscr get") +micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_fail_memoryview.py.exp b/tests/micropython/heapalloc_fail_memoryview.py.exp new file mode 100644 index 0000000000..e41a1e6cb2 --- /dev/null +++ b/tests/micropython/heapalloc_fail_memoryview.py.exp @@ -0,0 +1,2 @@ +MemoryError: memoryview create +MemoryError: memoryview subscr get diff --git a/tests/micropython/heapalloc_fail_set.py b/tests/micropython/heapalloc_fail_set.py new file mode 100644 index 0000000000..8eb887f711 --- /dev/null +++ b/tests/micropython/heapalloc_fail_set.py @@ -0,0 +1,23 @@ +# test handling of failed heap allocation with set + +import micropython + +# create set +x = 1 +micropython.heap_lock() +try: + { + x, + } +except MemoryError: + print("MemoryError: set create") +micropython.heap_unlock() + +# set copy +s = {1, 2} +micropython.heap_lock() +try: + s.copy() +except MemoryError: + print("MemoryError: set copy") +micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_fail_set.py.exp b/tests/micropython/heapalloc_fail_set.py.exp new file mode 100644 index 0000000000..dd749672dc --- /dev/null +++ b/tests/micropython/heapalloc_fail_set.py.exp @@ -0,0 +1,2 @@ +MemoryError: set create +MemoryError: set copy diff --git a/tests/micropython/heapalloc_fail_tuple.py b/tests/micropython/heapalloc_fail_tuple.py new file mode 100644 index 0000000000..de79385e3e --- /dev/null +++ b/tests/micropython/heapalloc_fail_tuple.py @@ -0,0 +1,12 @@ +# test handling of failed heap allocation with tuple + +import micropython + +# create tuple +x = 1 +micropython.heap_lock() +try: + (x,) +except MemoryError: + print("MemoryError: tuple create") +micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_fail_tuple.py.exp b/tests/micropython/heapalloc_fail_tuple.py.exp new file mode 100644 index 0000000000..5bf632d799 --- /dev/null +++ b/tests/micropython/heapalloc_fail_tuple.py.exp @@ -0,0 +1 @@ +MemoryError: tuple create diff --git a/tests/micropython/viper_types.py b/tests/micropython/viper_types.py new file mode 100644 index 0000000000..3af148171e --- /dev/null +++ b/tests/micropython/viper_types.py @@ -0,0 +1,32 @@ +# test various type conversions + +import micropython + +# converting incoming arg to bool +@micropython.viper +def f1(x: bool): + print(x) + + +f1(0) +f1(1) +f1([]) +f1([1]) + +# taking and returning a bool +@micropython.viper +def f2(x: bool) -> bool: + return x + + +print(f2([])) +print(f2([1])) + +# converting to bool within function +@micropython.viper +def f3(x) -> bool: + return bool(x) + + +print(f3([])) +print(f3(-1)) diff --git a/tests/micropython/viper_types.py.exp b/tests/micropython/viper_types.py.exp new file mode 100644 index 0000000000..b7bef156ea --- /dev/null +++ b/tests/micropython/viper_types.py.exp @@ -0,0 +1,8 @@ +False +True +False +True +False +True +False +True diff --git a/tests/run-tests b/tests/run-tests index e00d6930f0..184743b341 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -110,7 +110,16 @@ def run_micropython(pyb, args, test_file, is_special=False): banner = get(True) output_mupy = banner + b''.join(send_get(line) for line in f) send_get(b'\x04') # exit the REPL, so coverage info is saved - p.kill() + # At this point the process might have exited already, but trying to + # kill it 'again' normally doesn't result in exceptions as Python and/or + # the OS seem to try to handle this nicely. When running Linux on WSL + # though, the situation differs and calling Popen.kill after the process + # terminated results in a ProcessLookupError. Just catch that one here + # since we just want the process to be gone and that's the case. + try: + p.kill() + except ProcessLookupError: + pass os.close(emulator) os.close(subterminal) else: @@ -128,7 +137,7 @@ def run_micropython(pyb, args, test_file, is_special=False): # if running via .mpy, first compile the .py file if args.via_mpy: - subprocess.check_output([MPYCROSS, '-mcache-lookup-bc', '-o', 'mpytest.mpy', test_file]) + subprocess.check_output([MPYCROSS, '-mcache-lookup-bc', '-o', 'mpytest.mpy', '-X', 'emit=' + args.emit, test_file]) cmdlist.extend(['-m', 'mpytest']) else: cmdlist.append(test_file) @@ -198,7 +207,7 @@ def run_micropython(pyb, args, test_file, is_special=False): if lines_exp[i][1].match(lines_mupy[i_mupy]): lines_mupy[i_mupy] = lines_exp[i][0] else: - #print("don't match: %r %s" % (lines_exp[i][1], lines_mupy[i_mupy])) # DEBUG + print("don't match: %r %s" % (lines_exp[i][1], lines_mupy[i_mupy])) # DEBUG pass i_mupy += 1 if i_mupy >= len(lines_mupy): diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 06b5d37903..55739d7af8 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -13,6 +13,7 @@ false true 80000000 80000000 abc +% # GC 0 0 @@ -70,10 +71,10 @@ sched(2)=1 sched(3)=1 sched(4)=0 unlocked -3 -2 -1 0 +1 +2 +3 0123456789 b'0123456789' 7300 7300 diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 9572f8f2aa..5c3a6af32d 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -41,7 +41,7 @@ class FreezeError(Exception): class Config: - MPY_VERSION = 3 + MPY_VERSION = 4 MICROPY_LONGINT_IMPL_NONE = 0 MICROPY_LONGINT_IMPL_LONGLONG = 1 MICROPY_LONGINT_IMPL_MPZ = 2 @@ -49,6 +49,50 @@ class Config: config = Config() + +class QStrType: + def __init__(self, str): + self.str = str + self.qstr_esc = qstrutil.qstr_escape(self.str) + self.qstr_id = "MP_QSTR_" + self.qstr_esc + + +# Initialise global list of qstrs with static qstrs +global_qstrs = [None] # MP_QSTR_NULL should never be referenced +for n in qstrutil.static_qstr_list: + global_qstrs.append(QStrType(n)) + + +class QStrWindow: + def __init__(self, size): + self.window = [] + self.size = size + + def push(self, val): + self.window = [val] + self.window[: self.size - 1] + + def access(self, idx): + val = self.window[idx] + self.window = [val] + self.window[:idx] + self.window[idx + 1 :] + return val + + +MP_CODE_BYTECODE = 2 +MP_CODE_NATIVE_PY = 3 +MP_CODE_NATIVE_VIPER = 4 +MP_CODE_NATIVE_ASM = 5 + +MP_NATIVE_ARCH_NONE = 0 +MP_NATIVE_ARCH_X86 = 1 +MP_NATIVE_ARCH_X64 = 2 +MP_NATIVE_ARCH_ARMV6 = 3 +MP_NATIVE_ARCH_ARMV6M = 4 +MP_NATIVE_ARCH_ARMV7M = 5 +MP_NATIVE_ARCH_ARMV7EM = 6 +MP_NATIVE_ARCH_ARMV7EMSP = 7 +MP_NATIVE_ARCH_ARMV7EMDP = 8 +MP_NATIVE_ARCH_XTENSA = 9 + MP_OPCODE_BYTE = 0 MP_OPCODE_QSTR = 1 MP_OPCODE_VAR_UINT = 2 @@ -106,7 +150,7 @@ def make_opcode_format(): OC4(O, O, U, U), # 0x38-0x3b OC4(U, O, B, O), # 0x3c-0x3f OC4(O, B, B, O), # 0x40-0x43 - OC4(B, B, O, B), # 0x44-0x47 + OC4(O, U, O, B), # 0x44-0x47 OC4(U, U, U, U), # 0x48-0x4b OC4(U, U, U, U), # 0x4c-0x4f OC4(V, V, U, V), # 0x50-0x53 @@ -158,7 +202,7 @@ def make_opcode_format(): # this function mirrors that in py/bc.c -def mp_opcode_format(bytecode, ip, opcode_format=make_opcode_format()): +def mp_opcode_format(bytecode, ip, count_var_uint, opcode_format=make_opcode_format()): opcode = bytecode[ip] ip_start = ip f = (opcode_format[opcode >> 2] >> (2 * (opcode & 3))) & 3 @@ -187,9 +231,10 @@ def mp_opcode_format(bytecode, ip, opcode_format=make_opcode_format()): ) ip += 1 if f == MP_OPCODE_VAR_UINT: - while bytecode[ip] & 0x80 != 0: + if count_var_uint: + while bytecode[ip] & 0x80 != 0: + ip += 1 ip += 1 - ip += 1 elif f == MP_OPCODE_OFFSET: ip += 2 ip += extra_byte @@ -207,8 +252,7 @@ def decode_uint(bytecode, ip): return ip, unum -def extract_prelude(bytecode): - ip = 0 +def extract_prelude(bytecode, ip): ip, n_state = decode_uint(bytecode, ip) ip, n_exc_stack = decode_uint(bytecode, ip) scope_flags = bytecode[ip] @@ -241,21 +285,40 @@ def extract_prelude(bytecode): ) -class RawCode: +class MPFunTable: + pass + + +class RawCode(object): # a set of all escaped names, to make sure they are unique escaped_names = set() - def __init__(self, bytecode, qstrs, objs, raw_codes): + # convert code kind number to string + code_kind_str = { + MP_CODE_BYTECODE: "MP_CODE_BYTECODE", + MP_CODE_NATIVE_PY: "MP_CODE_NATIVE_PY", + MP_CODE_NATIVE_VIPER: "MP_CODE_NATIVE_VIPER", + MP_CODE_NATIVE_ASM: "MP_CODE_NATIVE_ASM", + } + + def __init__(self, code_kind, bytecode, prelude_offset, qstrs, objs, raw_codes): # set core variables + self.code_kind = code_kind self.bytecode = bytecode + self.prelude_offset = prelude_offset self.qstrs = qstrs self.objs = objs self.raw_codes = raw_codes - # extract prelude - self.ip, self.ip2, self.prelude = extract_prelude(self.bytecode) - self.simple_name = self._unpack_qstr(self.ip2) - self.source_file = self._unpack_qstr(self.ip2 + 2) + if self.prelude_offset is None: + # no prelude, assign a dummy simple_name + self.prelude_offset = 0 + self.simple_name = global_qstrs[1] + else: + # extract prelude + self.ip, self.ip2, self.prelude = extract_prelude(self.bytecode, self.prelude_offset) + self.simple_name = self._unpack_qstr(self.ip2) + self.source_file = self._unpack_qstr(self.ip2 + 2) def _unpack_qstr(self, ip): qst = self.bytecode[ip] | self.bytecode[ip + 1] << 8 @@ -267,7 +330,7 @@ class RawCode: rc.freeze("") # TODO - def freeze(self, parent_name): + def freeze_children(self, parent_name): self.escaped_name = parent_name + self.simple_name.qstr_esc # make sure the escaped name is unique @@ -277,71 +340,17 @@ class RawCode: i += 1 RawCode.escaped_names.add(self.escaped_name) - sizes = { - "bytecode": 0, - "strings": 0, - "raw_code_overhead": 0, - "const_table_overhead": 0, - "string_overhead": 0, - "number_overhead": 0, - } # emit children first for rc in self.raw_codes: - subsize = rc.freeze(self.escaped_name + "_") - for k in sizes: - sizes[k] += subsize[k] - - # generate bytecode data - print() - print( - "// frozen bytecode for file %s, scope %s%s" - % (self.source_file.str, parent_name, self.simple_name.str) - ) - print("// bytecode size", len(self.bytecode)) - print("STATIC ", end="") - if not config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE: - print("const ", end="") - print("byte bytecode_data_%s[%u] = {" % (self.escaped_name, len(self.bytecode))) - sizes["bytecode"] += len(self.bytecode) - print(" ", end="") - for i in range(self.ip2): - print(" 0x%02x," % self.bytecode[i], end="") - print() - print(" // simple name") - print(" ", self.simple_name.qstr_id, "& 0xff,", self.simple_name.qstr_id, ">> 8,") - print(" // source file") - print(" ", self.source_file.qstr_id, "& 0xff,", self.source_file.qstr_id, ">> 8,") - print(" // code info") - print(" ", end="") - for i in range(self.ip2 + 4, self.ip): - print(" 0x%02x," % self.bytecode[i], end="") - print() - print(" // bytecode") - ip = self.ip - while ip < len(self.bytecode): - f, sz = mp_opcode_format(self.bytecode, ip) - opcode = self.bytecode[ip] - if opcode in opcode_names: - opcode = opcode_names[opcode] - else: - opcode = "0x%02x" % opcode - if f == 1: - qst = self._unpack_qstr(ip + 1).qstr_id - extra = "" if sz == 3 else " 0x%02x," % self.bytecode[ip + 3] - print(" {}, {} & 0xff, {} >> 8,{}".format(opcode, qst, qst, extra)) - else: - print( - " {},{}".format( - opcode, "".join(" 0x%02x," % self.bytecode[ip + i] for i in range(1, sz)) - ) - ) - ip += sz - print("};") + rc.freeze(self.escaped_name + "_") + def freeze_constants(self): # generate constant objects for i, obj in enumerate(self.objs): obj_name = "const_obj_%s_%u" % (self.escaped_name, i) - if obj is Ellipsis: + if obj is MPFunTable: + pass + elif obj is Ellipsis: print("#define %s mp_const_ellipsis_obj" % obj_name) elif is_str_type(obj) or is_bytes_type(obj): if is_str_type(obj): @@ -350,19 +359,15 @@ class RawCode: else: obj_type = "mp_type_bytes" print( - 'STATIC const mp_obj_str_t %s = {{&%s}, %u, %u, (const byte*)"%s"}; // %s' + 'STATIC const mp_obj_str_t %s = {{&%s}, %u, %u, (const byte*)"%s"};' % ( obj_name, obj_type, qstrutil.compute_hash(obj, config.MICROPY_QSTR_BYTES_IN_HASH), len(obj), "".join(("\\x%02x" % b) for b in obj), - obj, ) ) - sizes["strings"] += len(obj) - sizes["string_overhead"] += 16 - elif is_int_type(obj): if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_NONE: # TODO check if we can actually fit this long-int into a small-int @@ -385,10 +390,9 @@ class RawCode: digs = ",".join(("%#x" % d) for d in digs) print( "STATIC const mp_obj_int_t %s = {{&mp_type_int}, " - "{.neg=%u, .fixed_dig=1, .alloc=%u, .len=%u, .dig=(uint%u_t[]){%s}}};" - % (obj_name, neg, ndigs, ndigs, bits_per_dig, digs) + "{.neg=%u, .fixed_dig=1, .alloc=%u, .len=%u, .dig=(uint%u_t*)(const uint%u_t[]){%s}}};" + % (obj_name, neg, ndigs, ndigs, bits_per_dig, bits_per_dig, digs) ) - sizes["number_overhead"] += 16 elif type(obj) is float: print( "#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B" @@ -397,13 +401,11 @@ class RawCode: "STATIC const mp_obj_float_t %s = {{&mp_type_float}, %.16g};" % (obj_name, obj) ) print("#endif") - sizes["number_overhead"] += 8 elif type(obj) is complex: print( "STATIC const mp_obj_complex_t %s = {{&mp_type_complex}, %.16g, %.16g};" % (obj_name, obj.real, obj.imag) ) - sizes["number_overhead"] += 12 else: raise FreezeError(self, "freezing of object %r is not implemented" % (obj,)) @@ -415,11 +417,11 @@ class RawCode: % (self.escaped_name, const_table_len) ) for qst in self.qstrs: - sizes["const_table_overhead"] += 4 print(" MP_ROM_QSTR(%s)," % global_qstrs[qst].qstr_id) for i in range(len(self.objs)): - sizes["const_table_overhead"] += 4 - if type(self.objs[i]) is float: + if self.objs[i] is MPFunTable: + print(" mp_fun_table,") + elif type(self.objs[i]) is float: print( "#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B" ) @@ -436,54 +438,236 @@ class RawCode: else: print(" MP_ROM_PTR(&const_obj_%s_%u)," % (self.escaped_name, i)) for rc in self.raw_codes: - sizes["const_table_overhead"] += 4 print(" MP_ROM_PTR(&raw_code_%s)," % rc.escaped_name) print("};") + def freeze_module(self, qstr_links=(), type_sig=0): # generate module if self.simple_name.str != "": print("STATIC ", end="") print("const mp_raw_code_t raw_code_%s = {" % self.escaped_name) - print(" .kind = MP_CODE_BYTECODE,") + print(" .kind = %s," % RawCode.code_kind_str[self.code_kind]) print(" .scope_flags = 0x%02x," % self.prelude[2]) print(" .n_pos_args = %u," % self.prelude[3]) - print(" .data.u_byte = {") - print(" .bytecode = bytecode_data_%s," % self.escaped_name) - if const_table_len: - print(" .const_table = (mp_uint_t*)const_table_data_%s," % self.escaped_name) + print(" .fun_data = fun_data_%s," % self.escaped_name) + if len(self.qstrs) + len(self.objs) + len(self.raw_codes): + print(" .const_table = (mp_uint_t*)const_table_data_%s," % self.escaped_name) else: - print(" .const_table = NULL,") - print(" #if MICROPY_PERSISTENT_CODE_SAVE") - print(" .bc_len = %u," % len(self.bytecode)) - print(" .n_obj = %u," % len(self.objs)) - print(" .n_raw_code = %u," % len(self.raw_codes)) - print(" #endif") - print(" },") + print(" .const_table = NULL,") + print(" #if MICROPY_PERSISTENT_CODE_SAVE") + print(" .fun_data_len = %u," % len(self.bytecode)) + print(" .n_obj = %u," % len(self.objs)) + print(" .n_raw_code = %u," % len(self.raw_codes)) + print(" #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM") + print(" .prelude_offset = %u," % self.prelude_offset) + print(" .n_qstr = %u," % len(qstr_links)) + print(" .qstr_link = NULL,") # TODO + print(" #endif") + print(" #endif") + print(" #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM") + print(" .type_sig = %u," % type_sig) + print(" #endif") print("};") - sizes["raw_code_overhead"] += 16 - - return sizes -def read_uint(f): +class RawCodeBytecode(RawCode): + def __init__(self, bytecode, qstrs, objs, raw_codes): + super(RawCodeBytecode, self).__init__( + MP_CODE_BYTECODE, bytecode, 0, qstrs, objs, raw_codes + ) + + def freeze(self, parent_name): + self.freeze_children(parent_name) + + # generate bytecode data + print() + print( + "// frozen bytecode for file %s, scope %s%s" + % (self.source_file.str, parent_name, self.simple_name.str) + ) + print("STATIC ", end="") + if not config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE: + print("const ", end="") + print("byte fun_data_%s[%u] = {" % (self.escaped_name, len(self.bytecode))) + print(" ", end="") + for i in range(self.ip2): + print(" 0x%02x," % self.bytecode[i], end="") + print() + print(" ", self.simple_name.qstr_id, "& 0xff,", self.simple_name.qstr_id, ">> 8,") + print(" ", self.source_file.qstr_id, "& 0xff,", self.source_file.qstr_id, ">> 8,") + print(" ", end="") + for i in range(self.ip2 + 4, self.ip): + print(" 0x%02x," % self.bytecode[i], end="") + print() + ip = self.ip + while ip < len(self.bytecode): + f, sz = mp_opcode_format(self.bytecode, ip, True) + if f == 1: + qst = self._unpack_qstr(ip + 1).qstr_id + extra = "" if sz == 3 else " 0x%02x," % self.bytecode[ip + 3] + print(" ", "0x%02x," % self.bytecode[ip], qst, "& 0xff,", qst, ">> 8,", extra) + else: + print(" ", "".join("0x%02x, " % self.bytecode[ip + i] for i in range(sz))) + ip += sz + print("};") + + self.freeze_constants() + self.freeze_module() + + +class RawCodeNative(RawCode): + def __init__( + self, + code_kind, + fun_data, + prelude_offset, + prelude, + qstr_links, + qstrs, + objs, + raw_codes, + type_sig, + ): + super(RawCodeNative, self).__init__( + code_kind, fun_data, prelude_offset, qstrs, objs, raw_codes + ) + self.prelude = prelude + self.qstr_links = qstr_links + self.type_sig = type_sig + if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64): + self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",@progbits # ")))' + else: + self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",%progbits @ ")))' + + def _asm_thumb_rewrite_mov(self, pc, val): + print(" (%u & 0xf0) | (%s >> 12)," % (self.bytecode[pc], val), end="") + print(" (%u & 0xfb) | (%s >> 9 & 0x04)," % (self.bytecode[pc + 1], val), end="") + print(" (%s & 0xff)," % (val,), end="") + print(" (%u & 0x07) | (%s >> 4 & 0x70)," % (self.bytecode[pc + 3], val)) + + def _link_qstr(self, pc, kind, qst): + if kind == 0: + print(" %s & 0xff, %s >> 8," % (qst, qst)) + else: + if kind == 2: + qst = "((uintptr_t)MP_OBJ_NEW_QSTR(%s))" % qst + if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64): + print(" %s & 0xff, %s >> 8, 0, 0," % (qst, qst)) + elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP: + if is_obj: + self._asm_thumb_rewrite_mov(i, qst) + self._asm_thumb_rewrite_mov(i + 4, "(%s >> 16)" % qst) + else: + self._asm_thumb_rewrite_mov(i, qst) + else: + assert 0 + + def freeze(self, parent_name): + self.freeze_children(parent_name) + + # generate native code data + print() + if self.code_kind == MP_CODE_NATIVE_PY: + print( + "// frozen native code for file %s, scope %s%s" + % (self.source_file.str, parent_name, self.simple_name.str) + ) + elif self.code_kind == MP_CODE_NATIVE_VIPER: + print("// frozen viper code for scope %s" % (parent_name,)) + else: + print("// frozen assembler code for scope %s" % (parent_name,)) + print( + "STATIC const byte fun_data_%s[%u] %s = {" + % (self.escaped_name, len(self.bytecode), self.fun_data_attributes) + ) + + if self.code_kind == MP_CODE_NATIVE_PY: + i_top = self.prelude_offset + else: + i_top = len(self.bytecode) + i = 0 + qi = 0 + while i < i_top: + if qi < len(self.qstr_links) and i == self.qstr_links[qi][0]: + # link qstr + qi_off, qi_kind, qi_val = self.qstr_links[qi] + qst = global_qstrs[qi_val].qstr_id + self._link_qstr(i, qi_kind, qst) + i += 4 + qi += 1 + else: + # copy machine code (max 16 bytes) + i16 = min(i + 16, i_top) + if qi < len(self.qstr_links): + i16 = min(i16, self.qstr_links[qi][0]) + print(" ", end="") + for ii in range(i, i16): + print(" 0x%02x," % self.bytecode[ii], end="") + print() + i = i16 + + if self.code_kind == MP_CODE_NATIVE_PY: + print(" ", end="") + for i in range(self.prelude_offset, self.ip2): + print(" 0x%02x," % self.bytecode[i], end="") + print() + + print(" ", self.simple_name.qstr_id, "& 0xff,", self.simple_name.qstr_id, ">> 8,") + print(" ", self.source_file.qstr_id, "& 0xff,", self.source_file.qstr_id, ">> 8,") + + print(" ", end="") + for i in range(self.ip2 + 4, self.ip): + print(" 0x%02x," % self.bytecode[i], end="") + print() + + print("};") + + self.freeze_constants() + self.freeze_module(self.qstr_links, self.type_sig) + + +class BytecodeBuffer: + def __init__(self, size): + self.buf = bytearray(size) + self.idx = 0 + + def is_full(self): + return self.idx == len(self.buf) + + def append(self, b): + self.buf[self.idx] = b + self.idx += 1 + + +def read_byte(f, out=None): + b = bytes_cons(f.read(1))[0] + if out is not None: + out.append(b) + return b + + +def read_uint(f, out=None): i = 0 while True: - b = bytes_cons(f.read(1))[0] + b = read_byte(f, out) i = (i << 7) | (b & 0x7F) if b & 0x80 == 0: break return i -global_qstrs = [] -qstr_type = namedtuple("qstr", ("str", "qstr_esc", "qstr_id")) - - -def read_qstr(f): +def read_qstr(f, qstr_win): ln = read_uint(f) + if ln == 0: + # static qstr + return bytes_cons(f.read(1))[0] + if ln & 1: + # qstr in table + return qstr_win.access(ln >> 1) + ln >>= 1 data = str_cons(f.read(ln), "utf8") - qstr_esc = qstrutil.qstr_escape(data) - global_qstrs.append(qstr_type(data, qstr_esc, "MP_QSTR_" + qstr_esc)) + global_qstrs.append(QStrType(data)) + qstr_win.push(len(global_qstrs) - 1) return len(global_qstrs) - 1 @@ -507,33 +691,119 @@ def read_obj(f): assert 0 -def read_qstr_and_pack(f, bytecode, ip): - qst = read_qstr(f) - bytecode[ip] = qst & 0xFF - bytecode[ip + 1] = qst >> 8 +def read_prelude(f, bytecode): + n_state = read_uint(f, bytecode) + n_exc_stack = read_uint(f, bytecode) + scope_flags = read_byte(f, bytecode) + n_pos_args = read_byte(f, bytecode) + n_kwonly_args = read_byte(f, bytecode) + n_def_pos_args = read_byte(f, bytecode) + l1 = bytecode.idx + code_info_size = read_uint(f, bytecode) + l2 = bytecode.idx + for _ in range(code_info_size - (l2 - l1)): + read_byte(f, bytecode) + while read_byte(f, bytecode) != 255: + pass + return l2, ( + n_state, + n_exc_stack, + scope_flags, + n_pos_args, + n_kwonly_args, + n_def_pos_args, + code_info_size, + ) -def read_bytecode_qstrs(file, bytecode, ip): - while ip < len(bytecode): - f, sz = mp_opcode_format(bytecode, ip) - if f == 1: - read_qstr_and_pack(file, bytecode, ip + 1) - ip += sz +def read_qstr_and_pack(f, bytecode, qstr_win): + qst = read_qstr(f, qstr_win) + bytecode.append(qst & 0xFF) + bytecode.append(qst >> 8) -def read_raw_code(f): - bc_len = read_uint(f) - bytecode = bytearray(f.read(bc_len)) - ip, ip2, prelude = extract_prelude(bytecode) - read_qstr_and_pack(f, bytecode, ip2) # simple_name - read_qstr_and_pack(f, bytecode, ip2 + 2) # source_file - read_bytecode_qstrs(f, bytecode, ip) - n_obj = read_uint(f) - n_raw_code = read_uint(f) - qstrs = [read_qstr(f) for _ in range(prelude[3] + prelude[4])] - objs = [read_obj(f) for _ in range(n_obj)] - raw_codes = [read_raw_code(f) for _ in range(n_raw_code)] - return RawCode(bytecode, qstrs, objs, raw_codes) +def read_bytecode(file, bytecode, qstr_win): + while not bytecode.is_full(): + op = read_byte(file, bytecode) + f, sz = mp_opcode_format(bytecode.buf, bytecode.idx - 1, False) + sz -= 1 + if f == MP_OPCODE_QSTR: + read_qstr_and_pack(file, bytecode, qstr_win) + sz -= 2 + elif f == MP_OPCODE_VAR_UINT: + while read_byte(file, bytecode) & 0x80: + pass + for _ in range(sz): + read_byte(file, bytecode) + + +def read_raw_code(f, qstr_win): + kind_len = read_uint(f) + kind = (kind_len & 3) + MP_CODE_BYTECODE + fun_data_len = kind_len >> 2 + fun_data = BytecodeBuffer(fun_data_len) + + if kind == MP_CODE_BYTECODE: + name_idx, prelude = read_prelude(f, fun_data) + read_bytecode(f, fun_data, qstr_win) + else: + fun_data.buf[:] = f.read(fun_data_len) + + qstr_links = [] + if kind in (MP_CODE_NATIVE_PY, MP_CODE_NATIVE_VIPER): + # load qstr link table + n_qstr_link = read_uint(f) + for _ in range(n_qstr_link): + off = read_uint(f, qstr_win) + qst = read_qstr(f, qstr_win) + qstr_links.append((off >> 2, off & 3, qst)) + + type_sig = 0 + if kind == MP_CODE_NATIVE_PY: + prelude_offset = read_uint(f) + _, name_idx, prelude = extract_prelude(fun_data.buf, prelude_offset) + else: + prelude_offset = None + scope_flags = read_uint(f) + n_pos_args = 0 + if kind == MP_CODE_NATIVE_ASM: + n_pos_args = read_uint(f) + type_sig = read_uint(f) + prelude = (None, None, scope_flags, n_pos_args, 0) + + if kind in (MP_CODE_BYTECODE, MP_CODE_NATIVE_PY): + fun_data.idx = name_idx # rewind to where qstrs are in prelude + read_qstr_and_pack(f, fun_data, qstr_win) # simple_name + read_qstr_and_pack(f, fun_data, qstr_win) # source_file + + qstrs = [] + objs = [] + raw_codes = [] + if kind != MP_CODE_NATIVE_ASM: + # load constant table + n_obj = read_uint(f) + n_raw_code = read_uint(f) + qstrs = [read_qstr(f, qstr_win) for _ in range(prelude[3] + prelude[4])] + if kind != MP_CODE_BYTECODE: + objs.append(MPFunTable) + objs.extend([read_obj(f) for _ in range(n_obj)]) + raw_codes = [read_raw_code(f, qstr_win) for _ in range(n_raw_code)] + + if kind == MP_CODE_BYTECODE: + return RawCodeBytecode(fun_data.buf, qstrs, objs, raw_codes) + else: + return RawCodeNative( + kind, + fun_data.buf, + prelude_offset, + prelude, + qstr_links, + qstrs, + objs, + raw_codes, + type_sig, + ) + def read_mpy(filename): @@ -543,11 +813,15 @@ def read_mpy(filename): raise Exception("not a valid .mpy file") if header[1] != config.MPY_VERSION: raise Exception("incompatible .mpy version") - feature_flags = header[2] - config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = (feature_flags & 1) != 0 - config.MICROPY_PY_BUILTINS_STR_UNICODE = (feature_flags & 2) != 0 + feature_byte = header[2] + qw_size = read_uint(f) + config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = (feature_byte & 1) != 0 + config.MICROPY_PY_BUILTINS_STR_UNICODE = (feature_byte & 2) != 0 + config.native_arch = feature_byte >> 2 config.mp_small_int_bits = header[3] - return read_raw_code(f) + qstr_win = QStrWindow(qw_size) + return read_raw_code(f, qstr_win) + def dump_mpy(raw_codes): @@ -560,7 +834,7 @@ def freeze_mpy(base_qstrs, raw_codes): new = {} for q in global_qstrs: # don't add duplicates - if q.qstr_esc in base_qstrs or q.qstr_esc in new: + if q is None or q.qstr_esc in base_qstrs or q.qstr_esc in new: continue new[q.qstr_esc] = (len(new), q.qstr_esc, q.str) new = sorted(new.values(), key=lambda x: x[0]) @@ -608,13 +882,14 @@ def freeze_mpy(base_qstrs, raw_codes): print("#endif") print() - print("enum {") - for i in range(len(new)): - if i == 0: - print(" MP_QSTR_%s = MP_QSTRnumber_of," % new[i][1]) - else: - print(" MP_QSTR_%s," % new[i][1]) - print("};") + if new: + print("enum {") + for i in range(len(new)): + if i == 0: + print(" MP_QSTR_%s = MP_QSTRnumber_of," % new[i][1]) + else: + print(" MP_QSTR_%s," % new[i][1]) + print("};") print() print("const qstr_attr_t mp_qstr_frozen_const_attr[] = {") @@ -648,9 +923,8 @@ def freeze_mpy(base_qstrs, raw_codes): print(" },") print("};") - sizes = {} for rc in raw_codes: - sizes[rc.source_file.str] = rc.freeze(rc.source_file.str.replace("/", "_")[:-3] + "_") + rc.freeze(rc.source_file.str.replace("/", "_")[:-3] + "_") print() print("const char mp_frozen_mpy_names[] = {") @@ -664,22 +938,8 @@ def freeze_mpy(base_qstrs, raw_codes): print("const mp_raw_code_t *const mp_frozen_mpy_content[] = {") for rc in raw_codes: print(" &raw_code_%s," % rc.escaped_name) - size = sizes[rc.source_file.str] - print(" // Total size:", sum(size.values())) - for k in size: - print(" // {} {}".format(k, size[k])) print("};") - print() - print( - "// Total size:", sum([sum(x.values()) for x in sizes.values()]) + sum(qstr_size.values()) - ) - for k in size: - total = sum([x[k] for x in sizes.values()]) - print("// {} {}".format(k, total)) - for k in qstr_size: - print("// qstr {} {}".format(k, qstr_size[k])) - def main(): import argparse diff --git a/tools/pyboard.py b/tools/pyboard.py index 200f4578a4..908448da75 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -28,6 +28,7 @@ Or: Then: pyb.enter_raw_repl() + pyb.exec('import pyb') pyb.exec('pyb.LED(1).on()') pyb.exit_raw_repl() @@ -267,6 +268,9 @@ class Pyboard: self.serial.close() def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None): + # if data_consumer is used then data is not accumulated and the ending must be 1 byte long + assert data_consumer is None or len(ending) == 1 + data = self.serial.read(min_num_bytes) if data_consumer: data_consumer(data) @@ -276,9 +280,11 @@ class Pyboard: break elif self.serial.inWaiting() > 0: new_data = self.serial.read(1) - data = data + new_data if data_consumer: data_consumer(new_data) + data = new_data + else: + data = data + new_data timeout_count = 0 else: timeout_count += 1 diff --git a/tools/upip.py b/tools/upip.py index a7187e700d..212cd26d0b 100644 --- a/tools/upip.py +++ b/tools/upip.py @@ -17,6 +17,7 @@ gc.collect() debug = False +index_urls = ["https://micropython.org/pi", "https://pypi.org/pypi"] install_path = None cleanup_files = [] gzdict_sz = 16 + 15 @@ -60,7 +61,7 @@ def _makedirs(name, mode=0o777): ret = True except OSError as e: if e.args[0] != errno.EEXIST and e.args[0] != errno.EISDIR: - raise + raise e ret = False return ret @@ -167,11 +168,16 @@ def url_open(url): def get_pkg_metadata(name): - f = url_open("https://pypi.org/pypi/%s/json" % name) - try: - return json.load(f) - finally: - f.close() + for url in index_urls: + try: + f = url_open("%s/%s/json" % (url, name)) + except NotFoundError: + continue + try: + return json.load(f) + finally: + f.close() + raise NotFoundError("Package not found") def fatal(msg, exc=None): @@ -283,6 +289,7 @@ for installation, upip does not support arbitrary code in setup.py. def main(): global debug + global index_urls global install_path install_path = None @@ -316,6 +323,9 @@ def main(): if l[0] == "#": continue to_install.append(l.rstrip()) + elif opt == "-i": + index_urls = [sys.argv[i]] + i += 1 elif opt == "--debug": debug = True else: